Move patheffect details to (private) base subclass

bug: skia:11957
Change-Id: Iceaa0ac1d7a3f049d2725629d78c755ad03a2862
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/411302
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
diff --git a/include/core/SkPathEffect.h b/include/core/SkPathEffect.h
index ec7aa4d..7f21cf6 100644
--- a/include/core/SkPathEffect.h
+++ b/include/core/SkPathEffect.h
@@ -9,11 +9,12 @@
 #define SkPathEffect_DEFINED
 
 #include "include/core/SkFlattenable.h"
+#include "include/core/SkScalar.h"
+// not needed, but some of our clients need it (they don't IWYU)
 #include "include/core/SkPath.h"
-#include "include/core/SkPoint.h"
-#include "include/core/SkRect.h"
 
 class SkPath;
+struct SkRect;
 class SkStrokeRec;
 
 /** \class SkPathEffect
@@ -43,81 +44,11 @@
      */
     static sk_sp<SkPathEffect> MakeCompose(sk_sp<SkPathEffect> outer, sk_sp<SkPathEffect> inner);
 
-    /**
-     *  Given a src path (input) and a stroke-rec (input and output), apply
-     *  this effect to the src path, returning the new path in dst, and return
-     *  true. If this effect cannot be applied, return false and ignore dst
-     *  and stroke-rec.
-     *
-     *  The stroke-rec specifies the initial request for stroking (if any).
-     *  The effect can treat this as input only, or it can choose to change
-     *  the rec as well. For example, the effect can decide to change the
-     *  stroke's width or join, or the effect can change the rec from stroke
-     *  to fill (or fill to stroke) in addition to returning a new (dst) path.
-     *
-     *  If this method returns true, the caller will apply (as needed) the
-     *  resulting stroke-rec to dst and then draw.
-     */
-    bool filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect* cullR) const;
+    static SkFlattenable::Type GetFlattenableType() {
+        return kSkPathEffect_Type;
+    }
 
-    /** \class PointData
-
-        PointData aggregates all the information needed to draw the point
-        primitives returned by an 'asPoints' call.
-    */
-    class PointData {
-    public:
-        PointData()
-            : fFlags(0)
-            , fPoints(nullptr)
-            , fNumPoints(0) {
-            fSize.set(SK_Scalar1, SK_Scalar1);
-            // 'asPoints' needs to initialize/fill-in 'fClipRect' if it sets
-            // the kUseClip flag
-        }
-        ~PointData() {
-            delete [] fPoints;
-        }
-
-        // TODO: consider using passed-in flags to limit the work asPoints does.
-        // For example, a kNoPath flag could indicate don't bother generating
-        // stamped solutions.
-
-        // Currently none of these flags are supported.
-        enum PointFlags {
-            kCircles_PointFlag            = 0x01,   // draw points as circles (instead of rects)
-            kUsePath_PointFlag            = 0x02,   // draw points as stamps of the returned path
-            kUseClip_PointFlag            = 0x04,   // apply 'fClipRect' before drawing the points
-        };
-
-        uint32_t           fFlags;      // flags that impact the drawing of the points
-        SkPoint*           fPoints;     // the center point of each generated point
-        int                fNumPoints;  // number of points in fPoints
-        SkVector           fSize;       // the size to draw the points
-        SkRect             fClipRect;   // clip required to draw the points (if kUseClip is set)
-        SkPath             fPath;       // 'stamp' to be used at each point (if kUsePath is set)
-
-        SkPath             fFirst;      // If not empty, contains geometry for first point
-        SkPath             fLast;       // If not empty, contains geometry for last point
-    };
-
-    /**
-     *  Does applying this path effect to 'src' yield a set of points? If so,
-     *  optionally return the points in 'results'.
-     */
-    bool asPoints(PointData* results, const SkPath& src,
-                          const SkStrokeRec&, const SkMatrix&,
-                          const SkRect* cullR) const;
-
-    /**
-     *  If the PathEffect can be represented as a dash pattern, asADash will return kDash_DashType
-     *  and None otherwise. If a non NULL info is passed in, the various DashInfo will be filled
-     *  in if the PathEffect can be a dash pattern. If passed in info has an fCount equal or
-     *  greater to that of the effect, it will memcpy the values of the dash intervals into the
-     *  info. Thus the general approach will be call asADash once with default info to get DashType
-     *  and fCount. If effect can be represented as a dash pattern, allocate space for the intervals
-     *  in info, then call asADash again with the same info and the intervals will get copied in.
-     */
+    // move to base?
 
     enum DashType {
         kNone_DashType, //!< ignores the info parameter
@@ -138,48 +69,26 @@
 
     DashType asADash(DashInfo* info) const;
 
-    static void RegisterFlattenables();
-
-    static SkFlattenable::Type GetFlattenableType() {
-        return kSkPathEffect_Type;
-    }
-
-    SkFlattenable::Type getFlattenableType() const override {
-        return kSkPathEffect_Type;
-    }
-
-    static sk_sp<SkPathEffect> Deserialize(const void* data, size_t size,
-                                          const SkDeserialProcs* procs = nullptr) {
-        return sk_sp<SkPathEffect>(static_cast<SkPathEffect*>(
-                                  SkFlattenable::Deserialize(
-                                  kSkPathEffect_Type, data, size, procs).release()));
-    }
-
-protected:
-    SkPathEffect() {}
-
-    virtual bool onFilterPath(SkPath*, const SkPath&, SkStrokeRec*, const SkRect*) const = 0;
-    virtual bool onAsPoints(PointData*, const SkPath&, const SkStrokeRec&, const SkMatrix&,
-                            const SkRect*) const {
-        return false;
-    }
-    virtual DashType onAsADash(DashInfo*) const {
-        return kNone_DashType;
-    }
+    /**
+     *  Given a src path (input) and a stroke-rec (input and output), apply
+     *  this effect to the src path, returning the new path in dst, and return
+     *  true. If this effect cannot be applied, return false and ignore dst
+     *  and stroke-rec.
+     *
+     *  The stroke-rec specifies the initial request for stroking (if any).
+     *  The effect can treat this as input only, or it can choose to change
+     *  the rec as well. For example, the effect can decide to change the
+     *  stroke's width or join, or the effect can change the rec from stroke
+     *  to fill (or fill to stroke) in addition to returning a new (dst) path.
+     *
+     *  If this method returns true, the caller will apply (as needed) the
+     *  resulting stroke-rec to dst and then draw.
+     */
+    bool filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect* cullR) const;
 
 private:
-    friend class SkPathEffectPriv;
-
-    // Compute a conservative bounds for its effect, given the bounds of the path. 'bounds' is
-    // both the input and output; if false is returned, fast bounds could not be calculated and
-    // 'bounds' is undefined.
-    //
-    // If 'bounds' is null, performs a dry-run determining if bounds could be computed.
-    virtual bool computeFastBounds(SkRect* bounds) const = 0;
-
-    // illegal
-    SkPathEffect(const SkPathEffect&);
-    SkPathEffect& operator=(const SkPathEffect&);
+    SkPathEffect() = default;
+    friend class SkPathEffectBase;
 
     using INHERITED = SkFlattenable;
 };
diff --git a/include/effects/SkDiscretePathEffect.h b/include/effects/SkDiscretePathEffect.h
index 542536f..6054cbd 100644
--- a/include/effects/SkDiscretePathEffect.h
+++ b/include/effects/SkDiscretePathEffect.h
@@ -14,7 +14,7 @@
 
     This path effect chops a path into discrete segments, and randomly displaces them.
 */
-class SK_API SkDiscretePathEffect : public SkPathEffect {
+class SK_API SkDiscretePathEffect {
 public:
     /** Break the path into segments of segLength length, and randomly move the endpoints
         away from the original path by a maximum of deviation.
diff --git a/include/effects/SkOpPathEffect.h b/include/effects/SkOpPathEffect.h
index 9686644..268789e 100644
--- a/include/effects/SkOpPathEffect.h
+++ b/include/effects/SkOpPathEffect.h
@@ -8,6 +8,7 @@
 #ifndef SkOpPathEffect_DEFINED
 #define SkOpPathEffect_DEFINED
 
+#include "include/core/SkMatrix.h"
 #include "include/core/SkPaint.h"
 #include "include/core/SkPathEffect.h"
 #include "include/pathops/SkPathOps.h"
diff --git a/modules/sksg/src/SkSGGeometryEffect.cpp b/modules/sksg/src/SkSGGeometryEffect.cpp
index 57ad3cb..e66bbf1 100644
--- a/modules/sksg/src/SkSGGeometryEffect.cpp
+++ b/modules/sksg/src/SkSGGeometryEffect.cpp
@@ -14,6 +14,7 @@
 #include "include/effects/SkTrimPathEffect.h"
 #include "include/pathops/SkPathOps.h"
 #include "modules/sksg/src/SkSGTransformPriv.h"
+#include "src/core/SkPathEffectBase.h"
 #include "src/core/SkPathPriv.h"
 
 #include <cmath>
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index 6f54714..f576b58 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -28,6 +28,7 @@
 #include "src/core/SkDrawProcs.h"
 #include "src/core/SkMaskFilterBase.h"
 #include "src/core/SkMatrixUtils.h"
+#include "src/core/SkPathEffectBase.h"
 #include "src/core/SkPathPriv.h"
 #include "src/core/SkRasterClip.h"
 #include "src/core/SkRectPriv.h"
@@ -437,13 +438,13 @@
                     // most likely a dashed line - see if it is one of the ones
                     // we can accelerate
                     SkStrokeRec rec(paint);
-                    SkPathEffect::PointData pointData;
+                    SkPathEffectBase::PointData pointData;
 
                     SkPath path = SkPath::Line(pts[0], pts[1]);
 
                     SkRect cullRect = SkRect::Make(fRC->getBounds());
 
-                    if (paint.getPathEffect()->asPoints(&pointData, path, rec, ctm, &cullRect)) {
+                    if (as_PEB(paint.getPathEffect())->asPoints(&pointData, path, rec, ctm, &cullRect)) {
                         // 'asPoints' managed to find some fast path
 
                         SkPaint newP(paint);
@@ -470,7 +471,7 @@
                             // The rest of the dashed line can just be drawn as points
                             SkASSERT(pointData.fSize.fX == SkScalarHalf(newP.getStrokeWidth()));
 
-                            if (SkPathEffect::PointData::kCircles_PointFlag & pointData.fFlags) {
+                            if (SkPathEffectBase::PointData::kCircles_PointFlag & pointData.fFlags) {
                                 newP.setStrokeCap(SkPaint::kRound_Cap);
                             } else {
                                 newP.setStrokeCap(SkPaint::kButt_Cap);
@@ -491,7 +492,7 @@
                             break;
                         } else {
                             // The rest of the dashed line must be drawn as rects
-                            SkASSERT(!(SkPathEffect::PointData::kCircles_PointFlag &
+                            SkASSERT(!(SkPathEffectBase::PointData::kCircles_PointFlag &
                                       pointData.fFlags));
 
                             SkRect r;
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index 0255297..5047b83 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -26,7 +26,7 @@
 #include "src/core/SkOpts.h"
 #include "src/core/SkPaintDefaults.h"
 #include "src/core/SkPaintPriv.h"
-#include "src/core/SkPathEffectPriv.h"
+#include "src/core/SkPathEffectBase.h"
 #include "src/core/SkReadBuffer.h"
 #include "src/core/SkSafeRange.h"
 #include "src/core/SkStringUtils.h"
@@ -373,7 +373,7 @@
     }
     // Pass nullptr for the bounds to determine if they can be computed
     if (this->getPathEffect() &&
-        !SkPathEffectPriv::ComputeFastBounds(this->getPathEffect(), nullptr)) {
+        !as_PEB(this->getPathEffect())->computeFastBounds(nullptr)) {
         return false;
     }
     return true;
@@ -389,7 +389,7 @@
     SkRect tmpSrc;
     if (this->getPathEffect()) {
         tmpSrc = origSrc;
-        SkAssertResult(SkPathEffectPriv::ComputeFastBounds(this->getPathEffect(), &tmpSrc));
+        SkAssertResult(as_PEB(this->getPathEffect())->computeFastBounds(&tmpSrc));
         src = &tmpSrc;
     }
 
diff --git a/src/core/SkPathEffect.cpp b/src/core/SkPathEffect.cpp
index a14c1bf..9431736 100644
--- a/src/core/SkPathEffect.cpp
+++ b/src/core/SkPathEffect.cpp
@@ -7,7 +7,7 @@
 
 #include "include/core/SkPath.h"
 #include "include/core/SkPathEffect.h"
-#include "src/core/SkPathEffectPriv.h"
+#include "src/core/SkPathEffectBase.h"
 #include "src/core/SkReadBuffer.h"
 #include "src/core/SkWriteBuffer.h"
 
@@ -19,7 +19,7 @@
     if (dst == &src) {
         tmpDst = &tmp;
     }
-    if (this->onFilterPath(tmpDst, src, rec, bounds)) {
+    if (as_PEB(this)->onFilterPath(tmpDst, src, rec, bounds)) {
         if (dst == &src) {
             *dst = tmp;
         }
@@ -28,13 +28,13 @@
     return false;
 }
 
-bool SkPathEffect::asPoints(PointData* results, const SkPath& src,
+bool SkPathEffectBase::asPoints(PointData* results, const SkPath& src,
                     const SkStrokeRec& rec, const SkMatrix& mx, const SkRect* rect) const {
     return this->onAsPoints(results, src, rec, mx, rect);
 }
 
 SkPathEffect::DashType SkPathEffect::asADash(DashInfo* info) const {
-    return this->onAsADash(info);
+    return as_PEB(this)->onAsADash(info);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -45,7 +45,7 @@
  including flattening them. It does nothing in filterPath, and is only useful
  for managing the lifetimes of its two arguments.
  */
-class SkPairPathEffect : public SkPathEffect {
+class SkPairPathEffect : public SkPathEffectBase {
 protected:
     SkPairPathEffect(sk_sp<SkPathEffect> pe0, sk_sp<SkPathEffect> pe1)
         : fPE0(std::move(pe0)), fPE1(std::move(pe1))
@@ -64,16 +64,11 @@
     sk_sp<SkPathEffect> fPE1;
 
 private:
-    using INHERITED = SkPathEffect;
+    using INHERITED = SkPathEffectBase;
 };
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-/** \class SkComposePathEffect
-
- This subclass of SkPathEffect composes its two arguments, to create
- a compound pathEffect.
- */
 class SkComposePathEffect : public SkPairPathEffect {
 public:
     /** Construct a pathEffect whose effect is to apply first the inner pathEffect
@@ -91,7 +86,6 @@
         return sk_sp<SkPathEffect>(new SkComposePathEffect(outer, inner));
     }
 
-protected:
     SkComposePathEffect(sk_sp<SkPathEffect> outer, sk_sp<SkPathEffect> inner)
         : INHERITED(outer, inner) {}
 
@@ -106,15 +100,15 @@
         return fPE0->filterPath(dst, *ptr, rec, cullRect);
     }
 
-private:
     SK_FLATTENABLE_HOOKS(SkComposePathEffect)
 
     bool computeFastBounds(SkRect* bounds) const override {
         // inner (fPE1) is computed first, automatically updating bounds before computing outer.
-        return SkPathEffectPriv::ComputeFastBounds(fPE1.get(), bounds) &&
-               SkPathEffectPriv::ComputeFastBounds(fPE0.get(), bounds);
+        return as_PEB(fPE1)->computeFastBounds(bounds) &&
+               as_PEB(fPE0)->computeFastBounds(bounds);
     }
 
+private:
     // illegal
     SkComposePathEffect(const SkComposePathEffect&);
     SkComposePathEffect& operator=(const SkComposePathEffect&);
@@ -153,7 +147,6 @@
         return sk_sp<SkPathEffect>(new SkSumPathEffect(first, second));
     }
 
-protected:
     SkSumPathEffect(sk_sp<SkPathEffect> first, sk_sp<SkPathEffect> second)
         : INHERITED(first, second) {}
 
@@ -164,15 +157,15 @@
                fPE1->filterPath(dst, src, rec, cullRect);
     }
 
-private:
     SK_FLATTENABLE_HOOKS(SkSumPathEffect)
 
     bool computeFastBounds(SkRect* bounds) const override {
         // Unlike Compose(), PE0 modifies the path first for Sum
-        return SkPathEffectPriv::ComputeFastBounds(fPE0.get(), bounds) &&
-               SkPathEffectPriv::ComputeFastBounds(fPE1.get(), bounds);
+        return as_PEB(fPE0)->computeFastBounds(bounds) &&
+               as_PEB(fPE1)->computeFastBounds(bounds);
     }
 
+private:
     // illegal
     SkSumPathEffect(const SkSumPathEffect&);
     SkSumPathEffect& operator=(const SkSumPathEffect&);
@@ -198,7 +191,7 @@
     return SkComposePathEffect::Make(std::move(outer), std::move(inner));
 }
 
-void SkPathEffect::RegisterFlattenables() {
+void SkPathEffectBase::RegisterFlattenables() {
     SK_REGISTER_FLATTENABLE(SkComposePathEffect);
     SK_REGISTER_FLATTENABLE(SkSumPathEffect);
 }
diff --git a/src/core/SkPathEffectBase.h b/src/core/SkPathEffectBase.h
new file mode 100644
index 0000000..4e8d73e
--- /dev/null
+++ b/src/core/SkPathEffectBase.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkPathEffectBase_DEFINED
+#define SkPathEffectBase_DEFINED
+
+#include "include/core/SkPath.h"
+#include "include/core/SkPathEffect.h"
+#include "include/core/SkPoint.h"
+#include "include/core/SkRect.h"
+
+class SkPath;
+class SkStrokeRec;
+
+class SkPathEffectBase : public SkPathEffect {
+public:
+    SkPathEffectBase() {}
+
+    /** \class PointData
+
+        PointData aggregates all the information needed to draw the point
+        primitives returned by an 'asPoints' call.
+    */
+    class PointData {
+    public:
+        PointData()
+            : fFlags(0)
+            , fPoints(nullptr)
+            , fNumPoints(0) {
+            fSize.set(SK_Scalar1, SK_Scalar1);
+            // 'asPoints' needs to initialize/fill-in 'fClipRect' if it sets
+            // the kUseClip flag
+        }
+        ~PointData() {
+            delete [] fPoints;
+        }
+
+        // TODO: consider using passed-in flags to limit the work asPoints does.
+        // For example, a kNoPath flag could indicate don't bother generating
+        // stamped solutions.
+
+        // Currently none of these flags are supported.
+        enum PointFlags {
+            kCircles_PointFlag            = 0x01,   // draw points as circles (instead of rects)
+            kUsePath_PointFlag            = 0x02,   // draw points as stamps of the returned path
+            kUseClip_PointFlag            = 0x04,   // apply 'fClipRect' before drawing the points
+        };
+
+        uint32_t           fFlags;      // flags that impact the drawing of the points
+        SkPoint*           fPoints;     // the center point of each generated point
+        int                fNumPoints;  // number of points in fPoints
+        SkVector           fSize;       // the size to draw the points
+        SkRect             fClipRect;   // clip required to draw the points (if kUseClip is set)
+        SkPath             fPath;       // 'stamp' to be used at each point (if kUsePath is set)
+
+        SkPath             fFirst;      // If not empty, contains geometry for first point
+        SkPath             fLast;       // If not empty, contains geometry for last point
+    };
+
+    /**
+     *  Does applying this path effect to 'src' yield a set of points? If so,
+     *  optionally return the points in 'results'.
+     */
+    bool asPoints(PointData* results, const SkPath& src,
+                          const SkStrokeRec&, const SkMatrix&,
+                          const SkRect* cullR) const;
+
+    /**
+     *  If the PathEffect can be represented as a dash pattern, asADash will return kDash_DashType
+     *  and None otherwise. If a non NULL info is passed in, the various DashInfo will be filled
+     *  in if the PathEffect can be a dash pattern. If passed in info has an fCount equal or
+     *  greater to that of the effect, it will memcpy the values of the dash intervals into the
+     *  info. Thus the general approach will be call asADash once with default info to get DashType
+     *  and fCount. If effect can be represented as a dash pattern, allocate space for the intervals
+     *  in info, then call asADash again with the same info and the intervals will get copied in.
+     */
+
+    SkFlattenable::Type getFlattenableType() const override {
+        return kSkPathEffect_Type;
+    }
+
+    static sk_sp<SkPathEffect> Deserialize(const void* data, size_t size,
+                                          const SkDeserialProcs* procs = nullptr) {
+        return sk_sp<SkPathEffect>(static_cast<SkPathEffect*>(
+                                  SkFlattenable::Deserialize(
+                                  kSkPathEffect_Type, data, size, procs).release()));
+    }
+
+    virtual bool onFilterPath(SkPath*, const SkPath&, SkStrokeRec*, const SkRect*) const = 0;
+    virtual bool onAsPoints(PointData*, const SkPath&, const SkStrokeRec&, const SkMatrix&,
+                            const SkRect*) const {
+        return false;
+    }
+    virtual DashType onAsADash(DashInfo*) const {
+        return kNone_DashType;
+    }
+
+
+    // Compute a conservative bounds for its effect, given the bounds of the path. 'bounds' is
+    // both the input and output; if false is returned, fast bounds could not be calculated and
+    // 'bounds' is undefined.
+    //
+    // If 'bounds' is null, performs a dry-run determining if bounds could be computed.
+    virtual bool computeFastBounds(SkRect* bounds) const = 0;
+
+    static void RegisterFlattenables();
+
+private:
+    friend class SkPathEffectPriv;
+
+    using INHERITED = SkPathEffect;
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+static inline SkPathEffectBase* as_PEB(SkPathEffect* effect) {
+    return static_cast<SkPathEffectBase*>(effect);
+}
+
+static inline const SkPathEffectBase* as_PEB(const SkPathEffect* effect) {
+    return static_cast<const SkPathEffectBase*>(effect);
+}
+
+static inline const SkPathEffectBase* as_PEB(const sk_sp<SkPathEffect>& effect) {
+    return static_cast<SkPathEffectBase*>(effect.get());
+}
+
+static inline sk_sp<SkPathEffectBase> as_PEB_sp(sk_sp<SkPathEffect> effect) {
+    return sk_sp<SkPathEffectBase>(static_cast<SkPathEffectBase*>(effect.release()));
+}
+
+#endif
diff --git a/src/core/SkPathEffectPriv.h b/src/core/SkPathEffectPriv.h
deleted file mode 100644
index 145e775..0000000
--- a/src/core/SkPathEffectPriv.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2021 Google LLC
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkPathEffectPriv_DEFINED
-#define SkPathEffectPriv_DEFINED
-
-#include "include/core/SkPathEffect.h"
-
-// Provides access to internal SkPathEffect APIs
-class SkPathEffectPriv {
-public:
-
-    static bool ComputeFastBounds(const SkPathEffect* pe, SkRect* bounds) {
-        return pe->computeFastBounds(bounds);
-    }
-
-private:
-    SkPathEffectPriv();
-};
-
-#endif // SkPathEffectPriv_DEFINED
diff --git a/src/effects/Sk1DPathEffect.cpp b/src/effects/Sk1DPathEffect.cpp
index 00fa542..0110725 100644
--- a/src/effects/Sk1DPathEffect.cpp
+++ b/src/effects/Sk1DPathEffect.cpp
@@ -9,6 +9,7 @@
 #include "include/core/SkPathMeasure.h"
 #include "include/core/SkStrokeRec.h"
 #include "include/effects/Sk1DPathEffect.h"
+#include "src/core/SkPathEffectBase.h"
 #include "src/core/SkReadBuffer.h"
 #include "src/core/SkWriteBuffer.h"
 
@@ -16,7 +17,7 @@
 // Put in a governor to limit crash values from looping too long (and allocating too much ram).
 #define MAX_REASONABLE_ITERATIONS   100000
 
-class Sk1DPathEffect : public SkPathEffect {
+class Sk1DPathEffect : public SkPathEffectBase {
 public:
 protected:
     bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override {
diff --git a/src/effects/Sk2DPathEffect.cpp b/src/effects/Sk2DPathEffect.cpp
index 3c17bed..cca33db 100644
--- a/src/effects/Sk2DPathEffect.cpp
+++ b/src/effects/Sk2DPathEffect.cpp
@@ -9,10 +9,11 @@
 #include "include/core/SkRegion.h"
 #include "include/core/SkStrokeRec.h"
 #include "include/effects/Sk2DPathEffect.h"
+#include "src/core/SkPathEffectBase.h"
 #include "src/core/SkReadBuffer.h"
 #include "src/core/SkWriteBuffer.h"
 
-class Sk2DPathEffect : public SkPathEffect {
+class Sk2DPathEffect : public SkPathEffectBase {
 public:
     Sk2DPathEffect(const SkMatrix& mat) : fMatrix(mat) {
         // Calling invert will set the type mask on both matrices, making them thread safe.
diff --git a/src/effects/SkCornerPathEffect.cpp b/src/effects/SkCornerPathEffect.cpp
index 6788537..ce25bad 100644
--- a/src/effects/SkCornerPathEffect.cpp
+++ b/src/effects/SkCornerPathEffect.cpp
@@ -9,6 +9,7 @@
 #include "include/core/SkPath.h"
 #include "include/core/SkPoint.h"
 #include "include/effects/SkCornerPathEffect.h"
+#include "src/core/SkPathEffectBase.h"
 #include "src/core/SkReadBuffer.h"
 #include "src/core/SkWriteBuffer.h"
 
@@ -26,7 +27,7 @@
     }
 }
 
-class SkCornerPathEffectImpl : public SkPathEffect {
+class SkCornerPathEffectImpl : public SkPathEffectBase {
 public:
     explicit SkCornerPathEffectImpl(SkScalar radius) : fRadius(radius) {
         SkASSERT(radius > 0);
@@ -162,7 +163,7 @@
 private:
     const SkScalar fRadius;
 
-    using INHERITED = SkPathEffect;
+    using INHERITED = SkPathEffectBase;
 };
 
 //////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/effects/SkDashImpl.h b/src/effects/SkDashImpl.h
index 3fe7e2a..fbb343c 100644
--- a/src/effects/SkDashImpl.h
+++ b/src/effects/SkDashImpl.h
@@ -8,9 +8,9 @@
 #ifndef SkDashImpl_DEFINED
 #define SkDashImpl_DEFINED
 
-#include "include/core/SkPathEffect.h"
+#include "src/core/SkPathEffectBase.h"
 
-class SkDashImpl : public SkPathEffect {
+class SkDashImpl : public SkPathEffectBase {
 public:
     SkDashImpl(const SkScalar intervals[], int count, SkScalar phase);
 
@@ -42,7 +42,7 @@
     int32_t     fInitialDashIndex;
     SkScalar    fIntervalLength;
 
-    using INHERITED = SkPathEffect;
+    using INHERITED = SkPathEffectBase;
 };
 
 #endif
diff --git a/src/effects/SkDiscretePathEffect.cpp b/src/effects/SkDiscretePathEffect.cpp
index e6dabcf..cc2f49b 100644
--- a/src/effects/SkDiscretePathEffect.cpp
+++ b/src/effects/SkDiscretePathEffect.cpp
@@ -10,6 +10,7 @@
 #include "include/core/SkStrokeRec.h"
 #include "include/effects/SkDiscretePathEffect.h"
 #include "include/private/SkFixed.h"
+#include "src/core/SkPathEffectBase.h"
 #include "src/core/SkPointPriv.h"
 #include "src/core/SkReadBuffer.h"
 #include "src/core/SkWriteBuffer.h"
@@ -62,7 +63,7 @@
     *p += normal;
 }
 
-class SK_API SkDiscretePathEffectImpl : public SkPathEffect {
+class SK_API SkDiscretePathEffectImpl : public SkPathEffectBase {
 public:
     SkDiscretePathEffectImpl(SkScalar segLength, SkScalar deviation, uint32_t seedAssist)
         : fSegLength(segLength), fPerterb(deviation), fSeedAssist(seedAssist)
@@ -157,7 +158,7 @@
     /* Caller-supplied 32 bit seed assist */
     const uint32_t fSeedAssist;
 
-    using INHERITED = SkPathEffect;
+    using INHERITED = SkPathEffectBase;
 };
 
 //////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/effects/SkOpPE.h b/src/effects/SkOpPE.h
index fef0781..03d14d3 100644
--- a/src/effects/SkOpPE.h
+++ b/src/effects/SkOpPE.h
@@ -8,9 +8,10 @@
 #ifndef SkOpPE_DEFINED
 #define SkOpPE_DEFINED
 
-#include "include/effects/SkOpPathEffect.h"
+#include "include/pathops/SkPathOps.h"
+#include "src/core/SkPathEffectBase.h"
 
-class SkOpPE : public SkPathEffect {
+class SkOpPE : public SkPathEffectBase {
 public:
     SkOpPE(sk_sp<SkPathEffect> one, sk_sp<SkPathEffect> two, SkPathOp op);
 
@@ -28,10 +29,10 @@
     sk_sp<SkPathEffect> fTwo;
     SkPathOp            fOp;
 
-    using INHERITED = SkPathEffect;
+    using INHERITED = SkPathEffectBase;
 };
 
-class SkMatrixPE : public SkPathEffect {
+class SkMatrixPE : public SkPathEffectBase {
 public:
     SkMatrixPE(const SkMatrix&);
 
@@ -51,10 +52,10 @@
 
     SkMatrix    fMatrix;
 
-    using INHERITED = SkPathEffect;
+    using INHERITED = SkPathEffectBase;
 };
 
-class SkStrokePE : public SkPathEffect {
+class SkStrokePE : public SkPathEffectBase {
 public:
     SkStrokePE(SkScalar width, SkPaint::Join, SkPaint::Cap, SkScalar miter);
 
@@ -72,10 +73,10 @@
     SkPaint::Join   fJoin;
     SkPaint::Cap    fCap;
 
-    using INHERITED = SkPathEffect;
+    using INHERITED = SkPathEffectBase;
 };
 
-class SkStrokeAndFillPE : public SkPathEffect {
+class SkStrokeAndFillPE : public SkPathEffectBase {
 public:
     SkStrokeAndFillPE() {}
 
@@ -91,7 +92,7 @@
         return false;
     }
 
-    using INHERITED = SkPathEffect;
+    using INHERITED = SkPathEffectBase;
 };
 
 #endif
diff --git a/src/effects/SkOpPathEffect.cpp b/src/effects/SkOpPathEffect.cpp
index e39cb0c..c44ca06 100644
--- a/src/effects/SkOpPathEffect.cpp
+++ b/src/effects/SkOpPathEffect.cpp
@@ -6,7 +6,7 @@
  */
 
 #include "include/core/SkStrokeRec.h"
-#include "src/core/SkPathEffectPriv.h"
+#include "include/effects/SkOpPathEffect.h"
 #include "src/core/SkReadBuffer.h"
 #include "src/core/SkRectPriv.h"
 #include "src/core/SkWriteBuffer.h"
@@ -42,16 +42,16 @@
 
 bool SkOpPE::computeFastBounds(SkRect* bounds) const {
     if (!bounds) {
-        return (!SkToBool(fOne) || SkPathEffectPriv::ComputeFastBounds(fOne.get(), nullptr)) &&
-               (!SkToBool(fTwo) || SkPathEffectPriv::ComputeFastBounds(fTwo.get(), nullptr));
+        return (!SkToBool(fOne) || as_PEB(fOne)->computeFastBounds(nullptr)) &&
+               (!SkToBool(fTwo) || as_PEB(fTwo)->computeFastBounds(nullptr));
     }
 
     // bounds will hold the result of the fOne while b2 holds the result of fTwo's fast bounds
     SkRect b2 = *bounds;
-    if (fOne && !SkPathEffectPriv::ComputeFastBounds(fOne.get(), bounds)) {
+    if (fOne && !as_PEB(fOne)->computeFastBounds(bounds)) {
         return false;
     }
-    if (fTwo && !SkPathEffectPriv::ComputeFastBounds(fTwo.get(), &b2)) {
+    if (fTwo && !as_PEB(fTwo)->computeFastBounds(&b2)) {
         return false;
     }
 
diff --git a/src/effects/SkTrimPE.h b/src/effects/SkTrimPE.h
index 3d84c59..3dd320e 100644
--- a/src/effects/SkTrimPE.h
+++ b/src/effects/SkTrimPE.h
@@ -8,11 +8,10 @@
 #ifndef SkTrimImpl_DEFINED
 #define SkTrimImpl_DEFINED
 
-#include "include/core/SkPathEffect.h"
-
 #include "include/effects/SkTrimPathEffect.h"
+#include "src/core/SkPathEffectBase.h"
 
-class SkTrimPE : public SkPathEffect {
+class SkTrimPE : public SkPathEffectBase {
 public:
     SkTrimPE(SkScalar startT, SkScalar stopT, SkTrimPathEffect::Mode);
 
@@ -20,8 +19,6 @@
     void flatten(SkWriteBuffer&) const override;
     bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override;
 
-
-
 private:
     SK_FLATTENABLE_HOOKS(SkTrimPE)
 
@@ -35,7 +32,7 @@
                                  fStopT;
     const SkTrimPathEffect::Mode fMode;
 
-    using INHERITED = SkPathEffect;
+    using INHERITED = SkPathEffectBase;
 };
 
 #endif
diff --git a/src/gpu/GrStyle.h b/src/gpu/GrStyle.h
index 6a22e13..967bfe1 100644
--- a/src/gpu/GrStyle.h
+++ b/src/gpu/GrStyle.h
@@ -8,11 +8,11 @@
 #ifndef GrStyle_DEFINED
 #define GrStyle_DEFINED
 
-#include "include/core/SkPathEffect.h"
+#include "include/core/SkMatrix.h"
 #include "include/core/SkStrokeRec.h"
 #include "include/gpu/GrTypes.h"
 #include "include/private/SkTemplates.h"
-#include "src/core/SkPathEffectPriv.h"
+#include "src/core/SkPathEffectBase.h"
 
 /**
  * Represents the various ways that a GrStyledShape can be styled. It has fill/stroking information
@@ -172,7 +172,8 @@
     /** Given bounds of a path compute the bounds of path with the style applied. */
     void adjustBounds(SkRect* dst, const SkRect& src) const {
         *dst = src;
-        if (this->pathEffect() && !SkPathEffectPriv::ComputeFastBounds(this->pathEffect(), dst)) {
+        auto pe = as_PEB(this->pathEffect());
+        if (pe && !pe->computeFastBounds(dst)) {
             // Restore dst == src since ComputeFastBounds leaves it undefined when returning false
             *dst = src;
         }
@@ -187,7 +188,7 @@
     void initPathEffect(sk_sp<SkPathEffect> pe);
 
     struct DashInfo {
-        DashInfo() : fType(SkPathEffect::kNone_DashType) {}
+        DashInfo() : fType(SkPathEffectBase::kNone_DashType) {}
         DashInfo(const DashInfo& that) { *this = that; }
         DashInfo& operator=(const DashInfo& that) {
             fType = that.fType;
diff --git a/src/gpu/GrTestUtils.h b/src/gpu/GrTestUtils.h
index 77870a1..1b177a8 100644
--- a/src/gpu/GrTestUtils.h
+++ b/src/gpu/GrTestUtils.h
@@ -12,12 +12,12 @@
 
 #if GR_TEST_UTILS
 
-#include "include/core/SkPathEffect.h"
 #include "include/core/SkStrokeRec.h"
 #include "include/private/SkMacros.h"
 #include "include/private/SkTemplates.h"
 #include "include/utils/SkRandom.h"
 #include "src/core/SkMatrixProvider.h"
+#include "src/core/SkPathEffectBase.h"
 #include "src/gpu/GrColor.h"
 #include "src/gpu/GrFPArgs.h"
 #include "src/gpu/GrSamplerState.h"
@@ -67,7 +67,7 @@
 
 // We have a simplified dash path effect here to avoid relying on SkDashPathEffect which
 // is in the optional build target effects.
-class TestDashPathEffect : public SkPathEffect {
+class TestDashPathEffect : public SkPathEffectBase {
 public:
     static sk_sp<SkPathEffect> Make(const SkScalar* intervals, int count, SkScalar phase) {
         return sk_sp<SkPathEffect>(new TestDashPathEffect(intervals, count, phase));
diff --git a/src/ports/SkGlobalInitialization_default.cpp b/src/ports/SkGlobalInitialization_default.cpp
index 29fe799..d89cfe6 100644
--- a/src/ports/SkGlobalInitialization_default.cpp
+++ b/src/ports/SkGlobalInitialization_default.cpp
@@ -97,7 +97,7 @@
         SK_REGISTER_FLATTENABLE(SkStrokePE);
         SK_REGISTER_FLATTENABLE(SkStrokeAndFillPE);
         SK_REGISTER_FLATTENABLE(SkTrimPE);
-        SkPathEffect::RegisterFlattenables();
+        SkPathEffectBase::RegisterFlattenables();
 
         // Misc.
 #ifdef SK_SUPPORT_LEGACY_DRAWLOOPER
diff --git a/tests/DashPathEffectTest.cpp b/tests/DashPathEffectTest.cpp
index cc38b1b..379cd31 100644
--- a/tests/DashPathEffectTest.cpp
+++ b/tests/DashPathEffectTest.cpp
@@ -19,6 +19,7 @@
 #include "include/core/SkSurface.h"
 #include "include/core/SkTypes.h"
 #include "include/effects/SkDashPathEffect.h"
+#include "src/core/SkPathEffectBase.h"
 #include "tests/Test.h"
 
 // crbug.com/348821 was rooted in SkDashPathEffect refusing to flatten and unflatten itself when
@@ -75,13 +76,13 @@
     for (int i = 0; i < kNumMats; ++i) {
         for (int j = 0; j < (int)SK_ARRAY_COUNT(testCases); ++j) {
             for (int k = 0; k < 2; ++k) {  // exercise alternating endpoints
-                SkPathEffect::PointData results;
+                SkPathEffectBase::PointData results;
                 SkPath src;
 
                 src.moveTo(testCases[j].fPts[k]);
                 src.lineTo(testCases[j].fPts[(k+1)%2]);
 
-                bool actualResult = dash->asPoints(&results, src, rec, mats[i], &cull);
+                bool actualResult = as_PEB(dash)->asPoints(&results, src, rec, mats[i], &cull);
                 if (i < 2) {
                     REPORTER_ASSERT(r, actualResult == testCases[j].fExpectedResult);
                 } else {
diff --git a/tests/FlattenDrawableTest.cpp b/tests/FlattenDrawableTest.cpp
index 9f206cf..08d61bd 100644
--- a/tests/FlattenDrawableTest.cpp
+++ b/tests/FlattenDrawableTest.cpp
@@ -11,6 +11,7 @@
 #include "include/core/SkPictureRecorder.h"
 #include "include/core/SkRect.h"
 #include "include/core/SkStream.h"
+#include "src/core/SkPathEffectBase.h"
 #include "src/core/SkReadBuffer.h"
 #include "src/core/SkWriteBuffer.h"
 #include "tests/Test.h"
@@ -291,7 +292,7 @@
     auto data = SkData::MakeEmpty();
 
     #define test(name)  REPORTER_ASSERT(reporter, !name::Deserialize(data->data(), data->size()))
-    test(SkPathEffect);
+    test(SkPathEffectBase);
     test(SkMaskFilter);
     test(SkShaderBase); // todo: make this just be shader!
     test(SkColorFilterBase);
diff --git a/tests/GrStyledShapeTest.cpp b/tests/GrStyledShapeTest.cpp
index 42b7a2c..998703c 100644
--- a/tests/GrStyledShapeTest.cpp
+++ b/tests/GrStyledShapeTest.cpp
@@ -11,6 +11,7 @@
 #include "include/effects/SkDashPathEffect.h"
 #include "include/pathops/SkPathOps.h"
 #include "src/core/SkClipOpPriv.h"
+#include "src/core/SkPathEffectBase.h"
 #include "src/core/SkRectPriv.h"
 #include "src/gpu/geometry/GrStyledShape.h"
 #include "tests/Test.h"
@@ -1155,7 +1156,7 @@
      * This path effect takes any input path and turns it into a rrect. It passes through stroke
      * info.
      */
-    class RRectPathEffect : SkPathEffect {
+    class RRectPathEffect : SkPathEffectBase {
     public:
         static const SkRRect& RRect() {
             static const SkRRect kRRect = SkRRect::MakeRectXY(SkRect::MakeWH(12, 12), 3, 5);
@@ -1245,7 +1246,7 @@
     /**
      * This path effect just adds two lineTos to the input path.
      */
-    class AddLineTosPathEffect : SkPathEffect {
+    class AddLineTosPathEffect : SkPathEffectBase {
     public:
         static sk_sp<SkPathEffect> Make() { return sk_sp<SkPathEffect>(new AddLineTosPathEffect); }
         Factory getFactory() const override { return nullptr; }
@@ -1291,7 +1292,7 @@
     /**
      * This path effect just changes the stroke rec to hairline.
      */
-    class MakeHairlinePathEffect : SkPathEffect {
+    class MakeHairlinePathEffect : SkPathEffectBase {
     public:
         static sk_sp<SkPathEffect> Make() {
             return sk_sp<SkPathEffect>(new MakeHairlinePathEffect);
@@ -1376,7 +1377,7 @@
     /**
      * This path effect returns an empty path (possibly inverted)
      */
-    class EmptyPathEffect : SkPathEffect {
+    class EmptyPathEffect : SkPathEffectBase {
     public:
         static sk_sp<SkPathEffect> Make(bool invert) {
             return sk_sp<SkPathEffect>(new EmptyPathEffect(invert));
@@ -1467,7 +1468,7 @@
     /**
      * This path effect always fails to apply.
      */
-    class FailurePathEffect : SkPathEffect {
+    class FailurePathEffect : SkPathEffectBase {
     public:
         static sk_sp<SkPathEffect> Make() { return sk_sp<SkPathEffect>(new FailurePathEffect); }
         Factory getFactory() const override { return nullptr; }