(Mostly) respect FilterQuality in draw[stretchy]

Bug: b/77917978

For
  drawImageLattice
  drawBitmapLattice
  drawImageNine
  drawBitmapNine
, respect the SkFilterQuality on the SkPaint. Previously the GPU used
the lowest quality to avoid a bleeding effect, leading to ugly nine-
patches on Android.

For all backends, cap the filter quality at kLow_SkFilterQuality.
Update SkCanvas' documentation to specify this.

Change-Id: Id28c7753834975f039170f14bc51be4f2bd44d41
Reviewed-on: https://skia-review.googlesource.com/121891
Reviewed-by: Cary Clark <caryclark@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Leon Scroggins <scroggo@google.com>
Auto-Submit: Leon Scroggins <scroggo@google.com>
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index aa64683..a819cda 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -1599,7 +1599,9 @@
 
         If SkPaint paint is supplied, apply SkColorFilter, color alpha, SkImageFilter,
         SkBlendMode, and SkDrawLooper. If image is kAlpha_8_SkColorType, apply SkShader.
-        If paint contains SkMaskFilter, generate mask from image bounds.
+        If paint contains SkMaskFilter, generate mask from bitmap bounds. If paint's
+        SkFilterQuality is higher than kLow_SkFilterQuality, it will be treated as if it
+        were kLow_SkFilterQuality.
 
         If generated mask extends beyond image bounds, replicate image edge colors, just
         as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set
@@ -1728,7 +1730,9 @@
 
         If SkPaint paint is supplied, apply SkColorFilter, color alpha, SkImageFilter,
         SkBlendMode, and SkDrawLooper. If bitmap is kAlpha_8_SkColorType, apply SkShader.
-        If paint contains SkMaskFilter, generate mask from bitmap bounds.
+        If paint contains SkMaskFilter, generate mask from bitmap bounds. If paint's
+        SkFilterQuality is higher than kLow_SkFilterQuality, it will be treated as if it
+        were kLow_SkFilterQuality.
 
         If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
         just as SkShader made from SkShader::MakeBitmapShader with
@@ -1828,7 +1832,9 @@
 
         If SkPaint paint is supplied, apply SkColorFilter, color alpha, SkImageFilter,
         SkBlendMode, and SkDrawLooper. If bitmap is kAlpha_8_SkColorType, apply SkShader.
-        If paint contains SkMaskFilter, generate mask from bitmap bounds.
+        If paint contains SkMaskFilter, generate mask from bitmap bounds. If paint's
+        SkFilterQuality is higher than kLow_SkFilterQuality, it will be treated as if it
+        were kLow_SkFilterQuality.
 
         If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
         just as SkShader made from SkShader::MakeBitmapShader with
@@ -1856,7 +1862,9 @@
 
         If SkPaint paint is supplied, apply SkColorFilter, color alpha, SkImageFilter,
         SkBlendMode, and SkDrawLooper. If bitmap is kAlpha_8_SkColorType, apply SkShader.
-        If paint contains SkMaskFilter, generate mask from bitmap bounds.
+        If paint contains SkMaskFilter, generate mask from bitmap bounds. If paint's
+        SkFilterQuality is higher than kLow_SkFilterQuality, it will be treated as if it
+        were kLow_SkFilterQuality.
 
         If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
         just as SkShader made from SkShader::MakeBitmapShader with
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 7398f28..fa2c08a 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -1725,6 +1725,29 @@
                         constraint);
 }
 
+namespace {
+class NoneOrLowQualityFilterPaint : SkNoncopyable {
+public:
+    NoneOrLowQualityFilterPaint(const SkPaint* origPaint) {
+        if (origPaint && origPaint->getFilterQuality() > kLow_SkFilterQuality) {
+            fLazyPaint.set(*origPaint);
+            fLazyPaint.get()->setFilterQuality(kLow_SkFilterQuality);
+            fPaint = fLazyPaint.get();
+        } else {
+            fPaint = origPaint;
+        }
+    }
+
+    const SkPaint* get() const {
+        return fPaint;
+    }
+
+private:
+    const SkPaint* fPaint;
+    SkLazyPaint fLazyPaint;
+};
+} // namespace
+
 void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
                              const SkPaint* paint) {
     TRACE_EVENT0("skia", TRACE_FUNC);
@@ -1733,7 +1756,8 @@
         return;
     }
     if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
-        this->onDrawImageNine(image, center, dst, paint);
+        NoneOrLowQualityFilterPaint lowPaint(paint);
+        this->onDrawImageNine(image, center, dst, lowPaint.get());
     } else {
         this->drawImageRect(image, dst, paint);
     }
@@ -1755,7 +1779,8 @@
     }
 
     if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
-        this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
+        NoneOrLowQualityFilterPaint lowPaint(paint);
+        this->onDrawImageLattice(image, latticePlusBounds, dst, lowPaint.get());
     } else {
         this->drawImageRect(image, dst, paint);
     }
@@ -1796,7 +1821,8 @@
         return;
     }
     if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
-        this->onDrawBitmapNine(bitmap, center, dst, paint);
+        NoneOrLowQualityFilterPaint lowPaint(paint);
+        this->onDrawBitmapNine(bitmap, center, dst, lowPaint.get());
     } else {
         this->drawBitmapRect(bitmap, dst, paint);
     }
@@ -1817,7 +1843,8 @@
     }
 
     if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
-        this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
+        NoneOrLowQualityFilterPaint lowPaint(paint);
+        this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, lowPaint.get());
     } else {
         this->drawBitmapRect(bitmap, dst, paint);
     }
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 3a48e8c..138d41f 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1350,6 +1350,15 @@
     }
 }
 
+// When drawing nine-patches or n-patches, cap the filter quality at kBilerp.
+static GrSamplerState::Filter compute_lattice_filter_mode(const SkPaint& paint) {
+    if (paint.getFilterQuality() == kNone_SkFilterQuality) {
+        return GrSamplerState::Filter::kNearest;
+    }
+
+    return GrSamplerState::Filter::kBilerp;
+}
+
 void SkGpuDevice::drawProducerNine(GrTextureProducer* producer,
                                    const SkIRect& center, const SkRect& dst, const SkPaint& paint) {
     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawProducerNine", fContext.get());
@@ -1371,7 +1380,7 @@
         return;
     }
 
-    static const GrSamplerState::Filter kMode = GrSamplerState::Filter::kNearest;
+    const GrSamplerState::Filter kMode = compute_lattice_filter_mode(paint);
     auto fp = producer->createFragmentProcessor(
             SkMatrix::I(), SkRect::MakeIWH(producer->width(), producer->height()),
             GrTextureProducer::kNo_FilterConstraint, true, &kMode,
@@ -1426,7 +1435,7 @@
                                       const SkPaint& paint) {
     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawProducerLattice", fContext.get());
 
-    static const GrSamplerState::Filter kMode = GrSamplerState::Filter::kNearest;
+    const GrSamplerState::Filter kMode = compute_lattice_filter_mode(paint);
     std::unique_ptr<GrFragmentProcessor> fp(producer->createFragmentProcessor(
             SkMatrix::I(), SkRect::MakeIWH(producer->width(), producer->height()),
             GrTextureProducer::kNo_FilterConstraint, true, &kMode,