grab from latest android



git-svn-id: http://skia.googlecode.com/svn/trunk@27 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/images/SkImageRefPool.cpp b/src/images/SkImageRefPool.cpp
new file mode 100644
index 0000000..e322507
--- /dev/null
+++ b/src/images/SkImageRefPool.cpp
@@ -0,0 +1,186 @@
+#include "SkImageRefPool.h"
+#include "SkImageRef.h"
+#include "SkThread.h"
+
+SkImageRefPool::SkImageRefPool() {
+    fRAMBudget = 0; // means no explicit limit
+    fRAMUsed = 0;
+    fCount = 0;
+    fHead = fTail = NULL;
+}
+
+SkImageRefPool::~SkImageRefPool() {
+    //    SkASSERT(NULL == fHead);
+}
+
+void SkImageRefPool::setRAMBudget(size_t size) {
+    if (fRAMBudget != size) {
+        fRAMBudget = size;
+        this->purgeIfNeeded();
+    }
+}
+
+void SkImageRefPool::justAddedPixels(SkImageRef* ref) {
+#ifdef DUMP_IMAGEREF_LIFECYCLE
+    SkDebugf("=== ImagePool: add pixels %s [%d %d %d] bytes=%d heap=%d\n",
+             ref->getURI(),
+             ref->fBitmap.width(), ref->fBitmap.height(),
+             ref->fBitmap.bytesPerPixel(),
+             ref->fBitmap.getSize(), (int)fRAMUsed);
+#endif
+    fRAMUsed += ref->ramUsed();
+    this->purgeIfNeeded();
+}
+
+void SkImageRefPool::canLosePixels(SkImageRef* ref) {
+    // the refs near fHead have recently been released (used)
+    // if we purge, we purge from the tail
+    this->detach(ref);
+    this->addToHead(ref);
+    this->purgeIfNeeded();
+}
+
+void SkImageRefPool::purgeIfNeeded() {
+    // do nothing if we have a zero-budget (i.e. unlimited)
+    if (fRAMBudget != 0) {
+        this->setRAMUsed(fRAMBudget);
+    }
+}
+
+void SkImageRefPool::setRAMUsed(size_t limit) {
+    SkImageRef* ref = fTail;
+    
+    while (NULL != ref && fRAMUsed > limit) {
+        // only purge it if its pixels are unlocked
+        if (0 == ref->getLockCount() && ref->fBitmap.getPixels()) {
+            size_t size = ref->ramUsed();
+            SkASSERT(size <= fRAMUsed);
+            fRAMUsed -= size;
+
+#ifdef DUMP_IMAGEREF_LIFECYCLE
+            SkDebugf("=== ImagePool: purge %s [%d %d %d] bytes=%d heap=%d\n",
+                     ref->getURI(),
+                     ref->fBitmap.width(), ref->fBitmap.height(),
+                     ref->fBitmap.bytesPerPixel(),
+                     (int)size, (int)fRAMUsed);
+#endif
+            
+            // remember the bitmap config (don't call reset),
+            // just clear the pixel memory
+            ref->fBitmap.setPixels(NULL);
+            SkASSERT(NULL == ref->fBitmap.getPixels());
+        }
+        ref = ref->fPrev;
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SkImageRefPool::addToHead(SkImageRef* ref) {
+    ref->fNext = fHead;
+    ref->fPrev = NULL;
+    
+    if (fHead) {
+        SkASSERT(NULL == fHead->fPrev);
+        fHead->fPrev = ref;
+    }
+    fHead = ref;
+    
+    if (NULL == fTail) {
+        fTail = ref;
+    }
+    fCount += 1;
+    SkASSERT(computeCount() == fCount);
+    
+    fRAMUsed += ref->ramUsed();
+}
+
+void SkImageRefPool::addToTail(SkImageRef* ref) {
+    ref->fNext = NULL;
+    ref->fPrev = fTail;
+    
+    if (fTail) {
+        SkASSERT(NULL == fTail->fNext);
+        fTail->fNext = ref;
+    }
+    fTail = ref;
+    
+    if (NULL == fHead) {
+        fHead = ref;
+    }
+    fCount += 1;
+    SkASSERT(computeCount() == fCount);
+    
+    fRAMUsed += ref->ramUsed();
+}
+
+void SkImageRefPool::detach(SkImageRef* ref) {
+    SkASSERT(fCount > 0);
+    
+    if (fHead == ref) {
+        fHead = ref->fNext;
+    }
+    if (fTail == ref) {
+        fTail = ref->fPrev;
+    }
+    if (ref->fPrev) {
+        ref->fPrev->fNext = ref->fNext;
+    }
+    if (ref->fNext) {
+        ref->fNext->fPrev = ref->fPrev;
+    }
+    
+    ref->fNext = ref->fPrev = NULL;
+    
+    fCount -= 1;
+    SkASSERT(computeCount() == fCount);
+    
+    SkASSERT(fRAMUsed >= ref->ramUsed());
+    fRAMUsed -= ref->ramUsed();
+}
+
+int SkImageRefPool::computeCount() const {
+    SkImageRef* ref = fHead;
+    int count = 0;
+    
+    while (ref != NULL) {
+        count += 1;
+        ref = ref->fNext;
+    }
+    
+#ifdef SK_DEBUG
+    ref = fTail;
+    int count2 = 0;
+    
+    while (ref != NULL) {
+        count2 += 1;
+        ref = ref->fPrev;
+    }
+    SkASSERT(count2 == count);
+#endif
+    
+    return count;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkStream.h"
+
+void SkImageRefPool::dump() const {
+#if defined(SK_DEBUG) || defined(DUMP_IMAGEREF_LIFECYCLE)
+    SkDebugf("ImagePool dump: bugdet: %d used: %d count: %d\n",
+             (int)fRAMBudget, (int)fRAMUsed, fCount);
+    
+    SkImageRef* ref = fHead;
+    
+    while (ref != NULL) {
+        SkDebugf("  [%3d %3d %d] ram=%d data=%d locks=%d %s\n", ref->fBitmap.width(),
+                 ref->fBitmap.height(), ref->fBitmap.config(),
+                 ref->ramUsed(), (int)ref->fStream->getLength(),
+                 ref->getLockCount(), ref->getURI());
+        
+        ref = ref->fNext;
+    }
+#endif
+}
+