Index: src/core/SkBitmapProcState.cpp |
diff --git a/src/core/SkBitmapProcState.cpp b/src/core/SkBitmapProcState.cpp |
index 25f90d60af4e76930102082d2f63c9da7028e312..9ecfc2280bd8e055afd632d34342d5677f7c256d 100644 |
--- a/src/core/SkBitmapProcState.cpp |
+++ b/src/core/SkBitmapProcState.cpp |
@@ -13,6 +13,7 @@ |
#include "SkUtilsArm.h" |
#include "SkBitmapScaler.h" |
#include "SkMipMap.h" |
+#include "SkPixelRef.h" |
#include "SkScaledImageCache.h" |
#if !SK_ARM_NEON_IS_NONE |
@@ -109,15 +110,14 @@ static SkScalar effective_matrix_scale_sqrd(const SkMatrix& mat) { |
// 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. |
-void SkBitmapProcState::possiblyScaleImage() { |
+bool SkBitmapProcState::possiblyScaleImage() { |
+ SkASSERT(NULL == fBitmap); |
+ SkASSERT(NULL == fScaledCacheID); |
if (fFilterLevel <= SkPaint::kLow_FilterLevel) { |
- // none or low (bilerp) does not need to look any further |
- return; |
+ return false; |
} |
- // STEP 1: Highest quality direct scale? |
- |
// Check to see if the transformation matrix is simple, and if we're |
// doing high quality scaling. If so, do the bitmap scale here and |
// remove the scaling component from the matrix. |
@@ -129,7 +129,6 @@ void SkBitmapProcState::possiblyScaleImage() { |
SkScalar invScaleX = fInvMatrix.getScaleX(); |
SkScalar invScaleY = fInvMatrix.getScaleY(); |
- SkASSERT(NULL == fScaledCacheID); |
fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap, |
invScaleX, invScaleY, |
&fScaledBitmap); |
@@ -151,7 +150,7 @@ void SkBitmapProcState::possiblyScaleImage() { |
simd)) { |
// we failed to create fScaledBitmap, so just return and let |
// the scanline proc handle it. |
- return; |
+ return true; |
} |
fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap, |
@@ -159,25 +158,19 @@ void SkBitmapProcState::possiblyScaleImage() { |
invScaleY, |
fScaledBitmap); |
} |
- fScaledBitmap.lockPixels(); |
- |
+ fScaledBitmap.lockPixels(); // wonder if Resize() should have locked this |
fBitmap = &fScaledBitmap; |
// set the inv matrix type to translate-only; |
- |
fInvMatrix.setTranslate(fInvMatrix.getTranslateX() / fInvMatrix.getScaleX(), |
fInvMatrix.getTranslateY() / fInvMatrix.getScaleY()); |
// no need for any further filtering; we just did it! |
- |
fFilterLevel = SkPaint::kNone_FilterLevel; |
- |
- return; |
+ return true; |
} |
/* |
- * If we get here, the caller has requested either Med or High filter-level |
- * |
* If High, then our special-case for scale-only did not take, and so we |
* have to make a choice: |
* 1. fall back on mipmaps + bilerp |
@@ -202,7 +195,7 @@ void SkBitmapProcState::possiblyScaleImage() { |
const SkScalar bicubicLimit = SkFloatToScalar(4.0f); |
const SkScalar bicubicLimitSqd = bicubicLimit * bicubicLimit; |
if (scaleSqd < bicubicLimitSqd) { // use bicubic scanline |
- return; |
+ return false; |
} |
// else set the filter-level to Medium, since we're scaling down and |
@@ -247,15 +240,61 @@ void SkBitmapProcState::possiblyScaleImage() { |
level.fRowBytes); |
fScaledBitmap.setPixels(level.fPixels); |
fBitmap = &fScaledBitmap; |
+ fFilterLevel = SkPaint::kLow_FilterLevel; |
+ return true; |
} |
} |
} |
+ return false; |
+} |
+ |
+static bool get_locked_pixels(const SkBitmap& src, int pow2, SkBitmap* dst) { |
+ SkPixelRef* pr = src.pixelRef(); |
+ if (pr && pr->decodeInto(pow2, dst)) { |
+ return true; |
+ } |
+ |
/* |
- * At this point, we may or may not have built a mipmap. Regardless, we |
- * now fall back on Low so will bilerp whatever fBitmap now points at. |
+ * If decodeInto() fails, it is possibe that we have an old subclass that |
+ * does not, or cannot, implement that. In that case we fall back to the |
+ * older protocol of having the pixelRef handle the caching for us. |
*/ |
- fFilterLevel = SkPaint::kLow_FilterLevel; |
+ *dst = src; |
+ dst->lockPixels(); |
+ return SkToBool(dst->getPixels()); |
+} |
+ |
+bool SkBitmapProcState::lockBaseBitmap() { |
+ SkPixelRef* pr = fOrigBitmap.pixelRef(); |
+ |
+ if (pr->isLocked() || !pr->implementsDecodeInto()) { |
+ // fast-case, no need to look in our cache |
+ fScaledBitmap = fOrigBitmap; |
+ } else { |
+ fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap, |
+ SK_Scalar1, SK_Scalar1, |
+ &fScaledBitmap); |
+ if (NULL == fScaledCacheID) { |
+ if (!get_locked_pixels(fOrigBitmap, 0, &fScaledBitmap)) { |
+ return false; |
+ } |
+ |
+ // TODO: if fScaled comes back at a different width/height than fOrig, |
+ // we need to update the matrix we are using to sample from this guy. |
+ |
+ fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap, |
+ SK_Scalar1, SK_Scalar1, |
+ fScaledBitmap); |
+ if (!fScaledCacheID) { |
+ fScaledBitmap.reset(); |
+ return false; |
+ } |
+ } |
+ } |
+ fScaledBitmap.lockPixels(); // just 'cause the cache made a copy :( |
+ fBitmap = &fScaledBitmap; |
+ return true; |
} |
void SkBitmapProcState::endContext() { |
@@ -277,17 +316,10 @@ SkBitmapProcState::~SkBitmapProcState() { |
} |
bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { |
- if (fOrigBitmap.width() == 0 || fOrigBitmap.height() == 0) { |
- return false; |
- } |
+ SkASSERT(fOrigBitmap.width() && fOrigBitmap.height()); |
- fBitmap = &fOrigBitmap; |
+ fBitmap = NULL; |
fInvMatrix = inv; |
- |
- // initialize our filter quality to the one requested by the caller. |
- // We may downgrade it later if we determine that we either don't need |
- // or can't provide as high a quality filtering as the user requested. |
- |
fFilterLevel = paint.getFilterLevel(); |
// possiblyScaleImage will look to see if it can rescale the image as a |
@@ -295,8 +327,13 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { |
// a nearby mipmap level. If it does, it will adjust the working |
// matrix as well as the working bitmap. It may also adjust the filter |
// quality to avoid re-filtering an already perfectly scaled image. |
- |
- this->possiblyScaleImage(); |
+ if (!this->possiblyScaleImage()) { |
+ if (!this->lockBaseBitmap()) { |
+ return false; |
+ } |
+ } |
+ |
+ SkASSERT(fBitmap); |
bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0; |
bool clampClamp = SkShader::kClamp_TileMode == fTileModeX && |
@@ -322,7 +359,6 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { |
SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX()); |
SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY()); |
fInvMatrix.setTranslate(tx, ty); |
- |
} |
} |
} |