Loading libs/hwui/VectorDrawable.cpp +55 −108 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -104,7 +49,12 @@ Path::Path(const Path& path) : Node(path) { mStagingProperties.syncProperties(path.mStagingProperties); } const SkPath& Path::getUpdatedPath() { 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()); Loading @@ -112,10 +62,6 @@ const SkPath& Path::getUpdatedPath() { } return mSkPath; } void Path::getStagingPath(SkPath* outPath) { outPath->reset(); VectorDrawableUtils::verbsToPath(outPath, mStagingProperties.getData()); } void Path::syncProperties() { Loading Loading @@ -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(); Path::getUpdatedPath(useStagingData, tempStagingPath); SkPath *outPath; if (useStagingData) { SkPath inPath = *tempStagingPath; applyTrim(tempStagingPath, inPath, mStagingProperties.getTrimPathStart(), mStagingProperties.getTrimPathEnd(), mStagingProperties.getTrimPathOffset()); outPath = tempStagingPath; } else { if (mProperties.getTrimPathStart() != 0.0f || mProperties.getTrimPathEnd() != 1.0f) { mProperties.mTrimDirty = false; applyTrim(&mTrimmedSkPath, mSkPath, mProperties.getTrimPathStart(), mProperties.getTrimPathEnd(), mProperties.getTrimPathOffset()); return mTrimmedSkPath; outPath = &mTrimmedSkPath; } else { return mSkPath; 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() { Loading @@ -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())); Loading @@ -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); } Loading @@ -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())); Loading @@ -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); } } Loading Loading @@ -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() { Loading Loading @@ -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) { Loading libs/hwui/VectorDrawable.h +6 −19 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading @@ -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; Loading Loading @@ -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; } Loading @@ -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); Loading @@ -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 { Loading Loading @@ -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); Loading libs/hwui/tests/unit/VectorDrawableTests.cpp +1 −46 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading
libs/hwui/VectorDrawable.cpp +55 −108 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -104,7 +49,12 @@ Path::Path(const Path& path) : Node(path) { mStagingProperties.syncProperties(path.mStagingProperties); } const SkPath& Path::getUpdatedPath() { 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()); Loading @@ -112,10 +62,6 @@ const SkPath& Path::getUpdatedPath() { } return mSkPath; } void Path::getStagingPath(SkPath* outPath) { outPath->reset(); VectorDrawableUtils::verbsToPath(outPath, mStagingProperties.getData()); } void Path::syncProperties() { Loading Loading @@ -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(); Path::getUpdatedPath(useStagingData, tempStagingPath); SkPath *outPath; if (useStagingData) { SkPath inPath = *tempStagingPath; applyTrim(tempStagingPath, inPath, mStagingProperties.getTrimPathStart(), mStagingProperties.getTrimPathEnd(), mStagingProperties.getTrimPathOffset()); outPath = tempStagingPath; } else { if (mProperties.getTrimPathStart() != 0.0f || mProperties.getTrimPathEnd() != 1.0f) { mProperties.mTrimDirty = false; applyTrim(&mTrimmedSkPath, mSkPath, mProperties.getTrimPathStart(), mProperties.getTrimPathEnd(), mProperties.getTrimPathOffset()); return mTrimmedSkPath; outPath = &mTrimmedSkPath; } else { return mSkPath; 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() { Loading @@ -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())); Loading @@ -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); } Loading @@ -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())); Loading @@ -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); } } Loading Loading @@ -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() { Loading Loading @@ -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) { Loading
libs/hwui/VectorDrawable.h +6 −19 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading @@ -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; Loading Loading @@ -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; } Loading @@ -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); Loading @@ -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 { Loading Loading @@ -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); Loading
libs/hwui/tests/unit/VectorDrawableTests.cpp +1 −46 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading