Particles: Improvements to SkCurve

Added explicit Linear segment type, merge math evaluation helpers for
scalar and color curves. Add logic to visitFields that cuts down on the
serialized size of simple curves, and makes the GUI easier to work with.

Remove the curve plot from the GUI. It was incorrect (wrong points at
cubic handle locations), not terribly helpful, and difficult to
maintain.

Bug: skia:
Change-Id: I190cb5d118b1f4b910984e4df50ee3351c8be895
Reviewed-on: https://skia-review.googlesource.com/c/195884
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/modules/particles/include/SkCurve.h b/modules/particles/include/SkCurve.h
index ec61228..076a1aa 100644
--- a/modules/particles/include/SkCurve.h
+++ b/modules/particles/include/SkCurve.h
@@ -44,20 +44,26 @@
  *     50% of the time.
  */
 
+enum SkCurveSegmentType {
+    kConstant_SegmentType,
+    kLinear_SegmentType,
+    kCubic_SegmentType,
+};
+
 struct SkCurveSegment {
     SkScalar eval(SkScalar x, SkScalar t, bool negate) const;
     void visitFields(SkFieldVisitor* v);
 
     void setConstant(SkScalar c) {
-        fConstant = true;
-        fRanged   = false;
+        fType   = kConstant_SegmentType;
+        fRanged = false;
         fMin[0] = c;
     }
 
     SkScalar fMin[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
     SkScalar fMax[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
 
-    bool fConstant      = true;
+    int  fType          = kConstant_SegmentType;
     bool fRanged        = false;
     bool fBidirectional = false;
 };
@@ -71,9 +77,6 @@
     SkScalar eval(SkScalar x, SkRandom& random) const;
     void visitFields(SkFieldVisitor* v);
 
-    // Returns the (very conversative) range of this SkCurve in extents (as [minimum, maximum]).
-    void getExtents(SkScalar extents[2]) const;
-
     // It should always be true that (fXValues.count() + 1) == fSegments.count()
     SkTArray<SkScalar, true>       fXValues;
     SkTArray<SkCurveSegment, true> fSegments;
@@ -97,7 +100,7 @@
     void visitFields(SkFieldVisitor* v);
 
     void setConstant(SkColor4f c) {
-        fConstant = true;
+        fType   = kConstant_SegmentType;
         fRanged = false;
         fMin[0] = c;
     }
@@ -105,7 +108,7 @@
     SkColor4f fMin[4];
     SkColor4f fMax[4];
 
-    bool fConstant = true;
+    int  fType   = kConstant_SegmentType;
     bool fRanged = false;
 };
 
diff --git a/modules/particles/src/SkCurve.cpp b/modules/particles/src/SkCurve.cpp
index 1f14a79..3dc7819 100644
--- a/modules/particles/src/SkCurve.cpp
+++ b/modules/particles/src/SkCurve.cpp
@@ -10,24 +10,43 @@
 #include "SkRandom.h"
 #include "SkReflected.h"
 
-static SkScalar eval_cubic(const SkScalar* pts, SkScalar x) {
-    SkScalar ix = (1 - x);
-    return pts[0]*ix*ix*ix + pts[1]*3*ix*ix*x + pts[2]*3*ix*x*x + pts[3]*x*x*x;
-}
+constexpr SkFieldVisitor::EnumStringMapping gCurveSegmentTypeMapping[] = {
+    { kConstant_SegmentType, "Constant" },
+    { kLinear_SegmentType,   "Linear" },
+    { kCubic_SegmentType,    "Cubic" },
+};
 
 static SkColor4f operator+(SkColor4f c1, SkColor4f c2) {
     return { c1.fR + c2.fR, c1.fG + c2.fG, c1.fB + c2.fB, c1.fA + c2.fA };
 }
 
-static SkColor4f eval_cubic(const SkColor4f* pts, SkScalar x) {
+static SkColor4f operator-(SkColor4f c1, SkColor4f c2) {
+    return { c1.fR - c2.fR, c1.fG - c2.fG, c1.fB - c2.fB, c1.fA - c2.fA };
+}
+
+template <typename T>
+static T eval_cubic(const T* pts, SkScalar x) {
     SkScalar ix = (1 - x);
     return pts[0]*(ix*ix*ix) + pts[1]*(3*ix*ix*x) + pts[2]*(3*ix*x*x) + pts[3]*(x*x*x);
 }
 
+template <typename T>
+static T eval_segment(const T* pts, SkScalar x, int type) {
+    switch (type) {
+        case kLinear_SegmentType:
+            return pts[0] + (pts[3] - pts[0]) * x;
+        case kCubic_SegmentType:
+            return eval_cubic(pts, x);
+        case kConstant_SegmentType:
+        default:
+            return pts[0];
+    }
+}
+
 SkScalar SkCurveSegment::eval(SkScalar x, SkScalar t, bool negate) const {
-    SkScalar result = fConstant ? fMin[0] : eval_cubic(fMin, x);
+    SkScalar result = eval_segment(fMin, x, fType);
     if (fRanged) {
-        result += ((fConstant ? fMax[0] : eval_cubic(fMax, x)) - result) * t;
+        result += (eval_segment(fMax, x, fType) - result) * t;
     }
     if (fBidirectional && negate) {
         result = -result;
@@ -36,17 +55,27 @@
 }
 
 void SkCurveSegment::visitFields(SkFieldVisitor* v) {
-    v->visit("Constant", fConstant);
+    v->visit("Type", fType, gCurveSegmentTypeMapping, SK_ARRAY_COUNT(gCurveSegmentTypeMapping));
     v->visit("Ranged", fRanged);
     v->visit("Bidirectional", fBidirectional);
     v->visit("A0", fMin[0]);
-    v->visit("B0", fMin[1]);
-    v->visit("C0", fMin[2]);
-    v->visit("D0", fMin[3]);
-    v->visit("A1", fMax[0]);
-    v->visit("B1", fMax[1]);
-    v->visit("C1", fMax[2]);
-    v->visit("D1", fMax[3]);
+    if (fType == kCubic_SegmentType) {
+        v->visit("B0", fMin[1]);
+        v->visit("C0", fMin[2]);
+    }
+    if (fType != kConstant_SegmentType) {
+        v->visit("D0", fMin[3]);
+    }
+    if (fRanged) {
+        v->visit("A1", fMax[0]);
+        if (fType == kCubic_SegmentType) {
+            v->visit("B1", fMax[1]);
+            v->visit("C1", fMax[2]);
+        }
+        if (fType != kConstant_SegmentType) {
+            v->visit("D1", fMax[3]);
+        }
+    }
 }
 
 SkScalar SkCurve::eval(SkScalar x, SkRandom& random) const {
@@ -88,46 +117,35 @@
     }
 }
 
-// TODO: This implementation is extremely conservative, because it uses the position of the control
-// points as the actual range. The curve typically doesn't reach that far. Evaluating the curve at
-// each of [0, 1/3, 2/3, 1] would be tighter, but can be too tight in some cases.
-void SkCurve::getExtents(SkScalar extents[2]) const {
-    extents[0] = INFINITY;
-    extents[1] = -INFINITY;
-    auto extend = [=](SkScalar y) {
-        extents[0] = SkTMin(extents[0], y);
-        extents[1] = SkTMax(extents[1], y);
-    };
-    for (const auto& segment : fSegments) {
-        for (int i = 0; i < (segment.fConstant ? 1 : 4); ++i) {
-            extend(segment.fMin[i]);
-            if (segment.fRanged) {
-                extend(segment.fMax[i]);
-            }
-        }
-    }
-}
-
 SkColor4f SkColorCurveSegment::eval(SkScalar x, SkRandom& random) const {
-    SkColor4f result = fConstant ? fMin[0] : eval_cubic(fMin, x);
+    SkColor4f result = eval_segment(fMin, x, fType);
     if (fRanged) {
-        result = result +
-                ((fConstant ? fMax[0] : eval_cubic(fMax, x)) + (result * -1)) * random.nextF();
+        result = result + (eval_segment(fMax, x, fType) - result) * random.nextF();
     }
     return result;
 }
 
 void SkColorCurveSegment::visitFields(SkFieldVisitor* v) {
-    v->visit("Constant", fConstant);
+    v->visit("Type", fType, gCurveSegmentTypeMapping, SK_ARRAY_COUNT(gCurveSegmentTypeMapping));
     v->visit("Ranged", fRanged);
     v->visit("A0", fMin[0]);
-    v->visit("B0", fMin[1]);
-    v->visit("C0", fMin[2]);
-    v->visit("D0", fMin[3]);
-    v->visit("A1", fMax[0]);
-    v->visit("B1", fMax[1]);
-    v->visit("C1", fMax[2]);
-    v->visit("D1", fMax[3]);
+    if (fType == kCubic_SegmentType) {
+        v->visit("B0", fMin[1]);
+        v->visit("C0", fMin[2]);
+    }
+    if (fType != kConstant_SegmentType) {
+        v->visit("D0", fMin[3]);
+    }
+    if (fRanged) {
+        v->visit("A1", fMax[0]);
+        if (fType == kCubic_SegmentType) {
+            v->visit("B1", fMax[1]);
+            v->visit("C1", fMax[2]);
+        }
+        if (fType != kConstant_SegmentType) {
+            v->visit("D1", fMax[3]);
+        }
+    }
 }
 
 SkColor4f SkColorCurve::eval(SkScalar x, SkRandom& random) const {
diff --git a/resources/particles/default.json b/resources/particles/default.json
index 3e7a72d..f9da78f 100644
--- a/resources/particles/default.json
+++ b/resources/particles/default.json
@@ -6,17 +6,11 @@
       "XValues": [],
       "Segments": [
          {
-            "Constant": true,
+            "Type": "Constant",
             "Ranged": true,
             "Bidirectional": false,
             "A0": 1,
-            "B0": 0,
-            "C0": 0,
-            "D0": 0,
-            "A1": 3,
-            "B1": 0,
-            "C1": 0,
-            "D1": 0
+            "A1": 3
          }
       ]
    },
@@ -39,17 +33,11 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": true,
+                  "Type": "Constant",
                   "Ranged": true,
                   "Bidirectional": false,
                   "A0": -30,
-                  "B0": 0,
-                  "C0": 0,
-                  "D0": 0,
-                  "A1": 30,
-                  "B1": 0,
-                  "C1": 0,
-                  "D1": 0
+                  "A1": 30
                }
             ]
          },
@@ -57,17 +45,11 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": true,
+                  "Type": "Constant",
                   "Ranged": true,
                   "Bidirectional": false,
                   "A0": 10,
-                  "B0": 0,
-                  "C0": 0,
-                  "D0": 0,
-                  "A1": 30,
-                  "B1": 0,
-                  "C1": 0,
-                  "D1": 0
+                  "A1": 30
                }
             ]
          }
@@ -81,16 +63,10 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": false,
+                  "Type": "Linear",
                   "Ranged": false,
                   "A0": [ 1, 0.196078, 0.0784314, 1 ],
-                  "B0": [ 1, 0.392157, 0.0784314, 1 ],
-                  "C0": [ 1, 0.588235, 0.0784314, 1 ],
-                  "D0": [ 1, 0.784314, 0.0784314, 1 ],
-                  "A1": [ 0, 0, 0, 0 ],
-                  "B1": [ 0, 0, 0, 0 ],
-                  "C1": [ 0, 0, 0, 0 ],
-                  "D1": [ 0, 0, 0, 0 ]
+                  "D0": [ 1, 0.784314, 0.0784314, 1 ]
                }
             ]
          }
diff --git a/resources/particles/explosion.json b/resources/particles/explosion.json
index 970a0d6..e403d3c 100644
--- a/resources/particles/explosion.json
+++ b/resources/particles/explosion.json
@@ -6,17 +6,11 @@
       "XValues": [],
       "Segments": [
          {
-            "Constant": true,
+            "Type": "Constant",
             "Ranged": true,
             "Bidirectional": false,
             "A0": 1,
-            "B0": 0,
-            "C0": 0,
-            "D0": 0,
-            "A1": 3,
-            "B1": 0,
-            "C1": 0,
-            "D1": 0
+            "A1": 3
          }
       ]
    },
@@ -47,17 +41,11 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": false,
+                  "Type": "Linear",
                   "Ranged": false,
                   "Bidirectional": false,
                   "A0": 0,
-                  "B0": 0.333,
-                  "C0": 0.666,
-                  "D0": 1,
-                  "A1": 0,
-                  "B1": 0,
-                  "C1": 0,
-                  "D1": 0
+                  "D0": 1
                }
             ]
          }
diff --git a/resources/particles/penguin_cannon.json b/resources/particles/penguin_cannon.json
index 69f94c0..17415b9 100644
--- a/resources/particles/penguin_cannon.json
+++ b/resources/particles/penguin_cannon.json
@@ -6,17 +6,10 @@
       "XValues": [],
       "Segments": [
          {
-            "Constant": true,
+            "Type": "Constant",
             "Ranged": false,
             "Bidirectional": false,
-            "A0": 20,
-            "B0": 0,
-            "C0": 0,
-            "D0": 0,
-            "A1": 0,
-            "B1": 0,
-            "C1": 0,
-            "D1": 0
+            "A0": 20
          }
       ]
    },
@@ -41,17 +34,11 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": true,
+                  "Type": "Constant",
                   "Ranged": true,
                   "Bidirectional": false,
                   "A0": 10,
-                  "B0": 0,
-                  "C0": 0,
-                  "D0": 0,
-                  "A1": 70,
-                  "B1": 0,
-                  "C1": 0,
-                  "D1": 0
+                  "A1": 70
                }
             ]
          },
@@ -59,17 +46,11 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": true,
+                  "Type": "Constant",
                   "Ranged": true,
                   "Bidirectional": false,
                   "A0": 140,
-                  "B0": 0,
-                  "C0": 0,
-                  "D0": 0,
-                  "A1": 200,
-                  "B1": 0,
-                  "C1": 0,
-                  "D1": 0
+                  "A1": 200
                }
             ]
          }
@@ -85,17 +66,10 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": true,
+                  "Type": "Constant",
                   "Ranged": false,
                   "Bidirectional": false,
-                  "A0": 180,
-                  "B0": 0,
-                  "C0": 0,
-                  "D0": 0,
-                  "A1": 0,
-                  "B1": 0,
-                  "C1": 0,
-                  "D1": 0
+                  "A0": 180
                }
             ]
          },
@@ -103,17 +77,10 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": true,
+                  "Type": "Constant",
                   "Ranged": false,
                   "Bidirectional": false,
-                  "A0": 50,
-                  "B0": 0,
-                  "C0": 0,
-                  "D0": 0,
-                  "A1": 0,
-                  "B1": 0,
-                  "C1": 0,
-                  "D1": 0
+                  "A0": 50
                }
             ]
          }
@@ -126,17 +93,10 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": true,
+                  "Type": "Constant",
                   "Ranged": false,
                   "Bidirectional": false,
-                  "A0": 0,
-                  "B0": 0,
-                  "C0": 0,
-                  "D0": 0,
-                  "A1": 0,
-                  "B1": 0,
-                  "C1": 0,
-                  "D1": 0
+                  "A0": 0
                }
             ]
          }
diff --git a/resources/particles/snowfall.json b/resources/particles/snowfall.json
index aa8b0bb..843e65f 100644
--- a/resources/particles/snowfall.json
+++ b/resources/particles/snowfall.json
@@ -6,17 +6,10 @@
       "XValues": [],
       "Segments": [
          {
-            "Constant": true,
+            "Type": "Constant",
             "Ranged": false,
             "Bidirectional": false,
-            "A0": 10,
-            "B0": 0,
-            "C0": 0,
-            "D0": 0,
-            "A1": 0,
-            "B1": 0,
-            "C1": 0,
-            "D1": 0
+            "A0": 10
          }
       ]
    },
@@ -39,17 +32,11 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": true,
+                  "Type": "Constant",
                   "Ranged": true,
                   "Bidirectional": false,
                   "A0": 170,
-                  "B0": 1,
-                  "C0": 0,
-                  "D0": 0,
-                  "A1": 190,
-                  "B1": 0,
-                  "C1": 0,
-                  "D1": 0
+                  "A1": 190
                }
             ]
          },
@@ -57,17 +44,11 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": true,
+                  "Type": "Constant",
                   "Ranged": true,
                   "Bidirectional": false,
                   "A0": 10,
-                  "B0": 0,
-                  "C0": 0,
-                  "D0": 0,
-                  "A1": 30,
-                  "B1": 0,
-                  "C1": 0,
-                  "D1": 0
+                  "A1": 30
                }
             ]
          }
@@ -81,7 +62,7 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": false,
+                  "Type": "Cubic",
                   "Ranged": true,
                   "Bidirectional": false,
                   "A0": 10,
diff --git a/resources/particles/spiral.json b/resources/particles/spiral.json
index 9257d53..b13df1f 100644
--- a/resources/particles/spiral.json
+++ b/resources/particles/spiral.json
@@ -6,17 +6,11 @@
       "XValues": [],
       "Segments": [
          {
-            "Constant": true,
+            "Type": "Constant",
             "Ranged": true,
             "Bidirectional": false,
             "A0": 2,
-            "B0": 0,
-            "C0": 0,
-            "D0": 0,
-            "A1": 3,
-            "B1": 0,
-            "C1": 0,
-            "D1": 0
+            "A1": 3
          }
       ]
    },
@@ -39,17 +33,11 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": false,
+                  "Type": "Linear",
                   "Ranged": false,
                   "Bidirectional": false,
                   "A0": 0,
-                  "B0": 360,
-                  "C0": 720,
-                  "D0": 1080,
-                  "A1": 0,
-                  "B1": 0,
-                  "C1": 0,
-                  "D1": 0
+                  "D0": 1080
                }
             ]
          },
@@ -57,17 +45,11 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": true,
+                  "Type": "Constant",
                   "Ranged": true,
                   "Bidirectional": false,
                   "A0": 50,
-                  "B0": 0,
-                  "C0": 0,
-                  "D0": 0,
-                  "A1": 60,
-                  "B1": 0,
-                  "C1": 0,
-                  "D1": 0
+                  "A1": 60
                }
             ]
          }
@@ -81,17 +63,11 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": false,
+                  "Type": "Linear",
                   "Ranged": false,
                   "Bidirectional": false,
                   "A0": 0.5,
-                  "B0": 1,
-                  "C0": 1.5,
-                  "D0": 2,
-                  "A1": 0,
-                  "B1": 0,
-                  "C1": 0,
-                  "D1": 0
+                  "D0": 2
                }
             ]
          }
@@ -103,15 +79,11 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": false,
+                  "Type": "Linear",
                   "Ranged": true,
                   "A0": [ 0.0999616, 0.140218, 0.784314, 1 ],
-                  "B0": [ 0.183679, 0.183692, 0.764706, 1 ],
-                  "C0": [ 0.242647, 0.43925, 0.916667, 1 ],
                   "D0": [ 0.523837, 0.886396, 0.980392, 1 ],
                   "A1": [ 0.378665, 0.121107, 0.705882, 1 ],
-                  "B1": [ 0.538658, 0.162534, 0.872549, 1 ],
-                  "C1": [ 0.672143, 0.259443, 0.867647, 1 ],
                   "D1": [ 0.934257, 0.229599, 0.955882, 1 ]
                }
             ]
diff --git a/resources/particles/swirl.json b/resources/particles/swirl.json
index fbc2b47..d3ccf5f 100644
--- a/resources/particles/swirl.json
+++ b/resources/particles/swirl.json
@@ -6,17 +6,11 @@
       "XValues": [],
       "Segments": [
          {
-            "Constant": true,
+            "Type": "Constant",
             "Ranged": true,
             "Bidirectional": false,
             "A0": 1,
-            "B0": 0,
-            "C0": 0,
-            "D0": 0,
-            "A1": 3,
-            "B1": 0,
-            "C1": 0,
-            "D1": 0
+            "A1": 3
          }
       ]
    },
@@ -39,17 +33,11 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": true,
+                  "Type": "Constant",
                   "Ranged": true,
                   "Bidirectional": false,
                   "A0": -10,
-                  "B0": 0,
-                  "C0": 0,
-                  "D0": 0,
-                  "A1": 10,
-                  "B1": 0,
-                  "C1": 0,
-                  "D1": 0
+                  "A1": 10
                }
             ]
          },
@@ -57,17 +45,11 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": true,
+                  "Type": "Constant",
                   "Ranged": true,
                   "Bidirectional": false,
                   "A0": 50,
-                  "B0": 0,
-                  "C0": 0,
-                  "D0": 0,
-                  "A1": 60,
-                  "B1": 0,
-                  "C1": 0,
-                  "D1": 0
+                  "A1": 60
                }
             ]
          }
@@ -83,17 +65,10 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": true,
+                  "Type": "Constant",
                   "Ranged": false,
                   "Bidirectional": false,
-                  "A0": 90,
-                  "B0": 0,
-                  "C0": 0,
-                  "D0": 0,
-                  "A1": 0,
-                  "B1": 0,
-                  "C1": 0,
-                  "D1": 0
+                  "A0": 90
                }
             ]
          },
@@ -101,17 +76,13 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": false,
+                  "Type": "Cubic",
                   "Ranged": false,
                   "Bidirectional": true,
                   "A0": 180,
                   "B0": -90,
                   "C0": -120,
-                  "D0": -200,
-                  "A1": 0,
-                  "B1": 0,
-                  "C1": 0,
-                  "D1": 0
+                  "D0": -200
                }
             ]
          }
@@ -123,17 +94,11 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": false,
+                  "Type": "Linear",
                   "Ranged": false,
                   "Bidirectional": false,
                   "A0": 3,
-                  "B0": 2.5,
-                  "C0": 2,
-                  "D0": 1.5,
-                  "A1": 0,
-                  "B1": 0,
-                  "C1": 0,
-                  "D1": 0
+                  "D0": 1.5
                }
             ]
          }
@@ -145,15 +110,11 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": false,
+                  "Type": "Linear",
                   "Ranged": true,
                   "A0": [ 0.0999616, 0.140218, 0.784314, 1 ],
-                  "B0": [ 0.183679, 0.183692, 0.764706, 1 ],
-                  "C0": [ 0.242647, 0.43925, 0.916667, 1 ],
                   "D0": [ 0.523837, 0.886396, 0.980392, 1 ],
                   "A1": [ 0.378665, 0.121107, 0.705882, 1 ],
-                  "B1": [ 0.538658, 0.162534, 0.872549, 1 ],
-                  "C1": [ 0.672143, 0.259443, 0.867647, 1 ],
                   "D1": [ 0.934257, 0.229599, 0.955882, 1 ]
                }
             ]
diff --git a/resources/particles/warp.json b/resources/particles/warp.json
index b96074e..9b81db7 100644
--- a/resources/particles/warp.json
+++ b/resources/particles/warp.json
@@ -6,17 +6,10 @@
       "XValues": [],
       "Segments": [
          {
-            "Constant": true,
+            "Type": "Constant",
             "Ranged": false,
             "Bidirectional": false,
-            "A0": 30,
-            "B0": 0,
-            "C0": 0,
-            "D0": 0,
-            "A1": 0,
-            "B1": 0,
-            "C1": 0,
-            "D1": 0
+            "A0": 30
          }
       ]
    },
@@ -45,17 +38,11 @@
             "XValues": [],
             "Segments": [
                {
-                  "Constant": false,
+                  "Type": "Linear",
                   "Ranged": false,
                   "Bidirectional": false,
                   "A0": 0.25,
-                  "B0": 1,
-                  "C0": 2,
-                  "D0": 3,
-                  "A1": 0,
-                  "B1": 0,
-                  "C1": 0,
-                  "D1": 0
+                  "D0": 3
                }
             ]
          }
diff --git a/tools/viewer/ParticlesSlide.cpp b/tools/viewer/ParticlesSlide.cpp
index 5585d3b..5742cbd 100644
--- a/tools/viewer/ParticlesSlide.cpp
+++ b/tools/viewer/ParticlesSlide.cpp
@@ -90,59 +90,6 @@
 
 #undef IF_OPEN
 
-    void visit(const char* name, SkCurve& c) override {
-        this->enterObject(item(name));
-        if (fTreeStack.back()) {
-            // Get vertical extents of the curve
-            SkScalar extents[2];
-            c.getExtents(extents);
-
-            // Grow the extents by 10%, at least 1.0f
-            SkScalar grow = SkTMax((extents[1] - extents[0]) * 0.1f, 1.0f);
-            extents[0] -= grow;
-            extents[1] += grow;
-
-            {
-                ImGui::DragCanvas dc(&c, { 0.0f, extents[1] }, { 1.0f, extents[0] }, 0.5f);
-                dc.fillColor(IM_COL32(0, 0, 0, 128));
-
-                for (int i = 0; i < c.fSegments.count(); ++i) {
-                    SkSTArray<8, ImVec2, true> pts;
-                    SkScalar rangeMin = (i == 0) ? 0.0f : c.fXValues[i - 1];
-                    SkScalar rangeMax = (i == c.fXValues.count()) ? 1.0f : c.fXValues[i];
-                    auto screenPoint = [&](int idx, bool useMax) {
-                        SkScalar xVal = rangeMin + (idx / 3.0f) * (rangeMax - rangeMin);
-                        SkScalar* yVals = useMax ? c.fSegments[i].fMax : c.fSegments[i].fMin;
-                        SkScalar yVal = yVals[c.fSegments[i].fConstant ? 0 : idx];
-                        SkPoint pt = dc.fLocalToScreen.mapXY(xVal, yVal);
-                        return ImVec2(pt.fX, pt.fY);
-                    };
-                    for (int i = 0; i < 4; ++i) {
-                        pts.push_back(screenPoint(i, false));
-                    }
-                    if (c.fSegments[i].fRanged) {
-                        for (int i = 3; i >= 0; --i) {
-                            pts.push_back(screenPoint(i, true));
-                        }
-                    }
-
-                    if (c.fSegments[i].fRanged) {
-                        dc.fDrawList->PathLineTo(pts[0]);
-                        dc.fDrawList->PathBezierCurveTo(pts[1], pts[2], pts[3]);
-                        dc.fDrawList->PathLineTo(pts[4]);
-                        dc.fDrawList->PathBezierCurveTo(pts[5], pts[6], pts[7]);
-                        dc.fDrawList->PathFillConvex(IM_COL32(255, 255, 255, 128));
-                    } else {
-                        dc.fDrawList->AddBezierCurve(pts[0], pts[1], pts[2], pts[3],
-                                                     IM_COL32(255, 255, 255, 255), 1.0f);
-                    }
-                }
-            }
-            c.visitFields(this);
-        }
-        this->exitObject();
-    }
-
     void visit(sk_sp<SkReflected>& e, const SkReflected::Type* baseType) override {
         if (fTreeStack.back()) {
             const SkReflected::Type* curType = e ? e->getType() : nullptr;