allow SkBitmapCache to operate on a local instance, for testability

BUG=skia:
R=mtklein@google.com, danakj@chromium.org, piotaixr@chromium.org, junov@chromium.org

Author: reed@google.com

Review URL: https://codereview.chromium.org/576763002
diff --git a/src/core/SkBitmapCache.cpp b/src/core/SkBitmapCache.cpp
index 84f1036..5044d30 100644
--- a/src/core/SkBitmapCache.cpp
+++ b/src/core/SkBitmapCache.cpp
@@ -70,33 +70,41 @@
     }
 };
 
-bool SkBitmapCache::Find(const SkBitmap& src, SkScalar invScaleX, SkScalar invScaleY,
-                         SkBitmap* result) {
+#define CHECK_LOCAL(localCache, localName, globalName, ...) \
+    (localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__)
+
+bool SkBitmapCache::Find(const SkBitmap& src, SkScalar invScaleX, SkScalar invScaleY, SkBitmap* result,
+                         SkResourceCache* localCache) {
     if (0 == invScaleX || 0 == invScaleY) {
         // degenerate, and the key we use for mipmaps
         return false;
     }
     BitmapKey key(src.getGenerationID(), invScaleX, invScaleY, get_bounds_from_bitmap(src));
-    return SkResourceCache::Find(key, BitmapRec::Visitor, result);
+
+    return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Visitor, result);
 }
 
 void SkBitmapCache::Add(const SkBitmap& src, SkScalar invScaleX, SkScalar invScaleY,
-                        const SkBitmap& result) {
+                        const SkBitmap& result, SkResourceCache* localCache) {
     if (0 == invScaleX || 0 == invScaleY) {
         // degenerate, and the key we use for mipmaps
         return;
     }
     SkASSERT(result.isImmutable());
-    SkResourceCache::Add(SkNEW_ARGS(BitmapRec, (src.getGenerationID(), invScaleX, invScaleY,
-                                                get_bounds_from_bitmap(src), result)));
+    BitmapRec* rec = SkNEW_ARGS(BitmapRec, (src.getGenerationID(), invScaleX, invScaleY,
+                                            get_bounds_from_bitmap(src), result));
+    CHECK_LOCAL(localCache, add, Add, rec);
 }
 
-bool SkBitmapCache::Find(uint32_t genID, const SkIRect& subset, SkBitmap* result) {
+bool SkBitmapCache::Find(uint32_t genID, const SkIRect& subset, SkBitmap* result,
+                         SkResourceCache* localCache) {
     BitmapKey key(genID, SK_Scalar1, SK_Scalar1, subset);
-    return SkResourceCache::Find(key, BitmapRec::Visitor, result);
+
+    return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Visitor, result);
 }
 
-bool SkBitmapCache::Add(uint32_t genID, const SkIRect& subset, const SkBitmap& result) {
+bool SkBitmapCache::Add(uint32_t genID, const SkIRect& subset, const SkBitmap& result,
+                        SkResourceCache* localCache) {
     SkASSERT(result.isImmutable());
 
     if (subset.isEmpty()
@@ -106,9 +114,9 @@
         || result.height() != subset.height()) {
         return false;
     } else {
-        SkResourceCache::Add(SkNEW_ARGS(BitmapRec, (genID, SK_Scalar1, SK_Scalar1,
-                                                    subset, result)));
+        BitmapRec* rec = SkNEW_ARGS(BitmapRec, (genID, SK_Scalar1, SK_Scalar1, subset, result));
 
+        CHECK_LOCAL(localCache, add, Add, rec);
         return true;
     }
 }
diff --git a/src/core/SkBitmapCache.h b/src/core/SkBitmapCache.h
index aec7a7d..181c858 100644
--- a/src/core/SkBitmapCache.h
+++ b/src/core/SkBitmapCache.h
@@ -11,6 +11,7 @@
 #include "SkScalar.h"
 #include "SkBitmap.h"
 
+class SkResourceCache;
 class SkMipMap;
 
 class SkBitmapCache {
@@ -25,25 +26,28 @@
      *  Search based on the src bitmap and inverse scales in X and Y. If found, returns true and
      *  result will be set to the matching bitmap with its pixels already locked.
      */
-    static bool Find(const SkBitmap& src, SkScalar invScaleX, SkScalar invScaleY, SkBitmap* result);
+    static bool Find(const SkBitmap& src, SkScalar invScaleX, SkScalar invScaleY, SkBitmap* result,
+                     SkResourceCache* localCache = NULL);
 
     /*
      *  result must be marked isImmutable()
      */
     static void Add(const SkBitmap& src, SkScalar invScaleX, SkScalar invScaleY,
-            const SkBitmap& result);
+            const SkBitmap& result, SkResourceCache* localCache = NULL);
 
     /**
      *  Search based on the bitmap's genID and subset. If found, returns true and
      *  result will be set to the matching bitmap with its pixels already locked.
      */
-    static bool Find(uint32_t genID, const SkIRect& subset, SkBitmap* result);
+    static bool Find(uint32_t genID, const SkIRect& subset, SkBitmap* result,
+                     SkResourceCache* localCache = NULL);
 
     /**
      * The width and the height of the provided subset must be the same as the result bitmap ones.
      * result must be marked isImmutable()
      */
-    static bool Add(uint32_t genID, const SkIRect& subset, const SkBitmap& result);
+    static bool Add(uint32_t genID, const SkIRect& subset, const SkBitmap& result,
+                    SkResourceCache* localCache = NULL);
 };
 
 class SkMipMapCache {
diff --git a/src/core/SkResourceCache.cpp b/src/core/SkResourceCache.cpp
index 732557d..3098a9a 100644
--- a/src/core/SkResourceCache.cpp
+++ b/src/core/SkResourceCache.cpp
@@ -432,6 +432,11 @@
     return get_cache()->setTotalByteLimit(newLimit);
 }
 
+SkResourceCache::DiscardableFactory SkResourceCache::GetDiscardableFactory() {
+    SkAutoMutexAcquire am(gMutex);
+    return get_cache()->discardableFactory();
+}
+
 SkBitmap::Allocator* SkResourceCache::GetAllocator() {
     SkAutoMutexAcquire am(gMutex);
     return get_cache()->allocator();
diff --git a/src/core/SkResourceCache.h b/src/core/SkResourceCache.h
index d4e1dfa..5219698 100644
--- a/src/core/SkResourceCache.h
+++ b/src/core/SkResourceCache.h
@@ -126,6 +126,11 @@
     static void PurgeAll();
 
     /**
+     *  Returns the DiscardableFactory used by the global cache, or NULL.
+     */
+    static DiscardableFactory GetDiscardableFactory();
+
+    /**
      * Use this allocator for bitmaps, so they can use ashmem when available.
      * Returns NULL if the ResourceCache has not been initialized with a DiscardableFactory.
      */
@@ -189,6 +194,7 @@
         this->purgeAsNeeded(true);
     }
 
+    DiscardableFactory discardableFactory() const { return fDiscardableFactory; }
     SkBitmap::Allocator* allocator() const { return fAllocator; };
 
     /**
diff --git a/tests/SkResourceCacheTest.cpp b/tests/SkResourceCacheTest.cpp
index 20c3f7f..f13476a 100644
--- a/tests/SkResourceCacheTest.cpp
+++ b/tests/SkResourceCacheTest.cpp
@@ -4,11 +4,13 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
+
 #include "Test.h"
-#include "SkCanvas.h"
-#include "SkGraphics.h"
 #include "SkBitmapCache.h"
+#include "SkCanvas.h"
 #include "SkDiscardableMemoryPool.h"
+#include "SkGraphics.h"
+#include "SkResourceCache.h"
 
 static const int kCanvasSize = 1;
 static const int kBitmapSize = 16;
@@ -74,72 +76,93 @@
     SkGraphics::SetResourceCacheTotalByteLimit(originalByteLimit);
 }
 
-#if 0  // skia:2912
+////////////////////////////////////////////////////////////////////////////////////////
 
-static SkBitmap createAllocatedBitmap(const SkImageInfo& info) {
-    SkBitmap cachedBitmap;
-    cachedBitmap.setInfo(info);
-    SkBitmap::Allocator* allocator = SkBitmapCache::GetAllocator();
+static void make_bitmap(SkBitmap* bitmap, const SkImageInfo& info, SkBitmap::Allocator* allocator) {
     if (allocator) {
-        allocator->allocPixelRef(&cachedBitmap, 0);
+        bitmap->setInfo(info);
+        allocator->allocPixelRef(bitmap, 0);
     } else {
-        cachedBitmap.allocPixels();
+        bitmap->allocPixels(info);
     }
-
-    return cachedBitmap;
 }
 
 // http://skbug.com/2894
 DEF_TEST(BitmapCache_add_rect, reporter) {
-    SkBitmap bm;
-    SkIRect rect = SkIRect::MakeWH(5, 5);
-    SkBitmap cachedBitmap = createAllocatedBitmap(SkImageInfo::MakeN32Premul(5, 5));
+    SkResourceCache::DiscardableFactory factory = SkResourceCache::GetDiscardableFactory();
+    SkBitmap::Allocator* allocator = SkBitmapCache::GetAllocator();
+
+    SkAutoTDelete<SkResourceCache> cache;
+    if (factory) {
+        cache.reset(SkNEW_ARGS(SkResourceCache, (factory)));
+    } else {
+        const size_t byteLimit = 100 * 1024;
+        cache.reset(SkNEW_ARGS(SkResourceCache, (byteLimit)));
+    }
+    SkBitmap cachedBitmap;
+    make_bitmap(&cachedBitmap, SkImageInfo::MakeN32Premul(5, 5), allocator);
     cachedBitmap.setImmutable();
 
+    SkBitmap bm;
+    SkIRect rect = SkIRect::MakeWH(5, 5);
+
     // Wrong subset size
-    REPORTER_ASSERT(reporter, ! SkBitmapCache::Add(cachedBitmap.getGenerationID(), SkIRect::MakeWH(4, 6), cachedBitmap));
-    REPORTER_ASSERT(reporter, ! SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm));
+    REPORTER_ASSERT(reporter, !SkBitmapCache::Add(cachedBitmap.getGenerationID(), SkIRect::MakeWH(4, 6), cachedBitmap, cache));
+    REPORTER_ASSERT(reporter, !SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache));
     // Wrong offset value
-    REPORTER_ASSERT(reporter, ! SkBitmapCache::Add(cachedBitmap.getGenerationID(), SkIRect::MakeXYWH(-1, 0, 5, 5), cachedBitmap));
-    REPORTER_ASSERT(reporter, ! SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm));
+    REPORTER_ASSERT(reporter, !SkBitmapCache::Add(cachedBitmap.getGenerationID(), SkIRect::MakeXYWH(-1, 0, 5, 5), cachedBitmap, cache));
+    REPORTER_ASSERT(reporter, !SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache));
 
     // Should not be in the cache
-    REPORTER_ASSERT(reporter, !SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm));
+    REPORTER_ASSERT(reporter, !SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache));
 
-    REPORTER_ASSERT(reporter, SkBitmapCache::Add(cachedBitmap.getGenerationID(), rect, cachedBitmap));
+    REPORTER_ASSERT(reporter, SkBitmapCache::Add(cachedBitmap.getGenerationID(), rect, cachedBitmap, cache));
     // Should be in the cache, we just added it
-    REPORTER_ASSERT(reporter, SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm));
+    REPORTER_ASSERT(reporter, SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache));
 }
 
 DEF_TEST(BitmapCache_discarded_bitmap, reporter) {
-    SkBitmap bm;
-    SkIRect rect = SkIRect::MakeWH(5, 5);
-    SkBitmap cachedBitmap = createAllocatedBitmap(SkImageInfo::MakeN32Premul(5, 5));
+    SkResourceCache::DiscardableFactory factory = SkResourceCache::GetDiscardableFactory();
+    SkBitmap::Allocator* allocator = SkBitmapCache::GetAllocator();
+    
+    SkAutoTDelete<SkResourceCache> cache;
+    if (factory) {
+        cache.reset(SkNEW_ARGS(SkResourceCache, (factory)));
+    } else {
+        const size_t byteLimit = 100 * 1024;
+        cache.reset(SkNEW_ARGS(SkResourceCache, (byteLimit)));
+    }
+    SkBitmap cachedBitmap;
+    make_bitmap(&cachedBitmap, SkImageInfo::MakeN32Premul(5, 5), allocator);
     cachedBitmap.setImmutable();
     cachedBitmap.unlockPixels();
 
+    SkBitmap bm;
+    SkIRect rect = SkIRect::MakeWH(5, 5);
+
     // Add a bitmap to the cache.
-    REPORTER_ASSERT(reporter, SkBitmapCache::Add(cachedBitmap.getGenerationID(), rect, cachedBitmap));
-    REPORTER_ASSERT(reporter, SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm));
+    REPORTER_ASSERT(reporter, SkBitmapCache::Add(cachedBitmap.getGenerationID(), rect, cachedBitmap, cache));
+    REPORTER_ASSERT(reporter, SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache));
 
     // Finding more than once works fine.
-    REPORTER_ASSERT(reporter, SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm));
+    REPORTER_ASSERT(reporter, SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache));
     bm.unlockPixels();
 
     // Drop the pixels in the bitmap.
-    REPORTER_ASSERT(reporter, SkGetGlobalDiscardableMemoryPool()->getRAMUsed() > 0);
-    SkGetGlobalDiscardableMemoryPool()->dumpPool();
-    REPORTER_ASSERT(reporter, SkGetGlobalDiscardableMemoryPool()->getRAMUsed() == 0);
+    if (factory) {
+        REPORTER_ASSERT(reporter, SkGetGlobalDiscardableMemoryPool()->getRAMUsed() > 0);
+        SkGetGlobalDiscardableMemoryPool()->dumpPool();
+        REPORTER_ASSERT(reporter, SkGetGlobalDiscardableMemoryPool()->getRAMUsed() == 0);
 
-    // The bitmap is not in the cache since it has been dropped.
-    REPORTER_ASSERT(reporter, !SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm));
+        // The bitmap is not in the cache since it has been dropped.
+        REPORTER_ASSERT(reporter, !SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache));
+    }
 
-    cachedBitmap = createAllocatedBitmap(SkImageInfo::MakeN32Premul(5, 5));
+    make_bitmap(&cachedBitmap, SkImageInfo::MakeN32Premul(5, 5), allocator);
     cachedBitmap.setImmutable();
     cachedBitmap.unlockPixels();
 
     // We can add the bitmap back to the cache and find it again.
-    REPORTER_ASSERT(reporter, SkBitmapCache::Add(cachedBitmap.getGenerationID(), rect, cachedBitmap));
-    REPORTER_ASSERT(reporter, SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm));
+    REPORTER_ASSERT(reporter, SkBitmapCache::Add(cachedBitmap.getGenerationID(), rect, cachedBitmap, cache));
+    REPORTER_ASSERT(reporter, SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache));
 }
-#endif