drawBitmapRect() should not touch the CTM when mask filters are present
authorfmalita <fmalita@chromium.org>
Fri, 26 Aug 2016 20:04:14 +0000 (13:04 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 26 Aug 2016 20:04:14 +0000 (13:04 -0700)
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
src/core/SkBitmapDevice.cpp

index 0747ab0..ea9a09f 100644 (file)
@@ -93,17 +93,43 @@ static sk_sp<SkImage> 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<SkImage> 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<SkImage> 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"); )
index 3f3e5fd..4f8074d 100644 (file)
@@ -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: