Update HWUI to store its own SkBitmap objects

This enables us to...

1) simplify the lifecycle/ownership between Java and HWUI
2) remove DisplayListRenderer::drawBitmapData and associated logic
3) track pixel lifecycle using standard SkPixelRef refcounting
4) Remove uncessary calls to ref/unref the bitmap's pixels and colorTable

Change-Id: I3c95078da20995444f6388a029414280fd654318
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 8e1e8d3..9996ce1 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -11,6 +11,9 @@
 #include "SkRegion.h"
 #include <android_runtime/AndroidRuntime.h>
 
+#include <Caches.h>
+#include <TextureCache.h>
+
 void doThrowNPE(JNIEnv* env) {
     jniThrowNullPointerException(env, NULL);
 }
@@ -500,10 +503,28 @@
         JNIEnv* env = vm2env(fVM);
         env->DeleteGlobalRef(fStorageObj);
     }
+
+    if (android::uirenderer::Caches::hasInstance()) {
+        android::uirenderer::Caches::getInstance().textureCache.releaseTexture(getStableID());
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
+static bool computeAllocationSize(const SkImageInfo& info, size_t* size, size_t* rowBytes) {
+        int32_t rowBytes32 = SkToS32(info.minRowBytes());
+        int64_t bigSize = (int64_t)info.height() * rowBytes32;
+        if (rowBytes32 < 0 || !sk_64_isS32(bigSize)) {
+            return false; // allocation will be too large
+        }
+
+        *size = sk_64_asS32(bigSize);
+        *rowBytes = rowBytes32;
+
+        SkASSERT(*size >= info.getSafeSize(*rowBytes));
+        return true;
+}
+
 jbyteArray GraphicsJNI::allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
                                              SkColorTable* ctable) {
     const SkImageInfo& info = bitmap->info();
@@ -512,7 +533,11 @@
         return NULL;
     }
 
-    const size_t size = bitmap->getSize();
+    size_t size, rowBytes;
+    if (!computeAllocationSize(info, &size, &rowBytes)) {
+        return NULL;
+    }
+
     jbyteArray arrayObj = (jbyteArray) env->CallObjectMethod(gVMRuntime,
                                                              gVMRuntime_newNonMovableArray,
                                                              gByte_class, size);
@@ -525,8 +550,7 @@
         return NULL;
     }
     SkASSERT(addr);
-    SkPixelRef* pr = new AndroidPixelRef(env, info, (void*) addr,
-            bitmap->rowBytes(), arrayObj, ctable);
+    SkPixelRef* pr = new AndroidPixelRef(env, info, (void*) addr, rowBytes, arrayObj, ctable);
     bitmap->setPixelRef(pr)->unref();
     // since we're already allocated, we lockPixels right away
     // HeapAllocator behaves this way too
@@ -535,6 +559,56 @@
     return arrayObj;
 }
 
+struct AndroidPixelRefContext {
+    int32_t stableID;
+};
+
+static void allocatePixelsReleaseProc(void* ptr, void* ctx) {
+    AndroidPixelRefContext* context = (AndroidPixelRefContext*)ctx;
+    if (android::uirenderer::Caches::hasInstance()) {
+         android::uirenderer::Caches::getInstance().textureCache.releaseTexture(context->stableID);
+    }
+
+    sk_free(ptr);
+    delete context;
+}
+
+bool GraphicsJNI::allocatePixels(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ctable) {
+    const SkImageInfo& info = bitmap->info();
+    if (info.fColorType == kUnknown_SkColorType) {
+        doThrowIAE(env, "unknown bitmap configuration");
+        return NULL;
+    }
+
+    size_t size, rowBytes;
+    if (!computeAllocationSize(info, &size, &rowBytes)) {
+        return false;
+    }
+
+    void* addr = sk_malloc_flags(size, 0);
+    if (NULL == addr) {
+        return false;
+    }
+
+    AndroidPixelRefContext* context = new AndroidPixelRefContext;
+    SkMallocPixelRef* pr = SkMallocPixelRef::NewWithProc(info, rowBytes, ctable, addr,
+                                                         &allocatePixelsReleaseProc, context);
+    if (!pr) {
+        delete context;
+        return false;
+    }
+
+    // set the stableID in the context so that it can be used later in
+    // allocatePixelsReleaseProc to remove the texture from the cache.
+    context->stableID = pr->getStableID();
+
+    bitmap->setPixelRef(pr)->unref();
+    // since we're already allocated, we can lockPixels right away
+    bitmap->lockPixels();
+
+    return true;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env)