Particle cleanup: split SkParticleBinding out of SkParticleEffect

Also simplify type registration.

Change-Id: Ia47febb2ae2cd5821476c3dd33a688b688aa6d6d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/238359
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/modules/canvaskit/particles_bindings.cpp b/modules/canvaskit/particles_bindings.cpp
index 5003ef1..a0c4366 100644
--- a/modules/canvaskit/particles_bindings.cpp
+++ b/modules/canvaskit/particles_bindings.cpp
@@ -8,7 +8,6 @@
 #include "include/core/SkCanvas.h"
 #include "include/core/SkTypes.h"
 #include "include/utils/SkRandom.h"
-#include "modules/particles/include/SkParticleDrawable.h"
 #include "modules/particles/include/SkParticleEffect.h"
 #include "modules/particles/include/SkParticleSerialization.h"
 
@@ -29,9 +28,7 @@
     function("MakeParticles", optional_override([](std::string json)->sk_sp<SkParticleEffect> {
         static bool didInit = false;
         if (!didInit) {
-            REGISTER_REFLECTED(SkReflected);
-            SkParticleBinding::RegisterBindingTypes();
-            SkParticleDrawable::RegisterDrawableTypes();
+            SkParticleEffect::RegisterParticleTypes();
             didInit = true;
         }
         SkRandom r;
diff --git a/modules/particles/include/SkParticleBinding.h b/modules/particles/include/SkParticleBinding.h
new file mode 100644
index 0000000..f3d7b15
--- /dev/null
+++ b/modules/particles/include/SkParticleBinding.h
@@ -0,0 +1,75 @@
+/*
+* Copyright 2019 Google LLC
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#ifndef SkParticleBinding_DEFINED
+#define SkParticleBinding_DEFINED
+
+#include "include/core/SkString.h"
+#include "modules/particles/include/SkReflected.h"
+#include "src/sksl/SkSLExternalValue.h"
+
+#include <memory>
+
+struct SkCurve;
+struct SkColorCurve;
+class SkRandom;
+
+namespace SkSL {
+    class Compiler;
+}
+
+class SkParticleExternalValue : public SkSL::ExternalValue {
+public:
+    SkParticleExternalValue(const char* name, SkSL::Compiler& compiler, const SkSL::Type& type)
+        : SkSL::ExternalValue(name, type)
+        , fCompiler(compiler)
+        , fRandom(nullptr) {
+    }
+
+    void setRandom(SkRandom* random) { fRandom = random; }
+
+protected:
+    SkSL::Compiler& fCompiler;
+    SkRandom* fRandom;
+};
+
+class SkParticleBinding : public SkReflected {
+public:
+    SkParticleBinding(const char* name = "name") : fName(name) {}
+
+    REFLECTED_ABSTRACT(SkParticleBinding, SkReflected)
+
+    void visitFields(SkFieldVisitor* v) override;
+    virtual std::unique_ptr<SkParticleExternalValue> toValue(SkSL::Compiler&) = 0;
+
+    static void RegisterBindingTypes();
+
+    /*
+     * All SkParticleBinding objects expose a particular native object to an effect's SkSL code.
+     * In all cases, the 'name' is the symbol that will be used to access the object from the SkSL.
+     * Each binding is a callable object, so the SkSL name behaves like a function. The behavior of
+     * each kind of binding is described below.
+     */
+
+    // Binds an SkCurve to an effect's SkSL. The curve is a one-dimensional function, described
+    // in SkCurve.h. It is called in the SkSL as 'name(t)', and returns a single float value.
+    static sk_sp<SkParticleBinding> MakeCurve(const char* name, const SkCurve& curve);
+
+    // Binds an SkColorCurve to an effect's SkSL. The curve is a one-dimensional, function,
+    // described in SkCurve.h. It is called in the SkSL as 'name(t)', and returns a float4 value.
+    static sk_sp<SkParticleBinding> MakeColorCurve(const char* name, const SkColorCurve& curve);
+
+    // Binds an SkPath to an effect's SkSL. The path is specified using SVG syntax. It is called
+    // in the SkSL as 'name(t)'. 't' is a normalized distance along the path. This returns a float4
+    // value, containing the position in .xy, and the normal in .zw.
+    static sk_sp<SkParticleBinding> MakePathBinding(const char* name, const char* path);
+
+protected:
+    SkString fName;
+};
+
+#endif // SkParticleBinding_DEFINED
diff --git a/modules/particles/include/SkParticleEffect.h b/modules/particles/include/SkParticleEffect.h
index cf7066c..3d7454e 100644
--- a/modules/particles/include/SkParticleEffect.h
+++ b/modules/particles/include/SkParticleEffect.h
@@ -14,56 +14,19 @@
 #include "include/private/SkTemplates.h"
 #include "include/utils/SkRandom.h"
 #include "modules/particles/include/SkParticleData.h"
-#include "modules/particles/include/SkReflected.h"
 
 #include <memory>
 
 class SkCanvas;
-struct SkCurve;
-struct SkColorCurve;
+class SkFieldVisitor;
+class SkParticleBinding;
 class SkParticleDrawable;
 class SkParticleExternalValue;
 
 namespace SkSL {
     struct ByteCode;
-    class Compiler;
 }
 
-class SkParticleBinding : public SkReflected {
-public:
-    SkParticleBinding(const char* name = "name") : fName(name) {}
-
-    REFLECTED_ABSTRACT(SkParticleBinding, SkReflected)
-
-    void visitFields(SkFieldVisitor* v) override;
-    virtual std::unique_ptr<SkParticleExternalValue> toValue(SkSL::Compiler&) = 0;
-
-    static void RegisterBindingTypes();
-
-    /*
-     * All SkParticleBinding objects expose a particular native object to an effect's SkSL code.
-     * In all cases, the 'name' is the symbol that will be used to access the object from the SkSL.
-     * Each binding is a callable object, so the SkSL name behaves like a function. The behavior of
-     * each kind of binding is described below.
-     */
-
-    // Binds an SkCurve to an effect's SkSL. The curve is a one-dimensional function, described
-    // in SkCurve.h. It is called in the SkSL as 'name(t)', and returns a single float value.
-    static sk_sp<SkParticleBinding> MakeCurve(const char* name, const SkCurve& curve);
-
-    // Binds an SkColorCurve to an effect's SkSL. The curve is a one-dimensional, function,
-    // described in SkCurve.h. It is called in the SkSL as 'name(t)', and returns a float4 value.
-    static sk_sp<SkParticleBinding> MakeColorCurve(const char* name, const SkColorCurve& curve);
-
-    // Binds an SkPath to an effect's SkSL. The path is specified using SVG syntax. It is called
-    // in the SkSL as 'name(t)'. 't' is a normalized distance along the path. This returns a float4
-    // value, containing the position in .xy, and the normal in .zw.
-    static sk_sp<SkParticleBinding> MakePathBinding(const char* name, const char* path);
-
-protected:
-    SkString fName;
-};
-
 class SkParticleEffectParams : public SkRefCnt {
 public:
     SkParticleEffectParams();
@@ -137,6 +100,8 @@
     bool isAlive() const { return fSpawnTime >= 0; }
     int getCount() const { return fCount; }
 
+    static void RegisterParticleTypes();
+
 private:
     void setCapacity(int capacity);
 
diff --git a/modules/particles/particles.gni b/modules/particles/particles.gni
index 0a7ca8c..49a313a 100644
--- a/modules/particles/particles.gni
+++ b/modules/particles/particles.gni
@@ -8,6 +8,7 @@
 
 skia_particle_sources = [
   "$_src/SkCurve.cpp",
+  "$_src/SkParticleBinding.cpp",
   "$_src/SkParticleDrawable.cpp",
   "$_src/SkParticleEffect.cpp",
   "$_src/SkReflected.cpp",
diff --git a/modules/particles/src/SkParticleBinding.cpp b/modules/particles/src/SkParticleBinding.cpp
new file mode 100644
index 0000000..8bf8757
--- /dev/null
+++ b/modules/particles/src/SkParticleBinding.cpp
@@ -0,0 +1,268 @@
+/*
+* Copyright 2019 Google LLC
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#include "modules/particles/include/SkParticleBinding.h"
+
+#include "include/core/SkContourMeasure.h"
+#include "include/core/SkPath.h"
+#include "include/utils/SkParsePath.h"
+#include "include/utils/SkRandom.h"
+#include "include/utils/SkTextUtils.h"
+#include "modules/particles/include/SkCurve.h"
+#include "modules/particles/include/SkReflected.h"
+#include "src/sksl/SkSLCompiler.h"
+
+void SkParticleBinding::visitFields(SkFieldVisitor* v) {
+    v->visit("Name", fName);
+}
+
+// Exposes an SkCurve as an external, callable value. c(x) returns a float.
+class SkCurveExternalValue : public SkParticleExternalValue {
+public:
+    SkCurveExternalValue(const char* name, SkSL::Compiler& compiler, const SkCurve& curve)
+        : SkParticleExternalValue(name, compiler, *compiler.context().fFloat_Type)
+        , fCurve(curve) { }
+
+    bool canCall() const override { return true; }
+    int callParameterCount() const override { return 1; }
+    void getCallParameterTypes(const SkSL::Type** outTypes) const override {
+        outTypes[0] = fCompiler.context().fFloat_Type.get();
+    }
+
+    void call(int index, float* arguments, float* outReturn) override {
+        *outReturn = fCurve.eval(*arguments, fRandom[index]);
+    }
+
+private:
+    SkCurve fCurve;
+};
+
+class SkCurveBinding : public SkParticleBinding {
+public:
+    SkCurveBinding(const char* name = "", const SkCurve& curve = 0.0f)
+        : SkParticleBinding(name)
+        , fCurve(curve) {}
+
+    REFLECTED(SkCurveBinding, SkParticleBinding)
+
+    void visitFields(SkFieldVisitor* v) override {
+        SkParticleBinding::visitFields(v);
+        v->visit("Curve", fCurve);
+    }
+
+    std::unique_ptr<SkParticleExternalValue> toValue(SkSL::Compiler& compiler) override {
+        return std::unique_ptr<SkParticleExternalValue>(
+                new SkCurveExternalValue(fName.c_str(), compiler, fCurve));
+    }
+
+private:
+    SkCurve fCurve;
+};
+
+// Exposes an SkColorCurve as an external, callable value. c(x) returns a float4.
+class SkColorCurveExternalValue : public SkParticleExternalValue {
+public:
+    SkColorCurveExternalValue(const char* name, SkSL::Compiler& compiler, const SkColorCurve& curve)
+        : SkParticleExternalValue(name, compiler, *compiler.context().fFloat4_Type)
+        , fCurve(curve) {
+    }
+
+    bool canCall() const override { return true; }
+    int callParameterCount() const override { return 1; }
+    void getCallParameterTypes(const SkSL::Type** outTypes) const override {
+        outTypes[0] = fCompiler.context().fFloat_Type.get();
+    }
+
+    void call(int index, float* arguments, float* outReturn) override {
+        SkColor4f color = fCurve.eval(*arguments, fRandom[index]);
+        memcpy(outReturn, color.vec(), 4 * sizeof(float));
+    }
+
+private:
+    SkColorCurve fCurve;
+};
+
+class SkColorCurveBinding : public SkParticleBinding {
+public:
+    SkColorCurveBinding(const char* name = "",
+                        const SkColorCurve& curve = SkColor4f{ 1.0f, 1.0f, 1.0f, 1.0f })
+        : SkParticleBinding(name)
+        , fCurve(curve) {
+    }
+
+    REFLECTED(SkColorCurveBinding, SkParticleBinding)
+
+        void visitFields(SkFieldVisitor* v) override {
+        SkParticleBinding::visitFields(v);
+        v->visit("Curve", fCurve);
+    }
+
+    std::unique_ptr<SkParticleExternalValue> toValue(SkSL::Compiler& compiler) override {
+        return std::unique_ptr<SkParticleExternalValue>(
+            new SkColorCurveExternalValue(fName.c_str(), compiler, fCurve));
+    }
+
+private:
+    SkColorCurve fCurve;
+};
+
+struct SkPathContours {
+    SkScalar fTotalLength;
+    SkTArray<sk_sp<SkContourMeasure>> fContours;
+
+    void rebuild(const SkPath& path) {
+        fTotalLength = 0;
+        fContours.reset();
+
+        SkContourMeasureIter iter(path, false);
+        while (auto contour = iter.next()) {
+            fContours.push_back(contour);
+            fTotalLength += contour->length();
+        }
+    }
+};
+
+// Exposes an SkPath as an external, callable value. p(x) returns a float4 { pos.xy, normal.xy }
+class SkPathExternalValue : public SkParticleExternalValue {
+public:
+    SkPathExternalValue(const char* name, SkSL::Compiler& compiler, const SkPathContours* path)
+        : SkParticleExternalValue(name, compiler, *compiler.context().fFloat4_Type)
+        , fPath(path) { }
+
+    bool canCall() const override { return true; }
+    int callParameterCount() const override { return 1; }
+    void getCallParameterTypes(const SkSL::Type** outTypes) const override {
+        outTypes[0] = fCompiler.context().fFloat_Type.get();
+    }
+
+    void call(int index, float* arguments, float* outReturn) override {
+        SkScalar len = fPath->fTotalLength * arguments[0];
+        int idx = 0;
+        while (idx < fPath->fContours.count() && len > fPath->fContours[idx]->length()) {
+            len -= fPath->fContours[idx++]->length();
+        }
+        SkVector localXAxis;
+        if (!fPath->fContours[idx]->getPosTan(len, (SkPoint*)outReturn, &localXAxis)) {
+            outReturn[0] = outReturn[1] = 0.0f;
+            localXAxis = { 1, 0 };
+        }
+        outReturn[2] = localXAxis.fY;
+        outReturn[3] = -localXAxis.fX;
+    }
+
+private:
+    const SkPathContours* fPath;
+};
+
+class SkPathBinding : public SkParticleBinding {
+public:
+    SkPathBinding(const char* name = "", const char* path = "")
+            : SkParticleBinding(name)
+            , fPath(path) {
+        this->rebuild();
+    }
+
+    REFLECTED(SkPathBinding, SkParticleBinding)
+
+    void visitFields(SkFieldVisitor* v) override {
+        SkString oldPath = fPath;
+
+        SkParticleBinding::visitFields(v);
+        v->visit("Path", fPath);
+
+        if (fPath != oldPath) {
+            this->rebuild();
+        }
+    }
+
+    std::unique_ptr<SkParticleExternalValue> toValue(SkSL::Compiler& compiler) override {
+        return std::unique_ptr<SkParticleExternalValue>(
+            new SkPathExternalValue(fName.c_str(), compiler, &fContours));
+    }
+
+private:
+    SkString fPath;
+
+    void rebuild() {
+        SkPath path;
+        if (SkParsePath::FromSVGString(fPath.c_str(), &path)) {
+            fContours.rebuild(path);
+        }
+    }
+
+    // Cached
+    SkPathContours fContours;
+};
+
+class SkTextBinding : public SkParticleBinding {
+public:
+    SkTextBinding(const char* name = "", const char* text = "", SkScalar fontSize = 96)
+            : SkParticleBinding(name)
+            , fText(text)
+            , fFontSize(fontSize) {
+        this->rebuild();
+    }
+
+    REFLECTED(SkTextBinding, SkParticleBinding)
+
+    void visitFields(SkFieldVisitor* v) override {
+        SkString oldText = fText;
+        SkScalar oldSize = fFontSize;
+
+        SkParticleBinding::visitFields(v);
+        v->visit("Text", fText);
+        v->visit("FontSize", fFontSize);
+
+        if (fText != oldText || fFontSize != oldSize) {
+            this->rebuild();
+        }
+    }
+
+    std::unique_ptr<SkParticleExternalValue> toValue(SkSL::Compiler& compiler) override {
+        return std::unique_ptr<SkParticleExternalValue>(
+            new SkPathExternalValue(fName.c_str(), compiler, &fContours));
+    }
+
+private:
+    SkString fText;
+    SkScalar fFontSize;
+
+    void rebuild() {
+        if (fText.isEmpty()) {
+            return;
+        }
+
+        SkFont font(nullptr, fFontSize);
+        SkPath path;
+        SkTextUtils::GetPath(fText.c_str(), fText.size(), SkTextEncoding::kUTF8, 0, 0, font, &path);
+        fContours.rebuild(path);
+    }
+
+    // Cached
+    SkPathContours fContours;
+};
+
+sk_sp<SkParticleBinding> SkParticleBinding::MakeCurve(const char* name, const SkCurve& curve) {
+    return sk_sp<SkParticleBinding>(new SkCurveBinding(name, curve));
+}
+
+sk_sp<SkParticleBinding> SkParticleBinding::MakeColorCurve(const char* name,
+                                                           const SkColorCurve& curve) {
+    return sk_sp<SkParticleBinding>(new SkColorCurveBinding(name, curve));
+}
+
+sk_sp<SkParticleBinding> SkParticleBinding::MakePathBinding(const char* name, const char* path) {
+    return sk_sp<SkParticleBinding>(new SkPathBinding(name, path));
+}
+
+void SkParticleBinding::RegisterBindingTypes() {
+    REGISTER_REFLECTED(SkParticleBinding);
+    REGISTER_REFLECTED(SkCurveBinding);
+    REGISTER_REFLECTED(SkColorCurveBinding);
+    REGISTER_REFLECTED(SkPathBinding);
+    REGISTER_REFLECTED(SkTextBinding);
+}
diff --git a/modules/particles/src/SkParticleEffect.cpp b/modules/particles/src/SkParticleEffect.cpp
index 917a745..b166395 100644
--- a/modules/particles/src/SkParticleEffect.cpp
+++ b/modules/particles/src/SkParticleEffect.cpp
@@ -7,305 +7,25 @@
 
 #include "modules/particles/include/SkParticleEffect.h"
 
-#include "include/core/SkCanvas.h"
-#include "include/core/SkContourMeasure.h"
 #include "include/core/SkPaint.h"
-#include "include/core/SkPath.h"
-#include "include/core/SkRSXform.h"
-#include "include/private/SkColorData.h"
-#include "include/utils/SkParsePath.h"
-#include "include/utils/SkTextUtils.h"
 #include "modules/particles/include/SkCurve.h"
+#include "modules/particles/include/SkParticleBinding.h"
 #include "modules/particles/include/SkParticleDrawable.h"
 #include "modules/particles/include/SkReflected.h"
 #include "src/core/SkMakeUnique.h"
 #include "src/sksl/SkSLByteCode.h"
 #include "src/sksl/SkSLCompiler.h"
-#include "src/sksl/SkSLExternalValue.h"
-
-void SkParticleBinding::visitFields(SkFieldVisitor* v) {
-    v->visit("Name", fName);
-}
-
-class SkParticleExternalValue : public SkSL::ExternalValue {
-public:
-    SkParticleExternalValue(const char* name, SkSL::Compiler& compiler, const SkSL::Type& type)
-        : INHERITED(name, type)
-        , fCompiler(compiler)
-        , fRandom(nullptr) {
-    }
-
-    void setRandom(SkRandom* random) { fRandom = random; }
-
-protected:
-    SkSL::Compiler& fCompiler;
-    SkRandom* fRandom;
-    typedef SkSL::ExternalValue INHERITED;
-};
-
-// Exposes an SkCurve as an external, callable value. c(x) returns a float.
-class SkCurveExternalValue : public SkParticleExternalValue {
-public:
-    SkCurveExternalValue(const char* name, SkSL::Compiler& compiler, const SkCurve& curve)
-        : INHERITED(name, compiler, *compiler.context().fFloat_Type)
-        , fCurve(curve) { }
-
-    bool canCall() const override { return true; }
-    int callParameterCount() const override { return 1; }
-    void getCallParameterTypes(const SkSL::Type** outTypes) const override {
-        outTypes[0] = fCompiler.context().fFloat_Type.get();
-    }
-
-    void call(int index, float* arguments, float* outReturn) override {
-        *outReturn = fCurve.eval(*arguments, fRandom[index]);
-    }
-
-private:
-    SkCurve fCurve;
-    typedef SkParticleExternalValue INHERITED;
-};
-
-class SkCurveBinding : public SkParticleBinding {
-public:
-    SkCurveBinding(const char* name = "", const SkCurve& curve = 0.0f)
-        : SkParticleBinding(name)
-        , fCurve(curve) {}
-
-    REFLECTED(SkCurveBinding, SkParticleBinding)
-
-    void visitFields(SkFieldVisitor* v) override {
-        SkParticleBinding::visitFields(v);
-        v->visit("Curve", fCurve);
-    }
-
-    std::unique_ptr<SkParticleExternalValue> toValue(SkSL::Compiler& compiler) override {
-        return std::unique_ptr<SkParticleExternalValue>(
-                new SkCurveExternalValue(fName.c_str(), compiler, fCurve));
-    }
-
-private:
-    SkCurve fCurve;
-};
-
-// Exposes an SkColorCurve as an external, callable value. c(x) returns a float4.
-class SkColorCurveExternalValue : public SkParticleExternalValue {
-public:
-    SkColorCurveExternalValue(const char* name, SkSL::Compiler& compiler, const SkColorCurve& curve)
-        : INHERITED(name, compiler, *compiler.context().fFloat4_Type)
-        , fCurve(curve) {
-    }
-
-    bool canCall() const override { return true; }
-    int callParameterCount() const override { return 1; }
-    void getCallParameterTypes(const SkSL::Type** outTypes) const override {
-        outTypes[0] = fCompiler.context().fFloat_Type.get();
-    }
-
-    void call(int index, float* arguments, float* outReturn) override {
-        SkColor4f color = fCurve.eval(*arguments, fRandom[index]);
-        memcpy(outReturn, color.vec(), 4 * sizeof(float));
-    }
-
-private:
-    SkColorCurve fCurve;
-    typedef SkParticleExternalValue INHERITED;
-};
-
-class SkColorCurveBinding : public SkParticleBinding {
-public:
-    SkColorCurveBinding(const char* name = "",
-                        const SkColorCurve& curve = SkColor4f{ 1.0f, 1.0f, 1.0f, 1.0f })
-        : SkParticleBinding(name)
-        , fCurve(curve) {
-    }
-
-    REFLECTED(SkColorCurveBinding, SkParticleBinding)
-
-        void visitFields(SkFieldVisitor* v) override {
-        SkParticleBinding::visitFields(v);
-        v->visit("Curve", fCurve);
-    }
-
-    std::unique_ptr<SkParticleExternalValue> toValue(SkSL::Compiler& compiler) override {
-        return std::unique_ptr<SkParticleExternalValue>(
-            new SkColorCurveExternalValue(fName.c_str(), compiler, fCurve));
-    }
-
-private:
-    SkColorCurve fCurve;
-};
-
-struct SkPathContours {
-    SkScalar fTotalLength;
-    SkTArray<sk_sp<SkContourMeasure>> fContours;
-
-    void rebuild(const SkPath& path) {
-        fTotalLength = 0;
-        fContours.reset();
-
-        SkContourMeasureIter iter(path, false);
-        while (auto contour = iter.next()) {
-            fContours.push_back(contour);
-            fTotalLength += contour->length();
-        }
-    }
-};
-
-// Exposes an SkPath as an external, callable value. p(x) returns a float4 { pos.xy, normal.xy }
-class SkPathExternalValue : public SkParticleExternalValue {
-public:
-    SkPathExternalValue(const char* name, SkSL::Compiler& compiler, const SkPathContours* path)
-        : INHERITED(name, compiler, *compiler.context().fFloat4_Type)
-        , fPath(path) { }
-
-    bool canCall() const override { return true; }
-    int callParameterCount() const override { return 1; }
-    void getCallParameterTypes(const SkSL::Type** outTypes) const override {
-        outTypes[0] = fCompiler.context().fFloat_Type.get();
-    }
-
-    void call(int index, float* arguments, float* outReturn) override {
-        SkScalar len = fPath->fTotalLength * arguments[0];
-        int idx = 0;
-        while (idx < fPath->fContours.count() && len > fPath->fContours[idx]->length()) {
-            len -= fPath->fContours[idx++]->length();
-        }
-        SkVector localXAxis;
-        if (!fPath->fContours[idx]->getPosTan(len, (SkPoint*)outReturn, &localXAxis)) {
-            outReturn[0] = outReturn[1] = 0.0f;
-            localXAxis = { 1, 0 };
-        }
-        outReturn[2] = localXAxis.fY;
-        outReturn[3] = -localXAxis.fX;
-    }
-
-private:
-    const SkPathContours* fPath;
-    typedef SkParticleExternalValue INHERITED;
-};
-
-class SkPathBinding : public SkParticleBinding {
-public:
-    SkPathBinding(const char* name = "", const char* path = "")
-            : SkParticleBinding(name)
-            , fPath(path) {
-        this->rebuild();
-    }
-
-    REFLECTED(SkPathBinding, SkParticleBinding)
-
-    void visitFields(SkFieldVisitor* v) override {
-        SkString oldPath = fPath;
-
-        SkParticleBinding::visitFields(v);
-        v->visit("Path", fPath);
-
-        if (fPath != oldPath) {
-            this->rebuild();
-        }
-    }
-
-    std::unique_ptr<SkParticleExternalValue> toValue(SkSL::Compiler& compiler) override {
-        return std::unique_ptr<SkParticleExternalValue>(
-            new SkPathExternalValue(fName.c_str(), compiler, &fContours));
-    }
-
-private:
-    SkString fPath;
-
-    void rebuild() {
-        SkPath path;
-        if (SkParsePath::FromSVGString(fPath.c_str(), &path)) {
-            fContours.rebuild(path);
-        }
-    }
-
-    // Cached
-    SkPathContours fContours;
-};
-
-class SkTextBinding : public SkParticleBinding {
-public:
-    SkTextBinding(const char* name = "", const char* text = "", SkScalar fontSize = 96)
-            : SkParticleBinding(name)
-            , fText(text)
-            , fFontSize(fontSize) {
-        this->rebuild();
-    }
-
-    REFLECTED(SkTextBinding, SkParticleBinding)
-
-    void visitFields(SkFieldVisitor* v) override {
-        SkString oldText = fText;
-        SkScalar oldSize = fFontSize;
-
-        SkParticleBinding::visitFields(v);
-        v->visit("Text", fText);
-        v->visit("FontSize", fFontSize);
-
-        if (fText != oldText || fFontSize != oldSize) {
-            this->rebuild();
-        }
-    }
-
-    std::unique_ptr<SkParticleExternalValue> toValue(SkSL::Compiler& compiler) override {
-        return std::unique_ptr<SkParticleExternalValue>(
-            new SkPathExternalValue(fName.c_str(), compiler, &fContours));
-    }
-
-private:
-    SkString fText;
-    SkScalar fFontSize;
-
-    void rebuild() {
-        if (fText.isEmpty()) {
-            return;
-        }
-
-        SkFont font(nullptr, fFontSize);
-        SkPath path;
-        SkTextUtils::GetPath(fText.c_str(), fText.size(), SkTextEncoding::kUTF8, 0, 0, font, &path);
-        fContours.rebuild(path);
-    }
-
-    // Cached
-    SkPathContours fContours;
-};
-
-sk_sp<SkParticleBinding> SkParticleBinding::MakeCurve(const char* name, const SkCurve& curve) {
-    return sk_sp<SkParticleBinding>(new SkCurveBinding(name, curve));
-}
-
-sk_sp<SkParticleBinding> SkParticleBinding::MakeColorCurve(const char* name,
-                                                           const SkColorCurve& curve) {
-    return sk_sp<SkParticleBinding>(new SkColorCurveBinding(name, curve));
-}
-
-sk_sp<SkParticleBinding> SkParticleBinding::MakePathBinding(const char* name, const char* path) {
-    return sk_sp<SkParticleBinding>(new SkPathBinding(name, path));
-}
-
-void SkParticleBinding::RegisterBindingTypes() {
-    REGISTER_REFLECTED(SkParticleBinding);
-    REGISTER_REFLECTED(SkCurveBinding);
-    REGISTER_REFLECTED(SkColorCurveBinding);
-    REGISTER_REFLECTED(SkPathBinding);
-    REGISTER_REFLECTED(SkTextBinding);
-}
 
 // Exposes a particle's random generator as an external, readable value. read returns a float [0, 1)
 class SkRandomExternalValue : public SkParticleExternalValue {
 public:
     SkRandomExternalValue(const char* name, SkSL::Compiler& compiler)
-        : INHERITED(name, compiler, *compiler.context().fFloat_Type) {}
+        : SkParticleExternalValue(name, compiler, *compiler.context().fFloat_Type) {}
 
     bool canRead() const override { return true; }
     void read(int index, float* target) override {
         *target = fRandom[index].nextF();
     }
-
-private:
-    typedef SkParticleExternalValue INHERITED;
 };
 
 static const char* kCodeHeader =
@@ -561,3 +281,9 @@
     fCapacity = capacity;
     fCount = SkTMin(fCount, fCapacity);
 }
+
+void SkParticleEffect::RegisterParticleTypes() {
+    REGISTER_REFLECTED(SkReflected);
+    SkParticleBinding::RegisterBindingTypes();
+    SkParticleDrawable::RegisterDrawableTypes();
+}
diff --git a/tools/cpu_modules.cpp b/tools/cpu_modules.cpp
index 4354a73..a749ebf 100644
--- a/tools/cpu_modules.cpp
+++ b/tools/cpu_modules.cpp
@@ -5,17 +5,12 @@
  * found in the LICENSE file.
  */
 
-#include "modules/particles/include/SkParticleDrawable.h"
 #include "modules/particles/include/SkParticleEffect.h"
-#include "modules/particles/include/SkParticleSerialization.h"
-#include "modules/particles/include/SkReflected.h"
 
 // Doesn't do anything important; just exists to show we can use modules/particles without the GPU
 // backend being available.
 int main(int argc, char** argv) {
     // Register types for serialization
-    REGISTER_REFLECTED(SkReflected);
-    SkParticleBinding::RegisterBindingTypes();
-    SkParticleDrawable::RegisterDrawableTypes();
+    SkParticleEffect::RegisterParticleTypes();
     return 0;
 }
diff --git a/tools/viewer/ParticlesSlide.cpp b/tools/viewer/ParticlesSlide.cpp
index f243327..b8ddf78 100644
--- a/tools/viewer/ParticlesSlide.cpp
+++ b/tools/viewer/ParticlesSlide.cpp
@@ -7,7 +7,6 @@
 
 #include "tools/viewer/ParticlesSlide.h"
 
-#include "modules/particles/include/SkParticleDrawable.h"
 #include "modules/particles/include/SkParticleEffect.h"
 #include "modules/particles/include/SkParticleSerialization.h"
 #include "modules/particles/include/SkReflected.h"
@@ -203,9 +202,7 @@
 
 ParticlesSlide::ParticlesSlide() {
     // Register types for serialization
-    REGISTER_REFLECTED(SkReflected);
-    SkParticleBinding::RegisterBindingTypes();
-    SkParticleDrawable::RegisterDrawableTypes();
+    SkParticleEffect::RegisterParticleTypes();
     fName = "Particles";
     fPlayPosition.set(200.0f, 200.0f);
 }