summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/androidfw/.clang-format5
-rw-r--r--libs/androidfw/ResourceTypes.cpp85
-rw-r--r--libs/androidfw/tests/Idmap_test.cpp100
-rw-r--r--libs/androidfw/tests/data/overlay/overlay.apkbin1254 -> 2442 bytes
-rw-r--r--libs/androidfw/tests/data/overlay/res/values/values.xml2
-rw-r--r--libs/hwui/SkiaCanvas.cpp39
-rw-r--r--libs/hwui/SkiaCanvasProxy.cpp17
-rw-r--r--libs/hwui/SkiaCanvasProxy.h5
-rw-r--r--libs/hwui/VectorDrawable.cpp163
-rw-r--r--libs/hwui/VectorDrawable.h25
-rw-r--r--libs/hwui/tests/unit/FatalTestCanvas.h4
-rw-r--r--libs/hwui/tests/unit/VectorDrawableTests.cpp47
12 files changed, 204 insertions, 288 deletions
diff --git a/libs/androidfw/.clang-format b/libs/androidfw/.clang-format
index ee1bee2bc644..c91502a257f3 100644
--- a/libs/androidfw/.clang-format
+++ b/libs/androidfw/.clang-format
@@ -1,2 +1,7 @@
BasedOnStyle: Google
ColumnLimit: 100
+AllowShortBlocksOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+PointerAlignment: Left
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 359cface8b7f..244c52577a1a 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -6431,32 +6431,42 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
}
if (newEntryCount > 0) {
+ bool addToType = true;
uint8_t typeIndex = typeSpec->id - 1;
ssize_t idmapIndex = idmapEntries.indexOfKey(typeSpec->id);
if (idmapIndex >= 0) {
typeIndex = idmapEntries[idmapIndex].targetTypeId() - 1;
+ } else if (header->resourceIDMap != NULL) {
+ // This is an overlay, but the types in this overlay are not
+ // overlaying anything according to the idmap. We can skip these
+ // as they will otherwise conflict with the other resources in the package
+ // without a mapping.
+ addToType = false;
}
- TypeList& typeList = group->types.editItemAt(typeIndex);
- if (!typeList.isEmpty()) {
- const Type* existingType = typeList[0];
- if (existingType->entryCount != newEntryCount && idmapIndex < 0) {
- ALOGW("ResTable_typeSpec entry count inconsistent: given %d, previously %d",
- (int) newEntryCount, (int) existingType->entryCount);
- // We should normally abort here, but some legacy apps declare
- // resources in the 'android' package (old bug in AAPT).
+ if (addToType) {
+ TypeList& typeList = group->types.editItemAt(typeIndex);
+ if (!typeList.isEmpty()) {
+ const Type* existingType = typeList[0];
+ if (existingType->entryCount != newEntryCount && idmapIndex < 0) {
+ ALOGW("ResTable_typeSpec entry count inconsistent: "
+ "given %d, previously %d",
+ (int) newEntryCount, (int) existingType->entryCount);
+ // We should normally abort here, but some legacy apps declare
+ // resources in the 'android' package (old bug in AAPT).
+ }
}
- }
- Type* t = new Type(header, package, newEntryCount);
- t->typeSpec = typeSpec;
- t->typeSpecFlags = (const uint32_t*)(
- ((const uint8_t*)typeSpec) + dtohs(typeSpec->header.headerSize));
- if (idmapIndex >= 0) {
- t->idmapEntries = idmapEntries[idmapIndex];
+ Type* t = new Type(header, package, newEntryCount);
+ t->typeSpec = typeSpec;
+ t->typeSpecFlags = (const uint32_t*)(
+ ((const uint8_t*)typeSpec) + dtohs(typeSpec->header.headerSize));
+ if (idmapIndex >= 0) {
+ t->idmapEntries = idmapEntries[idmapIndex];
+ }
+ typeList.add(t);
+ group->largestTypeId = max(group->largestTypeId, typeSpec->id);
}
- typeList.add(t);
- group->largestTypeId = max(group->largestTypeId, typeSpec->id);
} else {
ALOGV("Skipping empty ResTable_typeSpec for type %d", typeSpec->id);
}
@@ -6499,31 +6509,40 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
}
if (newEntryCount > 0) {
+ bool addToType = true;
uint8_t typeIndex = type->id - 1;
ssize_t idmapIndex = idmapEntries.indexOfKey(type->id);
if (idmapIndex >= 0) {
typeIndex = idmapEntries[idmapIndex].targetTypeId() - 1;
+ } else if (header->resourceIDMap != NULL) {
+ // This is an overlay, but the types in this overlay are not
+ // overlaying anything according to the idmap. We can skip these
+ // as they will otherwise conflict with the other resources in the package
+ // without a mapping.
+ addToType = false;
}
- TypeList& typeList = group->types.editItemAt(typeIndex);
- if (typeList.isEmpty()) {
- ALOGE("No TypeSpec for type %d", type->id);
- return (mError=BAD_TYPE);
- }
+ if (addToType) {
+ TypeList& typeList = group->types.editItemAt(typeIndex);
+ if (typeList.isEmpty()) {
+ ALOGE("No TypeSpec for type %d", type->id);
+ return (mError=BAD_TYPE);
+ }
- Type* t = typeList.editItemAt(typeList.size() - 1);
- if (t->package != package) {
- ALOGE("No TypeSpec for type %d", type->id);
- return (mError=BAD_TYPE);
- }
+ Type* t = typeList.editItemAt(typeList.size() - 1);
+ if (t->package != package) {
+ ALOGE("No TypeSpec for type %d", type->id);
+ return (mError=BAD_TYPE);
+ }
- t->configs.add(type);
+ t->configs.add(type);
- if (kDebugTableGetEntry) {
- ResTable_config thisConfig;
- thisConfig.copyFromDtoH(type->config);
- ALOGI("Adding config to type %d: %s\n", type->id,
- thisConfig.toString().string());
+ if (kDebugTableGetEntry) {
+ ResTable_config thisConfig;
+ thisConfig.copyFromDtoH(type->config);
+ ALOGI("Adding config to type %d: %s\n", type->id,
+ thisConfig.toString().string());
+ }
}
} else {
ALOGV("Skipping empty ResTable_type for type %d", type->id);
diff --git a/libs/androidfw/tests/Idmap_test.cpp b/libs/androidfw/tests/Idmap_test.cpp
index 0928b1b976c3..d12be184745c 100644
--- a/libs/androidfw/tests/Idmap_test.cpp
+++ b/libs/androidfw/tests/Idmap_test.cpp
@@ -30,25 +30,23 @@ class IdmapTest : public ::testing::Test {
protected:
void SetUp() override {
std::string contents;
- ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk",
- "resources.arsc", &contents));
- ASSERT_EQ(NO_ERROR,
- target_table_.add(contents.data(), contents.size(), 0, true));
-
- ASSERT_TRUE(
- ReadFileFromZipToString(GetTestDataPath() + "/overlay/overlay.apk",
- "resources.arsc", &overlay_data_));
+ ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc",
+ &contents));
+ ASSERT_EQ(NO_ERROR, target_table_.add(contents.data(), contents.size(), 0, true));
+
+ ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlay/overlay.apk",
+ "resources.arsc", &overlay_data_));
ResTable overlay_table;
- ASSERT_EQ(NO_ERROR,
- overlay_table.add(overlay_data_.data(), overlay_data_.size()));
+ ASSERT_EQ(NO_ERROR, overlay_table.add(overlay_data_.data(), overlay_data_.size()));
char target_name[256] = "com.android.basic";
- ASSERT_EQ(NO_ERROR,
- target_table_.createIdmap(overlay_table, 0, 0, target_name,
- target_name, &data_, &data_size_));
+ ASSERT_EQ(NO_ERROR, target_table_.createIdmap(overlay_table, 0, 0, target_name, target_name,
+ &data_, &data_size_));
}
- void TearDown() override { ::free(data_); }
+ void TearDown() override {
+ ::free(data_);
+ }
ResTable target_table_;
std::string overlay_data_;
@@ -56,13 +54,12 @@ class IdmapTest : public ::testing::Test {
size_t data_size_ = 0;
};
-TEST_F(IdmapTest, canLoadIdmap) {
+TEST_F(IdmapTest, CanLoadIdmap) {
ASSERT_EQ(NO_ERROR,
- target_table_.add(overlay_data_.data(), overlay_data_.size(), data_,
- data_size_));
+ target_table_.add(overlay_data_.data(), overlay_data_.size(), data_, data_size_));
}
-TEST_F(IdmapTest, overlayOverridesResourceValue) {
+TEST_F(IdmapTest, OverlayOverridesResourceValue) {
Res_value val;
ssize_t block = target_table_.getResource(R::string::test2, &val, false);
ASSERT_GE(block, 0);
@@ -71,45 +68,60 @@ TEST_F(IdmapTest, overlayOverridesResourceValue) {
ASSERT_TRUE(pool != NULL);
ASSERT_LT(val.data, pool->size());
- size_t strLen;
- const char16_t* targetStr16 = pool->stringAt(val.data, &strLen);
- ASSERT_TRUE(targetStr16 != NULL);
- ASSERT_EQ(String16("test2"), String16(targetStr16, strLen));
+ size_t str_len;
+ const char16_t* target_str16 = pool->stringAt(val.data, &str_len);
+ ASSERT_TRUE(target_str16 != NULL);
+ ASSERT_EQ(String16("test2"), String16(target_str16, str_len));
ASSERT_EQ(NO_ERROR,
- target_table_.add(overlay_data_.data(), overlay_data_.size(), data_,
- data_size_));
+ target_table_.add(overlay_data_.data(), overlay_data_.size(), data_, data_size_));
- ssize_t newBlock = target_table_.getResource(R::string::test2, &val, false);
- ASSERT_GE(newBlock, 0);
- ASSERT_NE(block, newBlock);
+ ssize_t new_block = target_table_.getResource(R::string::test2, &val, false);
+ ASSERT_GE(new_block, 0);
+ ASSERT_NE(block, new_block);
ASSERT_EQ(Res_value::TYPE_STRING, val.dataType);
- pool = target_table_.getTableStringBlock(newBlock);
+ pool = target_table_.getTableStringBlock(new_block);
ASSERT_TRUE(pool != NULL);
ASSERT_LT(val.data, pool->size());
- targetStr16 = pool->stringAt(val.data, &strLen);
- ASSERT_TRUE(targetStr16 != NULL);
- ASSERT_EQ(String16("test2-overlay"), String16(targetStr16, strLen));
+ target_str16 = pool->stringAt(val.data, &str_len);
+ ASSERT_TRUE(target_str16 != NULL);
+ ASSERT_EQ(String16("test2-overlay"), String16(target_str16, str_len));
}
-TEST_F(IdmapTest, overlaidResourceHasSameName) {
+TEST_F(IdmapTest, OverlaidResourceHasSameName) {
ASSERT_EQ(NO_ERROR,
- target_table_.add(overlay_data_.data(), overlay_data_.size(), data_,
- data_size_));
+ target_table_.add(overlay_data_.data(), overlay_data_.size(), data_, data_size_));
+
+ ResTable::resource_name res_name;
+ ASSERT_TRUE(target_table_.getResourceName(R::array::integerArray1, false, &res_name));
+
+ ASSERT_TRUE(res_name.package != NULL);
+ ASSERT_TRUE(res_name.type != NULL);
+ ASSERT_TRUE(res_name.name != NULL);
+
+ EXPECT_EQ(String16("com.android.basic"), String16(res_name.package, res_name.packageLen));
+ EXPECT_EQ(String16("array"), String16(res_name.type, res_name.typeLen));
+ EXPECT_EQ(String16("integerArray1"), String16(res_name.name, res_name.nameLen));
+}
- ResTable::resource_name resName;
- ASSERT_TRUE(
- target_table_.getResourceName(R::array::integerArray1, false, &resName));
+constexpr const uint32_t kNonOverlaidResourceId = 0x7fff0000u;
- ASSERT_TRUE(resName.package != NULL);
- ASSERT_TRUE(resName.type != NULL);
- ASSERT_TRUE(resName.name != NULL);
+TEST_F(IdmapTest, OverlayDoesNotIncludeNonOverlaidResources) {
+ // First check that the resource we're trying to not include when overlaid is present when
+ // the overlay is loaded as a standalone APK.
+ ResTable table;
+ ASSERT_EQ(NO_ERROR, table.add(overlay_data_.data(), overlay_data_.size(), 0, true));
- EXPECT_EQ(String16("com.android.basic"),
- String16(resName.package, resName.packageLen));
- EXPECT_EQ(String16("array"), String16(resName.type, resName.typeLen));
- EXPECT_EQ(String16("integerArray1"), String16(resName.name, resName.nameLen));
+ Res_value val;
+ ssize_t block = table.getResource(kNonOverlaidResourceId, &val, false /*mayBeBag*/);
+ ASSERT_GE(block, 0);
+
+ // Now add the overlay and verify that the unoverlaid resource is gone.
+ ASSERT_EQ(NO_ERROR,
+ target_table_.add(overlay_data_.data(), overlay_data_.size(), data_, data_size_));
+ block = target_table_.getResource(kNonOverlaidResourceId, &val, false /*mayBeBag*/);
+ ASSERT_LT(block, 0);
}
} // namespace
diff --git a/libs/androidfw/tests/data/overlay/overlay.apk b/libs/androidfw/tests/data/overlay/overlay.apk
index e0e054343601..40bf17c5951a 100644
--- a/libs/androidfw/tests/data/overlay/overlay.apk
+++ b/libs/androidfw/tests/data/overlay/overlay.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/overlay/res/values/values.xml b/libs/androidfw/tests/data/overlay/res/values/values.xml
index 3e1af9878429..8e4417e457d1 100644
--- a/libs/androidfw/tests/data/overlay/res/values/values.xml
+++ b/libs/androidfw/tests/data/overlay/res/values/values.xml
@@ -20,4 +20,6 @@
<item>10</item>
<item>11</item>
</integer-array>
+ <public type="animator" name="unoverlaid" id="0x7fff0000" />
+ <item type="animator" name="unoverlaid">@null</item>
</resources>
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 812e4d885b39..daf14af87288 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -522,8 +522,10 @@ void SkiaCanvas::drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount,
SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid");
#endif
const int ptCount = vertexCount >> 1;
- mCanvas->drawVertices(vertexMode, ptCount, (SkPoint*)verts, (SkPoint*)texs,
- (SkColor*)colors, indices, indexCount, paint);
+ mCanvas->drawVertices(SkVertices::MakeCopy(vertexMode, ptCount, (SkPoint*)verts,
+ (SkPoint*)texs, (SkColor*)colors,
+ indexCount, indices),
+ SkBlendMode::kModulate, paint);
}
// ----------------------------------------------------------------------------
@@ -560,23 +562,17 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& hwuiBitmap, int meshWidth, int meshHeigh
hwuiBitmap.getSkBitmap(&bitmap);
const int ptCount = (meshWidth + 1) * (meshHeight + 1);
const int indexCount = meshWidth * meshHeight * 6;
-
- /* Our temp storage holds 2 or 3 arrays.
- texture points [ptCount * sizeof(SkPoint)]
- optionally vertex points [ptCount * sizeof(SkPoint)] if we need a
- copy to convert from float to fixed
- indices [ptCount * sizeof(uint16_t)]
- */
- ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[]
- storageSize += indexCount * sizeof(uint16_t); // indices[]
-
-
-#ifndef SK_SCALAR_IS_FLOAT
- SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid");
-#endif
- std::unique_ptr<char[]> storage(new char[storageSize]);
- SkPoint* texs = (SkPoint*)storage.get();
- uint16_t* indices = (uint16_t*)(texs + ptCount);
+ uint32_t flags = SkVertices::kHasTexCoords_BuilderFlag;
+ if (colors) {
+ flags |= SkVertices::kHasColors_BuilderFlag;
+ }
+ SkVertices::Builder builder(SkCanvas::kTriangles_VertexMode, ptCount, indexCount, flags);
+ memcpy(builder.positions(), vertices, ptCount * sizeof(SkPoint));
+ if (colors) {
+ memcpy(builder.colors(), colors, ptCount * sizeof(SkColor));
+ }
+ SkPoint* texs = builder.texCoords();
+ uint16_t* indices = builder.indices();
// cons up texture coordinates and indices
{
@@ -625,7 +621,6 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& hwuiBitmap, int meshWidth, int meshHeigh
index += 1;
}
SkASSERT(indexPtr - indices == indexCount);
- SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize);
}
// double-check that we have legal indices
@@ -646,9 +641,7 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& hwuiBitmap, int meshWidth, int meshHeigh
sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
tmpPaint.setShader(image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode));
- mCanvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, (SkPoint*)vertices,
- texs, (const SkColor*)colors, indices,
- indexCount, tmpPaint);
+ mCanvas->drawVertices(builder.detach(), SkBlendMode::kModulate, tmpPaint);
}
void SkiaCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk,
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
index 20ca80b95465..f6e92dca2bb9 100644
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -31,6 +31,7 @@
#include <SkRSXform.h>
#include <SkSurface.h>
#include <SkTextBlobRunIterator.h>
+#include <SkVertices.h>
namespace android {
namespace uirenderer {
@@ -180,20 +181,20 @@ void SkiaCanvasProxy::onDrawImageLattice(const SkImage* image, const Lattice& la
}
}
-void SkiaCanvasProxy::onDrawVertices(VertexMode mode, int vertexCount, const SkPoint vertices[],
- const SkPoint texs[], const SkColor colors[], SkBlendMode, const uint16_t indices[],
- int indexCount, const SkPaint& paint) {
+void SkiaCanvasProxy::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
+ const SkPaint& paint) {
// TODO: should we pass through blendmode
if (mFilterHwuiCalls) {
return;
}
// convert the SkPoints into floats
static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
- const int floatCount = vertexCount << 1;
- const float* vArray = &vertices[0].fX;
- const float* tArray = (texs) ? &texs[0].fX : NULL;
- const int* cArray = (colors) ? (int*)colors : NULL;
- mCanvas->drawVertices(mode, floatCount, vArray, tArray, cArray, indices, indexCount, paint);
+ const int floatCount = vertices->vertexCount() << 1;
+ const float* vArray = (const float*)vertices->positions();
+ const float* tArray = (const float*)vertices->texCoords();
+ const int* cArray = (const int*)vertices->colors();
+ mCanvas->drawVertices(vertices->mode(), floatCount, vArray, tArray, cArray,
+ vertices->indices(), vertices->indexCount(), paint);
}
sk_sp<SkSurface> SkiaCanvasProxy::onNewSurface(const SkImageInfo&, const SkSurfaceProps&) {
diff --git a/libs/hwui/SkiaCanvasProxy.h b/libs/hwui/SkiaCanvasProxy.h
index 3b1dd7383f36..d11a779b3600 100644
--- a/libs/hwui/SkiaCanvasProxy.h
+++ b/libs/hwui/SkiaCanvasProxy.h
@@ -75,10 +75,7 @@ protected:
const SkPaint*);
virtual void onDrawImageLattice(const SkImage*, const Lattice& lattice, const SkRect& dst,
const SkPaint*);
- virtual void onDrawVertices(VertexMode, int vertexCount, const SkPoint vertices[],
- const SkPoint texs[], const SkColor colors[], SkBlendMode,
- const uint16_t indices[], int indexCount,
- const SkPaint&) override;
+ virtual void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
virtual void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 68d3dd5efb79..8823a9212958 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -33,65 +33,10 @@ namespace VectorDrawable {
const int Tree::MAX_CACHED_BITMAP_SIZE = 2048;
-void Path::draw(SkCanvas* outCanvas, const SkMatrix& groupStackedMatrix, float scaleX, float scaleY,
- bool useStagingData) {
- float matrixScale = getMatrixScale(groupStackedMatrix);
- if (matrixScale == 0) {
- // When either x or y is scaled to 0, we don't need to draw anything.
- return;
- }
-
- SkMatrix pathMatrix(groupStackedMatrix);
- pathMatrix.postScale(scaleX, scaleY);
-
- //TODO: try apply the path matrix to the canvas instead of creating a new path.
- SkPath renderPath;
- renderPath.reset();
-
- if (useStagingData) {
- SkPath tmpPath;
- getStagingPath(&tmpPath);
- renderPath.addPath(tmpPath, pathMatrix);
- } else {
- renderPath.addPath(getUpdatedPath(), pathMatrix);
- }
-
- float minScale = fmin(scaleX, scaleY);
- float strokeScale = minScale * matrixScale;
- drawPath(outCanvas, renderPath, strokeScale, pathMatrix, useStagingData);
-}
-
void Path::dump() {
ALOGD("Path: %s has %zu points", mName.c_str(), mProperties.getData().points.size());
}
-float Path::getMatrixScale(const SkMatrix& groupStackedMatrix) {
- // Given unit vectors A = (0, 1) and B = (1, 0).
- // After matrix mapping, we got A' and B'. Let theta = the angel b/t A' and B'.
- // Therefore, the final scale we want is min(|A'| * sin(theta), |B'| * sin(theta)),
- // which is (|A'| * |B'| * sin(theta)) / max (|A'|, |B'|);
- // If max (|A'|, |B'|) = 0, that means either x or y has a scale of 0.
- //
- // For non-skew case, which is most of the cases, matrix scale is computing exactly the
- // scale on x and y axis, and take the minimal of these two.
- // For skew case, an unit square will mapped to a parallelogram. And this function will
- // return the minimal height of the 2 bases.
- SkVector skVectors[2];
- skVectors[0].set(0, 1);
- skVectors[1].set(1, 0);
- groupStackedMatrix.mapVectors(skVectors, 2);
- float scaleX = hypotf(skVectors[0].fX, skVectors[0].fY);
- float scaleY = hypotf(skVectors[1].fX, skVectors[1].fY);
- float crossProduct = skVectors[0].cross(skVectors[1]);
- float maxScale = fmax(scaleX, scaleY);
-
- float matrixScale = 0;
- if (maxScale > 0) {
- matrixScale = fabs(crossProduct) / maxScale;
- }
- return matrixScale;
-}
-
// Called from UI thread during the initial setup/theme change.
Path::Path(const char* pathStr, size_t strLength) {
PathParser::ParseResult result;
@@ -104,18 +49,19 @@ Path::Path(const Path& path) : Node(path) {
mStagingProperties.syncProperties(path.mStagingProperties);
}
-const SkPath& Path::getUpdatedPath() {
- if (mSkPathDirty) {
- mSkPath.reset();
- VectorDrawableUtils::verbsToPath(&mSkPath, mProperties.getData());
- mSkPathDirty = false;
+const SkPath& Path::getUpdatedPath(bool useStagingData, SkPath* tempStagingPath) {
+ if (useStagingData) {
+ tempStagingPath->reset();
+ VectorDrawableUtils::verbsToPath(tempStagingPath, mStagingProperties.getData());
+ return *tempStagingPath;
+ } else {
+ if (mSkPathDirty) {
+ mSkPath.reset();
+ VectorDrawableUtils::verbsToPath(&mSkPath, mProperties.getData());
+ mSkPathDirty = false;
+ }
+ return mSkPath;
}
- return mSkPath;
-}
-
-void Path::getStagingPath(SkPath* outPath) {
- outPath->reset();
- VectorDrawableUtils::verbsToPath(outPath, mStagingProperties.getData());
}
void Path::syncProperties() {
@@ -157,26 +103,35 @@ static void applyTrim(SkPath* outPath, const SkPath& inPath, float trimPathStart
}
}
-const SkPath& FullPath::getUpdatedPath() {
- if (!mSkPathDirty && !mProperties.mTrimDirty) {
+const SkPath& FullPath::getUpdatedPath(bool useStagingData, SkPath* tempStagingPath) {
+ if (!useStagingData && !mSkPathDirty && !mProperties.mTrimDirty) {
return mTrimmedSkPath;
}
- Path::getUpdatedPath();
- if (mProperties.getTrimPathStart() != 0.0f || mProperties.getTrimPathEnd() != 1.0f) {
- mProperties.mTrimDirty = false;
- applyTrim(&mTrimmedSkPath, mSkPath, mProperties.getTrimPathStart(),
- mProperties.getTrimPathEnd(), mProperties.getTrimPathOffset());
- return mTrimmedSkPath;
+ Path::getUpdatedPath(useStagingData, tempStagingPath);
+ SkPath *outPath;
+ if (useStagingData) {
+ SkPath inPath = *tempStagingPath;
+ applyTrim(tempStagingPath, inPath, mStagingProperties.getTrimPathStart(),
+ mStagingProperties.getTrimPathEnd(), mStagingProperties.getTrimPathOffset());
+ outPath = tempStagingPath;
} else {
- return mSkPath;
+ if (mProperties.getTrimPathStart() != 0.0f || mProperties.getTrimPathEnd() != 1.0f) {
+ mProperties.mTrimDirty = false;
+ applyTrim(&mTrimmedSkPath, mSkPath, mProperties.getTrimPathStart(),
+ mProperties.getTrimPathEnd(), mProperties.getTrimPathOffset());
+ outPath = &mTrimmedSkPath;
+ } else {
+ outPath = &mSkPath;
+ }
}
-}
-
-void FullPath::getStagingPath(SkPath* outPath) {
- Path::getStagingPath(outPath);
- SkPath inPath = *outPath;
- applyTrim(outPath, inPath, mStagingProperties.getTrimPathStart(),
- mStagingProperties.getTrimPathEnd(), mStagingProperties.getTrimPathOffset());
+ const FullPathProperties& properties = useStagingData ? mStagingProperties : mProperties;
+ bool setFillPath = properties.getFillGradient() != nullptr
+ || properties.getFillColor() != SK_ColorTRANSPARENT;
+ if (setFillPath) {
+ SkPath::FillType ft = static_cast<SkPath::FillType>(properties.getFillType());
+ outPath->setFillType(ft);
+ }
+ return *outPath;
}
void FullPath::dump() {
@@ -192,16 +147,17 @@ inline SkColor applyAlpha(SkColor color, float alpha) {
return SkColorSetA(color, alphaBytes * alpha);
}
-void FullPath::drawPath(SkCanvas* outCanvas, SkPath& renderPath, float strokeScale,
- const SkMatrix& matrix, bool useStagingData){
+void FullPath::draw(SkCanvas* outCanvas, bool useStagingData) {
const FullPathProperties& properties = useStagingData ? mStagingProperties : mProperties;
+ SkPath tempStagingPath;
+ const SkPath& renderPath = getUpdatedPath(useStagingData, &tempStagingPath);
// Draw path's fill, if fill color or gradient is valid
bool needsFill = false;
SkPaint paint;
if (properties.getFillGradient() != nullptr) {
paint.setColor(applyAlpha(SK_ColorBLACK, properties.getFillAlpha()));
- paint.setShader(properties.getFillGradient()->makeWithLocalMatrix(matrix));
+ paint.setShader(sk_sp<SkShader>(SkSafeRef(properties.getFillGradient())));
needsFill = true;
} else if (properties.getFillColor() != SK_ColorTRANSPARENT) {
paint.setColor(applyAlpha(properties.getFillColor(), properties.getFillAlpha()));
@@ -211,8 +167,6 @@ void FullPath::drawPath(SkCanvas* outCanvas, SkPath& renderPath, float strokeSca
if (needsFill) {
paint.setStyle(SkPaint::Style::kFill_Style);
paint.setAntiAlias(true);
- SkPath::FillType ft = static_cast<SkPath::FillType>(properties.getFillType());
- renderPath.setFillType(ft);
outCanvas->drawPath(renderPath, paint);
}
@@ -220,7 +174,7 @@ void FullPath::drawPath(SkCanvas* outCanvas, SkPath& renderPath, float strokeSca
bool needsStroke = false;
if (properties.getStrokeGradient() != nullptr) {
paint.setColor(applyAlpha(SK_ColorBLACK, properties.getStrokeAlpha()));
- paint.setShader(properties.getStrokeGradient()->makeWithLocalMatrix(matrix));
+ paint.setShader(sk_sp<SkShader>(SkSafeRef(properties.getStrokeGradient())));
needsStroke = true;
} else if (properties.getStrokeColor() != SK_ColorTRANSPARENT) {
paint.setColor(applyAlpha(properties.getStrokeColor(), properties.getStrokeAlpha()));
@@ -232,7 +186,7 @@ void FullPath::drawPath(SkCanvas* outCanvas, SkPath& renderPath, float strokeSca
paint.setStrokeJoin(SkPaint::Join(properties.getStrokeLineJoin()));
paint.setStrokeCap(SkPaint::Cap(properties.getStrokeLineCap()));
paint.setStrokeMiter(properties.getStrokeMiterLimit());
- paint.setStrokeWidth(properties.getStrokeWidth() * strokeScale);
+ paint.setStrokeWidth(properties.getStrokeWidth());
outCanvas->drawPath(renderPath, paint);
}
}
@@ -306,36 +260,28 @@ void FullPath::FullPathProperties::setPropertyValue(int propertyId, float value)
}
}
-void ClipPath::drawPath(SkCanvas* outCanvas, SkPath& renderPath,
- float strokeScale, const SkMatrix& matrix, bool useStagingData){
- outCanvas->clipPath(renderPath);
+void ClipPath::draw(SkCanvas* outCanvas, bool useStagingData) {
+ SkPath tempStagingPath;
+ outCanvas->clipPath(getUpdatedPath(useStagingData, &tempStagingPath));
}
Group::Group(const Group& group) : Node(group) {
mStagingProperties.syncProperties(group.mStagingProperties);
}
-void Group::draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix, float scaleX,
- float scaleY, bool useStagingData) {
- // TODO: Try apply the matrix to the canvas instead of passing it down the tree
-
- // Calculate current group's matrix by preConcat the parent's and
- // and the current one on the top of the stack.
- // Basically the Mfinal = Mviewport * M0 * M1 * M2;
- // Mi the local matrix at level i of the group tree.
+void Group::draw(SkCanvas* outCanvas, bool useStagingData) {
+ // Save the current clip and matrix information, which is local to this group.
+ SkAutoCanvasRestore saver(outCanvas, true);
+ // apply the current group's matrix to the canvas
SkMatrix stackedMatrix;
const GroupProperties& prop = useStagingData ? mStagingProperties : mProperties;
getLocalMatrix(&stackedMatrix, prop);
- stackedMatrix.postConcat(currentMatrix);
-
- // Save the current clip information, which is local to this group.
- outCanvas->save();
+ outCanvas->concat(stackedMatrix);
// Draw the group tree in the same order as the XML file.
for (auto& child : mChildren) {
- child->draw(outCanvas, stackedMatrix, scaleX, scaleY, useStagingData);
+ child->draw(outCanvas, useStagingData);
}
- // Restore the previous clip information.
- outCanvas->restore();
+ // Restore the previous clip and matrix information.
}
void Group::dump() {
@@ -556,7 +502,8 @@ void Tree::updateBitmapCache(Bitmap& bitmap, bool useStagingData) {
mStagingProperties.getViewportHeight() : mProperties.getViewportHeight();
float scaleX = outCache.width() / viewportWidth;
float scaleY = outCache.height() / viewportHeight;
- mRootNode->draw(&outCanvas, SkMatrix::I(), scaleX, scaleY, useStagingData);
+ outCanvas.scale(scaleX, scaleY);
+ mRootNode->draw(&outCanvas, useStagingData);
}
bool Tree::allocateBitmapIfNeeded(Cache& cache, int width, int height) {
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index 8244a3911183..729a4dd4ba76 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -109,8 +109,7 @@ public:
mName = node.mName;
}
Node() {}
- virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
- float scaleX, float scaleY, bool useStagingData) = 0;
+ virtual void draw(SkCanvas* outCanvas, bool useStagingData) = 0;
virtual void dump() = 0;
void setName(const char* name) {
mName = name;
@@ -169,9 +168,6 @@ public:
Path() {}
void dump() override;
- void draw(SkCanvas* outCanvas, const SkMatrix& groupStackedMatrix,
- float scaleX, float scaleY, bool useStagingData) override;
- static float getMatrixScale(const SkMatrix& groupStackedMatrix);
virtual void syncProperties() override;
virtual void onPropertyChanged(Properties* prop) override {
if (prop == &mStagingProperties) {
@@ -193,10 +189,7 @@ public:
PathProperties* mutateProperties() { return &mProperties; }
protected:
- virtual const SkPath& getUpdatedPath();
- virtual void getStagingPath(SkPath* outPath);
- virtual void drawPath(SkCanvas *outCanvas, SkPath& renderPath,
- float strokeScale, const SkMatrix& matrix, bool useStagingData) = 0;
+ virtual const SkPath& getUpdatedPath(bool useStagingData, SkPath* tempStagingPath);
// Internal data, render thread only.
bool mSkPathDirty = true;
@@ -364,6 +357,7 @@ public:
FullPath(const FullPath& path); // for cloning
FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
FullPath() : Path() {}
+ void draw(SkCanvas* outCanvas, bool useStagingData) override;
void dump() override;
FullPathProperties* mutateStagingProperties() { return &mStagingProperties; }
const FullPathProperties* stagingProperties() { return &mStagingProperties; }
@@ -387,10 +381,7 @@ public:
}
protected:
- const SkPath& getUpdatedPath() override;
- void getStagingPath(SkPath* outPath) override;
- void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
- float strokeScale, const SkMatrix& matrix, bool useStagingData) override;
+ const SkPath& getUpdatedPath(bool useStagingData, SkPath* tempStagingPath) override;
private:
FullPathProperties mProperties = FullPathProperties(this);
@@ -407,10 +398,7 @@ public:
ClipPath(const ClipPath& path) : Path(path) {}
ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
ClipPath() : Path() {}
-
-protected:
- void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
- float strokeScale, const SkMatrix& matrix, bool useStagingData) override;
+ void draw(SkCanvas* outCanvas, bool useStagingData) override;
};
class ANDROID_API Group: public Node {
@@ -519,8 +507,7 @@ public:
GroupProperties* mutateProperties() { return &mProperties; }
// Methods below could be called from either UI thread or Render Thread.
- virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
- float scaleX, float scaleY, bool useStagingData) override;
+ virtual void draw(SkCanvas* outCanvas, bool useStagingData) override;
void getLocalMatrix(SkMatrix* outMatrix, const GroupProperties& properties);
void dump() override;
static bool isValidProperty(int propertyId);
diff --git a/libs/hwui/tests/unit/FatalTestCanvas.h b/libs/hwui/tests/unit/FatalTestCanvas.h
index 4831722b93e6..03d94964ac76 100644
--- a/libs/hwui/tests/unit/FatalTestCanvas.h
+++ b/libs/hwui/tests/unit/FatalTestCanvas.h
@@ -80,9 +80,7 @@ public:
void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) {
ADD_FAILURE() << "onDrawPoints not expected in this test";
}
- void onDrawVertices(VertexMode, int vertexCount, const SkPoint vertices[], const SkPoint texs[],
- const SkColor colors[], SkBlendMode, const uint16_t indices[], int indexCount,
- const SkPaint&) {
+ void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) {
ADD_FAILURE() << "onDrawVertices not expected in this test";
}
void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int count,
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index 8e0d3ee572a6..6f264e1ebf62 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -347,51 +347,6 @@ TEST(VectorDrawableUtils, interpolatePathData) {
}
}
-TEST(VectorDrawable, matrixScale) {
- struct MatrixAndScale {
- float buffer[9];
- float matrixScale;
- };
-
- const MatrixAndScale sMatrixAndScales[] {
- {
- {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- 1.0
- },
- {
- {1.0f, 0.0f, 240.0f, 0.0f, 1.0f, 240.0f, 0.0f, 0.0f, 1.0f},
- 1.0f,
- },
- {
- {1.5f, 0.0f, 24.0f, 0.0f, 1.5f, 24.0f, 0.0f, 0.0f, 1.0f},
- 1.5f,
- },
- {
- {0.99999994f, 0.0f, 300.0f, 0.0f, 0.99999994f, 158.57864f, 0.0f, 0.0f, 1.0f},
- 0.99999994f,
- },
- {
- {0.7071067f, 0.7071067f, 402.5305f, -0.7071067f, 0.7071067f, 169.18524f, 0.0f, 0.0f, 1.0f},
- 0.99999994f,
- },
- {
- {0.0f, 0.9999999f, 482.5305f, -0.9999999f, 0.0f, 104.18525f, 0.0f, 0.0f, 1.0f},
- 0.9999999f,
- },
- {
- {-0.35810637f, -0.93368083f, 76.55821f, 0.93368083f, -0.35810637f, 89.538506f, 0.0f, 0.0f, 1.0f},
- 1.0000001f,
- },
- };
-
- for (MatrixAndScale matrixAndScale : sMatrixAndScales) {
- SkMatrix matrix;
- matrix.set9(matrixAndScale.buffer);
- float actualMatrixScale = VectorDrawable::Path::getMatrixScale(matrix);
- EXPECT_EQ(matrixAndScale.matrixScale, actualMatrixScale);
- }
-}
-
TEST(VectorDrawable, groupProperties) {
//TODO: Also need to test property sync and dirty flag when properties change.
VectorDrawable::Group group;
@@ -458,7 +413,7 @@ TEST(VectorDrawable, drawPathWithoutIncrementingShaderRefCount) {
// Setting the fill gradient increments the ref count of the shader by 1
path.mutateStagingProperties()->setFillGradient(shader);
- path.draw(&canvas, SkMatrix::I(), 1.0f, 1.0f, true);
+ path.draw(&canvas, true);
// Resetting the fill gradient decrements the ref count of the shader by 1
path.mutateStagingProperties()->setFillGradient(nullptr);