Index: src/core/SkBitmapProcState.cpp |
diff --git a/src/core/SkBitmapProcState.cpp b/src/core/SkBitmapProcState.cpp |
index 39f6a7803920fcbc2d0f9d3c1741aa762086dc09..cdc582bfeec64a70791d0ecb615186b98296e639 100644 |
--- a/src/core/SkBitmapProcState.cpp |
+++ b/src/core/SkBitmapProcState.cpp |
@@ -106,11 +106,33 @@ static SkScalar effective_matrix_scale_sqrd(const SkMatrix& mat) { |
return SkMaxScalar(v1.lengthSqd(), v2.lengthSqd()); |
} |
+class AutoScaledCacheUnlocker { |
+public: |
+ AutoScaledCacheUnlocker(SkScaledImageCache::ID** idPtr) : fIDPtr(idPtr) {} |
+ ~AutoScaledCacheUnlocker() { |
+ if (fIDPtr && *fIDPtr) { |
+ SkScaledImageCache::Unlock(*fIDPtr); |
+ *fIDPtr = NULL; |
+ } |
+ } |
+ |
+ // forgets the ID, so it won't call Unlock |
+ void release() { |
+ fIDPtr = NULL; |
+ } |
+ |
+private: |
+ SkScaledImageCache::ID** fIDPtr; |
+}; |
+#define AutoScaledCacheUnlocker(...) SK_REQUIRE_LOCAL_VAR(AutoScaledCacheUnlocker) |
+ |
// TODO -- we may want to pass the clip into this function so we only scale |
// the portion of the image that we're going to need. This will complicate |
// the interface to the cache, but might be well worth it. |
bool SkBitmapProcState::possiblyScaleImage() { |
+ AutoScaledCacheUnlocker unlocker(&fScaledCacheID); |
+ |
SkASSERT(NULL == fBitmap); |
SkASSERT(NULL == fScaledCacheID); |
@@ -132,6 +154,17 @@ bool SkBitmapProcState::possiblyScaleImage() { |
fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap, |
invScaleX, invScaleY, |
&fScaledBitmap); |
+ if (fScaledCacheID) { |
+ fScaledBitmap.lockPixels(); |
+ if (!fScaledBitmap.getPixels()) { |
+ fScaledBitmap.unlockPixels(); |
+ // found a purged entry (discardablememory?), release it |
+ SkScaledImageCache::Unlock(fScaledCacheID); |
+ fScaledCacheID = NULL; |
+ // fall through to rebuild |
+ } |
+ } |
+ |
if (NULL == fScaledCacheID) { |
int dest_width = SkScalarCeilToInt(fOrigBitmap.width() / invScaleX); |
int dest_height = SkScalarCeilToInt(fOrigBitmap.height() / invScaleY); |
@@ -154,18 +187,19 @@ bool SkBitmapProcState::possiblyScaleImage() { |
return false; |
} |
+ SkASSERT(NULL != fScaledBitmap.getPixels()); |
fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap, |
invScaleX, |
invScaleY, |
fScaledBitmap); |
- } |
- fScaledBitmap.lockPixels(); // wonder if Resize() should have locked this |
- if (!fScaledBitmap.getPixels()) { |
- // TODO: find out how this can happen, and add a unittest to exercise |
- // inspired by BUG=chromium:295895 |
- return false; |
+ if (!fScaledCacheID) { |
+ fScaledBitmap.reset(); |
+ return false; |
+ } |
+ SkASSERT(NULL != fScaledBitmap.getPixels()); |
} |
+ SkASSERT(NULL != fScaledBitmap.getPixels()); |
fBitmap = &fScaledBitmap; |
// set the inv matrix type to translate-only; |
@@ -174,6 +208,7 @@ bool SkBitmapProcState::possiblyScaleImage() { |
// no need for any further filtering; we just did it! |
fFilterLevel = SkPaint::kNone_FilterLevel; |
+ unlocker.release(); |
return true; |
} |
@@ -248,6 +283,7 @@ bool SkBitmapProcState::possiblyScaleImage() { |
fScaledBitmap.setPixels(level.fPixels); |
fBitmap = &fScaledBitmap; |
fFilterLevel = SkPaint::kLow_FilterLevel; |
+ unlocker.release(); |
return true; |
} |
} |
@@ -273,15 +309,34 @@ static bool get_locked_pixels(const SkBitmap& src, int pow2, SkBitmap* dst) { |
} |
bool SkBitmapProcState::lockBaseBitmap() { |
+ AutoScaledCacheUnlocker unlocker(&fScaledCacheID); |
+ |
SkPixelRef* pr = fOrigBitmap.pixelRef(); |
+ SkASSERT(NULL == fScaledCacheID); |
+ |
if (pr->isLocked() || !pr->implementsDecodeInto()) { |
// fast-case, no need to look in our cache |
fScaledBitmap = fOrigBitmap; |
+ fScaledBitmap.lockPixels(); |
+ if (NULL == fScaledBitmap.getPixels()) { |
+ return false; |
+ } |
} else { |
fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap, |
SK_Scalar1, SK_Scalar1, |
&fScaledBitmap); |
+ if (fScaledCacheID) { |
+ fScaledBitmap.lockPixels(); |
+ if (!fScaledBitmap.getPixels()) { |
+ fScaledBitmap.unlockPixels(); |
+ // found a purged entry (discardablememory?), release it |
+ SkScaledImageCache::Unlock(fScaledCacheID); |
+ fScaledCacheID = NULL; |
+ // fall through to rebuild |
+ } |
+ } |
+ |
if (NULL == fScaledCacheID) { |
if (!get_locked_pixels(fOrigBitmap, 0, &fScaledBitmap)) { |
return false; |
@@ -299,13 +354,8 @@ bool SkBitmapProcState::lockBaseBitmap() { |
} |
} |
} |
- fScaledBitmap.lockPixels(); // just 'cause the cache made a copy :( |
- if (!fScaledBitmap.getPixels()) { |
- // TODO: find out how this can happen, and add a unittest to exercise |
- // inspired by BUG=chromium:295895 |
- return false; |
- } |
fBitmap = &fScaledBitmap; |
+ unlocker.release(); |
return true; |
} |
@@ -334,6 +384,8 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { |
fInvMatrix = inv; |
fFilterLevel = paint.getFilterLevel(); |
+ SkASSERT(NULL == fScaledCacheID); |
+ |
// possiblyScaleImage will look to see if it can rescale the image as a |
// preprocess; either by scaling up to the target size, or by selecting |
// a nearby mipmap level. If it does, it will adjust the working |