Index: src/lazy/SkCachingPixelRef.cpp |
diff --git a/src/lazy/SkCachingPixelRef.cpp b/src/lazy/SkCachingPixelRef.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..cd3153de0f0e8ba051b03e1f6d0011812e3439b5 |
--- /dev/null |
+++ b/src/lazy/SkCachingPixelRef.cpp |
@@ -0,0 +1,110 @@ |
+/* |
+ * 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" |
+#include "SkScaledImageCache.h" |
+ |
+SkCachingPixelRef::SkCachingPixelRef() |
+ : fErrorInDecoding(false) |
+ , fScaledCacheId(NULL) { |
+ // Please note: a non-NULL cache is not thread-safe. |
+ memset(&fInfo, 0xFF, sizeof(fInfo)); |
+} |
+SkCachingPixelRef::~SkCachingPixelRef() { |
+ SkASSERT(NULL == fScaledCacheId); |
+ // Assert always unlock before unref. |
+} |
+ |
+const SkImageInfo* SkCachingPixelRef::getInfo() { |
+ if (fErrorInDecoding) { |
+ SkASSERT(fInfo.fWidth < 0); |
+ return NULL; // Don't try again. |
+ } |
+ if (fInfo.fWidth >= 0) { |
+ return &fInfo; // already successful |
+ } |
+ SkImageInfo tmp; |
+ if (!this->onDecodeInfo(&tmp)) { |
+ fErrorInDecoding = true; |
+ return NULL; |
+ } |
+ fInfo = tmp; |
+ SkASSERT(fInfo.fWidth >= 0); |
+ return &fInfo; |
+} |
+ |
+bool SkCachingPixelRef::configure(SkBitmap* bitmap) { |
+ const SkImageInfo* info = this->getInfo(); |
+ if (NULL == info) { |
+ return false; |
+ } |
+ return bitmap->setConfig(*info, 0); |
+} |
+ |
+void* SkCachingPixelRef::onLockPixels(SkColorTable** colorTable) { |
+ (void)colorTable; |
+ const SkImageInfo* info = this->getInfo(); |
+ if (NULL == info) { |
+ return NULL; |
+ } |
+ SkBitmap bitmap; |
+ |
+ fScaledCacheId = SkScaledImageCache::FindAndLock(this->getGenerationID(), |
+ info->fWidth, |
+ info->fHeight, |
+ &bitmap); |
+ if (NULL == fScaledCacheId) { |
+ // Cache has been purged, must re-decode. |
+ if (!this->onDecodeInto(0, &bitmap)) { |
+ return NULL; |
+ } |
+ fScaledCacheId = SkScaledImageCache::AddAndLock(this->getGenerationID(), |
+ info->fWidth, |
+ info->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) { |
+ SkScaledImageCache::Unlock( |
+ static_cast<SkScaledImageCache::ID*>(fScaledCacheId)); |
+ fScaledCacheId = NULL; |
+ } |
+} |
+ |
+bool SkCachingPixelRef::onDecodeInto(int pow2, SkBitmap* bitmap) { |
+ SkBitmap tmp; |
+ // TODO(halcanary) - Enable SkCachingPixelRef to use a custom |
+ // allocator. `tmp.allocPixels(fAllocator, NULL)` |
+ 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; |
+} |
+ |