[skottie] Clean up SkottieProperties

Split into Adapter and Value CUs.

No real changes, just shuffling things around.

TBR=
Change-Id: I50eaeb3950f4c59e7d7027955b3f49ca2a346e59
Reviewed-on: https://skia-review.googlesource.com/116186
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Florin Malita <fmalita@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index cc7468f..ff99776 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1357,9 +1357,10 @@
     include_dirs = [ "tools" ]
     sources = [
       "experimental/skottie/Skottie.cpp",
+      "experimental/skottie/SkottieAdapter.cpp",
       "experimental/skottie/SkottieAnimator.cpp",
       "experimental/skottie/SkottieParser.cpp",
-      "experimental/skottie/SkottieProperties.cpp",
+      "experimental/skottie/SkottieValue.cpp",
     ]
     deps = [
       ":experimental_sksg",
diff --git a/experimental/skottie/Skottie.cpp b/experimental/skottie/Skottie.cpp
index 5a04e5a..9c5849f 100644
--- a/experimental/skottie/Skottie.cpp
+++ b/experimental/skottie/Skottie.cpp
@@ -9,9 +9,10 @@
 
 #include "SkCanvas.h"
 #include "SkJSONCPP.h"
+#include "SkottieAdapter.h"
 #include "SkottieAnimator.h"
 #include "SkottieParser.h"
-#include "SkottieProperties.h"
+#include "SkottieValue.h"
 #include "SkData.h"
 #include "SkImage.h"
 #include "SkMakeUnique.h"
@@ -71,18 +72,18 @@
         return nullptr;
 
     auto matrix = sksg::Matrix::Make(SkMatrix::I(), std::move(parentMatrix));
-    auto composite = sk_make_sp<CompositeTransform>(matrix);
+    auto adapter = sk_make_sp<TransformAdapter>(matrix);
     auto anchor_attached = BindProperty<VectorValue>(t["a"], &ctx->fAnimators,
-            [composite](const VectorValue& a) {
-                composite->setAnchorPoint(ValueTraits<VectorValue>::As<SkPoint>(a));
+            [adapter](const VectorValue& a) {
+                adapter->setAnchorPoint(ValueTraits<VectorValue>::As<SkPoint>(a));
             });
     auto position_attached = BindProperty<VectorValue>(t["p"], &ctx->fAnimators,
-            [composite](const VectorValue& p) {
-                composite->setPosition(ValueTraits<VectorValue>::As<SkPoint>(p));
+            [adapter](const VectorValue& p) {
+                adapter->setPosition(ValueTraits<VectorValue>::As<SkPoint>(p));
             });
     auto scale_attached = BindProperty<VectorValue>(t["s"], &ctx->fAnimators,
-            [composite](const VectorValue& s) {
-                composite->setScale(ValueTraits<VectorValue>::As<SkVector>(s));
+            [adapter](const VectorValue& s) {
+                adapter->setScale(ValueTraits<VectorValue>::As<SkVector>(s));
             });
 
     auto* jrotation = &t["r"];
@@ -92,16 +93,16 @@
         jrotation = &t["rz"];
     }
     auto rotation_attached = BindProperty<ScalarValue>(*jrotation, &ctx->fAnimators,
-            [composite](const ScalarValue& r) {
-                composite->setRotation(r);
+            [adapter](const ScalarValue& r) {
+                adapter->setRotation(r);
             });
     auto skew_attached = BindProperty<ScalarValue>(t["sk"], &ctx->fAnimators,
-            [composite](const ScalarValue& sk) {
-                composite->setSkew(sk);
+            [adapter](const ScalarValue& sk) {
+                adapter->setSkew(sk);
             });
     auto skewaxis_attached = BindProperty<ScalarValue>(t["sa"], &ctx->fAnimators,
-            [composite](const ScalarValue& sa) {
-                composite->setSkewAxis(sa);
+            [adapter](const ScalarValue& sa) {
+                adapter->setSkewAxis(sa);
             });
 
     if (!anchor_attached &&
@@ -162,19 +163,19 @@
     SkASSERT(jrect.isObject());
 
     auto rect_node = sksg::RRect::Make();
-    auto composite = sk_make_sp<CompositeRRect>(rect_node);
+    auto adapter = sk_make_sp<RRectAdapter>(rect_node);
 
     auto p_attached = BindProperty<VectorValue>(jrect["p"], &ctx->fAnimators,
-        [composite](const VectorValue& p) {
-                composite->setPosition(ValueTraits<VectorValue>::As<SkPoint>(p));
+        [adapter](const VectorValue& p) {
+                adapter->setPosition(ValueTraits<VectorValue>::As<SkPoint>(p));
         });
     auto s_attached = BindProperty<VectorValue>(jrect["s"], &ctx->fAnimators,
-        [composite](const VectorValue& s) {
-            composite->setSize(ValueTraits<VectorValue>::As<SkSize>(s));
+        [adapter](const VectorValue& s) {
+            adapter->setSize(ValueTraits<VectorValue>::As<SkSize>(s));
         });
     auto r_attached = BindProperty<ScalarValue>(jrect["r"], &ctx->fAnimators,
-        [composite](const ScalarValue& r) {
-            composite->setRadius(SkSize::Make(r, r));
+        [adapter](const ScalarValue& r) {
+            adapter->setRadius(SkSize::Make(r, r));
         });
 
     if (!p_attached && !s_attached && !r_attached) {
@@ -188,17 +189,17 @@
     SkASSERT(jellipse.isObject());
 
     auto rect_node = sksg::RRect::Make();
-    auto composite = sk_make_sp<CompositeRRect>(rect_node);
+    auto adapter = sk_make_sp<RRectAdapter>(rect_node);
 
     auto p_attached = BindProperty<VectorValue>(jellipse["p"], &ctx->fAnimators,
-        [composite](const VectorValue& p) {
-            composite->setPosition(ValueTraits<VectorValue>::As<SkPoint>(p));
+        [adapter](const VectorValue& p) {
+            adapter->setPosition(ValueTraits<VectorValue>::As<SkPoint>(p));
         });
     auto s_attached = BindProperty<VectorValue>(jellipse["s"], &ctx->fAnimators,
-        [composite](const VectorValue& s) {
+        [adapter](const VectorValue& s) {
             const auto sz = ValueTraits<VectorValue>::As<SkSize>(s);
-            composite->setSize(sz);
-            composite->setRadius(SkSize::Make(sz.width() / 2, sz.height() / 2));
+            adapter->setSize(sz);
+            adapter->setRadius(SkSize::Make(sz.width() / 2, sz.height() / 2));
         });
 
     if (!p_attached && !s_attached) {
@@ -211,9 +212,9 @@
 sk_sp<sksg::GeometryNode> AttachPolystarGeometry(const Json::Value& jstar, AttachContext* ctx) {
     SkASSERT(jstar.isObject());
 
-    static constexpr CompositePolyStar::Type gTypes[] = {
-        CompositePolyStar::Type::kStar, // "sy": 1
-        CompositePolyStar::Type::kPoly, // "sy": 2
+    static constexpr PolyStarAdapter::Type gTypes[] = {
+        PolyStarAdapter::Type::kStar, // "sy": 1
+        PolyStarAdapter::Type::kPoly, // "sy": 2
     };
 
     const auto type = ParseDefault(jstar["sy"], 0) - 1;
@@ -223,35 +224,35 @@
     }
 
     auto path_node = sksg::Path::Make();
-    auto composite = sk_make_sp<CompositePolyStar>(path_node, gTypes[type]);
+    auto adapter = sk_make_sp<PolyStarAdapter>(path_node, gTypes[type]);
 
     BindProperty<VectorValue>(jstar["p"], &ctx->fAnimators,
-        [composite](const VectorValue& p) {
-            composite->setPosition(ValueTraits<VectorValue>::As<SkPoint>(p));
+        [adapter](const VectorValue& p) {
+            adapter->setPosition(ValueTraits<VectorValue>::As<SkPoint>(p));
         });
     BindProperty<ScalarValue>(jstar["pt"], &ctx->fAnimators,
-        [composite](const ScalarValue& pt) {
-            composite->setPointCount(pt);
+        [adapter](const ScalarValue& pt) {
+            adapter->setPointCount(pt);
         });
     BindProperty<ScalarValue>(jstar["ir"], &ctx->fAnimators,
-        [composite](const ScalarValue& ir) {
-            composite->setInnerRadius(ir);
+        [adapter](const ScalarValue& ir) {
+            adapter->setInnerRadius(ir);
         });
     BindProperty<ScalarValue>(jstar["or"], &ctx->fAnimators,
-        [composite](const ScalarValue& otr) {
-            composite->setOuterRadius(otr);
+        [adapter](const ScalarValue& otr) {
+            adapter->setOuterRadius(otr);
         });
     BindProperty<ScalarValue>(jstar["is"], &ctx->fAnimators,
-        [composite](const ScalarValue& is) {
-            composite->setInnerRoundness(is);
+        [adapter](const ScalarValue& is) {
+            adapter->setInnerRoundness(is);
         });
     BindProperty<ScalarValue>(jstar["os"], &ctx->fAnimators,
-        [composite](const ScalarValue& os) {
-            composite->setOuterRoundness(os);
+        [adapter](const ScalarValue& os) {
+            adapter->setOuterRoundness(os);
         });
     BindProperty<ScalarValue>(jstar["r"], &ctx->fAnimators,
-        [composite](const ScalarValue& r) {
-            composite->setRotation(r);
+        [adapter](const ScalarValue& r) {
+            adapter->setRotation(r);
         });
 
     return path_node;
@@ -281,31 +282,31 @@
         return nullptr;
 
     sk_sp<sksg::Gradient> gradient_node;
-    sk_sp<CompositeGradient> composite;
+    sk_sp<GradientAdapter> adapter;
 
     if (ParseDefault(obj["t"], 1) == 1) {
         auto linear_node = sksg::LinearGradient::Make();
-        composite = sk_make_sp<CompositeLinearGradient>(linear_node, stopCount);
+        adapter = sk_make_sp<LinearGradientAdapter>(linear_node, stopCount);
         gradient_node = std::move(linear_node);
     } else {
         auto radial_node = sksg::RadialGradient::Make();
-        composite = sk_make_sp<CompositeRadialGradient>(radial_node, stopCount);
+        adapter = sk_make_sp<RadialGradientAdapter>(radial_node, stopCount);
 
         // TODO: highlight, angle
         gradient_node = std::move(radial_node);
     }
 
     BindProperty<VectorValue>(stops["k"], &ctx->fAnimators,
-        [composite](const VectorValue& stops) {
-            composite->setColorStops(stops);
+        [adapter](const VectorValue& stops) {
+            adapter->setColorStops(stops);
         });
     BindProperty<VectorValue>(obj["s"], &ctx->fAnimators,
-        [composite](const VectorValue& s) {
-            composite->setStartPoint(ValueTraits<VectorValue>::As<SkPoint>(s));
+        [adapter](const VectorValue& s) {
+            adapter->setStartPoint(ValueTraits<VectorValue>::As<SkPoint>(s));
         });
     BindProperty<VectorValue>(obj["e"], &ctx->fAnimators,
-        [composite](const VectorValue& e) {
-            composite->setEndPoint(ValueTraits<VectorValue>::As<SkPoint>(e));
+        [adapter](const VectorValue& e) {
+            adapter->setEndPoint(ValueTraits<VectorValue>::As<SkPoint>(e));
         });
 
     return gradient_node;
@@ -430,18 +431,18 @@
         const auto trimEffect = sksg::TrimEffect::Make(i);
         trimmed.push_back(trimEffect);
 
-        const auto trimComposite = sk_make_sp<CompositeTrimEffect>(std::move(trimEffect));
+        const auto adapter = sk_make_sp<TrimEffectAdapter>(std::move(trimEffect));
         BindProperty<ScalarValue>(jtrim["s"], &ctx->fAnimators,
-            [trimComposite](const ScalarValue& s) {
-                trimComposite->setStart(s);
+            [adapter](const ScalarValue& s) {
+                adapter->setStart(s);
             });
         BindProperty<ScalarValue>(jtrim["e"], &ctx->fAnimators,
-            [trimComposite](const ScalarValue& e) {
-                trimComposite->setEnd(e);
+            [adapter](const ScalarValue& e) {
+                adapter->setEnd(e);
             });
         BindProperty<ScalarValue>(jtrim["o"], &ctx->fAnimators,
-            [trimComposite](const ScalarValue& o) {
-                trimComposite->setOffset(o);
+            [adapter](const ScalarValue& o) {
+                adapter->setOffset(o);
             });
     }
 
diff --git a/experimental/skottie/SkottieAdapter.cpp b/experimental/skottie/SkottieAdapter.cpp
new file mode 100644
index 0000000..5186e2c
--- /dev/null
+++ b/experimental/skottie/SkottieAdapter.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkottieAdapter.h"
+
+#include "SkMatrix.h"
+#include "SkottieValue.h"
+#include "SkPath.h"
+#include "SkRRect.h"
+#include "SkSGGradient.h"
+#include "SkSGPath.h"
+#include "SkSGRect.h"
+#include "SkSGTransform.h"
+#include "SkSGTrimEffect.h"
+
+#include <cmath>
+
+namespace skottie {
+
+RRectAdapter::RRectAdapter(sk_sp<sksg::RRect> wrapped_node)
+    : fRRectNode(std::move(wrapped_node)) {}
+
+void RRectAdapter::apply() {
+    // BM "position" == "center position"
+    auto rr = SkRRect::MakeRectXY(SkRect::MakeXYWH(fPosition.x() - fSize.width() / 2,
+                                                   fPosition.y() - fSize.height() / 2,
+                                                   fSize.width(), fSize.height()),
+                                  fRadius.width(),
+                                  fRadius.height());
+   fRRectNode->setRRect(rr);
+}
+
+TransformAdapter::TransformAdapter(sk_sp<sksg::Matrix> matrix)
+    : fMatrixNode(std::move(matrix)) {}
+
+void TransformAdapter::apply() {
+    SkMatrix t = SkMatrix::MakeTrans(-fAnchorPoint.x(), -fAnchorPoint.y());
+
+    t.postScale(fScale.x() / 100, fScale.y() / 100); // 100% based
+    t.postRotate(fRotation);
+    t.postTranslate(fPosition.x(), fPosition.y());
+    // TODO: skew
+
+    fMatrixNode->setMatrix(t);
+}
+
+PolyStarAdapter::PolyStarAdapter(sk_sp<sksg::Path> wrapped_node, Type t)
+    : fPathNode(std::move(wrapped_node))
+    , fType(t) {}
+
+void PolyStarAdapter::apply() {
+    const auto count = SkScalarTruncToInt(fPointCount);
+    const auto arc   = SK_ScalarPI * 2 / count;
+
+    const auto pt_on_circle = [](const SkPoint& c, SkScalar r, SkScalar a) {
+        return SkPoint::Make(c.x() + r * std::cos(a),
+                             c.y() + r * std::sin(a));
+    };
+
+    // TODO: inner/outer "roundness"?
+
+    SkPath poly;
+
+    auto angle = SkDegreesToRadians(fRotation);
+    poly.moveTo(pt_on_circle(fPosition, fOuterRadius, angle));
+
+    for (int i = 0; i < count; ++i) {
+        if (fType == Type::kStar) {
+            poly.lineTo(pt_on_circle(fPosition, fInnerRadius, angle + arc * 0.5f));
+        }
+        angle += arc;
+        poly.lineTo(pt_on_circle(fPosition, fOuterRadius, angle));
+    }
+
+    poly.close();
+    fPathNode->setPath(poly);
+}
+
+GradientAdapter::GradientAdapter(sk_sp<sksg::Gradient> grad, size_t stopCount)
+    : fGradient(std::move(grad))
+    , fStopCount(stopCount) {}
+
+void GradientAdapter::apply() {
+    this->onApply();
+
+    // |fColorStops| holds |fStopCount| x [ pos, r, g, g ] + ? x [ pos, alpha ]
+
+    if (fColorStops.size() < fStopCount * 4 || ((fColorStops.size() - fStopCount * 4) % 2)) {
+        SkDebugf("!! Invalid gradient stop array size: %zu", fColorStops.size());
+        return;
+    }
+
+    std::vector<sksg::Gradient::ColorStop> stops;
+
+    // TODO: merge/lerp opacity stops
+    const auto csEnd = fColorStops.cbegin() + fStopCount * 4;
+    for (auto cs = fColorStops.cbegin(); cs != csEnd; cs += 4) {
+        const auto pos = cs[0];
+        const VectorValue rgb({ cs[1], cs[2], cs[3] });
+
+        stops.push_back({ pos, ValueTraits<VectorValue>::As<SkColor>(rgb) });
+    }
+
+    fGradient->setColorStops(std::move(stops));
+}
+
+LinearGradientAdapter::LinearGradientAdapter(sk_sp<sksg::LinearGradient> grad, size_t stopCount)
+    : INHERITED(std::move(grad), stopCount) {}
+
+void LinearGradientAdapter::onApply() {
+    auto* grad = static_cast<sksg::LinearGradient*>(fGradient.get());
+    grad->setStartPoint(this->startPoint());
+    grad->setEndPoint(this->endPoint());
+}
+
+RadialGradientAdapter::RadialGradientAdapter(sk_sp<sksg::RadialGradient> grad, size_t stopCount)
+    : INHERITED(std::move(grad), stopCount) {}
+
+void RadialGradientAdapter::onApply() {
+    auto* grad = static_cast<sksg::RadialGradient*>(fGradient.get());
+    grad->setStartCenter(this->startPoint());
+    grad->setEndCenter(this->startPoint());
+    grad->setStartRadius(0);
+    grad->setEndRadius(SkPoint::Distance(this->startPoint(), this->endPoint()));
+}
+
+TrimEffectAdapter::TrimEffectAdapter(sk_sp<sksg::TrimEffect> trimEffect)
+    : fTrimEffect(std::move(trimEffect)) {
+    SkASSERT(fTrimEffect);
+}
+
+void TrimEffectAdapter::apply() {
+    // BM semantics: start/end are percentages, offset is "degrees" (?!).
+    const auto  start = fStart  / 100,
+                  end = fEnd    / 100,
+               offset = fOffset / 360;
+
+    auto startT = SkTMin(start, end) + offset,
+          stopT = SkTMax(start, end) + offset;
+    auto   mode = SkTrimPathEffect::Mode::kNormal;
+
+    if (stopT - startT < 1) {
+        startT -= SkScalarFloorToScalar(startT);
+        stopT  -= SkScalarFloorToScalar(stopT);
+
+        if (startT > stopT) {
+            SkTSwap(startT, stopT);
+            mode = SkTrimPathEffect::Mode::kInverted;
+        }
+    } else {
+        startT = 0;
+        stopT  = 1;
+    }
+
+    fTrimEffect->setStart(startT);
+    fTrimEffect->setStop(stopT);
+    fTrimEffect->setMode(mode);
+}
+
+} // namespace skottie
diff --git a/experimental/skottie/SkottieAdapter.h b/experimental/skottie/SkottieAdapter.h
new file mode 100644
index 0000000..e96c616
--- /dev/null
+++ b/experimental/skottie/SkottieAdapter.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkottieAdapter_DEFINED
+#define SkottieAdapter_DEFINED
+
+#include "SkPoint.h"
+#include "SkRefCnt.h"
+#include "SkSize.h"
+
+#include <vector>
+
+namespace sksg {
+
+class Gradient;
+class LinearGradient;
+class Matrix;
+class Path;
+class RadialGradient;
+class RRect;
+class TrimEffect;
+
+};
+
+namespace skottie {
+
+#define ADAPTER_PROPERTY(p_name, p_type, p_default) \
+    void set##p_name(const p_type& p) {             \
+        if (p == f##p_name) return;                 \
+        f##p_name = p;                              \
+        this->apply();                              \
+    }                                               \
+  private:                                          \
+    p_type f##p_name = p_default;                   \
+  public:
+
+class RRectAdapter final : public SkRefCnt {
+public:
+    explicit RRectAdapter(sk_sp<sksg::RRect>);
+
+    ADAPTER_PROPERTY(Position, SkPoint , SkPoint::Make(0, 0))
+    ADAPTER_PROPERTY(Size    , SkSize  ,  SkSize::Make(0, 0))
+    ADAPTER_PROPERTY(Radius  , SkSize  ,  SkSize::Make(0, 0))
+
+private:
+    void apply();
+
+    sk_sp<sksg::RRect> fRRectNode;
+
+    using INHERITED = SkRefCnt;
+};
+
+class PolyStarAdapter final : public SkRefCnt {
+public:
+    enum class Type {
+        kStar, kPoly,
+    };
+
+    PolyStarAdapter(sk_sp<sksg::Path>, Type);
+
+    ADAPTER_PROPERTY(Position      , SkPoint , SkPoint::Make(0, 0))
+    ADAPTER_PROPERTY(PointCount    , SkScalar, 0)
+    ADAPTER_PROPERTY(InnerRadius   , SkScalar, 0)
+    ADAPTER_PROPERTY(OuterRadius   , SkScalar, 0)
+    ADAPTER_PROPERTY(InnerRoundness, SkScalar, 0)
+    ADAPTER_PROPERTY(OuterRoundness, SkScalar, 0)
+    ADAPTER_PROPERTY(Rotation      , SkScalar, 0)
+
+private:
+    void apply();
+
+    sk_sp<sksg::Path> fPathNode;
+    Type              fType;
+
+    using INHERITED = SkRefCnt;
+};
+
+class TransformAdapter final : public SkRefCnt {
+public:
+    explicit TransformAdapter(sk_sp<sksg::Matrix>);
+
+    ADAPTER_PROPERTY(AnchorPoint, SkPoint , SkPoint::Make(0, 0))
+    ADAPTER_PROPERTY(Position   , SkPoint , SkPoint::Make(0, 0))
+    ADAPTER_PROPERTY(Scale      , SkVector, SkPoint::Make(100, 100))
+    ADAPTER_PROPERTY(Rotation   , SkScalar, 0)
+    ADAPTER_PROPERTY(Skew       , SkScalar, 0)
+    ADAPTER_PROPERTY(SkewAxis   , SkScalar, 0)
+
+private:
+    void apply();
+
+    sk_sp<sksg::Matrix> fMatrixNode;
+
+    using INHERITED = SkRefCnt;
+};
+
+class GradientAdapter : public SkRefCnt {
+public:
+    ADAPTER_PROPERTY(StartPoint, SkPoint              , SkPoint::Make(0, 0)    )
+    ADAPTER_PROPERTY(EndPoint  , SkPoint              , SkPoint::Make(0, 0)    )
+    ADAPTER_PROPERTY(ColorStops, std::vector<SkScalar>, std::vector<SkScalar>())
+
+protected:
+    GradientAdapter(sk_sp<sksg::Gradient>, size_t stopCount);
+
+    const SkPoint& startPoint() const { return fStartPoint; }
+    const SkPoint& endPoint()   const { return fEndPoint;   }
+
+    sk_sp<sksg::Gradient> fGradient;
+    size_t                fStopCount;
+
+    virtual void onApply() = 0;
+
+private:
+    void apply();
+
+    using INHERITED = SkRefCnt;
+};
+
+class LinearGradientAdapter final : public GradientAdapter {
+public:
+    LinearGradientAdapter(sk_sp<sksg::LinearGradient>, size_t stopCount);
+
+private:
+    void onApply() override;
+
+    using INHERITED = GradientAdapter;
+};
+
+class RadialGradientAdapter final : public GradientAdapter {
+public:
+    RadialGradientAdapter(sk_sp<sksg::RadialGradient>, size_t stopCount);
+
+private:
+    void onApply() override;
+
+    using INHERITED = GradientAdapter;
+};
+
+class TrimEffectAdapter final : public SkRefCnt {
+public:
+    explicit TrimEffectAdapter(sk_sp<sksg::TrimEffect>);
+
+    ADAPTER_PROPERTY(Start , SkScalar,   0)
+    ADAPTER_PROPERTY(End   , SkScalar, 100)
+    ADAPTER_PROPERTY(Offset, SkScalar,   0)
+
+private:
+    void apply();
+
+    sk_sp<sksg::TrimEffect> fTrimEffect;
+
+    using INHERITED = SkRefCnt;
+};
+
+#undef ADAPTER_PROPERTY
+
+} // namespace skottie
+
+#endif // SkottieAdapter_DEFINED
diff --git a/experimental/skottie/SkottieAnimator.cpp b/experimental/skottie/SkottieAnimator.cpp
index e189ebc..5f8d0db 100644
--- a/experimental/skottie/SkottieAnimator.cpp
+++ b/experimental/skottie/SkottieAnimator.cpp
@@ -9,7 +9,7 @@
 
 #include "SkCubicMap.h"
 #include "SkJSONCPP.h"
-#include "SkottieProperties.h"
+#include "SkottieValue.h"
 #include "SkottieParser.h"
 #include "SkTArray.h"
 
diff --git a/experimental/skottie/SkottieProperties.cpp b/experimental/skottie/SkottieProperties.cpp
deleted file mode 100644
index a774217..0000000
--- a/experimental/skottie/SkottieProperties.cpp
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright 2017 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkottieProperties.h"
-
-#include "SkColor.h"
-#include "SkJSONCPP.h"
-#include "SkPath.h"
-#include "SkSGColor.h"
-#include "SkSGGradient.h"
-#include "SkSGPath.h"
-#include "SkSGRect.h"
-#include "SkSGTransform.h"
-#include "SkSGTrimEffect.h"
-
-#include <cmath>
-
-namespace  skottie {
-
-namespace {
-
-SkColor VecToColor(const float* v, size_t size) {
-    // best effort to turn this into a color
-    const auto r = size > 0 ? v[0] : 0,
-               g = size > 1 ? v[1] : 0,
-               b = size > 2 ? v[2] : 0,
-               a = size > 3 ? v[3] : 1;
-
-    return SkColorSetARGB(SkTPin<SkScalar>(a, 0, 1) * 255,
-                          SkTPin<SkScalar>(r, 0, 1) * 255,
-                          SkTPin<SkScalar>(g, 0, 1) * 255,
-                          SkTPin<SkScalar>(b, 0, 1) * 255);
-}
-
-} // namespace
-
-template <>
-size_t ValueTraits<ScalarValue>::Cardinality(const ScalarValue&) {
-    return 1;
-}
-
-template <>
-template <>
-SkScalar ValueTraits<ScalarValue>::As<SkScalar>(const ScalarValue& v) {
-    return v;
-}
-
-template <>
-size_t ValueTraits<VectorValue>::Cardinality(const VectorValue& vec) {
-    return vec.size();
-}
-
-template <>
-template <>
-SkColor ValueTraits<VectorValue>::As<SkColor>(const VectorValue& vec) {
-    return VecToColor(vec.data(), vec.size());
-}
-
-template <>
-template <>
-SkPoint ValueTraits<VectorValue>::As<SkPoint>(const VectorValue& vec) {
-    // best effort to turn this into a point
-    const auto x = vec.size() > 0 ? vec[0] : 0,
-               y = vec.size() > 1 ? vec[1] : 0;
-    return SkPoint::Make(x, y);
-}
-
-template <>
-template <>
-SkSize ValueTraits<VectorValue>::As<SkSize>(const VectorValue& vec) {
-    const auto pt = ValueTraits::As<SkPoint>(vec);
-    return SkSize::Make(pt.x(), pt.y());
-}
-
-template <>
-size_t ValueTraits<ShapeValue>::Cardinality(const ShapeValue& path) {
-    return SkTo<size_t>(path.countVerbs());
-}
-
-template <>
-template <>
-SkPath ValueTraits<ShapeValue>::As<SkPath>(const ShapeValue& path) {
-    return path;
-}
-
-CompositeRRect::CompositeRRect(sk_sp<sksg::RRect> wrapped_node)
-    : fRRectNode(std::move(wrapped_node)) {}
-
-void CompositeRRect::apply() {
-    // BM "position" == "center position"
-    auto rr = SkRRect::MakeRectXY(SkRect::MakeXYWH(fPosition.x() - fSize.width() / 2,
-                                                   fPosition.y() - fSize.height() / 2,
-                                                   fSize.width(), fSize.height()),
-                                  fRadius.width(),
-                                  fRadius.height());
-   fRRectNode->setRRect(rr);
-}
-
-CompositeTransform::CompositeTransform(sk_sp<sksg::Matrix> matrix)
-    : fMatrixNode(std::move(matrix)) {}
-
-void CompositeTransform::apply() {
-    SkMatrix t = SkMatrix::MakeTrans(-fAnchorPoint.x(), -fAnchorPoint.y());
-
-    t.postScale(fScale.x() / 100, fScale.y() / 100); // 100% based
-    t.postRotate(fRotation);
-    t.postTranslate(fPosition.x(), fPosition.y());
-    // TODO: skew
-
-    fMatrixNode->setMatrix(t);
-}
-
-CompositePolyStar::CompositePolyStar(sk_sp<sksg::Path> wrapped_node, Type t)
-    : fPathNode(std::move(wrapped_node))
-    , fType(t) {}
-
-void CompositePolyStar::apply() {
-    const auto count = SkScalarTruncToInt(fPointCount);
-    const auto arc   = SK_ScalarPI * 2 / count;
-
-    const auto pt_on_circle = [](const SkPoint& c, SkScalar r, SkScalar a) {
-        return SkPoint::Make(c.x() + r * std::cos(a),
-                             c.y() + r * std::sin(a));
-    };
-
-    // TODO: inner/outer "roundness"?
-
-    SkPath poly;
-
-    auto angle = SkDegreesToRadians(fRotation);
-    poly.moveTo(pt_on_circle(fPosition, fOuterRadius, angle));
-
-    for (int i = 0; i < count; ++i) {
-        if (fType == Type::kStar) {
-            poly.lineTo(pt_on_circle(fPosition, fInnerRadius, angle + arc * 0.5f));
-        }
-        angle += arc;
-        poly.lineTo(pt_on_circle(fPosition, fOuterRadius, angle));
-    }
-
-    poly.close();
-    fPathNode->setPath(poly);
-}
-
-CompositeGradient::CompositeGradient(sk_sp<sksg::Gradient> grad, size_t stopCount)
-    : fGradient(std::move(grad))
-    , fStopCount(stopCount) {}
-
-void CompositeGradient::apply() {
-    this->onApply();
-
-    // |fColorStops| holds |fStopCount| x [ pos, r, g, g ] + ? x [ pos, alpha ]
-
-    if (fColorStops.size() < fStopCount * 4 || ((fColorStops.size() - fStopCount * 4) % 2)) {
-        SkDebugf("!! Invalid gradient stop array size: %zu", fColorStops.size());
-        return;
-    }
-
-    std::vector<sksg::Gradient::ColorStop> stops;
-
-    // TODO: merge/lerp opacity stops
-    const auto csEnd = fColorStops.cbegin() + fStopCount * 4;
-    for (auto cs = fColorStops.cbegin(); cs != csEnd; cs += 4) {
-        stops.push_back({ *cs, VecToColor(&*(cs + 1), 3) });
-    }
-
-    fGradient->setColorStops(std::move(stops));
-}
-
-CompositeLinearGradient::CompositeLinearGradient(sk_sp<sksg::LinearGradient> grad, size_t stopCount)
-    : INHERITED(std::move(grad), stopCount) {}
-
-void CompositeLinearGradient::onApply() {
-    auto* grad = static_cast<sksg::LinearGradient*>(fGradient.get());
-    grad->setStartPoint(this->startPoint());
-    grad->setEndPoint(this->endPoint());
-}
-
-CompositeRadialGradient::CompositeRadialGradient(sk_sp<sksg::RadialGradient> grad, size_t stopCount)
-    : INHERITED(std::move(grad), stopCount) {}
-
-void CompositeRadialGradient::onApply() {
-    auto* grad = static_cast<sksg::RadialGradient*>(fGradient.get());
-    grad->setStartCenter(this->startPoint());
-    grad->setEndCenter(this->startPoint());
-    grad->setStartRadius(0);
-    grad->setEndRadius(SkPoint::Distance(this->startPoint(), this->endPoint()));
-}
-
-CompositeTrimEffect::CompositeTrimEffect(sk_sp<sksg::TrimEffect> trimEffect)
-    : fTrimEffect(std::move(trimEffect)) {
-    SkASSERT(fTrimEffect);
-}
-
-void CompositeTrimEffect::apply() {
-    // BM semantics: start/end are percentages, offset is "degrees" (?!).
-    const auto  start = fStart  / 100,
-                  end = fEnd    / 100,
-               offset = fOffset / 360;
-
-    auto startT = SkTMin(start, end) + offset,
-          stopT = SkTMax(start, end) + offset;
-    auto   mode = SkTrimPathEffect::Mode::kNormal;
-
-    if (stopT - startT < 1) {
-        startT -= SkScalarFloorToScalar(startT);
-        stopT  -= SkScalarFloorToScalar(stopT);
-
-        if (startT > stopT) {
-            SkTSwap(startT, stopT);
-            mode = SkTrimPathEffect::Mode::kInverted;
-        }
-    } else {
-        startT = 0;
-        stopT  = 1;
-    }
-
-    fTrimEffect->setStart(startT);
-    fTrimEffect->setStop(stopT);
-    fTrimEffect->setMode(mode);
-}
-
-} // namespace skottie
diff --git a/experimental/skottie/SkottieProperties.h b/experimental/skottie/SkottieProperties.h
deleted file mode 100644
index 5e3fad0..0000000
--- a/experimental/skottie/SkottieProperties.h
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright 2017 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkottieProperties_DEFINED
-#define SkottieProperties_DEFINED
-
-#include "SkColor.h"
-#include "SkPath.h"
-#include "SkPoint.h"
-#include "SkSize.h"
-#include "SkRefCnt.h"
-#include "SkTArray.h"
-#include "SkTypes.h"
-
-#include <memory>
-#include <vector>
-
-namespace sksg {
-class Color;
-class Gradient;
-class LinearGradient;
-class Matrix;
-class Path;
-class RadialGradient;
-class RRect;
-class RenderNode;;
-class TrimEffect;
-}
-
-namespace Json { class Value; }
-
-namespace  skottie {
-
-template <typename T>
-struct ValueTraits {
-    static size_t Cardinality(const T&);
-
-    template <typename U>
-    static U As(const T&);
-};
-
-using ScalarValue = SkScalar;
-using VectorValue = std::vector<ScalarValue>;
-using ShapeValue  = SkPath;
-
-// Composite properties.
-
-#define COMPOSITE_PROPERTY(p_name, p_type, p_default) \
-    void set##p_name(const p_type& p) {               \
-        if (p == f##p_name) return;                   \
-        f##p_name = p;                                \
-        this->apply();                                \
-    }                                                 \
-  private:                                            \
-    p_type f##p_name = p_default;                     \
-  public:
-
-class CompositeRRect final : public SkRefCnt {
-public:
-    explicit CompositeRRect(sk_sp<sksg::RRect>);
-
-    COMPOSITE_PROPERTY(Position, SkPoint , SkPoint::Make(0, 0))
-    COMPOSITE_PROPERTY(Size    , SkSize  , SkSize::Make(0, 0))
-    COMPOSITE_PROPERTY(Radius  , SkSize  , SkSize::Make(0, 0))
-
-private:
-    void apply();
-
-    sk_sp<sksg::RRect> fRRectNode;
-
-    using INHERITED = SkRefCnt;
-};
-
-class CompositePolyStar final : public SkRefCnt {
-public:
-    enum class Type {
-        kStar, kPoly,
-    };
-
-    CompositePolyStar(sk_sp<sksg::Path>, Type);
-
-    COMPOSITE_PROPERTY(Position      , SkPoint , SkPoint::Make(0, 0))
-    COMPOSITE_PROPERTY(PointCount    , SkScalar, 0)
-    COMPOSITE_PROPERTY(InnerRadius   , SkScalar, 0)
-    COMPOSITE_PROPERTY(OuterRadius   , SkScalar, 0)
-    COMPOSITE_PROPERTY(InnerRoundness, SkScalar, 0)
-    COMPOSITE_PROPERTY(OuterRoundness, SkScalar, 0)
-    COMPOSITE_PROPERTY(Rotation      , SkScalar, 0)
-
-private:
-    void apply();
-
-    sk_sp<sksg::Path> fPathNode;
-    Type              fType;
-
-    using INHERITED = SkRefCnt;
-};
-
-class CompositeTransform final : public SkRefCnt {
-public:
-    explicit CompositeTransform(sk_sp<sksg::Matrix>);
-
-    COMPOSITE_PROPERTY(AnchorPoint, SkPoint , SkPoint::Make(0, 0))
-    COMPOSITE_PROPERTY(Position   , SkPoint , SkPoint::Make(0, 0))
-    COMPOSITE_PROPERTY(Scale      , SkVector, SkPoint::Make(100, 100))
-    COMPOSITE_PROPERTY(Rotation   , SkScalar, 0)
-    COMPOSITE_PROPERTY(Skew       , SkScalar, 0)
-    COMPOSITE_PROPERTY(SkewAxis   , SkScalar, 0)
-
-private:
-    void apply();
-
-    sk_sp<sksg::Matrix> fMatrixNode;
-
-    using INHERITED = SkRefCnt;
-};
-
-class CompositeGradient : public SkRefCnt {
-public:
-    COMPOSITE_PROPERTY(StartPoint, SkPoint              , SkPoint::Make(0, 0)    )
-    COMPOSITE_PROPERTY(EndPoint  , SkPoint              , SkPoint::Make(0, 0)    )
-    COMPOSITE_PROPERTY(ColorStops, std::vector<SkScalar>, std::vector<SkScalar>())
-
-protected:
-    CompositeGradient(sk_sp<sksg::Gradient>, size_t stopCount);
-
-    const SkPoint& startPoint() const { return fStartPoint; }
-    const SkPoint& endPoint()   const { return fEndPoint;   }
-
-    sk_sp<sksg::Gradient> fGradient;
-    size_t                fStopCount;
-
-    virtual void onApply() = 0;
-
-private:
-    void apply();
-
-    using INHERITED = SkRefCnt;
-};
-
-class CompositeLinearGradient final : public CompositeGradient {
-public:
-    CompositeLinearGradient(sk_sp<sksg::LinearGradient>, size_t stopCount);
-
-private:
-    void onApply() override;
-
-    using INHERITED = CompositeGradient;
-};
-
-class CompositeRadialGradient final : public CompositeGradient {
-public:
-    CompositeRadialGradient(sk_sp<sksg::RadialGradient>, size_t stopCount);
-
-private:
-    void onApply() override;
-
-    using INHERITED = CompositeGradient;
-};
-
-class CompositeTrimEffect final : public SkRefCnt {
-public:
-    explicit CompositeTrimEffect(sk_sp<sksg::TrimEffect>);
-
-    COMPOSITE_PROPERTY(Start , SkScalar,   0)
-    COMPOSITE_PROPERTY(End   , SkScalar, 100)
-    COMPOSITE_PROPERTY(Offset, SkScalar,   0)
-
-private:
-    void apply();
-
-    sk_sp<sksg::TrimEffect> fTrimEffect;
-
-    using INHERITED = SkRefCnt;
-};
-
-#undef COMPOSITE_PROPERTY
-
-} // namespace skottie
-
-#endif // SkottieProperties_DEFINED
diff --git a/experimental/skottie/SkottieValue.cpp b/experimental/skottie/SkottieValue.cpp
new file mode 100644
index 0000000..386c8ab
--- /dev/null
+++ b/experimental/skottie/SkottieValue.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkottieValue.h"
+
+#include "SkColor.h"
+#include "SkPoint.h"
+#include "SkSize.h"
+
+namespace  skottie {
+
+template <>
+size_t ValueTraits<ScalarValue>::Cardinality(const ScalarValue&) {
+    return 1;
+}
+
+template <>
+template <>
+SkScalar ValueTraits<ScalarValue>::As<SkScalar>(const ScalarValue& v) {
+    return v;
+}
+
+template <>
+size_t ValueTraits<VectorValue>::Cardinality(const VectorValue& vec) {
+    return vec.size();
+}
+
+template <>
+template <>
+SkColor ValueTraits<VectorValue>::As<SkColor>(const VectorValue& v) {
+    // best effort to turn this into a color
+    const auto r = v.size() > 0 ? v[0] : 0,
+               g = v.size() > 1 ? v[1] : 0,
+               b = v.size() > 2 ? v[2] : 0,
+               a = v.size() > 3 ? v[3] : 1;
+
+    return SkColorSetARGB(SkTPin<SkScalar>(a, 0, 1) * 255,
+                          SkTPin<SkScalar>(r, 0, 1) * 255,
+                          SkTPin<SkScalar>(g, 0, 1) * 255,
+                          SkTPin<SkScalar>(b, 0, 1) * 255);
+}
+
+template <>
+template <>
+SkPoint ValueTraits<VectorValue>::As<SkPoint>(const VectorValue& vec) {
+    // best effort to turn this into a point
+    const auto x = vec.size() > 0 ? vec[0] : 0,
+               y = vec.size() > 1 ? vec[1] : 0;
+    return SkPoint::Make(x, y);
+}
+
+template <>
+template <>
+SkSize ValueTraits<VectorValue>::As<SkSize>(const VectorValue& vec) {
+    const auto pt = ValueTraits::As<SkPoint>(vec);
+    return SkSize::Make(pt.x(), pt.y());
+}
+
+template <>
+size_t ValueTraits<ShapeValue>::Cardinality(const ShapeValue& path) {
+    return SkTo<size_t>(path.countVerbs());
+}
+
+template <>
+template <>
+SkPath ValueTraits<ShapeValue>::As<SkPath>(const ShapeValue& path) {
+    return path;
+}
+
+} // namespace skottie
diff --git a/experimental/skottie/SkottieValue.h b/experimental/skottie/SkottieValue.h
new file mode 100644
index 0000000..6d6d94a
--- /dev/null
+++ b/experimental/skottie/SkottieValue.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkottieValue_DEFINED
+#define SkottieValue_DEFINED
+
+#include "SkPath.h"
+#include "SkScalar.h"
+
+#include <vector>
+
+namespace  skottie {
+
+template <typename T>
+struct ValueTraits {
+    static size_t Cardinality(const T&);
+
+    template <typename U>
+    static U As(const T&);
+};
+
+using ScalarValue = SkScalar;
+using VectorValue = std::vector<ScalarValue>;
+using ShapeValue  = SkPath;
+
+} // namespace skottie
+
+#endif // SkottieValue_DEFINED