simplify handle-affine: subclass overrides just describe their leaf behavior

added new test case (that would have failed before) of blur with a colorfilter input

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1915943002

Review URL: https://codereview.chromium.org/1915943002
diff --git a/include/core/SkImageFilter.h b/include/core/SkImageFilter.h
index e2ec756..32a52d9 100644
--- a/include/core/SkImageFilter.h
+++ b/include/core/SkImageFilter.h
@@ -220,7 +220,7 @@
      *  them can handle affine (or more complex) matrices. This call returns true iff the filter
      *  and all of its (non-null) inputs can handle these more complex matrices.
      */
-    bool canHandleAffine() const { return this->onCanHandleAffine(); }
+    bool canHandleComplexCTM() const;
 
     /**
      * Return an imagefilter which transforms its input by the given matrix.
@@ -349,7 +349,11 @@
         return false;
     }
 
-    virtual bool onCanHandleAffine() const;
+    /**
+     *  Override this to describe the behavior of your subclass - as a leaf node. The caller will
+     *  take care of calling your inputs (and return false if any of them could not handle it).
+     */
+    virtual bool onCanHandleComplexCTM() const { return false; }
 
     /** Given a "srcBounds" rect, computes destination bounds for this filter.
      *  "dstBounds" are computed by transforming the crop rect by the context's
diff --git a/include/effects/SkColorFilterImageFilter.h b/include/effects/SkColorFilterImageFilter.h
index 10e1ffa..4d438e3 100644
--- a/include/effects/SkColorFilterImageFilter.h
+++ b/include/effects/SkColorFilterImageFilter.h
@@ -36,7 +36,7 @@
     sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context&,
                                         SkIPoint* offset) const override;
     bool onIsColorFilterNode(SkColorFilter**) const override;
-    bool onCanHandleAffine() const override;
+    bool onCanHandleComplexCTM() const override { return true; }
     bool affectsTransparentBlack() const override;
 
 private:
diff --git a/include/effects/SkComposeImageFilter.h b/include/effects/SkComposeImageFilter.h
index fe0814a..378b904 100644
--- a/include/effects/SkComposeImageFilter.h
+++ b/include/effects/SkComposeImageFilter.h
@@ -34,6 +34,7 @@
     sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context&,
                                         SkIPoint* offset) const override;
     SkIRect onFilterBounds(const SkIRect&, const SkMatrix&, MapDirection) const override;
+    bool onCanHandleComplexCTM() const override { return true; }
 
 private:
     typedef SkImageFilter INHERITED;
diff --git a/include/effects/SkMergeImageFilter.h b/include/effects/SkMergeImageFilter.h
index 3bab08b..20620d6 100644
--- a/include/effects/SkMergeImageFilter.h
+++ b/include/effects/SkMergeImageFilter.h
@@ -51,6 +51,7 @@
     void flatten(SkWriteBuffer&) const override;
     sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context&,
                                         SkIPoint* offset) const override;
+    bool onCanHandleComplexCTM() const override { return true; }
 
 private:
     SkMergeImageFilter(sk_sp<SkImageFilter> filters[], int count, const SkXfermode::Mode modes[],
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index f8731e9..7552626 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -1217,7 +1217,7 @@
      *  Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
      *  a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
      */
-    if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleAffine() &&
+    if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
         stashedMatrix.decomposeScale(&scale, &remainder))
     {
         // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp
index 6c73be2..ab175884 100644
--- a/src/core/SkImageFilter.cpp
+++ b/src/core/SkImageFilter.cpp
@@ -330,22 +330,18 @@
     return true;
 }
 
-bool SkImageFilter::onCanHandleAffine() const {
-    bool hasInputs = false;
-
+bool SkImageFilter::canHandleComplexCTM() const {
+    if (!this->onCanHandleComplexCTM()) {
+        return false;
+    }
     const int count = this->countInputs();
     for (int i = 0; i < count; ++i) {
         SkImageFilter* input = this->getInput(i);
-        if (input) {
-            if (!input->canHandleAffine()) {
-                return false;
-            }
-            hasInputs = true;
+        if (input && !input->canHandleComplexCTM()) {
+            return false;
         }
     }
-    // We return true iff we had 1 or more inputs, and all of them can handle affine.
-    // If we have no inputs, or 1 or more of them do not handle affine, then we return false.
-    return hasInputs;
+    return true;
 }
 
 bool SkImageFilter::applyCropRect(const Context& ctx, const SkIRect& srcBounds,
diff --git a/src/effects/SkColorFilterImageFilter.cpp b/src/effects/SkColorFilterImageFilter.cpp
index 7a2f4cc..8d412cc 100644
--- a/src/effects/SkColorFilterImageFilter.cpp
+++ b/src/effects/SkColorFilterImageFilter.cpp
@@ -126,12 +126,6 @@
     return false;
 }
 
-bool SkColorFilterImageFilter::onCanHandleAffine() const {
-    SkASSERT(1 == this->countInputs());
-    SkImageFilter* input = this->getInput(0);
-    return !input || input->canHandleAffine();
-}
-
 bool SkColorFilterImageFilter::affectsTransparentBlack() const {
     return fColorFilter->affectsTransparentBlack();
 }
diff --git a/tests/ImageFilterTest.cpp b/tests/ImageFilterTest.cpp
index 7aefd48..952e5e5 100644
--- a/tests/ImageFilterTest.cpp
+++ b/tests/ImageFilterTest.cpp
@@ -1711,11 +1711,11 @@
  *  Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
  *  than just scale/translate, but that other filters do.
  */
-DEF_TEST(ImageFilterDecomposeCTM, reporter) {
+DEF_TEST(ImageFilterComplexCTM, reporter) {
     // just need a colorfilter to exercise the corresponding imagefilter
     sk_sp<SkColorFilter> cf = SkColorFilter::MakeModeFilter(SK_ColorRED, SkXfermode::kSrcATop_Mode);
-    sk_sp<SkImageFilter> cfif = SkColorFilterImageFilter::Make(cf, nullptr);
-    sk_sp<SkImageFilter> blif = SkBlurImageFilter::Make(3, 3, nullptr);
+    sk_sp<SkImageFilter> cfif = SkColorFilterImageFilter::Make(cf, nullptr);    // can handle
+    sk_sp<SkImageFilter> blif = SkBlurImageFilter::Make(3, 3, nullptr);         // cannot handle
 
     struct {
         sk_sp<SkImageFilter> fFilter;
@@ -1724,13 +1724,17 @@
         { cfif,                                     true  },
         { SkColorFilterImageFilter::Make(cf, cfif), true  },
         { SkMergeImageFilter::Make(cfif, cfif),     true  },
+        { SkComposeImageFilter::Make(cfif, cfif),   true  },
+
         { blif,                                     false },
-        { SkMergeImageFilter::Make(cfif, blif),     false },
+        { SkBlurImageFilter::Make(3, 3, cfif),      false },
         { SkColorFilterImageFilter::Make(cf, blif), false },
+        { SkMergeImageFilter::Make(cfif, blif),     false },
+        { SkComposeImageFilter::Make(blif, cfif),   false },
     };
     
     for (const auto& rec : recs) {
-        const bool canHandle = rec.fFilter->canHandleAffine();
+        const bool canHandle = rec.fFilter->canHandleComplexCTM();
         REPORTER_ASSERT(reporter, canHandle == rec.fExpectCanHandle);
     }
 }