Fixing refcount leak in SkBitmapHeap caused by collisions in SkFlatDictionary
BUG=http://code.google.com/p/chromium/issues/detail?id=155875
TEST=DeferredCanvas unit test, subtest TestDeferredCanvasBitmapShaderNoLeak
Review URL: https://codereview.appspot.com/6713048
git-svn-id: http://skia.googlecode.com/svn/trunk@5982 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/tests/DeferredCanvasTest.cpp b/tests/DeferredCanvasTest.cpp
index 2c27971..bb54108 100644
--- a/tests/DeferredCanvasTest.cpp
+++ b/tests/DeferredCanvasTest.cpp
@@ -7,6 +7,7 @@
*/
#include "Test.h"
#include "SkBitmap.h"
+#include "SkBitmapProcShader.h"
#include "SkDeferredCanvas.h"
#include "SkDevice.h"
#include "SkShader.h"
@@ -348,6 +349,48 @@
}
+static void TestDeferredCanvasBitmapShaderNoLeak(skiatest::Reporter* reporter) {
+ // This is a regression test for crbug.com/155875
+ // This test covers a code path that inserts bitmaps into the bitmap heap through the
+ // flattening of SkBitmapProcShaders. The refcount in the bitmap heap is maintained through
+ // the flattening and unflattening of the shader.
+ SkBitmap store;
+ store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
+ store.allocPixels();
+ SkDevice device(store);
+ SkDeferredCanvas canvas(&device);
+ // test will fail if nbIterations is not in sync with
+ // BITMAPS_TO_KEEP in SkGPipeWrite.cpp
+ const int nbIterations = 5;
+ size_t bytesAllocated = 0;
+ for(int pass = 0; pass < 2; ++pass) {
+ for(int i = 0; i < nbIterations; ++i) {
+ SkPaint paint;
+ SkBitmap paintPattern;
+ paintPattern.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
+ paintPattern.allocPixels();
+ paint.setShader(SkNEW_ARGS(SkBitmapProcShader,
+ (paintPattern, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode)))->unref();
+ canvas.drawPaint(paint);
+ canvas.flush();
+
+ // In the first pass, memory allocation should be monotonically increasing as
+ // the bitmap heap slots fill up. In the second pass memory allocation should be
+ // stable as bitmap heap slots get recycled.
+ size_t newBytesAllocated = canvas.storageAllocatedForRecording();
+ if (pass == 0) {
+ REPORTER_ASSERT(reporter, newBytesAllocated > bytesAllocated);
+ bytesAllocated = newBytesAllocated;
+ } else {
+ REPORTER_ASSERT(reporter, newBytesAllocated == bytesAllocated);
+ }
+ }
+ }
+ // All cached resources should be evictable since last canvas call was flush()
+ canvas.freeMemoryIfPossible(~0);
+ REPORTER_ASSERT(reporter, 0 == canvas.storageAllocatedForRecording());
+}
+
static void TestDeferredCanvas(skiatest::Reporter* reporter) {
TestDeferredCanvasBitmapAccess(reporter);
TestDeferredCanvasFlush(reporter);
@@ -355,6 +398,7 @@
TestDeferredCanvasMemoryLimit(reporter);
TestDeferredCanvasBitmapCaching(reporter);
TestDeferredCanvasSkip(reporter);
+ TestDeferredCanvasBitmapShaderNoLeak(reporter);
}
#include "TestClassDef.h"