Fix SkImageSource::filterBounds()

Previously SkImageSource::filterBounds() uses the default
SkImageFilter::onFilterNodeBounds() which returns the input rect.

Now override onFilterNodeBounds() in SkImageSource to return src
or dst rect (with transform applied).

Change-Id: I6681e1ba97affb09ef1ca5bc03b3d0f66c10f149
Reviewed-on: https://skia-review.googlesource.com/46741
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Mike Reed <reed@google.com>
diff --git a/include/effects/SkImageSource.h b/include/effects/SkImageSource.h
index 04348c6..f2c1274 100644
--- a/include/effects/SkImageSource.h
+++ b/include/effects/SkImageSource.h
@@ -31,6 +31,8 @@
                                         SkIPoint* offset) const override;
     sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override;
 
+    SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix&, MapDirection) const override;
+
 private:
     explicit SkImageSource(sk_sp<SkImage>);
     SkImageSource(sk_sp<SkImage>,
diff --git a/src/effects/SkImageSource.cpp b/src/effects/SkImageSource.cpp
index cd2fb51..8ab02ce 100644
--- a/src/effects/SkImageSource.cpp
+++ b/src/effects/SkImageSource.cpp
@@ -146,6 +146,13 @@
     return fDstRect;
 }
 
+SkIRect SkImageSource::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
+                                          MapDirection direction) const {
+    SkRect bounds = kForward_MapDirection == direction ? fDstRect : fSrcRect;
+    ctm.mapRect(&bounds);
+    return bounds.roundOut();
+}
+
 #ifndef SK_IGNORE_TO_STRING
 void SkImageSource::toString(SkString* str) const {
     str->appendf("SkImageSource: (");
diff --git a/tests/ImageFilterTest.cpp b/tests/ImageFilterTest.cpp
index 05c0bff..b6d4c7b 100644
--- a/tests/ImageFilterTest.cpp
+++ b/tests/ImageFilterTest.cpp
@@ -1941,7 +1941,7 @@
     REPORTER_ASSERT(reporter, filter->cloneCount() == 1u);
 }
 
-// Test XfermodeimageFilter::onFilterBounds with different blending modes.
+// Test SkXfermodeImageFilter::filterBounds with different blending modes.
 DEF_TEST(XfermodeImageFilterBounds, reporter) {
     SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
     SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
@@ -2049,8 +2049,50 @@
     test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, &crop, crop_rect);
 }
 
-// Test ArithmeticImageFilter::onFilterBounds with different blending modes.
+// Test SkArithmeticImageFilter::filterBounds with different blending modes.
 DEF_TEST(ArithmeticImageFilterBounds, reporter) {
     test_arithmetic_combinations(reporter, 1);
     test_arithmetic_combinations(reporter, 0.5);
 }
+
+// Test SkImageSource::filterBounds.
+DEF_TEST(ImageSourceBounds, reporter) {
+    sk_sp<SkImage> image(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
+    // Default src and dst rects.
+    sk_sp<SkImageFilter> source1(SkImageSource::Make(image));
+    SkIRect imageBounds = SkIRect::MakeWH(64, 64);
+    SkIRect input(SkIRect::MakeXYWH(10, 20, 30, 40));  // The values don't matter.
+    REPORTER_ASSERT(reporter,
+                    imageBounds == source1->filterBounds(input, SkMatrix::I(),
+                                                         SkImageFilter::kForward_MapDirection));
+    REPORTER_ASSERT(reporter,
+                    imageBounds == source1->filterBounds(input, SkMatrix::I(),
+                                                         SkImageFilter::kReverse_MapDirection));
+    SkMatrix scale(SkMatrix::MakeScale(2));
+    SkIRect scaledBounds = SkIRect::MakeWH(128, 128);
+    REPORTER_ASSERT(reporter,
+                    scaledBounds == source1->filterBounds(input, scale,
+                                                          SkImageFilter::kForward_MapDirection));
+    REPORTER_ASSERT(reporter,
+                    scaledBounds == source1->filterBounds(input, scale,
+                                                          SkImageFilter::kReverse_MapDirection));
+
+    // Specified src and dst rects.
+    SkRect src(SkRect::MakeXYWH(0.5, 0.5, 100.5, 100.5));
+    SkRect dst(SkRect::MakeXYWH(-10.5, -10.5, 120.5, 120.5));
+    sk_sp<SkImageFilter> source2(SkImageSource::Make(image, src, dst, kMedium_SkFilterQuality));
+    REPORTER_ASSERT(reporter,
+                    dst.roundOut() == source2->filterBounds(input, SkMatrix::I(),
+                                                            SkImageFilter::kForward_MapDirection));
+    REPORTER_ASSERT(reporter,
+                    src.roundOut() == source2->filterBounds(input, SkMatrix::I(),
+                                                            SkImageFilter::kReverse_MapDirection));
+    scale.mapRect(&dst);
+    scale.mapRect(&src);
+    REPORTER_ASSERT(reporter,
+                    dst.roundOut() == source2->filterBounds(input, scale,
+                                                            SkImageFilter::kForward_MapDirection));
+    REPORTER_ASSERT(reporter,
+                    src.roundOut() == source2->filterBounds(input, scale,
+                                                            SkImageFilter::kReverse_MapDirection));
+}