Expose bounds for maskfilters

Bug: skia:12094
Change-Id: Ia0dfa15fef2cd2f5fe7e024e085e56880c12224b
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/419098
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Mike Reed <reed@google.com>
diff --git a/include/core/SkMaskFilter.h b/include/core/SkMaskFilter.h
index e3da3e4..a88416e 100644
--- a/include/core/SkMaskFilter.h
+++ b/include/core/SkMaskFilter.h
@@ -40,6 +40,13 @@
         return kSkMaskFilter_Type;
     }
 
+    /**
+     *  Returns the approximate bounds that would result from filtering the src rect.
+     *  The actual result may be different, but it should be contained within the
+     *  returned bounds.
+     */
+    SkRect approximateFilteredBounds(const SkRect& src) const;
+
     static sk_sp<SkMaskFilter> Deserialize(const void* data, size_t size,
                                           const SkDeserialProcs* procs = nullptr) {
         return sk_sp<SkMaskFilter>(static_cast<SkMaskFilter*>(
diff --git a/src/core/SkBlurMF.cpp b/src/core/SkBlurMF.cpp
index 0b8486a..8abd1ca 100644
--- a/src/core/SkBlurMF.cpp
+++ b/src/core/SkBlurMF.cpp
@@ -547,6 +547,9 @@
 
 void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src,
                                              SkRect* dst) const {
+    // TODO: if we're doing kInner blur, should we return a different outset?
+    //       i.e. pad == 0 ?
+
     SkScalar pad = 3.0f * fSigma;
 
     dst->setLTRB(src.fLeft  - pad, src.fTop    - pad,
diff --git a/src/core/SkMaskFilter.cpp b/src/core/SkMaskFilter.cpp
index d4655ec..d0bb09a 100644
--- a/src/core/SkMaskFilter.cpp
+++ b/src/core/SkMaskFilter.cpp
@@ -368,6 +368,12 @@
     }
 }
 
+SkRect SkMaskFilter::approximateFilteredBounds(const SkRect& src) const {
+    SkRect dst;
+    as_MFB(this)->computeFastBounds(src, &dst);
+    return dst;
+}
+
 void SkMaskFilter::RegisterFlattenables() {
     sk_register_blur_maskfilter_createproc();
 #if SK_SUPPORT_GPU
diff --git a/tests/BlurTest.cpp b/tests/BlurTest.cpp
index 01d28b3..ddcc3f7 100644
--- a/tests/BlurTest.cpp
+++ b/tests/BlurTest.cpp
@@ -386,6 +386,13 @@
                     } else {
                         REPORTER_ASSERT(reporter, !success);
                     }
+
+                    const SkRect src = {0, 0, 100, 100};
+                    const auto dst = mf->approximateFilteredBounds(src);
+
+                    // This is a very conservative test. With more knowledge, we could
+                    // consider more stringent tests.
+                    REPORTER_ASSERT(reporter, dst.contains(src));
                 }
             }
         }