summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Doris Liu <tianliu@google.com> 2016-10-12 20:56:55 +0000
committer android-build-merger <android-build-merger@google.com> 2016-10-12 20:56:55 +0000
commitc47199bb6a39b305309f9cc6587e82f89024fe7e (patch)
tree994ca8122385b0eb1f6e69b64ef2749948dd10e6
parente04c7f151b802eabb33c7d40010f5465c65849f1 (diff)
parentfc9cf72339c7ce61adb11ceb3b247f112577fb6b (diff)
Fix SkShader leak for Gradient VectorDrawable and test
am: fc9cf72339 Change-Id: I493a8c52cd4cca79971a4fd2e3eed7f566ce8ecd
-rw-r--r--libs/hwui/VectorDrawable.cpp8
-rw-r--r--libs/hwui/tests/unit/VectorDrawableTests.cpp44
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