Adding API to SkGPipe and SkDeferredCanvas for controlling memory usage externally

BUG=http://code.google.com/p/chromium/issues/detail?id=136828
Review URL: https://codereview.appspot.com/6454102

git-svn-id: http://skia.googlecode.com/svn/trunk@4971 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp
index 2ea642e..e020bea 100644
--- a/src/pipe/SkGPipeWrite.cpp
+++ b/src/pipe/SkGPipeWrite.cpp
@@ -290,6 +290,38 @@
         this->setMostRecentlyUsed(info);
         return info;
     }
+
+    size_t freeMemoryIfPossible(size_t bytesToFree) {
+        BitmapInfo* info = fLeastRecentlyUsed;
+        size_t origBytesAllocated = fBytesAllocated;
+        // Purge starting from LRU until a non-evictable bitmap is found
+        // or until everything is evicted.
+        while (info && info->drawCount() == 0) {
+            fBytesAllocated -= (info->fBytesAllocated + sizeof(BitmapInfo));
+            fBitmapCount--;
+            BitmapInfo* nextInfo = info->fMoreRecentlyUsed;
+            SkDELETE(info);
+            info = nextInfo;
+            if ((origBytesAllocated - fBytesAllocated) >= bytesToFree) {
+                break;
+            }
+        }
+
+        if (fLeastRecentlyUsed != info) { // at least one eviction
+            fLeastRecentlyUsed = info;
+            if (NULL != fLeastRecentlyUsed) {
+                fLeastRecentlyUsed->fLessRecentlyUsed = NULL;
+            } else {
+                // everything was evicted
+                fMostRecentlyUsed = NULL;
+                SkASSERT(0 == fBytesAllocated);
+                SkASSERT(0 == fBitmapCount);
+            }
+        }
+
+        return origBytesAllocated - fBytesAllocated;
+    }
+
 private:
     void setMostRecentlyUsed(BitmapInfo* info);
     BitmapInfo* bitmapToReplace(const SkBitmap& bm) const;
@@ -386,6 +418,7 @@
     }
 
     void flushRecording(bool detachCurrentBlock);
+    size_t freeMemoryIfPossible(size_t bytesToFree);
 
     size_t storageAllocatedForRecording() {
         return fSharedHeap.bytesAllocated();
@@ -1156,6 +1189,10 @@
     }
 }
 
+size_t SkGPipeCanvas::freeMemoryIfPossible(size_t bytesToFree) {
+    return fSharedHeap.freeMemoryIfPossible(bytesToFree);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 template <typename T> uint32_t castToU32(T value) {
@@ -1316,11 +1353,20 @@
     }
 }
 
-void SkGPipeWriter::flushRecording(bool detachCurrentBlock){
-    fCanvas->flushRecording(detachCurrentBlock);
+void SkGPipeWriter::flushRecording(bool detachCurrentBlock) {
+    if (fCanvas) {
+        fCanvas->flushRecording(detachCurrentBlock);
+    }
 }
 
-size_t SkGPipeWriter::storageAllocatedForRecording() {
+size_t SkGPipeWriter::freeMemoryIfPossible(size_t bytesToFree) {
+    if (fCanvas) {
+        return fCanvas->freeMemoryIfPossible(bytesToFree);
+    }
+    return 0;
+}
+
+size_t SkGPipeWriter::storageAllocatedForRecording() const {
     return NULL == fCanvas ? 0 : fCanvas->storageAllocatedForRecording();
 }