SkPaintFilterCanvas skip-draw support

At the time SkPaintFilterCanvas was introduced as a SkDrawFilter replacement,
no clients were relying on the draw veto logic.  Now Chromium does.

To facilitate migrating off SkDrawFilter, let's augment SkPaintFilterCanvas
with skip-draw semantics.

A side effect of the CL is that now we call the filter virtual even for null
paints.

BUG=skia:4782
R=reed@google.com,robertphillips@google.com
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1577933002

Review URL: https://codereview.chromium.org/1577933002
diff --git a/include/utils/SkPaintFilterCanvas.h b/include/utils/SkPaintFilterCanvas.h
index 0ad7e25..505f965 100644
--- a/include/utils/SkPaintFilterCanvas.h
+++ b/include/utils/SkPaintFilterCanvas.h
@@ -9,10 +9,11 @@
 #define SkPaintFilterCanvas_DEFINED
 
 #include "SkNWayCanvas.h"
+#include "SkTLazy.h"
 
 /** \class SkPaintFilterCanvas
 
-    A utility proxy base class for implementing paint filters.
+    A utility proxy base class for implementing draw/paint filters.
 */
 class SK_API SkPaintFilterCanvas : public SkNWayCanvas {
 public:
@@ -48,13 +49,28 @@
 protected:
     /**
      *  Called with the paint that will be used to draw the specified type.
-     *  The implementation may modify the paint as they wish.
      *
-     *  Note: The base implementation calls onFilterPaint() for top-level/explicit paints only.
+     *  Upon return, if filteredPaint is initialized it will replace the original paint
+     *  for the current draw.  Note that that implementation is responsible for
+     *  initializing *filteredPaint (e.g. via set(*paint)).
+     *
+     *  The result bool is used to determine whether the draw op is to be
+     *  executed (true) or skipped (false).  When the draw is skipped, filteredPaint is
+     *  ignored.
+     *
+     *  Note: The base implementation calls onFilter() for top-level/explicit paints only.
      *        To also filter encapsulated paints (e.g. SkPicture, SkTextBlob), clients may need to
      *        override the relevant methods (i.e. drawPicture, drawTextBlob).
      */
-    virtual void onFilterPaint(SkPaint* paint, Type type) const = 0;
+    virtual bool onFilter(const SkPaint* paint, Type type, SkTLazy<SkPaint>* filteredPaint) const {
+        if (paint) {
+            this->onFilterPaint(filteredPaint->set(*paint), type);
+        }
+        return true;
+    }
+
+    // DEPRECATED - do not use
+    virtual void onFilterPaint(SkPaint*, Type) const { }
 
     void onDrawPaint(const SkPaint&) override;
     void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;
@@ -66,11 +82,13 @@
     void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override;
     void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*,
                           SrcRectConstraint) override;
+    void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
+                          const SkPaint*) override;
     void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override;
     void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst,
                          const SkPaint*, SrcRectConstraint) override;
-    void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
-                          const SkPaint*) override;
+    void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
+                         const SkPaint*) override;
     void onDrawVertices(VertexMode vmode, int vertexCount,
                               const SkPoint vertices[], const SkPoint texs[],
                               const SkColor colors[], SkXfermode* xmode,
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index 9f0bd45..ce2cfb2 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -465,34 +465,39 @@
 public:
     FlagsFilterCanvas(SkCanvas* canvas, SkOSMenu::TriState lcd, SkOSMenu::TriState aa,
                       SkOSMenu::TriState subpixel, int hinting, int filterQuality)
-        : INHERITED(canvas->imageInfo().width(), canvas->imageInfo().height())
+        : INHERITED(canvas)
         , fLCDState(lcd)
         , fAAState(aa)
         , fSubpixelState(subpixel)
         , fHintingState(hinting)
         , fFilterQualityIndex(filterQuality) {
         SkASSERT((unsigned)filterQuality < SK_ARRAY_COUNT(gFilterQualityStates));
-
-        this->addCanvas(canvas);
     }
 
 protected:
-    void onFilterPaint(SkPaint* paint, Type t) const override {
+    bool onFilter(const SkPaint* paint, Type t, SkTLazy<SkPaint>* filteredPaint) const override {
+        if (!paint) {
+            return true;
+        }
+
+        filteredPaint->set(*paint);
         if (kText_Type == t && SkOSMenu::kMixedState != fLCDState) {
-            paint->setLCDRenderText(SkOSMenu::kOnState == fLCDState);
+            filteredPaint->get()->setLCDRenderText(SkOSMenu::kOnState == fLCDState);
         }
         if (SkOSMenu::kMixedState != fAAState) {
-            paint->setAntiAlias(SkOSMenu::kOnState == fAAState);
+            filteredPaint->get()->setAntiAlias(SkOSMenu::kOnState == fAAState);
         }
         if (0 != fFilterQualityIndex) {
-            paint->setFilterQuality(gFilterQualityStates[fFilterQualityIndex].fQuality);
+            filteredPaint->get()->setFilterQuality(
+                gFilterQualityStates[fFilterQualityIndex].fQuality);
         }
         if (SkOSMenu::kMixedState != fSubpixelState) {
-            paint->setSubpixelText(SkOSMenu::kOnState == fSubpixelState);
+            filteredPaint->get()->setSubpixelText(SkOSMenu::kOnState == fSubpixelState);
         }
         if (0 != fHintingState && fHintingState < (int)SK_ARRAY_COUNT(gHintingStates)) {
-            paint->setHinting(gHintingStates[fHintingState].hinting);
+            filteredPaint->get()->setHinting(gHintingStates[fHintingState].hinting);
         }
+        return true;
     }
 
 private:
diff --git a/src/utils/SkPaintFilterCanvas.cpp b/src/utils/SkPaintFilterCanvas.cpp
index ce1e4b7..0a5b7e6 100644
--- a/src/utils/SkPaintFilterCanvas.cpp
+++ b/src/utils/SkPaintFilterCanvas.cpp
@@ -12,20 +12,24 @@
 
 class SkPaintFilterCanvas::AutoPaintFilter {
 public:
-    AutoPaintFilter(const SkPaintFilterCanvas* canvas, Type type, const SkPaint* paint) {
-        if (paint) {
-            canvas->onFilterPaint(fLazyPaint.set(*paint), type);
-        }
+    AutoPaintFilter(const SkPaintFilterCanvas* canvas, Type type, const SkPaint* paint)
+        : fOrigPaint(paint) {
+        fShouldDraw = canvas->onFilter(fOrigPaint, type, &fFilteredPaint);
     }
 
-    AutoPaintFilter(const SkPaintFilterCanvas* canvas, Type type, const SkPaint& paint) {
-        canvas->onFilterPaint(fLazyPaint.set(paint), type);
+    AutoPaintFilter(const SkPaintFilterCanvas* canvas, Type type, const SkPaint& paint)
+        : AutoPaintFilter(canvas, type, &paint) { }
+
+    const SkPaint* paint() const {
+        return fFilteredPaint.isValid() ? fFilteredPaint.get() : fOrigPaint;
     }
 
-    const SkPaint* paint() const { return fLazyPaint.getMaybeNull(); }
+    bool shouldDraw() const { return fShouldDraw; }
 
 private:
-    SkTLazy<SkPaint> fLazyPaint;
+    const SkPaint*   fOrigPaint;
+    SkTLazy<SkPaint> fFilteredPaint;
+    bool             fShouldDraw;
 };
 
 SkPaintFilterCanvas::SkPaintFilterCanvas(int width, int height) : INHERITED(width, height) { }
@@ -44,70 +48,102 @@
 
 void SkPaintFilterCanvas::onDrawPaint(const SkPaint& paint) {
     AutoPaintFilter apf(this, kPaint_Type, paint);
-    this->INHERITED::onDrawPaint(*apf.paint());
+    if (apf.shouldDraw()) {
+        this->INHERITED::onDrawPaint(*apf.paint());
+    }
 }
 
 void SkPaintFilterCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
                                        const SkPaint& paint) {
     AutoPaintFilter apf(this, kPoint_Type, paint);
-    this->INHERITED::onDrawPoints(mode, count, pts, *apf.paint());
+    if (apf.shouldDraw()) {
+        this->INHERITED::onDrawPoints(mode, count, pts, *apf.paint());
+    }
 }
 
 void SkPaintFilterCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
     AutoPaintFilter apf(this, kRect_Type, paint);
-    this->INHERITED::onDrawRect(rect, *apf.paint());
+    if (apf.shouldDraw()) {
+        this->INHERITED::onDrawRect(rect, *apf.paint());
+    }
 }
 
 void SkPaintFilterCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
     AutoPaintFilter apf(this, kRRect_Type, paint);
-    this->INHERITED::onDrawRRect(rrect, *apf.paint());
+    if (apf.shouldDraw()) {
+        this->INHERITED::onDrawRRect(rrect, *apf.paint());
+    }
 }
 
 void SkPaintFilterCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
                                        const SkPaint& paint) {
     AutoPaintFilter apf(this, kDRRect_Type, paint);
-    this->INHERITED::onDrawDRRect(outer, inner, *apf.paint());
+    if (apf.shouldDraw()) {
+        this->INHERITED::onDrawDRRect(outer, inner, *apf.paint());
+    }
 }
 
 void SkPaintFilterCanvas::onDrawOval(const SkRect& rect, const SkPaint& paint) {
     AutoPaintFilter apf(this, kOval_Type, paint);
-    this->INHERITED::onDrawOval(rect, *apf.paint());
+    if (apf.shouldDraw()) {
+        this->INHERITED::onDrawOval(rect, *apf.paint());
+    }
 }
 
 void SkPaintFilterCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
     AutoPaintFilter apf(this, kPath_Type, paint);
-    this->INHERITED::onDrawPath(path, *apf.paint());
+    if (apf.shouldDraw()) {
+        this->INHERITED::onDrawPath(path, *apf.paint());
+    }
 }
 
 void SkPaintFilterCanvas::onDrawBitmap(const SkBitmap& bm, SkScalar left, SkScalar top,
                                        const SkPaint* paint) {
     AutoPaintFilter apf(this, kBitmap_Type, paint);
-    this->INHERITED::onDrawBitmap(bm, left, top, apf.paint());
+    if (apf.shouldDraw()) {
+        this->INHERITED::onDrawBitmap(bm, left, top, apf.paint());
+    }
 }
 
 void SkPaintFilterCanvas::onDrawBitmapRect(const SkBitmap& bm, const SkRect* src, const SkRect& dst,
                                            const SkPaint* paint, SrcRectConstraint constraint) {
     AutoPaintFilter apf(this, kBitmap_Type, paint);
-    this->INHERITED::onDrawBitmapRect(bm, src, dst, apf.paint(), constraint);
+    if (apf.shouldDraw()) {
+        this->INHERITED::onDrawBitmapRect(bm, src, dst, apf.paint(), constraint);
+    }
+}
+
+void SkPaintFilterCanvas::onDrawBitmapNine(const SkBitmap& bm, const SkIRect& center,
+                                           const SkRect& dst, const SkPaint* paint) {
+    AutoPaintFilter apf(this, kBitmap_Type, paint);
+    if (apf.shouldDraw()) {
+        this->INHERITED::onDrawBitmapNine(bm, center, dst, apf.paint());
+    }
 }
 
 void SkPaintFilterCanvas::onDrawImage(const SkImage* image, SkScalar left, SkScalar top,
                                       const SkPaint* paint) {
     AutoPaintFilter apf(this, kBitmap_Type, paint);
-    this->INHERITED::onDrawImage(image, left, top, apf.paint());
+    if (apf.shouldDraw()) {
+        this->INHERITED::onDrawImage(image, left, top, apf.paint());
+    }
 }
 
 void SkPaintFilterCanvas::onDrawImageRect(const SkImage* image, const SkRect* src,
                                           const SkRect& dst, const SkPaint* paint,
                                           SrcRectConstraint constraint) {
     AutoPaintFilter apf(this, kBitmap_Type, paint);
-    this->INHERITED::onDrawImageRect(image, src, dst, apf.paint(), constraint);
+    if (apf.shouldDraw()) {
+        this->INHERITED::onDrawImageRect(image, src, dst, apf.paint(), constraint);
+    }
 }
 
-void SkPaintFilterCanvas::onDrawBitmapNine(const SkBitmap& bm, const SkIRect& center,
-                                           const SkRect& dst, const SkPaint* paint) {
+void SkPaintFilterCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center,
+                                               const SkRect& dst, const SkPaint* paint) {
     AutoPaintFilter apf(this, kBitmap_Type, paint);
-    this->INHERITED::onDrawBitmapNine(bm, center, dst, apf.paint());
+    if (apf.shouldDraw()) {
+        this->INHERITED::onDrawImageNine(image, center, dst, apf.paint());
+    }
 }
 
 void SkPaintFilterCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
@@ -116,49 +152,65 @@
                                          const uint16_t indices[], int indexCount,
                                          const SkPaint& paint) {
     AutoPaintFilter apf(this, kVertices_Type, paint);
-    this->INHERITED::onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode, indices,
-                                    indexCount, *apf.paint());
+    if (apf.shouldDraw()) {
+        this->INHERITED::onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode, indices,
+                                        indexCount, *apf.paint());
+    }
 }
 
 void SkPaintFilterCanvas::onDrawPatch(const SkPoint cubics[], const SkColor colors[],
                                       const SkPoint texCoords[], SkXfermode* xmode,
                                       const SkPaint& paint) {
     AutoPaintFilter apf(this, kPatch_Type, paint);
-    this->INHERITED::onDrawPatch(cubics, colors, texCoords, xmode, *apf.paint());
+    if (apf.shouldDraw()) {
+        this->INHERITED::onDrawPatch(cubics, colors, texCoords, xmode, *apf.paint());
+    }
 }
 
 void SkPaintFilterCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* m,
                                         const SkPaint* paint) {
     AutoPaintFilter apf(this, kPicture_Type, paint);
-    this->INHERITED::onDrawPicture(picture, m, apf.paint());
+    if (apf.shouldDraw()) {
+        this->INHERITED::onDrawPicture(picture, m, apf.paint());
+    }
 }
 
 void SkPaintFilterCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
                                      const SkPaint& paint) {
     AutoPaintFilter apf(this, kText_Type, paint);
-    this->INHERITED::onDrawText(text, byteLength, x, y, *apf.paint());
+    if (apf.shouldDraw()) {
+        this->INHERITED::onDrawText(text, byteLength, x, y, *apf.paint());
+    }
 }
 
 void SkPaintFilterCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
                                         const SkPaint& paint) {
     AutoPaintFilter apf(this, kText_Type, paint);
-    this->INHERITED::onDrawPosText(text, byteLength, pos, *apf.paint());
+    if (apf.shouldDraw()) {
+        this->INHERITED::onDrawPosText(text, byteLength, pos, *apf.paint());
+    }
 }
 
 void SkPaintFilterCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
                                          SkScalar constY, const SkPaint& paint) {
     AutoPaintFilter apf(this, kText_Type, paint);
-    this->INHERITED::onDrawPosTextH(text, byteLength, xpos, constY, *apf.paint());
+    if (apf.shouldDraw()) {
+        this->INHERITED::onDrawPosTextH(text, byteLength, xpos, constY, *apf.paint());
+    }
 }
 
 void SkPaintFilterCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
                                            const SkMatrix* matrix, const SkPaint& paint) {
     AutoPaintFilter apf(this, kText_Type, paint);
-    this->INHERITED::onDrawTextOnPath(text, byteLength, path, matrix, *apf.paint());
+    if (apf.shouldDraw()) {
+        this->INHERITED::onDrawTextOnPath(text, byteLength, path, matrix, *apf.paint());
+    }
 }
 
 void SkPaintFilterCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
                                          const SkPaint& paint) {
     AutoPaintFilter apf(this, kTextBlob_Type, paint);
-    this->INHERITED::onDrawTextBlob(blob, x, y, *apf.paint());
+    if (apf.shouldDraw()) {
+        this->INHERITED::onDrawTextBlob(blob, x, y, *apf.paint());
+    }
 }
diff --git a/src/utils/debugger/SkDebugCanvas.cpp b/src/utils/debugger/SkDebugCanvas.cpp
index 560976c..9f11a9e 100644
--- a/src/utils/debugger/SkDebugCanvas.cpp
+++ b/src/utils/debugger/SkDebugCanvas.cpp
@@ -69,15 +69,19 @@
         , fFilterQuality(quality) {}
 
 protected:
-    void onFilterPaint(SkPaint* paint, Type) const override {
-        if (nullptr != fOverdrawXfermode.get()) {
-            paint->setAntiAlias(false);
-            paint->setXfermode(fOverdrawXfermode.get());
-        }
+    bool onFilter(const SkPaint* paint, Type, SkTLazy<SkPaint>* filteredPaint) const override {
+        if (paint) {
+            filteredPaint->set(*paint);
+            if (nullptr != fOverdrawXfermode.get()) {
+                filteredPaint->get()->setAntiAlias(false);
+                filteredPaint->get()->setXfermode(fOverdrawXfermode.get());
+            }
 
-        if (fOverrideFilterQuality) {
-            paint->setFilterQuality(fFilterQuality);
+            if (fOverrideFilterQuality) {
+                filteredPaint->get()->setFilterQuality(fFilterQuality);
+            }
         }
+        return true;
     }
 
     void onDrawPicture(const SkPicture* picture,
diff --git a/tests/CanvasTest.cpp b/tests/CanvasTest.cpp
index 87705dc..516dd05 100644
--- a/tests/CanvasTest.cpp
+++ b/tests/CanvasTest.cpp
@@ -730,7 +730,7 @@
     MockFilterCanvas(SkCanvas* canvas) : INHERITED(canvas) { }
 
 protected:
-    void onFilterPaint(SkPaint *paint, Type type) const override { }
+    bool onFilter(const SkPaint*, Type, SkTLazy<SkPaint>*) const override { return true; }
 
 private:
     typedef SkPaintFilterCanvas INHERITED;