diff options
| author | 2016-10-12 20:56:55 +0000 | |
|---|---|---|
| committer | 2016-10-12 20:56:55 +0000 | |
| commit | c47199bb6a39b305309f9cc6587e82f89024fe7e (patch) | |
| tree | 994ca8122385b0eb1f6e69b64ef2749948dd10e6 | |
| parent | e04c7f151b802eabb33c7d40010f5465c65849f1 (diff) | |
| parent | fc9cf72339c7ce61adb11ceb3b247f112577fb6b (diff) | |
Fix SkShader leak for Gradient VectorDrawable and test
am: fc9cf72339
Change-Id: I493a8c52cd4cca79971a4fd2e3eed7f566ce8ecd
| -rw-r--r-- | libs/hwui/VectorDrawable.cpp | 8 | ||||
| -rw-r--r-- | libs/hwui/tests/unit/VectorDrawableTests.cpp | 44 |
2 files changed, 50 insertions, 2 deletions
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp index 2b7994139641..aeee66106fb3 100644 --- a/libs/hwui/VectorDrawable.cpp +++ b/libs/hwui/VectorDrawable.cpp @@ -202,7 +202,9 @@ void FullPath::drawPath(SkCanvas* outCanvas, SkPath& renderPath, float strokeSca if (properties.getFillGradient() != nullptr) { paint.setColor(applyAlpha(SK_ColorBLACK, properties.getFillAlpha())); SkShader* newShader = properties.getFillGradient()->newWithLocalMatrix(matrix); - paint.setShader(newShader); + // newWithLocalMatrix(...) creates a new SkShader and returns a bare pointer. We need to + // remove the extra ref so that the ref count is correctly managed. + paint.setShader(newShader)->unref(); needsFill = true; } else if (properties.getFillColor() != SK_ColorTRANSPARENT) { paint.setColor(applyAlpha(properties.getFillColor(), properties.getFillAlpha())); @@ -222,7 +224,9 @@ void FullPath::drawPath(SkCanvas* outCanvas, SkPath& renderPath, float strokeSca if (properties.getStrokeGradient() != nullptr) { paint.setColor(applyAlpha(SK_ColorBLACK, properties.getStrokeAlpha())); SkShader* newShader = properties.getStrokeGradient()->newWithLocalMatrix(matrix); - paint.setShader(newShader); + // newWithLocalMatrix(...) creates a new SkShader and returns a bare pointer. We need to + // remove the extra ref so that the ref count is correctly managed. + paint.setShader(newShader)->unref(); needsStroke = true; } else if (properties.getStrokeColor() != SK_ColorTRANSPARENT) { paint.setColor(applyAlpha(properties.getStrokeColor(), properties.getStrokeAlpha())); diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp index 83b485fa705e..8e0d3ee572a6 100644 --- a/libs/hwui/tests/unit/VectorDrawableTests.cpp +++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp @@ -426,5 +426,49 @@ TEST(VectorDrawable, groupProperties) { EXPECT_EQ(1.0f, properties->getPivotY()); } + +static SkShader* createShader(bool* isDestroyed) { + class TestShader : public SkShader { + public: + TestShader(bool* isDestroyed) : SkShader(), mDestroyed(isDestroyed) { + } + ~TestShader() { + *mDestroyed = true; + } + + Factory getFactory() const override { return nullptr; } + private: + bool* mDestroyed; + }; + return new TestShader(isDestroyed); +} + +TEST(VectorDrawable, drawPathWithoutIncrementingShaderRefCount) { + VectorDrawable::FullPath path("m1 1", 4); + SkBitmap bitmap; + SkImageInfo info = SkImageInfo::Make(5, 5, kN32_SkColorType, kPremul_SkAlphaType); + bitmap.setInfo(info); + bitmap.allocPixels(info); + SkCanvas canvas(bitmap); + + bool shaderIsDestroyed = false; + + // Initial ref count is 1 + SkShader* shader = createShader(&shaderIsDestroyed); + + // 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); + // Resetting the fill gradient decrements the ref count of the shader by 1 + path.mutateStagingProperties()->setFillGradient(nullptr); + + // Expect ref count to be 1 again, i.e. nothing else to have a ref to the shader now. Unref() + // again should bring the ref count to zero and consequently trigger detor. + shader->unref(); + + // Verify that detor is called. + EXPECT_TRUE(shaderIsDestroyed); +} + }; // namespace uirenderer }; // namespace android |