Pass CTM to path effects (experimental)

Add an overload to SkPathEffect that can be used when the CTM is known
at the callsite. GPU callsites are not handled here, that will be
tackled in a separate CL.

Path effects must implement the filterPath virtual that accepts the CTM,
although they are not obligated to use it. If a path effect does
use the CTM, the output geometry must be in the original coordinate
space, not device space.

Bug: skia:11957
Change-Id: I01615985599fe2736de954bb10dac881b0554ae7
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/420239
Commit-Queue: Tyler Denniston <tdenniston@google.com>
Reviewed-by: Mike Reed <reed@google.com>
diff --git a/src/effects/Sk1DPathEffect.cpp b/src/effects/Sk1DPathEffect.cpp
index 0110725..44787a0 100644
--- a/src/effects/Sk1DPathEffect.cpp
+++ b/src/effects/Sk1DPathEffect.cpp
@@ -20,7 +20,8 @@
 class Sk1DPathEffect : public SkPathEffectBase {
 public:
 protected:
-    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override {
+    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*,
+                      const SkMatrix&) const override {
         SkPathMeasure   meas(src, false);
         do {
             int governor = MAX_REASONABLE_ITERATIONS;
@@ -92,9 +93,9 @@
     }
 
     bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
-                      const SkRect* cullRect) const override {
+                      const SkRect* cullRect, const SkMatrix& ctm) const override {
         rec->setFillStyle();
-        return this->INHERITED::onFilterPath(dst, src, rec, cullRect);
+        return this->INHERITED::onFilterPath(dst, src, rec, cullRect, ctm);
     }
 
     SkScalar begin(SkScalar contourLength) const override {
diff --git a/src/effects/Sk2DPathEffect.cpp b/src/effects/Sk2DPathEffect.cpp
index cca33db..c7e8d04 100644
--- a/src/effects/Sk2DPathEffect.cpp
+++ b/src/effects/Sk2DPathEffect.cpp
@@ -64,7 +64,7 @@
     }
 
     bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
-                      const SkRect* cullRect) const override {
+                      const SkRect* cullRect, const SkMatrix&) const override {
         if (!fMatrixIsInvertible) {
             return false;
         }
@@ -115,8 +115,8 @@
     }
 
     bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
-                      const SkRect* cullRect) const override {
-        if (this->INHERITED::onFilterPath(dst, src, rec, cullRect)) {
+                      const SkRect* cullRect, const SkMatrix& ctm) const override {
+        if (this->INHERITED::onFilterPath(dst, src, rec, cullRect, ctm)) {
             rec->setStrokeStyle(fWidth);
             return true;
         }
diff --git a/src/effects/SkCornerPathEffect.cpp b/src/effects/SkCornerPathEffect.cpp
index ce25bad..620e30f 100644
--- a/src/effects/SkCornerPathEffect.cpp
+++ b/src/effects/SkCornerPathEffect.cpp
@@ -33,7 +33,8 @@
         SkASSERT(radius > 0);
     }
 
-    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override {
+    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*,
+                      const SkMatrix&) const override {
         if (fRadius <= 0) {
             return false;
         }
diff --git a/src/effects/SkDashImpl.h b/src/effects/SkDashImpl.h
index fbb343c..8439ca0 100644
--- a/src/effects/SkDashImpl.h
+++ b/src/effects/SkDashImpl.h
@@ -17,7 +17,8 @@
 protected:
     ~SkDashImpl() override;
     void flatten(SkWriteBuffer&) const override;
-    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override;
+    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*,
+                      const SkMatrix&) const override;
 
     bool onAsPoints(PointData* results, const SkPath& src, const SkStrokeRec&, const SkMatrix&,
                     const SkRect*) const override;
diff --git a/src/effects/SkDashPathEffect.cpp b/src/effects/SkDashPathEffect.cpp
index d392dc2..0886784 100644
--- a/src/effects/SkDashPathEffect.cpp
+++ b/src/effects/SkDashPathEffect.cpp
@@ -40,7 +40,7 @@
 }
 
 bool SkDashImpl::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
-                              const SkRect* cullRect) const {
+                              const SkRect* cullRect, const SkMatrix&) const {
     return SkDashPath::InternalFilter(dst, src, rec, cullRect, fIntervals, fCount,
                                       fInitialDashLength, fInitialDashIndex, fIntervalLength);
 }
diff --git a/src/effects/SkDiscretePathEffect.cpp b/src/effects/SkDiscretePathEffect.cpp
index cc2f49b..a57a67f 100644
--- a/src/effects/SkDiscretePathEffect.cpp
+++ b/src/effects/SkDiscretePathEffect.cpp
@@ -74,7 +74,7 @@
     }
 
     bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
-                      const SkRect*) const override {
+                      const SkRect*, const SkMatrix&) const override {
         bool doFill = rec->isFillStyle();
 
         SkPathMeasure   meas(src, doFill);
diff --git a/src/effects/SkOpPE.h b/src/effects/SkOpPE.h
index 03d14d3..11c968f 100644
--- a/src/effects/SkOpPE.h
+++ b/src/effects/SkOpPE.h
@@ -18,7 +18,8 @@
 
 protected:
     void flatten(SkWriteBuffer&) const override;
-    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override;
+    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*,
+                      const SkMatrix&) const override;
 
 private:
     SK_FLATTENABLE_HOOKS(SkOpPE)
@@ -38,7 +39,8 @@
 
 protected:
     void flatten(SkWriteBuffer&) const override;
-    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override;
+    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*,
+                      const SkMatrix&) const override;
 
 private:
     SK_FLATTENABLE_HOOKS(SkMatrixPE)
@@ -61,7 +63,8 @@
 
 protected:
     void flatten(SkWriteBuffer&) const override;
-    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override;
+    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*,
+                      const SkMatrix&) const override;
 
 private:
     SK_FLATTENABLE_HOOKS(SkStrokePE)
@@ -82,7 +85,8 @@
 
 protected:
     void flatten(SkWriteBuffer&) const override;
-    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override;
+    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*,
+                      const SkMatrix&) const override;
 
 private:
     SK_FLATTENABLE_HOOKS(SkStrokeAndFillPE)
diff --git a/src/effects/SkOpPathEffect.cpp b/src/effects/SkOpPathEffect.cpp
index c44ca06..dd9a978 100644
--- a/src/effects/SkOpPathEffect.cpp
+++ b/src/effects/SkOpPathEffect.cpp
@@ -21,17 +21,17 @@
     : fOne(std::move(one)), fTwo(std::move(two)), fOp(op) {}
 
 bool SkOpPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
-                          const SkRect* cull) const {
+                          const SkRect* cull, const SkMatrix& ctm) const {
     SkPath one, two;
     if (fOne) {
-        if (!fOne->filterPath(&one, src, rec, cull)) {
+        if (!fOne->filterPath(&one, src, rec, cull, ctm)) {
             return false;
         }
     } else {
         one = src;
     }
     if (fTwo) {
-        if (!fTwo->filterPath(&two, src, rec, cull)) {
+        if (!fTwo->filterPath(&two, src, rec, cull, ctm)) {
             return false;
         }
     } else {
@@ -111,7 +111,8 @@
     SkASSERT(matrix.isFinite());
 }
 
-bool SkMatrixPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const {
+bool SkMatrixPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*,
+                              const SkMatrix&) const {
     src.transform(fMatrix, dst);
     return true;
 }
@@ -139,7 +140,8 @@
 SkStrokePE::SkStrokePE(SkScalar width, SkPaint::Join join, SkPaint::Cap cap, SkScalar miter)
     : fWidth(width), fMiter(miter), fJoin(join), fCap(cap) {}
 
-bool SkStrokePE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const {
+bool SkStrokePE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*,
+                              const SkMatrix&) const {
     SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
     rec.setStrokeStyle(fWidth);
     rec.setStrokeParams(fCap, fJoin, fMiter);
@@ -195,7 +197,7 @@
 }
 
 bool SkStrokeAndFillPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
-                                     const SkRect*) const {
+                                     const SkRect*, const SkMatrix&) const {
     // This one is weird, since we exist to allow this paint-style to go away. If we see it,
     // just let the normal machine run its course.
     if (rec->getStyle() == SkStrokeRec::kStrokeAndFill_Style) {
diff --git a/src/effects/SkTrimPE.h b/src/effects/SkTrimPE.h
index 3dd320e..4aa9420 100644
--- a/src/effects/SkTrimPE.h
+++ b/src/effects/SkTrimPE.h
@@ -17,7 +17,8 @@
 
 protected:
     void flatten(SkWriteBuffer&) const override;
-    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override;
+    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*,
+                      const SkMatrix&) const override;
 
 private:
     SK_FLATTENABLE_HOOKS(SkTrimPE)
diff --git a/src/effects/SkTrimPathEffect.cpp b/src/effects/SkTrimPathEffect.cpp
index 7c91491..51307f6 100644
--- a/src/effects/SkTrimPathEffect.cpp
+++ b/src/effects/SkTrimPathEffect.cpp
@@ -48,7 +48,8 @@
 SkTrimPE::SkTrimPE(SkScalar startT, SkScalar stopT, SkTrimPathEffect::Mode mode)
     : fStartT(startT), fStopT(stopT), fMode(mode) {}
 
-bool SkTrimPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const {
+bool SkTrimPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*,
+                            const SkMatrix&) const {
     if (fStartT >= fStopT) {
         SkASSERT(fMode == SkTrimPathEffect::Mode::kNormal);
         return true;