Chromium Code Reviews| Index: src/core/SkBitmapProcState.cpp |
| diff --git a/src/core/SkBitmapProcState.cpp b/src/core/SkBitmapProcState.cpp |
| index ada974adbf21b5b2a7ddf6aef16c7f2639b6e75e..fb995da3d49697f08a09357f3b68687f205a64ed 100644 |
| --- a/src/core/SkBitmapProcState.cpp |
| +++ b/src/core/SkBitmapProcState.cpp |
| @@ -278,6 +278,118 @@ bool SkBitmapProcState::possiblyScaleImage() { |
| return false; |
| } |
| +/* |
| + * Extract the "best" scale factors from a matrix. |
| + */ |
| +static bool extract_scale(const SkMatrix& matrix, SkVector* scale) { |
|
robertphillips
2015/01/16 18:37:01
SkASSERT(!matrix.hasPerspective()); ?
assert that
reed1
2015/01/16 19:01:11
Done.
|
| + SkVector v[2] = { { 1, 0 }, { 0, 1 } }; |
| + matrix.mapVectors(v, 2); |
| + SkScalar sx = SkPoint::Length(v[0].fX, v[0].fY); |
| + SkScalar sy = SkPoint::Length(v[1].fX, v[1].fY); |
| + if (!SkScalarIsFinite(sx) || !SkScalarIsFinite(sy) || |
| + SkScalarNearlyZero(sx) || SkScalarNearlyZero(sy)) |
| + { |
| + return false; |
| + } |
| + scale->set(sx, sy); |
| + return true; |
| +} |
| + |
|
robertphillips
2015/01/16 18:37:00
Is there someplace central we can document what we
reed1
2015/01/16 19:01:11
Will add comment above chooseProcs()
|
| +void SkBitmapProcState::processHQRequest() { |
| + SkASSERT(SkPaint::kHigh_FilterLevel == fFilterLevel); |
| + |
|
robertphillips
2015/01/16 18:37:01
reqeust ? valide ?
reed1
2015/01/16 19:01:11
Done.
|
| + // Our default return state is to downgrade the reqeust to Medium, w/ or w/o setting fBitmap |
| + // to a valide bitmap. If we succeed, we will set this to Low instead. |
| + fFilterLevel = SkPaint::kMedium_FilterLevel; |
| + |
| + if (kN32_SkColorType != fOrigBitmap.colorType() || !cache_size_okay(fOrigBitmap, fInvMatrix) || |
| + fInvMatrix.hasPerspective()) |
| + { |
| + return; // can't handle the reqeust |
| + } |
| + |
| + SkScalar invScaleX = fInvMatrix.getScaleX(); |
| + SkScalar invScaleY = fInvMatrix.getScaleY(); |
| + if (fInvMatrix.getType() & SkMatrix::kAffine_Mask) { |
| + SkVector scale; |
| + if (!extract_scale(fInvMatrix, &scale)) { |
| + return; // can't find suitable scale factors |
| + } |
| + invScaleX = scale.x(); |
| + invScaleY = scale.y(); |
| + } |
| + if (SkScalarNearlyEqual(invScaleX, 1) && SkScalarNearlyEqual(invScaleY, 1)) { |
| + return; // no need for HQ |
| + } |
| + |
| + SkScalar trueDestWidth = fOrigBitmap.width() / invScaleX; |
| + SkScalar trueDestHeight = fOrigBitmap.height() / invScaleY; |
| + SkScalar roundedDestWidth = SkScalarRoundToScalar(trueDestWidth); |
| + SkScalar roundedDestHeight = SkScalarRoundToScalar(trueDestHeight); |
| + |
| + if (!SkBitmapCache::Find(fOrigBitmap, roundedDestWidth, roundedDestHeight, &fScaledBitmap)) { |
| + if (!SkBitmapScaler::Resize(&fScaledBitmap, |
| + fOrigBitmap, |
| + SkBitmapScaler::RESIZE_BEST, |
| + roundedDestWidth, |
| + roundedDestHeight, |
| + SkResourceCache::GetAllocator())) { |
| + return; // we failed to create fScaledBitmap |
| + } |
| + |
| + SkASSERT(fScaledBitmap.getPixels()); |
| + fScaledBitmap.setImmutable(); |
| + SkBitmapCache::Add(fOrigBitmap, roundedDestWidth, roundedDestHeight, fScaledBitmap); |
| + } |
| + |
| + SkASSERT(fScaledBitmap.getPixels()); |
| + fBitmap = &fScaledBitmap; |
| + |
| + fInvMatrix.postScale(roundedDestWidth / fOrigBitmap.width(), |
| + roundedDestHeight / fOrigBitmap.height()); |
| + fFilterLevel = SkPaint::kLow_FilterLevel; |
| +} |
| + |
| +void SkBitmapProcState::processMediumRequest() { |
| + SkASSERT(SkPaint::kMedium_FilterLevel == fFilterLevel); |
| + |
|
robertphillips
2015/01/16 18:37:01
reqeust ?
valide ?
reed1
2015/01/16 19:01:11
Done.
|
| + // Our default return state is to downgrade the reqeust to Low, w/ or w/o setting fBitmap |
| + // to a valide bitmap. |
| + fFilterLevel = SkPaint::kLow_FilterLevel; |
| + |
| + SkScalar invScaleSqd = effective_matrix_scale_sqrd(fInvMatrix); |
| + |
| + if (invScaleSqd > SK_Scalar1) { |
| + fCurrMip.reset(SkMipMapCache::FindAndRef(fOrigBitmap)); |
| + if (NULL == fCurrMip.get()) { |
| + fCurrMip.reset(SkMipMapCache::AddAndRef(fOrigBitmap)); |
| + if (NULL == fCurrMip.get()) { |
| + return; |
| + } |
| + } |
| + // diagnostic for a crasher... |
| + if (NULL == fCurrMip->data()) { |
| + sk_throw(); |
| + } |
| + |
| + SkScalar levelScale = SkScalarInvert(SkScalarSqrt(invScaleSqd)); |
| + SkMipMap::Level level; |
| + if (fCurrMip->extractLevel(levelScale, &level)) { |
| + SkScalar invScaleFixup = level.fScale; |
| + fInvMatrix.postScale(invScaleFixup, invScaleFixup); |
| + |
| + const SkImageInfo info = fOrigBitmap.info().makeWH(level.fWidth, level.fHeight); |
| + // todo: if we could wrap the fCurrMip in a pixelref, then we could just install |
| + // that here, and not need to explicitly track it ourselves. |
| + fScaledBitmap.installPixels(info, level.fPixels, level.fRowBytes); |
| + fBitmap = &fScaledBitmap; |
| + } else { |
| + // failed to extract, so release the mipmap |
| + fCurrMip.reset(NULL); |
| + } |
| + } |
| +} |
| + |
| static bool get_locked_pixels(const SkBitmap& src, int pow2, SkBitmap* dst) { |
| SkPixelRef* pr = src.pixelRef(); |
| if (pr && pr->decodeInto(pow2, dst)) { |
| @@ -344,6 +456,9 @@ static bool valid_for_drawing(const SkBitmap& bm) { |
| return true; |
| } |
| +/* |
| + * Analyze filter-quality and matrix, and decide how to implement that. |
| + */ |
| bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { |
| if (!valid_for_drawing(fOrigBitmap)) { |
| return false; |
| @@ -353,6 +468,7 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { |
| fInvMatrix = inv; |
| fFilterLevel = paint.getFilterLevel(); |
| +#ifdef SK_SUPPORT_LEGACY_HQ_SCALING |
| // 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 |
| @@ -375,6 +491,24 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { |
| if (SkPaint::kMedium_FilterLevel == fFilterLevel) { |
| fFilterLevel = SkPaint::kLow_FilterLevel; |
| } |
| +#else |
| + if (SkPaint::kHigh_FilterLevel == fFilterLevel) { |
| + this->processHQRequest(); |
| + } |
| + SkASSERT(fFilterLevel < SkPaint::kHigh_FilterLevel); |
| + |
| + if (SkPaint::kMedium_FilterLevel == fFilterLevel) { |
| + this->processMediumRequest(); |
| + } |
| + SkASSERT(fFilterLevel < SkPaint::kMedium_FilterLevel); |
| + |
| + if (NULL == fBitmap) { |
| + if (!this->lockBaseBitmap()) { |
| + return false; |
| + } |
| + } |
| + SkASSERT(fBitmap); |
| +#endif |
| bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0; |
| bool clampClamp = SkShader::kClamp_TileMode == fTileModeX && |
| @@ -403,7 +537,7 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { |
| SkMatrix forward; |
| if (fInvMatrix.invert(&forward)) { |
| if (clampClamp ? just_trans_clamp(forward, *fBitmap) |
| - : just_trans_general(forward)) { |
| + : just_trans_general(forward)) { |
| SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX()); |
| SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY()); |
| fInvMatrix.setTranslate(tx, ty); |
| @@ -424,7 +558,7 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { |
| fShaderProc16 = NULL; |
| fSampleProc32 = NULL; |
| fSampleProc16 = NULL; |
| - |
| + |
| // recompute the triviality of the matrix here because we may have |
| // changed it! |
| @@ -452,7 +586,8 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { |
| // the image has a suitable size. |
| if (fInvType <= SkMatrix::kTranslate_Mask || |
| - !valid_for_filtering(fBitmap->width() | fBitmap->height())) { |
| + !valid_for_filtering(fBitmap->width() | fBitmap->height())) |
| + { |
| fFilterLevel = SkPaint::kNone_FilterLevel; |
| } |
| } |