Index: src/lazy/SkCachingPixelRef.cpp |
diff --git a/src/lazy/SkCachingPixelRef.cpp b/src/lazy/SkCachingPixelRef.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2761f1e8bb648982d83b812db5584c442d0f9c92 |
--- /dev/null |
+++ b/src/lazy/SkCachingPixelRef.cpp |
@@ -0,0 +1,112 @@ |
+/* |
+ * 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) { |
+ memset(&fInfo, 0xFF, sizeof(fInfo)); |
+} |
+SkCachingPixelRef::~SkCachingPixelRef() { |
+ SkASSERT(NULL == fScaledCacheId); |
+ // Assert always unlock before unref. |
+} |
+ |
+bool SkCachingPixelRef::getInfo(SkImageInfo* info) { |
+ SkASSERT(info != NULL); |
+ if (fErrorInDecoding) { |
+ return false; // Don't try again. |
+ } |
+ if (fInfo.fWidth < 0) { |
+ SkImageInfo tmp; |
+ if (!this->onDecodeInfo(&tmp)) { |
+ fErrorInDecoding = true; |
+ return false; |
+ } |
+ SkASSERT(tmp.fWidth >= 0); |
+ fInfo = tmp; |
+ } |
+ *info = fInfo; |
+ return true; |
+} |
+ |
+bool SkCachingPixelRef::configure(SkBitmap* bitmap) { |
+ SkASSERT(bitmap != NULL); |
+ SkImageInfo info; |
+ if (!this->getInfo(&info)) { |
+ return false; |
+ } |
+ return bitmap->setConfig(info, 0); |
+} |
+ |
+void* SkCachingPixelRef::onLockPixels(SkColorTable** colorTable) { |
+ (void)colorTable; |
+ SkImageInfo info; |
+ if (!this->getInfo(&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(pixels != NULL); |
+ // 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 (fScaledCacheId != NULL) { |
+ SkScaledImageCache::Unlock( |
+ static_cast<SkScaledImageCache::ID*>(fScaledCacheId)); |
+ fScaledCacheId = NULL; |
+ } |
+} |
+ |
+bool SkCachingPixelRef::onDecodeInto(int pow2, SkBitmap* bitmap) { |
+ SkASSERT(bitmap != NULL); |
+ SkBitmap tmp; |
+ SkImageInfo info; |
+ // TODO(halcanary) - Enable SkCachingPixelRef to use a custom |
+ // allocator. `tmp.allocPixels(fAllocator, NULL)` |
+ if (!(this->configure(&tmp) && tmp.allocPixels())) { |
+ return false; |
+ } |
+ SkAssertResult(this->getInfo(&info)); // since configure() succeeded. |
+ if (!this->onDecodePixels(info, tmp.getPixels(), tmp.rowBytes())) { |
+ fErrorInDecoding = true; |
+ return false; |
+ } |
+ *bitmap = tmp; |
+ return true; |
+} |
+ |