Implement srcRect and dstRect functionality in SkBitmapSource. This is required for the "preserveAspectRatio" options of SVG's feImage. Covered by new GM "bitmapsource".

This also includes some changes to the xfermodeimagefilter and tileimagefilter GMs to properly handle the CTM. This worked before only because SkBitmapSource was ignoring the CTM. Now that it respects it, we need to give the correct transform. This also means the GMs now work while zoomed. It also implements CTM support for SkTileImageFilter.

NOTE: this will require rebaselining a number of imagefilter GMs on Nexus4, since they render in perspective (using the CTM). The changes to the results should all be improvements.

R=reed@google.com, robertphillips@google.com

Review URL: https://codereview.chromium.org/106933002

git-svn-id: http://skia.googlecode.com/svn/trunk@12571 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/effects/SkBitmapSource.cpp b/src/effects/SkBitmapSource.cpp
index 72f51f8..ef5ea86 100644
--- a/src/effects/SkBitmapSource.cpp
+++ b/src/effects/SkBitmapSource.cpp
@@ -6,24 +6,74 @@
  */
 
 #include "SkBitmapSource.h"
+#include "SkDevice.h"
+#include "SkCanvas.h"
+#include "SkFlattenableBuffers.h"
+#include "SkValidationUtils.h"
 
 SkBitmapSource::SkBitmapSource(const SkBitmap& bitmap)
   : INHERITED(0, 0),
-    fBitmap(bitmap) {
+    fBitmap(bitmap),
+    fSrcRect(SkRect::MakeWH(SkIntToScalar(bitmap.width()),
+                            SkIntToScalar(bitmap.height()))),
+    fDstRect(fSrcRect) {
+}
+
+SkBitmapSource::SkBitmapSource(const SkBitmap& bitmap, const SkRect& srcRect, const SkRect& dstRect)
+  : INHERITED(0, 0),
+    fBitmap(bitmap),
+    fSrcRect(srcRect),
+    fDstRect(dstRect) {
 }
 
 SkBitmapSource::SkBitmapSource(SkFlattenableReadBuffer& buffer)
   : INHERITED(0, buffer) {
     fBitmap.unflatten(buffer);
+    buffer.readRect(&fSrcRect);
+    buffer.readRect(&fDstRect);
+    buffer.validate(SkIsValidRect(fSrcRect) && SkIsValidRect(fDstRect));
 }
 
 void SkBitmapSource::flatten(SkFlattenableWriteBuffer& buffer) const {
     this->INHERITED::flatten(buffer);
     fBitmap.flatten(buffer);
+    buffer.writeRect(fSrcRect);
+    buffer.writeRect(fDstRect);
 }
 
-bool SkBitmapSource::onFilterImage(Proxy*, const SkBitmap&, const SkMatrix&,
+bool SkBitmapSource::onFilterImage(Proxy* proxy, const SkBitmap&, const SkMatrix& matrix,
                                    SkBitmap* result, SkIPoint* offset) {
-    *result = fBitmap;
+    SkRect bounds, dstRect;
+    fBitmap.getBounds(&bounds);
+    matrix.mapRect(&dstRect, fDstRect);
+    if (fSrcRect == bounds && dstRect == bounds) {
+        // No regions cropped out or resized; return entire bitmap.
+        *result = fBitmap;
+        return true;
+    }
+    SkIRect dstIRect;
+    dstRect.roundOut(&dstIRect);
+
+    SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(dstIRect.width(), dstIRect.height()));
+    if (NULL == device.get()) {
+        return false;
+    }
+
+    SkCanvas canvas(device.get());
+    SkPaint paint;
+
+    // Subtract off the integer component of the translation (will be applied in loc, below).
+    dstRect.offset(-SkIntToScalar(dstIRect.fLeft), -SkIntToScalar(dstIRect.fTop));
+    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+    // FIXME: this probably shouldn't be necessary, but drawBitmapRectToRect asserts
+    // None filtering when it's translate-only
+    paint.setFilterLevel(
+        fSrcRect.width() == dstRect.width() && fSrcRect.height() == dstRect.height() ?
+        SkPaint::kNone_FilterLevel : SkPaint::kMedium_FilterLevel);
+    canvas.drawBitmapRectToRect(fBitmap, &fSrcRect, dstRect, &paint);
+
+    *result = device.get()->accessBitmap(false);
+    offset->fX += dstIRect.fLeft;
+    offset->fY += dstIRect.fTop;
     return true;
 }