Just expose factories for patheffects

bug: skia:11957
Change-Id: If2983fcd1b520a7ae77650d7e5ab226af9db52e0
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/410782
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Tyler Denniston <tdenniston@google.com>
diff --git a/src/effects/Sk2DPathEffect.cpp b/src/effects/Sk2DPathEffect.cpp
index 7374077..3c17bed 100644
--- a/src/effects/Sk2DPathEffect.cpp
+++ b/src/effects/Sk2DPathEffect.cpp
@@ -5,7 +5,6 @@
  * found in the LICENSE file.
  */
 
-
 #include "include/core/SkPath.h"
 #include "include/core/SkRegion.h"
 #include "include/core/SkStrokeRec.h"
@@ -13,128 +12,199 @@
 #include "src/core/SkReadBuffer.h"
 #include "src/core/SkWriteBuffer.h"
 
-Sk2DPathEffect::Sk2DPathEffect(const SkMatrix& mat) : fMatrix(mat) {
-    // Calling invert will set the type mask on both matrices, making them thread safe.
-    fMatrixIsInvertible = fMatrix.invert(&fInverse);
-}
+class Sk2DPathEffect : public SkPathEffect {
+public:
+    Sk2DPathEffect(const SkMatrix& mat) : fMatrix(mat) {
+        // Calling invert will set the type mask on both matrices, making them thread safe.
+        fMatrixIsInvertible = fMatrix.invert(&fInverse);
+    }
 
-bool Sk2DPathEffect::onFilterPath(SkPath* dst, const SkPath& src,
-                                  SkStrokeRec*, const SkRect*) const {
-    if (!fMatrixIsInvertible) {
+protected:
+    /** New virtual, to be overridden by subclasses.
+        This is called once from filterPath, and provides the
+        uv parameter bounds for the path. Subsequent calls to
+        next() will receive u and v values within these bounds,
+        and then a call to end() will signal the end of processing.
+    */
+    virtual void begin(const SkIRect& uvBounds, SkPath* dst) const {}
+    virtual void next(const SkPoint& loc, int u, int v, SkPath* dst) const {}
+    virtual void end(SkPath* dst) const {}
+
+    /** Low-level virtual called per span of locations in the u-direction.
+        The default implementation calls next() repeatedly with each
+        location.
+    */
+    virtual void nextSpan(int x, int y, int ucount, SkPath* path) const {
+        if (!fMatrixIsInvertible) {
+            return;
+        }
+    #if defined(SK_BUILD_FOR_FUZZER)
+        if (count > 100) {
+            return;
+        }
+    #endif
+
+        const SkMatrix& mat = this->getMatrix();
+        SkPoint src, dst;
+
+        src.set(SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf);
+        do {
+            mat.mapPoints(&dst, &src, 1);
+            this->next(dst, x++, y, path);
+            src.fX += SK_Scalar1;
+        } while (--ucount > 0);
+    }
+
+    const SkMatrix& getMatrix() const { return fMatrix; }
+
+    void flatten(SkWriteBuffer& buffer) const override {
+        this->INHERITED::flatten(buffer);
+        buffer.writeMatrix(fMatrix);
+    }
+
+    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
+                      const SkRect* cullRect) const override {
+        if (!fMatrixIsInvertible) {
+            return false;
+        }
+
+        SkPath  tmp;
+        SkIRect ir;
+
+        src.transform(fInverse, &tmp);
+        tmp.getBounds().round(&ir);
+        if (!ir.isEmpty()) {
+            this->begin(ir, dst);
+
+            SkRegion rgn;
+            rgn.setPath(tmp, SkRegion(ir));
+            SkRegion::Iterator iter(rgn);
+            for (; !iter.done(); iter.next()) {
+                const SkIRect& rect = iter.rect();
+                for (int y = rect.fTop; y < rect.fBottom; ++y) {
+                    this->nextSpan(rect.fLeft, y, rect.width(), dst);
+                }
+            }
+
+            this->end(dst);
+        }
+        return true;
+    }
+
+private:
+    SkMatrix    fMatrix, fInverse;
+    bool        fMatrixIsInvertible;
+
+    // For simplicity, assume fast bounds cannot be computed
+    bool computeFastBounds(SkRect*) const override { return false; }
+
+    friend class Sk2DPathEffectBlitter;
+    using INHERITED = SkPathEffect;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class SkLine2DPathEffectImpl : public Sk2DPathEffect {
+public:
+    SkLine2DPathEffectImpl(SkScalar width, const SkMatrix& matrix)
+        : Sk2DPathEffect(matrix)
+        , fWidth(width)
+    {
+        SkASSERT(width >= 0);
+    }
+
+    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
+                      const SkRect* cullRect) const override {
+        if (this->INHERITED::onFilterPath(dst, src, rec, cullRect)) {
+            rec->setStrokeStyle(fWidth);
+            return true;
+        }
         return false;
     }
 
-    SkPath  tmp;
-    SkIRect ir;
+    void nextSpan(int u, int v, int ucount, SkPath* dst) const override {
+        if (ucount > 1) {
+            SkPoint    src[2], dstP[2];
 
-    src.transform(fInverse, &tmp);
-    tmp.getBounds().round(&ir);
-    if (!ir.isEmpty()) {
-        this->begin(ir, dst);
+            src[0].set(SkIntToScalar(u) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf);
+            src[1].set(SkIntToScalar(u+ucount) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf);
+            this->getMatrix().mapPoints(dstP, src, 2);
 
-        SkRegion rgn;
-        rgn.setPath(tmp, SkRegion(ir));
-        SkRegion::Iterator iter(rgn);
-        for (; !iter.done(); iter.next()) {
-            const SkIRect& rect = iter.rect();
-            for (int y = rect.fTop; y < rect.fBottom; ++y) {
-                this->nextSpan(rect.fLeft, y, rect.width(), dst);
-            }
+            dst->moveTo(dstP[0]);
+            dst->lineTo(dstP[1]);
         }
-
-        this->end(dst);
     }
-    return true;
-}
 
-void Sk2DPathEffect::nextSpan(int x, int y, int count, SkPath* path) const {
-    if (!fMatrixIsInvertible) {
-        return;
+    static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
+        SkMatrix matrix;
+        buffer.readMatrix(&matrix);
+        SkScalar width = buffer.readScalar();
+        return SkLine2DPathEffect::Make(width, matrix);
     }
-#if defined(SK_BUILD_FOR_FUZZER)
-    if (count > 100) {
-        return;
+
+    void flatten(SkWriteBuffer &buffer) const override {
+        buffer.writeMatrix(this->getMatrix());
+        buffer.writeScalar(fWidth);
     }
-#endif
 
-    const SkMatrix& mat = this->getMatrix();
-    SkPoint src, dst;
+    Factory getFactory() const override { return CreateProc; }
+    const char* getTypeName() const override { return "SkLine2DPathEffect"; }
 
-    src.set(SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf);
-    do {
-        mat.mapPoints(&dst, &src, 1);
-        this->next(dst, x++, y, path);
-        src.fX += SK_Scalar1;
-    } while (--count > 0);
-}
+private:
+    SkScalar fWidth;
 
-void Sk2DPathEffect::begin(const SkIRect& uvBounds, SkPath* dst) const {}
-void Sk2DPathEffect::next(const SkPoint& loc, int u, int v, SkPath* dst) const {}
-void Sk2DPathEffect::end(SkPath* dst) const {}
+    using INHERITED = Sk2DPathEffect;
+};
 
-///////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////
 
-void Sk2DPathEffect::flatten(SkWriteBuffer& buffer) const {
-    this->INHERITED::flatten(buffer);
-    buffer.writeMatrix(fMatrix);
-}
+class SK_API SkPath2DPathEffectImpl : public Sk2DPathEffect {
+public:
+    SkPath2DPathEffectImpl(const SkMatrix& m, const SkPath& p) : INHERITED(m), fPath(p) {}
 
-///////////////////////////////////////////////////////////////////////////////
-
-bool SkLine2DPathEffect::onFilterPath(SkPath* dst, const SkPath& src,
-                                      SkStrokeRec* rec, const SkRect* cullRect) const {
-    if (this->INHERITED::onFilterPath(dst, src, rec, cullRect)) {
-        rec->setStrokeStyle(fWidth);
-        return true;
+    void next(const SkPoint& loc, int u, int v, SkPath* dst) const override {
+        dst->addPath(fPath, loc.fX, loc.fY);
     }
-    return false;
-}
 
-void SkLine2DPathEffect::nextSpan(int u, int v, int ucount, SkPath* dst) const {
-    if (ucount > 1) {
-        SkPoint    src[2], dstP[2];
-
-        src[0].set(SkIntToScalar(u) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf);
-        src[1].set(SkIntToScalar(u+ucount) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf);
-        this->getMatrix().mapPoints(dstP, src, 2);
-
-        dst->moveTo(dstP[0]);
-        dst->lineTo(dstP[1]);
+    static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
+        SkMatrix matrix;
+        buffer.readMatrix(&matrix);
+        SkPath path;
+        buffer.readPath(&path);
+        return SkPath2DPathEffect::Make(matrix, path);
     }
+
+    void flatten(SkWriteBuffer& buffer) const override {
+        buffer.writeMatrix(this->getMatrix());
+        buffer.writePath(fPath);
+    }
+
+    Factory getFactory() const override { return CreateProc; }
+    const char* getTypeName() const override { return "SkPath2DPathEffect"; }
+
+private:
+    SkPath  fPath;
+
+    using INHERITED = Sk2DPathEffect;
+};
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+sk_sp<SkPathEffect> SkLine2DPathEffect::Make(SkScalar width, const SkMatrix& matrix) {
+    if (!(width >= 0)) {
+        return nullptr;
+    }
+    return sk_sp<SkPathEffect>(new SkLine2DPathEffectImpl(width, matrix));
 }
 
-sk_sp<SkFlattenable> SkLine2DPathEffect::CreateProc(SkReadBuffer& buffer) {
-    SkMatrix matrix;
-    buffer.readMatrix(&matrix);
-    SkScalar width = buffer.readScalar();
-    return SkLine2DPathEffect::Make(width, matrix);
+sk_sp<SkPathEffect> SkPath2DPathEffect::Make(const SkMatrix& matrix, const SkPath& path) {
+    return sk_sp<SkPathEffect>(new SkPath2DPathEffectImpl(matrix, path));
 }
 
-void SkLine2DPathEffect::flatten(SkWriteBuffer &buffer) const {
-    buffer.writeMatrix(this->getMatrix());
-    buffer.writeScalar(fWidth);
+void SkLine2DPathEffect::RegisterFlattenables() {
+    SK_REGISTER_FLATTENABLE(SkLine2DPathEffectImpl);
 }
 
-///////////////////////////////////////////////////////////////////////////////
-
-SkPath2DPathEffect::SkPath2DPathEffect(const SkMatrix& m, const SkPath& p)
-    : INHERITED(m), fPath(p) {
-}
-
-sk_sp<SkFlattenable> SkPath2DPathEffect::CreateProc(SkReadBuffer& buffer) {
-    SkMatrix matrix;
-    buffer.readMatrix(&matrix);
-    SkPath path;
-    buffer.readPath(&path);
-    return SkPath2DPathEffect::Make(matrix, path);
-}
-
-void SkPath2DPathEffect::flatten(SkWriteBuffer& buffer) const {
-    buffer.writeMatrix(this->getMatrix());
-    buffer.writePath(fPath);
-}
-
-void SkPath2DPathEffect::next(const SkPoint& loc, int u, int v,
-                              SkPath* dst) const {
-    dst->addPath(fPath, loc.fX, loc.fY);
+void SkPath2DPathEffect::RegisterFlattenables() {
+    SK_REGISTER_FLATTENABLE(SkPath2DPathEffectImpl);
 }