pass dst-rect through from drawBitmapRect for better precision

BUG=skia:

Review URL: https://codereview.chromium.org/797963002
diff --git a/gm/bitmaprect.cpp b/gm/bitmaprect.cpp
index 53a855e..df30106 100644
--- a/gm/bitmaprect.cpp
+++ b/gm/bitmaprect.cpp
@@ -275,6 +275,7 @@
 private:
     typedef skiagm::GM INHERITED;
 };
+DEF_GM( return new BitmapRectRounding; )
 
 //////////////////////////////////////////////////////////////////////////////
 
@@ -298,4 +299,3 @@
 static skiagm::GMRegistry reg4(MyFactory4);
 #endif
 
-DEF_GM( return new BitmapRectRounding; )
diff --git a/include/core/SkDraw.h b/include/core/SkDraw.h
index 4b8d02b..2bb9c89 100644
--- a/include/core/SkDraw.h
+++ b/include/core/SkDraw.h
@@ -34,7 +34,11 @@
     void    drawPaint(const SkPaint&) const;
     void    drawPoints(SkCanvas::PointMode, size_t count, const SkPoint[],
                        const SkPaint&, bool forceUseDevice = false) const;
-    void    drawRect(const SkRect&, const SkPaint&) const;
+    void    drawRect(const SkRect& prePaintRect, const SkPaint&, const SkMatrix* paintMatrix,
+                     const SkRect* postPaintRect) const;
+    void    drawRect(const SkRect& rect, const SkPaint& paint) const {
+        this->drawRect(rect, paint, NULL, NULL);
+    }
     void    drawRRect(const SkRRect&, const SkPaint&) const;
     /**
      *  To save on mallocs, we allow a flag that tells us that srcPath is
@@ -55,7 +59,9 @@
         this->drawPath(path, paint, NULL, false, false, customBlitter);
     }
 
-    void    drawBitmap(const SkBitmap&, const SkMatrix&, const SkPaint&) const;
+    /* If dstOrNull is null, computes a dst by mapping the bitmap's bounds through the matrix. */
+    void    drawBitmap(const SkBitmap&, const SkMatrix&, const SkRect* dstOrNull,
+                       const SkPaint&) const;
     void    drawSprite(const SkBitmap&, int x, int y, const SkPaint&) const;
     void    drawText(const char text[], size_t byteLength, SkScalar x,
                      SkScalar y, const SkPaint& paint) const;
diff --git a/include/core/SkRect.h b/include/core/SkRect.h
index 0038c7c..8e4d669 100644
--- a/include/core/SkRect.h
+++ b/include/core/SkRect.h
@@ -395,6 +395,12 @@
         return r;
     }
 
+    static SkRect SK_WARN_UNUSED_RESULT MakeIWH(int w, int h) {
+        SkRect r;
+        r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h));
+        return r;
+    }
+
     static SkRect SK_WARN_UNUSED_RESULT MakeSize(const SkSize& size) {
         SkRect r;
         r.set(0, 0, size.width(), size.height());
diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp
index 020f1da..1f17e6f 100644
--- a/src/core/SkBitmapDevice.cpp
+++ b/src/core/SkBitmapDevice.cpp
@@ -218,7 +218,7 @@
 
 void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
                                 const SkMatrix& matrix, const SkPaint& paint) {
-    draw.drawBitmap(bitmap, matrix, paint);
+    draw.drawBitmap(bitmap, matrix, NULL, paint);
 }
 
 void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
@@ -291,7 +291,7 @@
         // 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.
-        this->drawBitmap(draw, *bitmapPtr, matrix, paint);
+        draw.drawBitmap(*bitmapPtr, matrix, dstPtr, paint);
         return;
     }
 
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index 61ab35d..0a6365c 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -786,7 +786,8 @@
     return SkTCast<SkPoint*>(&r);
 }
 
-void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const {
+void SkDraw::drawRect(const SkRect& prePaintRect, const SkPaint& paint,
+                      const SkMatrix* paintMatrix, const SkRect* postPaintRect) const {
     SkDEBUGCODE(this->validate();)
 
     // nothing to draw
@@ -794,22 +795,40 @@
         return;
     }
 
+    const SkMatrix* matrix;
+    SkMatrix combinedMatrixStorage;
+    if (paintMatrix) {
+        SkASSERT(postPaintRect);
+        combinedMatrixStorage.setConcat(*fMatrix, *paintMatrix);
+        matrix = &combinedMatrixStorage;
+    } else {
+        SkASSERT(!postPaintRect);
+        matrix = fMatrix;
+    }
+
     SkPoint strokeSize;
     RectType rtype = ComputeRectType(paint, *fMatrix, &strokeSize);
 
     if (kPath_RectType == rtype) {
+        SkDraw draw(*this);
+        if (paintMatrix) {
+            draw.fMatrix = matrix;
+        }
         SkPath  tmp;
-        tmp.addRect(rect);
+        tmp.addRect(prePaintRect);
         tmp.setFillType(SkPath::kWinding_FillType);
-        this->drawPath(tmp, paint, NULL, true);
+        draw.drawPath(tmp, paint, NULL, true);
         return;
     }
 
-    const SkMatrix& matrix = *fMatrix;
-    SkRect          devRect;
-
+    SkRect devRect;
+    if (paintMatrix) {
+        // skip the paintMatrix when transforming the rect by the CTM
+        fMatrix->mapPoints(rect_points(devRect), rect_points(*postPaintRect), 2);
+    } else {
+        fMatrix->mapPoints(rect_points(devRect), rect_points(prePaintRect), 2);
+    }
     // transform rect into devRect
-    matrix.mapPoints(rect_points(devRect), rect_points(rect), 2);
     devRect.sort();
 
     // look for the quick exit, before we build a blitter
@@ -832,10 +851,9 @@
         SkRect localDevRect;
         looper.mapRect(&localDevRect, devRect);
         SkMatrix localMatrix;
-        looper.mapMatrix(&localMatrix, matrix);
+        looper.mapMatrix(&localMatrix, *matrix);
 
-        SkAutoBlitterChoose blitterStorage(looper.getBitmap(), localMatrix,
-                                           paint);
+        SkAutoBlitterChoose blitterStorage(looper.getBitmap(), localMatrix, paint);
         const SkRasterClip& clip = looper.getRC();
         SkBlitter*          blitter = blitterStorage.get();
 
@@ -1227,7 +1245,7 @@
 }
 
 void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
-                        const SkPaint& origPaint) const {
+                        const SkRect* dstBounds, const SkPaint& origPaint) const {
     SkDEBUGCODE(this->validate();)
 
     // nothing to draw
@@ -1282,12 +1300,13 @@
         draw.drawBitmapAsMask(bitmap, paint);
     } else {
         SkAutoBitmapShaderInstall install(bitmap, paint);
-
-        SkRect  r;
-        r.set(0, 0, SkIntToScalar(bitmap.width()),
-              SkIntToScalar(bitmap.height()));
-        // is this ok if paint has a rasterizer?
-        draw.drawRect(r, install.paintWithShader());
+        const SkPaint& paintWithShader = install.paintWithShader();
+        const SkRect srcBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height());
+        if (dstBounds) {
+            this->drawRect(srcBounds, paintWithShader, &prematrix, dstBounds);
+        } else {
+            draw.drawRect(srcBounds, paintWithShader);
+        }
     }
 }