Hide legacy imagefilters::image using filter-quality

Small diffs in a GM -- due to the dual nature of kMedium (cpu and gpu)
Another reason to stop using it, and switch to the more-explicit
sampling.

Bug: skia:7650
Change-Id: Ie7575071b19778626da7f94804abaaa11861a050
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/370259
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Mike Reed <reed@google.com>
diff --git a/fuzz/FuzzCanvas.cpp b/fuzz/FuzzCanvas.cpp
index cd258de..271c240 100644
--- a/fuzz/FuzzCanvas.cpp
+++ b/fuzz/FuzzCanvas.cpp
@@ -630,7 +630,8 @@
             SkFilterQuality filterQuality;
             fuzz->next(&srcRect, &dstRect);
             fuzz->nextEnum(&filterQuality, SkFilterQuality::kLast_SkFilterQuality);
-            return SkImageFilters::Image(std::move(image), srcRect, dstRect, filterQuality);
+            return SkImageFilters::Image(std::move(image), srcRect, dstRect,
+                                         SkSamplingOptions(filterQuality));
         }
         case 11:
             return make_fuzz_lighting_imagefilter(fuzz, depth - 1);
diff --git a/gm/imagesource.cpp b/gm/imagesource.cpp
index b7d0583..84de781 100644
--- a/gm/imagesource.cpp
+++ b/gm/imagesource.cpp
@@ -58,6 +58,7 @@
         const SkRect dstRect = SkRect::MakeXYWH(0, 10, 60, 60);
         const SkRect clipRect = SkRect::MakeXYWH(0, 0, 100, 100);
         const SkRect bounds = SkRect::MakeIWH(fImage->width(), fImage->height());
+        const SkSamplingOptions sampling({1/3.0f, 1/3.0f});
 
         {
             // Draw an unscaled bitmap.
@@ -68,21 +69,21 @@
         {
             // Draw an unscaled subset of the source bitmap (srcRect -> srcRect).
             sk_sp<SkImageFilter> imageSourceSrcRect(
-                    SkImageFilters::Image(fImage, srcRect, srcRect, kHigh_SkFilterQuality));
+                    SkImageFilters::Image(fImage, srcRect, srcRect, sampling));
             fill_rect_filtered(canvas, clipRect, std::move(imageSourceSrcRect));
             canvas->translate(SkIntToScalar(100), 0);
         }
         {
             // Draw a subset of the bitmap scaled to a destination rect (srcRect -> dstRect).
             sk_sp<SkImageFilter> imageSourceSrcRectDstRect(
-                    SkImageFilters::Image(fImage, srcRect, dstRect, kHigh_SkFilterQuality));
+                    SkImageFilters::Image(fImage, srcRect, dstRect, sampling));
             fill_rect_filtered(canvas, clipRect, std::move(imageSourceSrcRectDstRect));
             canvas->translate(SkIntToScalar(100), 0);
         }
         {
             // Draw the entire bitmap scaled to a destination rect (bounds -> dstRect).
             sk_sp<SkImageFilter> imageSourceDstRectOnly(
-                    SkImageFilters::Image(fImage, bounds, dstRect, kHigh_SkFilterQuality));
+                    SkImageFilters::Image(fImage, bounds, dstRect, sampling));
             fill_rect_filtered(canvas, clipRect, std::move(imageSourceDstRectOnly));
             canvas->translate(SkIntToScalar(100), 0);
         }
diff --git a/gm/imagesource2.cpp b/gm/imagesource2.cpp
index 005a626..8825c1b 100644
--- a/gm/imagesource2.cpp
+++ b/gm/imagesource2.cpp
@@ -27,7 +27,8 @@
 // is shifted for high quality mode between cpu and gpu.
 class ImageSourceGM : public GM {
 public:
-    ImageSourceGM(const char* suffix, SkFilterQuality filter) : fSuffix(suffix), fFilter(filter) {
+    ImageSourceGM(const char* suffix, const SkSamplingOptions& sampling)
+        : fSuffix(suffix), fSampling(sampling) {
         this->setBGColor(0xFFFFFFFF);
     }
 
@@ -77,7 +78,7 @@
         const SkRect dstRect = SkRect::MakeLTRB(0.75f, 0.75f, 225.75f, 225.75f);
 
         SkPaint p;
-        p.setImageFilter(SkImageFilters::Image(fImage, srcRect, dstRect, fFilter));
+        p.setImageFilter(SkImageFilters::Image(fImage, srcRect, dstRect, fSampling));
 
         canvas->saveLayer(nullptr, &p);
         canvas->restore();
@@ -86,17 +87,18 @@
 private:
     static constexpr int kImageSize = 503;
 
-    SkString fSuffix;
-    SkFilterQuality fFilter;
-    sk_sp<SkImage>  fImage;
+    SkString          fSuffix;
+    SkSamplingOptions fSampling;
+    sk_sp<SkImage>    fImage;
 
     using INHERITED = GM;
 };
 
 //////////////////////////////////////////////////////////////////////////////
 
-DEF_GM(return new ImageSourceGM("none", kNone_SkFilterQuality);)
-DEF_GM(return new ImageSourceGM("low", kLow_SkFilterQuality);)
-DEF_GM(return new ImageSourceGM("med", kMedium_SkFilterQuality);)
-DEF_GM(return new ImageSourceGM("high", kHigh_SkFilterQuality);)
+DEF_GM(return new ImageSourceGM("none", SkSamplingOptions());)
+DEF_GM(return new ImageSourceGM("low", SkSamplingOptions(SkFilterMode::kLinear));)
+DEF_GM(return new ImageSourceGM("med", SkSamplingOptions(SkFilterMode::kLinear,
+                                                         SkMipmapMode::kLinear));)
+DEF_GM(return new ImageSourceGM("high", SkSamplingOptions({1/3.0f, 1/3.0f}));)
 }  // namespace skiagm
diff --git a/gm/pictureimagefilter.cpp b/gm/pictureimagefilter.cpp
index df0a330..b9eb287 100644
--- a/gm/pictureimagefilter.cpp
+++ b/gm/pictureimagefilter.cpp
@@ -78,14 +78,14 @@
         fLCDPicture = make_LCD_picture();
     }
 
-    sk_sp<SkImageFilter> make(sk_sp<SkPicture> pic, SkRect r, SkFilterQuality fq) {
+    sk_sp<SkImageFilter> make(sk_sp<SkPicture> pic, SkRect r, const SkSamplingOptions& sampling) {
         SkISize dim = { SkScalarRoundToInt(r.width()), SkScalarRoundToInt(r.height()) };
         auto img = SkImage::MakeFromPicture(pic, dim, nullptr, nullptr,
                                             SkImage::BitDepth::kU8, SkColorSpace::MakeSRGB());
-        return SkImageFilters::Image(img, r, r, fq);
+        return SkImageFilters::Image(img, r, r, sampling);
     }
-    sk_sp<SkImageFilter> make(SkFilterQuality fq) {
-        return make(fPicture, fPicture->cullRect(), fq);
+    sk_sp<SkImageFilter> make(const SkSamplingOptions& sampling) {
+        return make(fPicture, fPicture->cullRect(), sampling);
     }
 
     void onDraw(SkCanvas* canvas) override {
@@ -98,8 +98,8 @@
             sk_sp<SkImageFilter> pictureSourceSrcRect(SkImageFilters::Picture(fPicture, srcRect));
             sk_sp<SkImageFilter> pictureSourceEmptyRect(SkImageFilters::Picture(fPicture,
                                                                                 emptyRect));
-            sk_sp<SkImageFilter> pictureSourceResampled = make(kLow_SkFilterQuality);
-            sk_sp<SkImageFilter> pictureSourcePixelated = make(kNone_SkFilterQuality);
+            sk_sp<SkImageFilter> pictureSourceResampled = make(SkSamplingOptions(SkFilterMode::kLinear));
+            sk_sp<SkImageFilter> pictureSourcePixelated = make(SkSamplingOptions());
 
             canvas->save();
             // Draw the picture unscaled.
@@ -122,7 +122,7 @@
                 canvas->drawRect(bounds, stroke);
 
                 SkPaint paint;
-                paint.setImageFilter(make(fLCDPicture, fPicture->cullRect(), kNone_SkFilterQuality));
+                paint.setImageFilter(make(fLCDPicture, fPicture->cullRect(), SkSamplingOptions()));
 
                 canvas->scale(4, 4);
                 canvas->translate(-0.9f*srcRect.fLeft, -2.45f*srcRect.fTop);
diff --git a/gm/resizeimagefilter.cpp b/gm/resizeimagefilter.cpp
index c9b1a89..3518bc9 100644
--- a/gm/resizeimagefilter.cpp
+++ b/gm/resizeimagefilter.cpp
@@ -108,7 +108,8 @@
             SkRect inRect = SkRect::MakeXYWH(-4, -4, 20, 20);
             SkRect outRect = SkRect::MakeXYWH(-24, -24, 120, 120);
             sk_sp<SkImageFilter> source(
-                SkImageFilters::Image(std::move(image), inRect, outRect, kHigh_SkFilterQuality));
+                SkImageFilters::Image(std::move(image), inRect, outRect,
+                                      SkSamplingOptions({1/3.0f, 1/3.0f})));
             canvas->translate(srcRect.width() + SkIntToScalar(10), 0);
             this->draw(canvas, srcRect, deviceSize, samplings[3], std::move(source));
         }
diff --git a/include/effects/SkImageFilters.h b/include/effects/SkImageFilters.h
index c7e3a4f..4175051 100644
--- a/include/effects/SkImageFilters.h
+++ b/include/effects/SkImageFilters.h
@@ -19,6 +19,10 @@
 
 #include <cstddef>
 
+#ifndef SK_SUPPORT_LEGACY_IMAGEFILTER_IMAGE
+#define SK_SUPPORT_LEGACY_IMAGEFILTER_IMAGE
+#endif
+
 class SkColorFilter;
 class SkPaint;
 class SkRegion;
@@ -185,25 +189,38 @@
     /**
      *  Create a filter that draws the 'srcRect' portion of image into 'dstRect' using the given
      *  filter quality. Similar to SkCanvas::drawImageRect. Returns null if 'image' is null.
-     *  @param image         The image that is output by the filter, subset by 'srcRect'.
-     *  @param srcRect       The source pixels sampled into 'dstRect'
-     *  @param dstRect       The local rectangle to draw the image into.
-     *  @param filterQuality The filter quality that is used when sampling the image.
+     *  @param image    The image that is output by the filter, subset by 'srcRect'.
+     *  @param srcRect  The source pixels sampled into 'dstRect'
+     *  @param dstRect  The local rectangle to draw the image into.
+     *  @param sampling The sampling to use when drawing the image.
      */
     static sk_sp<SkImageFilter> Image(sk_sp<SkImage> image, const SkRect& srcRect,
-                                      const SkRect& dstRect, SkFilterQuality filterQuality);
+                                      const SkRect& dstRect, const SkSamplingOptions& sampling);
+
     /**
-     *  Create a filter that produces the image contents.
-     *  @param image The image that is output by the filter.
+     *  Create a filter that draws the image using the given sampling.
+     *  Similar to SkCanvas::drawImage. Returns null if 'image' is null.
+     *  @param image    The image that is output by the filter.
+     *  @param sampling The sampling to use when drawing the image.
+     */
+    static sk_sp<SkImageFilter> Image(sk_sp<SkImage> image, const SkSamplingOptions& sampling);
+
+    /**
+     *  Create a filter that draws the image using Mitchel cubic resampling.
+     *  @param image    The image that is output by the filter.
      */
     static sk_sp<SkImageFilter> Image(sk_sp<SkImage> image) {
-        // Defaults to kHigh_SkFilterQuality because the dstRect of the image filter will be mapped
-        // by the layer matrix set during filtering. If that has a scale factor, then the image
-        // will not be drawn at a 1-to-1 pixel scale, even that is what this appears to create here.
-        SkRect r = image ? SkRect::MakeWH(image->width(), image->height()) : SkRect::MakeEmpty();
-        return Image(std::move(image), r, r, kHigh_SkFilterQuality);
+        return Image(std::move(image), SkSamplingOptions({1/3.0f, 1/3.0f}));
     }
 
+#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_IMAGE
+    static sk_sp<SkImageFilter> Image(sk_sp<SkImage> image, const SkRect& srcRect,
+                                      const SkRect& dstRect, SkFilterQuality filterQuality) {
+        SkSamplingOptions sampling(filterQuality, SkSamplingOptions::kMedium_asMipmapLinear);
+        return Image(std::move(image), srcRect, dstRect, sampling);
+    }
+#endif
+
     /**
      *  Create a filter that mimics a zoom/magnifying lens effect.
      *  @param srcRect
diff --git a/src/core/SkPicturePriv.h b/src/core/SkPicturePriv.h
index 4484727..82ca186 100644
--- a/src/core/SkPicturePriv.h
+++ b/src/core/SkPicturePriv.h
@@ -95,10 +95,11 @@
         kSamplingInDrawImage_Version        = 81,
         kPictureShaderFilterParam_Version   = 82,
         kMatrixImageFilterSampling_Version  = 83,
+        kImageFilterImageSampling_Version   = 84,
 
         // Only SKPs within the min/current picture version range (inclusive) can be read.
         kMin_Version     = kEdgeAAQuadColor4f_Version,
-        kCurrent_Version = kMatrixImageFilterSampling_Version
+        kCurrent_Version = kImageFilterImageSampling_Version
     };
 
     static_assert(SkPicturePriv::kMin_Version <= SkPicturePriv::kCubicResamplerImageShader_Version,
diff --git a/src/effects/imagefilters/SkImageFilters.cpp b/src/effects/imagefilters/SkImageFilters.cpp
index c216acd..7c31403 100644
--- a/src/effects/imagefilters/SkImageFilters.cpp
+++ b/src/effects/imagefilters/SkImageFilters.cpp
@@ -87,8 +87,17 @@
 
 sk_sp<SkImageFilter> SkImageFilters::Image(
         sk_sp<SkImage> image, const SkRect& srcRect, const SkRect& dstRect,
-        SkFilterQuality filterQuality) {
-    return SkImageSource::Make(std::move(image), srcRect, dstRect, filterQuality);
+        const SkSamplingOptions& sampling) {
+    return SkImageSource::Make(std::move(image), srcRect, dstRect, sampling);
+}
+
+sk_sp<SkImageFilter> SkImageFilters::Image(sk_sp<SkImage> image,
+                                           const SkSamplingOptions& sampling) {
+    if (image) {
+        auto r = SkRect::MakeIWH(image->width(), image->height());
+        return Image(std::move(image), r, r, sampling);
+    }
+    return nullptr;
 }
 
 sk_sp<SkImageFilter> SkImageFilters::Magnifier(
diff --git a/src/effects/imagefilters/SkImageSource.cpp b/src/effects/imagefilters/SkImageSource.cpp
index e0438bf..d5eeef2 100644
--- a/src/effects/imagefilters/SkImageSource.cpp
+++ b/src/effects/imagefilters/SkImageSource.cpp
@@ -12,6 +12,7 @@
 #include "include/core/SkString.h"
 #include "src/core/SkImageFilter_Base.h"
 #include "src/core/SkReadBuffer.h"
+#include "src/core/SkSamplingPriv.h"
 #include "src/core/SkSpecialImage.h"
 #include "src/core/SkSpecialSurface.h"
 #include "src/core/SkWriteBuffer.h"
@@ -21,12 +22,12 @@
 class SkImageSourceImpl final : public SkImageFilter_Base {
 public:
     SkImageSourceImpl(sk_sp<SkImage> image, const SkRect& srcRect, const SkRect& dstRect,
-                      SkFilterQuality filterQuality)
+                      const SkSamplingOptions& sampling)
             : INHERITED(nullptr, 0, nullptr)
             , fImage(std::move(image))
             , fSrcRect(srcRect)
             , fDstRect(dstRect)
-            , fFilterQuality(filterQuality) {}
+            , fSampling(sampling) {}
 
     SkRect computeFastBounds(const SkRect& src) const override;
 
@@ -42,30 +43,25 @@
     friend void SkImageSource::RegisterFlattenables();
     SK_FLATTENABLE_HOOKS(SkImageSourceImpl)
 
-    sk_sp<SkImage>   fImage;
-    SkRect           fSrcRect, fDstRect;
-    SkFilterQuality  fFilterQuality;
+    sk_sp<SkImage>    fImage;
+    SkRect            fSrcRect, fDstRect;
+    SkSamplingOptions fSampling;
 
     using INHERITED = SkImageFilter_Base;
 };
 
 } // end namespace
 
-sk_sp<SkImageFilter> SkImageSource::Make(sk_sp<SkImage> image) {
-    SkRect rect = image ? SkRect::MakeIWH(image->width(), image->height()) : SkRect::MakeEmpty();
-    return SkImageSource::Make(std::move(image), rect, rect, kHigh_SkFilterQuality);
-}
-
 sk_sp<SkImageFilter> SkImageSource::Make(sk_sp<SkImage> image,
                                          const SkRect& srcRect,
                                          const SkRect& dstRect,
-                                         SkFilterQuality filterQuality) {
+                                         const SkSamplingOptions& sampling) {
     if (!image || srcRect.width() <= 0.0f || srcRect.height() <= 0.0f) {
         return nullptr;
     }
 
     return sk_sp<SkImageFilter>(new SkImageSourceImpl(
-            std::move(image), srcRect, dstRect, filterQuality));
+            std::move(image), srcRect, dstRect, sampling));
 }
 
 void SkImageSource::RegisterFlattenables() {
@@ -77,7 +73,13 @@
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 sk_sp<SkFlattenable> SkImageSourceImpl::CreateProc(SkReadBuffer& buffer) {
-    SkFilterQuality filterQuality = buffer.checkFilterQuality();
+    SkSamplingOptions sampling;
+    if (buffer.isVersionLT(SkPicturePriv::kImageFilterImageSampling_Version)) {
+        sampling = SkSamplingOptions(buffer.checkFilterQuality(),
+                                     SkSamplingOptions::kMedium_asMipmapLinear);
+    } else {
+        sampling = buffer.readSampling();
+    }
 
     SkRect src, dst;
     buffer.readRect(&src);
@@ -88,11 +90,11 @@
         return nullptr;
     }
 
-    return SkImageSource::Make(std::move(image), src, dst, filterQuality);
+    return SkImageSource::Make(std::move(image), src, dst, sampling);
 }
 
 void SkImageSourceImpl::flatten(SkWriteBuffer& buffer) const {
-    buffer.writeInt(fFilterQuality);
+    SkSamplingPriv::Write(buffer, fSampling);
     buffer.writeRect(fSrcRect);
     buffer.writeRect(fDstRect);
     buffer.writeImage(fImage.get());
@@ -140,12 +142,9 @@
     dstRect.offset(-SkIntToScalar(dstIRect.fLeft), -SkIntToScalar(dstIRect.fTop));
     paint.setBlendMode(SkBlendMode::kSrc);
 
-    // TODO: take sampling explicitly, rather than filter-quality
-    SkSamplingOptions sampling(fFilterQuality, canvas->recordingContext() ?
-                               SkSamplingOptions::kMedium_asMipmapLinear :
-                               SkSamplingOptions::kMedium_asMipmapNearest);
     // FIXME: this probably shouldn't be necessary, but drawImageRect asserts
-    // None filtering when it's translate-only
+    SkSamplingOptions sampling = fSampling;
+    // None filtering when it's translate-only (even for cubicresampling? <reed>)
     if (fSrcRect.width() == dstRect.width() && fSrcRect.height() == dstRect.height()) {
         sampling = SkSamplingOptions();
     }
diff --git a/src/effects/imagefilters/SkImageSource.h b/src/effects/imagefilters/SkImageSource.h
index 1572df7..c2f2d03 100644
--- a/src/effects/imagefilters/SkImageSource.h
+++ b/src/effects/imagefilters/SkImageSource.h
@@ -11,14 +11,12 @@
 #include "include/core/SkImage.h"
 #include "include/core/SkImageFilter.h"
 
-// DEPRECATED: Use include/effects/SkImageFilters::Image
-class SK_API SkImageSource {
+class SkImageSource {
 public:
-    static sk_sp<SkImageFilter> Make(sk_sp<SkImage> image);
     static sk_sp<SkImageFilter> Make(sk_sp<SkImage> image,
                                      const SkRect& srcRect,
                                      const SkRect& dstRect,
-                                     SkFilterQuality filterQuality);
+                                     const SkSamplingOptions& sampling);
 
     static void RegisterFlattenables();
 
diff --git a/tests/ImageFilterTest.cpp b/tests/ImageFilterTest.cpp
index ea16907..9a1d46b 100644
--- a/tests/ImageFilterTest.cpp
+++ b/tests/ImageFilterTest.cpp
@@ -1981,7 +1981,9 @@
     // 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(SkImageFilters::Image(image, src, dst, kMedium_SkFilterQuality));
+    sk_sp<SkImageFilter> source2(SkImageFilters::Image(image, src, dst,
+                                                       SkSamplingOptions(SkFilterMode::kLinear,
+                                                                         SkMipmapMode::kLinear)));
     REPORTER_ASSERT(reporter,
                     dst.roundOut() == source2->filterBounds(input, SkMatrix::I(),
                                                             SkImageFilter::kForward_MapDirection,
diff --git a/tests/Skbug6389.cpp b/tests/Skbug6389.cpp
index 0b93cfb..1aa20ab 100644
--- a/tests/Skbug6389.cpp
+++ b/tests/Skbug6389.cpp
@@ -17,6 +17,6 @@
     SkPaint p;
     p.setMaskFilter(SkMaskFilter::MakeBlur(SkBlurStyle::kNormal_SkBlurStyle, 5));
     p.setImageFilter(SkImageFilters::Image(GetResourceAsImage("images/mandrill_512.png"),
-                                           {0, 0, 0, 0}, {0, 0, 0, 0}, kNone_SkFilterQuality));
+                                           {0, 0, 0, 0}, {0, 0, 0, 0}, SkSamplingOptions()));
     s->getCanvas()->drawPaint(p);
 }