Return target rect for SkPictureImageFilter forward bounds mapping

When mapping bounds in the forward direction, return the target rect of
the picture (fCropRect). This matches the behavior of SkImageSource
which can be considered to be semantically similar.

Bug: skia:10744
Change-Id: Ief213a847041ea6b276b2e7493e49db01715eda9
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/319616
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
diff --git a/src/effects/imagefilters/SkPictureImageFilter.cpp b/src/effects/imagefilters/SkPictureImageFilter.cpp
index e589ec2..21dc7df 100644
--- a/src/effects/imagefilters/SkPictureImageFilter.cpp
+++ b/src/effects/imagefilters/SkPictureImageFilter.cpp
@@ -37,6 +37,10 @@
     void flatten(SkWriteBuffer&) const override;
     sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override;
 
+    SkRect computeFastBounds(const SkRect& src) const override;
+    SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix& ctm,
+                               MapDirection, const SkIRect* inputRect) const override;
+
 private:
     friend void SkPictureImageFilter::RegisterFlattenables();
     SK_FLATTENABLE_HOOKS(SkPictureImageFilterImpl)
@@ -124,3 +128,19 @@
     offset->fY = bounds.fTop;
     return surf->makeImageSnapshot();
 }
+
+SkRect SkPictureImageFilterImpl::computeFastBounds(const SkRect& src) const {
+    return fCropRect;
+}
+
+SkIRect SkPictureImageFilterImpl::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
+                                                     MapDirection direction,
+                                                     const SkIRect* inputRect) const {
+    if (kReverse_MapDirection == direction) {
+        return INHERITED::onFilterNodeBounds(src, ctm, direction, inputRect);
+    }
+
+    SkRect dstRect = fCropRect;
+    ctm.mapRect(&dstRect);
+    return dstRect.roundOut();
+}
diff --git a/tests/ImageFilterTest.cpp b/tests/ImageFilterTest.cpp
index 13ca18f..76f7325 100644
--- a/tests/ImageFilterTest.cpp
+++ b/tests/ImageFilterTest.cpp
@@ -2001,3 +2001,53 @@
                                                              &input));
 }
 
+// Test SkPictureImageFilter::filterBounds.
+DEF_TEST(PictureImageSourceBounds, reporter) {
+    SkPictureRecorder recorder;
+    SkCanvas* recordingCanvas = recorder.beginRecording(64, 64);
+
+    SkPaint greenPaint;
+    greenPaint.setColor(SK_ColorGREEN);
+    recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
+    sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
+
+    // Default target rect.
+    sk_sp<SkImageFilter> source1(SkImageFilters::Picture(picture));
+    SkIRect pictureBounds = SkIRect::MakeWH(64, 64);
+    SkIRect input(SkIRect::MakeXYWH(10, 20, 30, 40));
+    REPORTER_ASSERT(reporter,
+                    pictureBounds == source1->filterBounds(input, SkMatrix::I(),
+                                                           SkImageFilter::kForward_MapDirection,
+                                                           nullptr));
+    REPORTER_ASSERT(reporter,
+                    input == source1->filterBounds(input, SkMatrix::I(),
+                                                   SkImageFilter::kReverse_MapDirection, &input));
+    SkMatrix scale(SkMatrix::Scale(2, 2));
+    SkIRect scaledPictureBounds = SkIRect::MakeWH(128, 128);
+    REPORTER_ASSERT(reporter,
+                    scaledPictureBounds == source1->filterBounds(input, scale,
+                                                                 SkImageFilter::kForward_MapDirection,
+                                                                 nullptr));
+    REPORTER_ASSERT(reporter, input == source1->filterBounds(input, scale,
+                                                             SkImageFilter::kReverse_MapDirection,
+                                                             &input));
+
+    // Specified target rect.
+    SkRect targetRect(SkRect::MakeXYWH(9.5, 9.5, 31, 21));
+    sk_sp<SkImageFilter> source2(SkImageFilters::Picture(picture, targetRect));
+    REPORTER_ASSERT(reporter,
+                    targetRect.roundOut() == source2->filterBounds(input, SkMatrix::I(),
+                                                                   SkImageFilter::kForward_MapDirection,
+                                                                   nullptr));
+    REPORTER_ASSERT(reporter,
+                    input == source2->filterBounds(input, SkMatrix::I(),
+                                                   SkImageFilter::kReverse_MapDirection, &input));
+    scale.mapRect(&targetRect);
+    REPORTER_ASSERT(reporter,
+                    targetRect.roundOut() == source2->filterBounds(input, scale,
+                                                                   SkImageFilter::kForward_MapDirection,
+                                                                   nullptr));
+    REPORTER_ASSERT(reporter, input == source2->filterBounds(input, scale,
+                                                             SkImageFilter::kReverse_MapDirection,
+                                                             &input));
+}