Chromium Code Reviews| Index: src/core/SkBitmapProcState.cpp |
| diff --git a/src/core/SkBitmapProcState.cpp b/src/core/SkBitmapProcState.cpp |
| index 25f90d60af4e76930102082d2f63c9da7028e312..70e93ae4b8251de35fb29b9197e12c278e8aaf7d 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,64 @@ 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, the possibly we just have an old subclass that |
|
scroggo
2013/09/10 21:51:41
If decodeInto() fails, it is possible* we just hav
reed1
2013/09/11 14:16:36
Done.
|
| + * 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() { |
| + /* |
| + * TODO |
| + * |
| + * If a pixelRef does not need to support decodeInto(), because it |
| + * naturally always has the pixels around (e.g. SkMallocPixelRef) we should |
| + * have a way to detect that, so we can skip all of this caching and just |
| + * jump to its lockPixels() method (which should be free). |
| + */ |
| + |
| + 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 +319,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 +330,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 +362,6 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { |
| SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX()); |
| SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY()); |
| fInvMatrix.setTranslate(tx, ty); |
| - |
| } |
| } |
| } |