Index: src/lazy/SkCachingPixelRef.cpp |
diff --git a/src/lazy/SkCachingPixelRef.cpp b/src/lazy/SkCachingPixelRef.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4832cad5fc36dc9eea610634c36d1234d62493bd |
--- /dev/null |
+++ b/src/lazy/SkCachingPixelRef.cpp |
@@ -0,0 +1,105 @@ |
+/* |
+ * Copyright 2013 Google Inc. |
+ * |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ */ |
+ |
+#include "SkCachingPixelRef.h" |
+ |
+SkCachingPixelRef::SkCachingPixelRef(SkScaledImageCache* cache) |
+ : fErrorInDecoding(false) |
+ , fCache(cache) |
+ , fScaledCacheId(NULL) |
+ , fBitmapSize(SkISize::Make(0, 0)) { |
+ if (NULL == fCache) { |
+ fCache = SkScaledImageCache::GetGlobalInstance(); |
+ } |
+} |
+SkCachingPixelRef::~SkCachingPixelRef() { |
+ SkASSERT(NULL == fScaledCacheId); |
+ // Assert always unlock before unref. |
+} |
+ |
+bool SkCachingPixelRef::updateInfo() { |
+ if (fErrorInDecoding) { |
+ return false; // Don't try again. |
+ } |
+ if (!fBitmapSize.isZero()) { |
+ return true; // Use cached values. |
+ } |
+ if (!this->onDecodeInfo(&fBitmapSize, &fBitmapConfig, &fBitmapAlphaType)) { |
+ fErrorInDecoding = true; |
+ return false; |
+ } |
+ SkASSERT(!fBitmapSize.isZero()); |
+ return true; |
+} |
+ |
+bool SkCachingPixelRef::configure(SkBitmap* bitmap) { |
+ if (!this->updateInfo()) { |
+ return false; |
+ } |
+ return bitmap->setConfig(fBitmapConfig, fBitmapSize.width(), |
+ fBitmapSize.height(), 0, fBitmapAlphaType); |
+} |
+ |
+void* SkCachingPixelRef::onLockPixels(SkColorTable** colorTable) { |
+ (void)colorTable; |
+ if (!this->updateInfo()) { |
+ return NULL; |
+ } |
+ SkBitmap bitmap; |
+ |
+ fScaledCacheId = fCache->findAndLock(this->getGenerationID(), |
+ fBitmapSize.fWidth, |
+ fBitmapSize.fHeight, |
+ &bitmap); |
+ if (NULL == fScaledCacheId) { |
+ // Cache has been purged, must re-decode. |
+ if (!this->onDecodeInto(0, &bitmap)) { |
+ return NULL; |
+ } |
+ fScaledCacheId = fCache->addAndLock(this->getGenerationID(), |
+ fBitmapSize.fWidth, |
+ fBitmapSize.fHeight, |
+ bitmap); |
+ SkASSERT(fScaledCacheId != NULL); |
+ } |
+ // Now bitmap should contain a concrete PixelRef of the decoded |
+ // image. |
+ SkAutoLockPixels autoLockPixels(bitmap); |
+ void* pixels = bitmap.getPixels(); |
+ SkASSERT(NULL != pixels); |
+ // At this point, the autoLockPixels will unlockPixels() |
+ // to remove bitmap's lock on the pixels. We will then |
+ // destroy bitmap. The *only* guarantee that this pointer |
+ // remains valid is the guarantee made by |
+ // SkScaledImageCache that it will not destroy the *other* |
+ // bitmap (SkScaledImageCache::Rec.fBitmap) that holds a |
+ // reference to the concrete PixelRef while this record is |
+ // locked. |
+ return pixels; |
+} |
+ |
+void SkCachingPixelRef::onUnlockPixels() { |
+ if (NULL != fScaledCacheId) { |
+ fCache->unlock(fScaledCacheId); |
+ fScaledCacheId = NULL; |
+ } |
+} |
+ |
+bool SkCachingPixelRef::onDecodeInto(int pow2, SkBitmap* bitmap) { |
+ SkBitmap tmp; |
+ if (!(this->configure(&tmp) && tmp.allocPixels(NULL, NULL))) { |
+ fErrorInDecoding = true; |
+ return false; |
+ } |
+ if (!this->onDecode(tmp.getPixels(), tmp.rowBytes())) { |
+ fErrorInDecoding = true; |
+ return false; |
+ } |
+ *bitmap = tmp; |
+ return true; |
+} |
+ |