From ab83da71426195dad58a85e2caff213358c8461d Mon Sep 17 00:00:00 2001 From: fmalita Date: Fri, 26 Aug 2016 13:04:14 -0700 Subject: [PATCH] drawBitmapRect() should not touch the CTM when mask filters are present Blur sigma calculations are CTM dependent, so we cannot take the drawBitmap() fast path in the presence of mask filters. BUG=skia:5682 R=reed@google.com GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2286873002 Review-Url: https://codereview.chromium.org/2286873002 --- gm/drawbitmaprect.cpp | 53 +++++++++++++++++++++++++++++++++++---------- src/core/SkBitmapDevice.cpp | 15 +++++++++++-- 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/gm/drawbitmaprect.cpp b/gm/drawbitmaprect.cpp index 0747ab0..ea9a09f 100644 --- a/gm/drawbitmaprect.cpp +++ b/gm/drawbitmaprect.cpp @@ -93,17 +93,43 @@ static sk_sp makebm(SkCanvas* origCanvas, SkBitmap* resultBM, int w, in return image; } -static void canvasproc(SkCanvas* canvas, SkImage*, const SkBitmap& bm, const SkIRect& srcR, - const SkRect& dstR) { - canvas->drawBitmapRect(bm, srcR, dstR, nullptr); +static void bitmapproc(SkCanvas* canvas, SkImage*, const SkBitmap& bm, const SkIRect& srcR, + const SkRect& dstR, const SkPaint* paint) { + canvas->drawBitmapRect(bm, srcR, dstR, paint); +} + +static void bitmapsubsetproc(SkCanvas* canvas, SkImage*, const SkBitmap& bm, const SkIRect& srcR, + const SkRect& dstR, const SkPaint* paint) { + if (!bm.bounds().contains(srcR)) { + bitmapproc(canvas, nullptr, bm, srcR, dstR, paint); + return; + } + + SkBitmap subset; + if (bm.extractSubset(&subset, srcR)) { + canvas->drawBitmapRect(subset, dstR, paint); + } } static void imageproc(SkCanvas* canvas, SkImage* image, const SkBitmap&, const SkIRect& srcR, - const SkRect& dstR) { - canvas->drawImageRect(image, srcR, dstR, nullptr); + const SkRect& dstR, const SkPaint* paint) { + canvas->drawImageRect(image, srcR, dstR, paint); } -typedef void DrawRectRectProc(SkCanvas*, SkImage*, const SkBitmap&, const SkIRect&, const SkRect&); +static void imagesubsetproc(SkCanvas* canvas, SkImage* image, const SkBitmap& bm, + const SkIRect& srcR, const SkRect& dstR, const SkPaint* paint) { + if (!image->bounds().contains(srcR)) { + imageproc(canvas, image, bm, srcR, dstR, paint); + return; + } + + if (sk_sp subset = image->makeSubset(srcR)) { + canvas->drawImageRect(subset, dstR, paint); + } +} + +typedef void DrawRectRectProc(SkCanvas*, SkImage*, const SkBitmap&, const SkIRect&, const SkRect&, + const SkPaint*); static const int gSize = 1024; static const int gBmpSize = 2048; @@ -164,7 +190,7 @@ protected: for (int h = 1; h <= kMaxSrcRectSize; h *= 4) { SkIRect srcRect = SkIRect::MakeXYWH((gBmpSize - w) / 2, (gBmpSize - h) / 2, w, h); - fProc(canvas, fImage.get(), fLargeBitmap, srcRect, dstRect); + fProc(canvas, fImage.get(), fLargeBitmap, srcRect, dstRect, nullptr); SkString label; label.appendf("%d x %d", w, h); @@ -206,9 +232,10 @@ protected: paint.setMaskFilter(SkBlurMaskFilter::Make( kNormal_SkBlurStyle, SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(5)), - SkBlurMaskFilter::kHighQuality_BlurFlag | - SkBlurMaskFilter::kIgnoreTransform_BlurFlag)); - canvas->drawBitmapRect(bm, srcRect, dstRect, &paint); + SkBlurMaskFilter::kHighQuality_BlurFlag)); + + sk_sp image(SkImage::MakeFromBitmap(bm)); + fProc(canvas, image.get(), bm, srcRect, dstRect, &paint); } } @@ -216,5 +243,7 @@ private: typedef skiagm::GM INHERITED; }; -DEF_GM( return new DrawBitmapRectGM(canvasproc, nullptr); ) -DEF_GM( return new DrawBitmapRectGM(imageproc, "-imagerect"); ) +DEF_GM( return new DrawBitmapRectGM(bitmapproc , nullptr); ) +DEF_GM( return new DrawBitmapRectGM(bitmapsubsetproc, "-subset"); ) +DEF_GM( return new DrawBitmapRectGM(imageproc , "-imagerect"); ) +DEF_GM( return new DrawBitmapRectGM(imagesubsetproc , "-imagerect-subset"); ) diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp index 3f3e5fd..4f8074d 100644 --- a/src/core/SkBitmapDevice.cpp +++ b/src/core/SkBitmapDevice.cpp @@ -233,6 +233,15 @@ void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, draw.drawBitmap(bitmap, matrix, nullptr, paint); } +static inline bool CanApplyDstMatrixAsCTM(const SkMatrix& m, const SkPaint& paint) { + if (!paint.getMaskFilter()) { + return true; + } + + // Some mask filters parameters (sigma) depend on the CTM/scale. + return m.getType() <= SkMatrix::kTranslate_Mask; +} + void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) { @@ -309,8 +318,10 @@ void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, // We can go faster by just calling drawBitmap, which will concat the // matrix with the CTM, and try to call drawSprite if it can. If not, // it will make a shader and call drawRect, as we do below. - draw.drawBitmap(*bitmapPtr, matrix, dstPtr, paint); - return; + if (CanApplyDstMatrixAsCTM(matrix, paint)) { + draw.drawBitmap(*bitmapPtr, matrix, dstPtr, paint); + return; + } } USE_SHADER: -- 2.7.4