aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorFlorin Malita <fmalita@chromium.org>2018-08-25 20:22:34 -0400
committerSkia Commit-Bot <skia-commit-bot@chromium.org>2018-08-26 00:39:48 +0000
commit471a946cf126632d3c75470c6a06ccde5cb0a5bc (patch)
tree6cb0fa61056cd1d7436452334a57e731efae2703 /modules
parent3054989426549ba1dac83d3b84bf28d118edf75d (diff)
downloadskqp-471a946cf126632d3c75470c6a06ccde5cb0a5bc.tar.gz
[skottie] Make AnimationBuilder available for value parsing
Plumb AnimationBuilder throught a bazillion layers to make it reachable when parsing animatable values. This is in preparation of keyframed text, which will require access to the font set when parsing. Refactor only, no functional changes. TBR= Change-Id: Ide2ef2ba66fbcc75fdcc785f987b364d45dff5b6 Reviewed-on: https://skia-review.googlesource.com/149264 Commit-Queue: Florin Malita <fmalita@chromium.org> Reviewed-by: Florin Malita <fmalita@chromium.org>
Diffstat (limited to 'modules')
-rw-r--r--modules/skottie/skottie.gni1
-rw-r--r--modules/skottie/src/Skottie.cpp37
-rw-r--r--modules/skottie/src/SkottieAnimator.cpp65
-rw-r--r--modules/skottie/src/SkottieAnimator.h39
-rw-r--r--modules/skottie/src/SkottieJson.cpp59
-rw-r--r--modules/skottie/src/SkottieLayer.cpp49
-rw-r--r--modules/skottie/src/SkottieLayerEffect.cpp7
-rw-r--r--modules/skottie/src/SkottiePrecompLayer.cpp5
-rw-r--r--modules/skottie/src/SkottiePriv.h61
-rw-r--r--modules/skottie/src/SkottieShapeLayer.cpp156
-rw-r--r--modules/skottie/src/SkottieTextLayer.cpp2
-rw-r--r--modules/skottie/src/SkottieValue.cpp75
-rw-r--r--modules/skottie/src/SkottieValue.h9
13 files changed, 301 insertions, 264 deletions
diff --git a/modules/skottie/skottie.gni b/modules/skottie/skottie.gni
index eb85a4abe3..6d285ea207 100644
--- a/modules/skottie/skottie.gni
+++ b/modules/skottie/skottie.gni
@@ -14,7 +14,6 @@ skia_skottie_sources = [
"$_src/SkottieAdapter.cpp",
"$_src/SkottieAdapter.h",
"$_src/SkottieAnimator.cpp",
- "$_src/SkottieAnimator.h",
"$_src/SkottieJson.cpp",
"$_src/SkottieJson.h",
"$_src/SkottieLayer.cpp",
diff --git a/modules/skottie/src/Skottie.cpp b/modules/skottie/src/Skottie.cpp
index 40e94ecd6d..e7f3dda466 100644
--- a/modules/skottie/src/Skottie.cpp
+++ b/modules/skottie/src/Skottie.cpp
@@ -25,7 +25,6 @@
#include "SkTime.h"
#include "SkTo.h"
#include "SkottieAdapter.h"
-#include "SkottieAnimator.h"
#include "SkottieJson.h"
#include "SkottiePriv.h"
#include "SkottieValue.h"
@@ -43,23 +42,24 @@ void LogJSON(const skjson::Value& json, const char msg[]) {
LOG("%s: %s\n", msg, dump.c_str());
}
-sk_sp<sksg::Matrix> AttachMatrix(const skjson::ObjectValue& t, AnimatorScope* ascope,
- sk_sp<sksg::Matrix> parentMatrix) {
+sk_sp<sksg::Matrix> AnimationBuilder::attachMatrix(const skjson::ObjectValue& t,
+ AnimatorScope* ascope,
+ sk_sp<sksg::Matrix> parentMatrix) const {
static const VectorValue g_default_vec_0 = { 0, 0},
g_default_vec_100 = {100, 100};
auto matrix = sksg::Matrix::Make(SkMatrix::I(), parentMatrix);
auto adapter = sk_make_sp<TransformAdapter>(matrix);
- auto bound = BindProperty<VectorValue>(t["a"], ascope,
+ auto bound = this->bindProperty<VectorValue>(t["a"], ascope,
[adapter](const VectorValue& a) {
adapter->setAnchorPoint(ValueTraits<VectorValue>::As<SkPoint>(a));
}, g_default_vec_0);
- bound |= BindProperty<VectorValue>(t["p"], ascope,
+ bound |= this->bindProperty<VectorValue>(t["p"], ascope,
[adapter](const VectorValue& p) {
adapter->setPosition(ValueTraits<VectorValue>::As<SkPoint>(p));
}, g_default_vec_0);
- bound |= BindProperty<VectorValue>(t["s"], ascope,
+ bound |= this->bindProperty<VectorValue>(t["s"], ascope,
[adapter](const VectorValue& s) {
adapter->setScale(ValueTraits<VectorValue>::As<SkVector>(s));
}, g_default_vec_100);
@@ -70,15 +70,15 @@ sk_sp<sksg::Matrix> AttachMatrix(const skjson::ObjectValue& t, AnimatorScope* as
// we can still make use of rz.
jrotation = &t["rz"];
}
- bound |= BindProperty<ScalarValue>(*jrotation, ascope,
+ bound |= this->bindProperty<ScalarValue>(*jrotation, ascope,
[adapter](const ScalarValue& r) {
adapter->setRotation(r);
}, 0.0f);
- bound |= BindProperty<ScalarValue>(t["sk"], ascope,
+ bound |= this->bindProperty<ScalarValue>(t["sk"], ascope,
[adapter](const ScalarValue& sk) {
adapter->setSkew(sk);
}, 0.0f);
- bound |= BindProperty<ScalarValue>(t["sa"], ascope,
+ bound |= this->bindProperty<ScalarValue>(t["sa"], ascope,
[adapter](const ScalarValue& sa) {
adapter->setSkewAxis(sa);
}, 0.0f);
@@ -86,14 +86,15 @@ sk_sp<sksg::Matrix> AttachMatrix(const skjson::ObjectValue& t, AnimatorScope* as
return bound ? matrix : parentMatrix;
}
-sk_sp<sksg::RenderNode> AttachOpacity(const skjson::ObjectValue& jtransform, AnimatorScope* ascope,
- sk_sp<sksg::RenderNode> childNode) {
+sk_sp<sksg::RenderNode> AnimationBuilder::attachOpacity(const skjson::ObjectValue& jtransform,
+ AnimatorScope* ascope,
+ sk_sp<sksg::RenderNode> childNode) const {
if (!childNode)
return nullptr;
auto opacityNode = sksg::OpacityEffect::Make(childNode);
- if (!BindProperty<ScalarValue>(jtransform["o"], ascope,
+ if (!this->bindProperty<ScalarValue>(jtransform["o"], ascope,
[opacityNode](const ScalarValue& o) {
// BM opacity is [0..100]
opacityNode->setOpacity(o * 0.01f);
@@ -105,9 +106,10 @@ sk_sp<sksg::RenderNode> AttachOpacity(const skjson::ObjectValue& jtransform, Ani
return std::move(opacityNode);
}
-sk_sp<sksg::Path> AttachPath(const skjson::Value& jpath, AnimatorScope* ascope) {
+sk_sp<sksg::Path> AnimationBuilder::attachPath(const skjson::Value& jpath,
+ AnimatorScope* ascope) const {
auto path_node = sksg::Path::Make();
- return BindProperty<ShapeValue>(jpath, ascope,
+ return this->bindProperty<ShapeValue>(jpath, ascope,
[path_node](const ShapeValue& p) {
// FillType is tracked in the SG node, not in keyframes -- make sure we preserve it.
auto path = ValueTraits<ShapeValue>::As<SkPath>(p);
@@ -118,10 +120,11 @@ sk_sp<sksg::Path> AttachPath(const skjson::Value& jpath, AnimatorScope* ascope)
: nullptr;
}
-sk_sp<sksg::Color> AttachColor(const skjson::ObjectValue& jcolor, AnimatorScope* ascope,
- const char prop_name[]) {
+sk_sp<sksg::Color> AnimationBuilder::attachColor(const skjson::ObjectValue& jcolor,
+ AnimatorScope* ascope,
+ const char prop_name[]) const {
auto color_node = sksg::Color::Make(SK_ColorBLACK);
- BindProperty<VectorValue>(jcolor[prop_name], ascope,
+ this->bindProperty<VectorValue>(jcolor[prop_name], ascope,
[color_node](const VectorValue& c) {
color_node->setColor(ValueTraits<VectorValue>::As<SkColor>(c));
});
diff --git a/modules/skottie/src/SkottieAnimator.cpp b/modules/skottie/src/SkottieAnimator.cpp
index c9c43b4037..7837f3ee4e 100644
--- a/modules/skottie/src/SkottieAnimator.cpp
+++ b/modules/skottie/src/SkottieAnimator.cpp
@@ -5,11 +5,11 @@
* found in the LICENSE file.
*/
-#include "SkottieAnimator.h"
-
#include "SkCubicMap.h"
#include "SkottieJson.h"
+#include "SkottiePriv.h"
#include "SkottieValue.h"
+#include "SkSGScene.h"
#include "SkString.h"
#include "SkTArray.h"
@@ -68,9 +68,9 @@ protected:
: SkTPin(fCubicMaps[rec.cmidx].computeYFromX(lt), 0.0f, 1.0f);
}
- virtual int parseValue(const skjson::Value&) = 0;
+ virtual int parseValue(const skjson::Value&, const AnimationBuilder* abuilder) = 0;
- void parseKeyFrames(const skjson::ArrayValue& jframes) {
+ void parseKeyFrames(const skjson::ArrayValue& jframes, const AnimationBuilder* abuilder) {
for (const skjson::ObjectValue* jframe : jframes) {
if (!jframe) continue;
@@ -88,7 +88,7 @@ protected:
fRecs.back().t1 = t0;
}
- const auto vidx0 = this->parseValue((*jframe)["s"]);
+ const auto vidx0 = this->parseValue((*jframe)["s"], abuilder);
if (vidx0 < 0)
continue;
@@ -97,7 +97,7 @@ protected:
if (!ParseDefault<bool>((*jframe)["h"], false)) {
// Regular frame, requires an end value.
- vidx1 = this->parseValue((*jframe)["e"]);
+ vidx1 = this->parseValue((*jframe)["e"], abuilder);
if (vidx1 < 0)
continue;
@@ -176,10 +176,12 @@ template <typename T>
class KeyframeAnimator final : public KeyframeAnimatorBase {
public:
static std::unique_ptr<KeyframeAnimator> Make(const skjson::ArrayValue* jv,
+ const AnimationBuilder* abuilder,
std::function<void(const T&)>&& apply) {
if (!jv) return nullptr;
- std::unique_ptr<KeyframeAnimator> animator(new KeyframeAnimator(*jv, std::move(apply)));
+ std::unique_ptr<KeyframeAnimator> animator(
+ new KeyframeAnimator(*jv, abuilder, std::move(apply)));
if (!animator->count())
return nullptr;
@@ -193,14 +195,16 @@ protected:
private:
KeyframeAnimator(const skjson::ArrayValue& jframes,
+ const AnimationBuilder* abuilder,
std::function<void(const T&)>&& apply)
: fApplyFunc(std::move(apply)) {
- this->parseKeyFrames(jframes);
+ this->parseKeyFrames(jframes, abuilder);
}
- int parseValue(const skjson::Value& jv) override {
+ int parseValue(const skjson::Value& jv, const AnimationBuilder* abuilder) override {
T val;
- if (!Parse<T>(jv, &val) || (!fVs.empty() && !ValueTraits<T>::CanLerp(val, fVs.back()))) {
+ if (!ValueTraits<T>::FromJSON(jv, abuilder, &val) ||
+ (!fVs.empty() && !ValueTraits<T>::CanLerp(val, fVs.back()))) {
return -1;
}
@@ -241,7 +245,8 @@ private:
template <typename T>
static inline bool BindPropertyImpl(const skjson::ObjectValue* jprop,
- sksg::AnimatorList* animators,
+ const AnimationBuilder* abuilder,
+ AnimatorScope* ascope,
std::function<void(const T&)>&& apply,
const T* noop = nullptr) {
if (!jprop) return false;
@@ -257,7 +262,7 @@ static inline bool BindPropertyImpl(const skjson::ObjectValue* jprop,
// For those, we attempt to parse both ways.
if (!ParseDefault<bool>(jpropA, false)) {
T val;
- if (Parse<T>(jpropK, &val)) {
+ if (ValueTraits<T>::FromJSON(jpropK, abuilder, &val)) {
// Static property.
if (noop && val == *noop)
return false;
@@ -272,13 +277,13 @@ static inline bool BindPropertyImpl(const skjson::ObjectValue* jprop,
}
// Keyframe property.
- auto animator = KeyframeAnimator<T>::Make(jpropK, std::move(apply));
+ auto animator = KeyframeAnimator<T>::Make(jpropK, abuilder, std::move(apply));
if (!animator) {
return LogFail(*jprop, "Could not parse keyframed property");
}
- animators->push_back(std::move(animator));
+ ascope->push_back(std::move(animator));
return true;
}
@@ -286,6 +291,7 @@ static inline bool BindPropertyImpl(const skjson::ObjectValue* jprop,
class SplitPointAnimator final : public sksg::Animator {
public:
static std::unique_ptr<SplitPointAnimator> Make(const skjson::ObjectValue* jprop,
+ const AnimationBuilder* abuilder,
std::function<void(const VectorValue&)>&& apply,
const VectorValue*) {
if (!jprop) return nullptr;
@@ -297,9 +303,9 @@ public:
// the object itself, so the scope is bound to the life time of the object.
auto* split_animator_ptr = split_animator.get();
- if (!BindPropertyImpl<ScalarValue>((*jprop)["x"], &split_animator->fAnimators,
+ if (!BindPropertyImpl<ScalarValue>((*jprop)["x"], abuilder, &split_animator->fAnimators,
[split_animator_ptr](const ScalarValue& x) { split_animator_ptr->setX(x); }) ||
- !BindPropertyImpl<ScalarValue>((*jprop)["y"], &split_animator->fAnimators,
+ !BindPropertyImpl<ScalarValue>((*jprop)["y"], abuilder, &split_animator->fAnimators,
[split_animator_ptr](const ScalarValue& y) { split_animator_ptr->setY(y); })) {
LogFail(*jprop, "Could not parse split property");
return nullptr;
@@ -340,11 +346,12 @@ private:
};
bool BindSplitPositionProperty(const skjson::Value& jv,
- sksg::AnimatorList* animators,
+ const AnimationBuilder* abuilder,
+ AnimatorScope* ascope,
std::function<void(const VectorValue&)>&& apply,
const VectorValue* noop) {
- if (auto split_animator = SplitPointAnimator::Make(jv, std::move(apply), noop)) {
- animators->push_back(std::unique_ptr<sksg::Animator>(split_animator.release()));
+ if (auto split_animator = SplitPointAnimator::Make(jv, abuilder, std::move(apply), noop)) {
+ ascope->push_back(std::unique_ptr<sksg::Animator>(split_animator.release()));
return true;
}
@@ -354,32 +361,32 @@ bool BindSplitPositionProperty(const skjson::Value& jv,
} // namespace
template <>
-bool BindProperty(const skjson::Value& jv,
+bool AnimationBuilder::bindProperty(const skjson::Value& jv,
AnimatorScope* ascope,
std::function<void(const ScalarValue&)>&& apply,
- const ScalarValue* noop) {
- return BindPropertyImpl(jv, ascope, std::move(apply), noop);
+ const ScalarValue* noop) const {
+ return BindPropertyImpl(jv, this, ascope, std::move(apply), noop);
}
template <>
-bool BindProperty(const skjson::Value& jv,
+bool AnimationBuilder::bindProperty(const skjson::Value& jv,
AnimatorScope* ascope,
std::function<void(const VectorValue&)>&& apply,
- const VectorValue* noop) {
+ const VectorValue* noop) const {
if (!jv.is<skjson::ObjectValue>())
return false;
return ParseDefault<bool>(jv.as<skjson::ObjectValue>()["s"], false)
- ? BindSplitPositionProperty(jv, ascope, std::move(apply), noop)
- : BindPropertyImpl(jv, ascope, std::move(apply), noop);
+ ? BindSplitPositionProperty(jv, this, ascope, std::move(apply), noop)
+ : BindPropertyImpl(jv, this, ascope, std::move(apply), noop);
}
template <>
-bool BindProperty(const skjson::Value& jv,
+bool AnimationBuilder::bindProperty(const skjson::Value& jv,
AnimatorScope* ascope,
std::function<void(const ShapeValue&)>&& apply,
- const ShapeValue* noop) {
- return BindPropertyImpl(jv, ascope, std::move(apply), noop);
+ const ShapeValue* noop) const {
+ return BindPropertyImpl(jv, this, ascope, std::move(apply), noop);
}
} // namespace internal
diff --git a/modules/skottie/src/SkottieAnimator.h b/modules/skottie/src/SkottieAnimator.h
deleted file mode 100644
index 33abf1c03c..0000000000
--- a/modules/skottie/src/SkottieAnimator.h
+++ /dev/null
@@ -1,39 +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 SkottieAnimator_DEFINED
-#define SkottieAnimator_DEFINED
-
-#include "SkottiePriv.h"
-
-#include <functional>
-
-namespace skjson { class Value; }
-
-namespace skottie {
-namespace internal {
-
-// This is the workhorse for property binding: depending on whether the property is animated,
-// it will either apply immediately or instantiate and attach a keyframe animator.
-template <typename T>
-bool BindProperty(const skjson::Value&,
- AnimatorScope*,
- std::function<void(const T&)>&&,
- const T* default_igore = nullptr);
-
-template <typename T>
-bool BindProperty(const skjson::Value& jv,
- AnimatorScope* animators,
- std::function<void(const T&)>&& apply,
- const T& default_ignore) {
- return BindProperty(jv, animators, std::move(apply), &default_ignore);
-}
-
-} // namespace internal
-} // namespace skottie
-
-#endif // SkottieAnimator_DEFINED
diff --git a/modules/skottie/src/SkottieJson.cpp b/modules/skottie/src/SkottieJson.cpp
index 568f4df560..7f1c3b60c2 100644
--- a/modules/skottie/src/SkottieJson.cpp
+++ b/modules/skottie/src/SkottieJson.cpp
@@ -110,63 +110,4 @@ bool Parse<std::vector<float>>(const Value& v, std::vector<float>* vec) {
return true;
}
-namespace {
-
-bool ParsePointVec(const Value& v, std::vector<SkPoint>* pts) {
- if (!v.is<ArrayValue>())
- return false;
- const auto& av = v.as<ArrayValue>();
-
- pts->clear();
- pts->reserve(av.size());
-
- std::vector<float> vec;
- for (size_t i = 0; i < av.size(); ++i) {
- if (!Parse(av[i], &vec) || vec.size() != 2)
- return false;
- pts->push_back(SkPoint::Make(vec[0], vec[1]));
- }
-
- return true;
-}
-
-} // namespace
-
-template <>
-bool Parse<ShapeValue>(const Value& v, ShapeValue* sh) {
- SkASSERT(sh->fVertices.empty());
-
- // Some versions wrap values as single-element arrays.
- if (const skjson::ArrayValue* av = v) {
- if (av->size() == 1) {
- return Parse((*av)[0], sh);
- }
- }
-
- if (!v.is<skjson::ObjectValue>())
- return false;
- const auto& ov = v.as<ObjectValue>();
-
- std::vector<SkPoint> inPts, // Cubic Bezier "in" control points, relative to vertices.
- outPts, // Cubic Bezier "out" control points, relative to vertices.
- verts; // Cubic Bezier vertices.
-
- if (!ParsePointVec(ov["i"], &inPts) ||
- !ParsePointVec(ov["o"], &outPts) ||
- !ParsePointVec(ov["v"], &verts) ||
- inPts.size() != outPts.size() ||
- inPts.size() != verts.size()) {
-
- return false;
- }
-
- sh->fVertices.reserve(inPts.size());
- for (size_t i = 0; i < inPts.size(); ++i) {
- sh->fVertices.push_back(BezierVertex({inPts[i], outPts[i], verts[i]}));
- }
- sh->fClosed = ParseDefault<bool>(ov["c"], false);
-
- return true;
-}
-
} // namespace skottie
diff --git a/modules/skottie/src/SkottieLayer.cpp b/modules/skottie/src/SkottieLayer.cpp
index 1b00ffd6de..83cfc9fa71 100644
--- a/modules/skottie/src/SkottieLayer.cpp
+++ b/modules/skottie/src/SkottieLayer.cpp
@@ -12,7 +12,6 @@
#include "SkImage.h"
#include "SkJSON.h"
#include "SkMakeUnique.h"
-#include "SkottieAnimator.h"
#include "SkottieJson.h"
#include "SkottieValue.h"
#include "SkParse.h"
@@ -65,6 +64,7 @@ const MaskInfo* GetMaskInfo(char mode) {
}
sk_sp<sksg::RenderNode> AttachMask(const skjson::ArrayValue* jmask,
+ const AnimationBuilder* abuilder,
AnimatorScope* ascope,
sk_sp<sksg::RenderNode> childNode) {
if (!jmask) return childNode;
@@ -100,7 +100,7 @@ sk_sp<sksg::RenderNode> AttachMask(const skjson::ArrayValue* jmask,
continue;
}
- auto mask_path = AttachPath((*m)["pt"], ascope);
+ auto mask_path = abuilder->attachPath((*m)["pt"], ascope);
if (!mask_path) {
LogJSON(*m, "!! Could not parse mask path");
continue;
@@ -118,7 +118,7 @@ sk_sp<sksg::RenderNode> AttachMask(const skjson::ArrayValue* jmask,
mask_paint->setBlendMode(mask_stack.empty() ? SkBlendMode::kSrc
: mask_info->fBlendMode);
- has_opacity |= BindProperty<ScalarValue>((*m)["o"], ascope,
+ has_opacity |= abuilder->bindProperty<ScalarValue>((*m)["o"], ascope,
[mask_paint](const ScalarValue& o) {
mask_paint->setOpacity(o * 0.01f);
}, 100.0f);
@@ -164,7 +164,7 @@ sk_sp<sksg::RenderNode> AttachMask(const skjson::ArrayValue* jmask,
} // namespace
sk_sp<sksg::RenderNode> AnimationBuilder::attachNestedAnimation(const char* name,
- AnimatorScope* ascope) {
+ AnimatorScope* ascope) const {
class SkottieSGAdapter final : public sksg::RenderNode {
public:
explicit SkottieSGAdapter(sk_sp<Animation> animation)
@@ -230,7 +230,7 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachNestedAnimation(const char* name
sk_sp<sksg::RenderNode> AnimationBuilder::attachAssetRef(
const skjson::ObjectValue& jlayer, AnimatorScope* ascope,
sk_sp<sksg::RenderNode>(AnimationBuilder::* attach_proc)(const skjson::ObjectValue& comp,
- AnimatorScope* ascope)) {
+ AnimatorScope* ascope) const) const {
const auto refId = ParseDefault<SkString>(jlayer["refId"], SkString());
if (refId.isEmpty()) {
@@ -261,7 +261,7 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachAssetRef(
}
sk_sp<sksg::RenderNode> AnimationBuilder::attachSolidLayer(const skjson::ObjectValue& jlayer,
- AnimatorScope*) {
+ AnimatorScope*) const {
const auto size = SkSize::Make(ParseDefault<float>(jlayer["sw"], 0.0f),
ParseDefault<float>(jlayer["sh"], 0.0f));
const skjson::StringValue* hex_str = jlayer["sc"];
@@ -281,7 +281,7 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachSolidLayer(const skjson::ObjectV
}
sk_sp<sksg::RenderNode> AnimationBuilder::attachImageAsset(const skjson::ObjectValue& jimage,
- AnimatorScope*) {
+ AnimatorScope*) const {
const skjson::StringValue* name = jimage["p"];
const skjson::StringValue* path = jimage["u"];
if (!name) {
@@ -306,12 +306,12 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachImageAsset(const skjson::ObjectV
}
sk_sp<sksg::RenderNode> AnimationBuilder::attachImageLayer(const skjson::ObjectValue& jlayer,
- AnimatorScope* ascope) {
+ AnimatorScope* ascope) const {
return this->attachAssetRef(jlayer, ascope, &AnimationBuilder::attachImageAsset);
}
sk_sp<sksg::RenderNode> AnimationBuilder::attachNullLayer(const skjson::ObjectValue& layer,
- AnimatorScope*) {
+ AnimatorScope*) const {
// Null layers are used solely to drive dependent transforms,
// but we use free-floating sksg::Matrices for that purpose.
return nullptr;
@@ -326,7 +326,8 @@ struct AnimationBuilder::AttachLayerContext {
SkTHashMap<int, sk_sp<sksg::Matrix>> fLayerMatrixMap;
sk_sp<sksg::RenderNode> fCurrentMatte;
- sk_sp<sksg::Matrix> AttachLayerMatrix(const skjson::ObjectValue& jlayer) {
+ sk_sp<sksg::Matrix> AttachLayerMatrix(const skjson::ObjectValue& jlayer,
+ const AnimationBuilder* abuilder) {
const auto layer_index = ParseDefault<int>(jlayer["ind"], -1);
if (layer_index < 0)
return nullptr;
@@ -334,11 +335,12 @@ struct AnimationBuilder::AttachLayerContext {
if (auto* m = fLayerMatrixMap.find(layer_index))
return *m;
- return this->AttachLayerMatrixImpl(jlayer, layer_index);
+ return this->AttachLayerMatrixImpl(jlayer, abuilder, layer_index);
}
private:
sk_sp<sksg::Matrix> AttachParentLayerMatrix(const skjson::ObjectValue& jlayer,
+ const AnimationBuilder* abuilder,
int layer_index) {
const auto parent_index = ParseDefault<int>(jlayer["parent"], -1);
if (parent_index < 0 || parent_index == layer_index)
@@ -351,24 +353,27 @@ private:
if (!l) continue;
if (ParseDefault<int>((*l)["ind"], -1) == parent_index) {
- return this->AttachLayerMatrixImpl(*l, parent_index);
+ return this->AttachLayerMatrixImpl(*l, abuilder, parent_index);
}
}
return nullptr;
}
- sk_sp<sksg::Matrix> AttachLayerMatrixImpl(const skjson::ObjectValue& jlayer, int layer_index) {
+ sk_sp<sksg::Matrix> AttachLayerMatrixImpl(const skjson::ObjectValue& jlayer,
+ const AnimationBuilder* abuilder,
+ int layer_index) {
SkASSERT(!fLayerMatrixMap.find(layer_index));
// Add a stub entry to break recursion cycles.
fLayerMatrixMap.set(layer_index, nullptr);
- auto parent_matrix = this->AttachParentLayerMatrix(jlayer, layer_index);
+ auto parent_matrix = this->AttachParentLayerMatrix(jlayer, abuilder, layer_index);
if (const skjson::ObjectValue* jtransform = jlayer["ks"]) {
- return *fLayerMatrixMap.set(layer_index, AttachMatrix(*jtransform, fScope,
- std::move(parent_matrix)));
+ return *fLayerMatrixMap.set(layer_index,
+ abuilder->attachMatrix(*jtransform, fScope,
+ std::move(parent_matrix)));
}
return nullptr;
@@ -376,11 +381,11 @@ private:
};
sk_sp<sksg::RenderNode> AnimationBuilder::attachLayer(const skjson::ObjectValue* jlayer,
- AttachLayerContext* layerCtx) {
+ AttachLayerContext* layerCtx) const {
if (!jlayer) return nullptr;
using LayerAttacher = sk_sp<sksg::RenderNode> (AnimationBuilder::*)(const skjson::ObjectValue&,
- AnimatorScope*);
+ AnimatorScope*) const;
static constexpr LayerAttacher gLayerAttachers[] = {
&AnimationBuilder::attachPrecompLayer, // 'ty': 0
&AnimationBuilder::attachSolidLayer, // 'ty': 1
@@ -409,17 +414,17 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachLayer(const skjson::ObjectValue*
}
// Optional layer mask.
- layer = AttachMask((*jlayer)["masksProperties"], &layer_animators, std::move(layer));
+ layer = AttachMask((*jlayer)["masksProperties"], this, &layer_animators, std::move(layer));
// Optional layer transform.
- if (auto layerMatrix = layerCtx->AttachLayerMatrix(*jlayer)) {
+ if (auto layerMatrix = layerCtx->AttachLayerMatrix(*jlayer, this)) {
layer = sksg::Transform::Make(std::move(layer), std::move(layerMatrix));
}
// Optional layer opacity.
// TODO: de-dupe this "ks" lookup with matrix above.
if (const skjson::ObjectValue* jtransform = (*jlayer)["ks"]) {
- layer = AttachOpacity(*jtransform, &layer_animators, std::move(layer));
+ layer = this->attachOpacity(*jtransform, &layer_animators, std::move(layer));
}
// Optional layer effects.
@@ -492,7 +497,7 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachLayer(const skjson::ObjectValue*
}
sk_sp<sksg::RenderNode> AnimationBuilder::attachComposition(const skjson::ObjectValue& comp,
- AnimatorScope* scope) {
+ AnimatorScope* scope) const {
const skjson::ArrayValue* jlayers = comp["layers"];
if (!jlayers) return nullptr;
diff --git a/modules/skottie/src/SkottieLayerEffect.cpp b/modules/skottie/src/SkottieLayerEffect.cpp
index f3e9331ba6..f2743a31bc 100644
--- a/modules/skottie/src/SkottieLayerEffect.cpp
+++ b/modules/skottie/src/SkottieLayerEffect.cpp
@@ -18,6 +18,7 @@ namespace internal {
namespace {
sk_sp<sksg::RenderNode> AttachFillLayerEffect(const skjson::ArrayValue* jeffect_props,
+ const AnimationBuilder* abuilder,
AnimatorScope* ascope,
sk_sp<sksg::RenderNode> layer) {
if (!jeffect_props) return layer;
@@ -29,7 +30,7 @@ sk_sp<sksg::RenderNode> AttachFillLayerEffect(const skjson::ArrayValue* jeffect_
switch (const auto ty = ParseDefault<int>((*jprop)["ty"], -1)) {
case 2: // color
- color_node = AttachColor(*jprop, ascope, "v");
+ color_node = abuilder->attachColor(*jprop, ascope, "v");
break;
default:
LOG("?? Ignoring unsupported fill effect poperty type: %d\n", ty);
@@ -46,13 +47,13 @@ sk_sp<sksg::RenderNode> AttachFillLayerEffect(const skjson::ArrayValue* jeffect_
sk_sp<sksg::RenderNode> AnimationBuilder::attachLayerEffects(const skjson::ArrayValue& jeffects,
AnimatorScope* ascope,
- sk_sp<sksg::RenderNode> layer) {
+ sk_sp<sksg::RenderNode> layer) const {
for (const skjson::ObjectValue* jeffect : jeffects) {
if (!jeffect) continue;
switch (const auto ty = ParseDefault<int>((*jeffect)["ty"], -1)) {
case 21: // Fill
- layer = AttachFillLayerEffect((*jeffect)["ef"], ascope, std::move(layer));
+ layer = AttachFillLayerEffect((*jeffect)["ef"], this, ascope, std::move(layer));
break;
default:
LOG("?? Unsupported layer effect type: %d\n", ty);
diff --git a/modules/skottie/src/SkottiePrecompLayer.cpp b/modules/skottie/src/SkottiePrecompLayer.cpp
index 22668252fd..8fc4167d81 100644
--- a/modules/skottie/src/SkottiePrecompLayer.cpp
+++ b/modules/skottie/src/SkottiePrecompLayer.cpp
@@ -8,7 +8,6 @@
#include "SkottiePriv.h"
#include "SkJSON.h"
-#include "SkottieAnimator.h"
#include "SkottieJson.h"
#include "SkottieValue.h"
#include "SkMakeUnique.h"
@@ -20,7 +19,7 @@ namespace skottie {
namespace internal {
sk_sp<sksg::RenderNode> AnimationBuilder::attachPrecompLayer(const skjson::ObjectValue& jlayer,
- AnimatorScope* ascope) {
+ AnimatorScope* ascope) const {
const skjson::ObjectValue* time_remap = jlayer["tm"];
const auto start_time = ParseDefault<float>(jlayer["st"], 0.0f),
stretch_time = ParseDefault<float>(jlayer["sr"], 1.0f);
@@ -70,7 +69,7 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachPrecompLayer(const skjson::Objec
// because both the lambda and the mapper are scoped/owned by ctx->fAnimators.
auto* raw_mapper = time_mapper.get();
auto frame_rate = fFrameRate;
- BindProperty<ScalarValue>(*time_remap, ascope,
+ this->bindProperty<ScalarValue>(*time_remap, ascope,
[raw_mapper, frame_rate](const ScalarValue& t) {
raw_mapper->remapTime(t * frame_rate);
});
diff --git a/modules/skottie/src/SkottiePriv.h b/modules/skottie/src/SkottiePriv.h
index 37332f6532..355102939d 100644
--- a/modules/skottie/src/SkottiePriv.h
+++ b/modules/skottie/src/SkottiePriv.h
@@ -49,6 +49,30 @@ public:
std::unique_ptr<sksg::Scene> parse(const skjson::ObjectValue&);
+ // This is the workhorse for property binding: depending on whether the property is animated,
+ // it will either apply immediately or instantiate and attach a keyframe animator.
+ template <typename T>
+ bool bindProperty(const skjson::Value&,
+ AnimatorScope*,
+ std::function<void(const T&)>&&,
+ const T* default_igore = nullptr) const;
+
+ template <typename T>
+ bool bindProperty(const skjson::Value& jv,
+ AnimatorScope* ascope,
+ std::function<void(const T&)>&& apply,
+ const T& default_ignore) const {
+ return this->bindProperty(jv, ascope, std::move(apply), &default_ignore);
+ }
+
+ sk_sp<sksg::Color> attachColor(const skjson::ObjectValue&, AnimatorScope*,
+ const char prop_name[]) const;
+ sk_sp<sksg::Matrix> attachMatrix(const skjson::ObjectValue&, AnimatorScope*,
+ sk_sp<sksg::Matrix>) const;
+ sk_sp<sksg::RenderNode> attachOpacity(const skjson::ObjectValue&, AnimatorScope*,
+ sk_sp<sksg::RenderNode>) const;
+ sk_sp<sksg::Path> attachPath(const skjson::Value&, AnimatorScope*) const;
+
private:
struct AttachLayerContext;
@@ -56,24 +80,24 @@ private:
void parseFonts (const skjson::ObjectValue* jfonts,
const skjson::ArrayValue* jchars);
- sk_sp<sksg::RenderNode> attachComposition(const skjson::ObjectValue&, AnimatorScope*);
- sk_sp<sksg::RenderNode> attachLayer(const skjson::ObjectValue*, AttachLayerContext*);
+ sk_sp<sksg::RenderNode> attachComposition(const skjson::ObjectValue&, AnimatorScope*) const;
+ sk_sp<sksg::RenderNode> attachLayer(const skjson::ObjectValue*, AttachLayerContext*) const;
sk_sp<sksg::RenderNode> attachLayerEffects(const skjson::ArrayValue& jeffects, AnimatorScope*,
- sk_sp<sksg::RenderNode>);
+ sk_sp<sksg::RenderNode>) const;
sk_sp<sksg::RenderNode> attachAssetRef(const skjson::ObjectValue&, AnimatorScope*,
sk_sp<sksg::RenderNode>(AnimationBuilder::*)(const skjson::ObjectValue&,
- AnimatorScope* ctx));
- sk_sp<sksg::RenderNode> attachImageAsset(const skjson::ObjectValue&, AnimatorScope*);
+ AnimatorScope* ctx) const) const;
+ sk_sp<sksg::RenderNode> attachImageAsset(const skjson::ObjectValue&, AnimatorScope*) const;
- sk_sp<sksg::RenderNode> attachNestedAnimation(const char* name, AnimatorScope* ascope);
+ sk_sp<sksg::RenderNode> attachNestedAnimation(const char* name, AnimatorScope* ascope) const;
- sk_sp<sksg::RenderNode> attachImageLayer (const skjson::ObjectValue&, AnimatorScope*);
- sk_sp<sksg::RenderNode> attachNullLayer (const skjson::ObjectValue&, AnimatorScope*);
- sk_sp<sksg::RenderNode> attachPrecompLayer(const skjson::ObjectValue&, AnimatorScope*);
- sk_sp<sksg::RenderNode> attachShapeLayer (const skjson::ObjectValue&, AnimatorScope*);
- sk_sp<sksg::RenderNode> attachSolidLayer (const skjson::ObjectValue&, AnimatorScope*);
- sk_sp<sksg::RenderNode> attachTextLayer (const skjson::ObjectValue&, AnimatorScope*);
+ sk_sp<sksg::RenderNode> attachImageLayer (const skjson::ObjectValue&, AnimatorScope*) const;
+ sk_sp<sksg::RenderNode> attachNullLayer (const skjson::ObjectValue&, AnimatorScope*) const;
+ sk_sp<sksg::RenderNode> attachPrecompLayer(const skjson::ObjectValue&, AnimatorScope*) const;
+ sk_sp<sksg::RenderNode> attachShapeLayer (const skjson::ObjectValue&, AnimatorScope*) const;
+ sk_sp<sksg::RenderNode> attachSolidLayer (const skjson::ObjectValue&, AnimatorScope*) const;
+ sk_sp<sksg::RenderNode> attachTextLayer (const skjson::ObjectValue&, AnimatorScope*) const;
sk_sp<ResourceProvider> fResourceProvider;
sk_sp<SkFontMgr> fFontMgr;
@@ -100,20 +124,13 @@ private:
using AssetCache = SkTHashMap<SkString, sk_sp<sksg::RenderNode>>;
using FontMap = SkTHashMap<SkString, FontInfo>;
- AssetMap fAssets;
- AssetCache fAssetCache;
- FontMap fFonts;
+ AssetMap fAssets;
+ FontMap fFonts;
+ mutable AssetCache fAssetCache;
using INHERITED = SkNoncopyable;
};
-// Shared helpers
-sk_sp<sksg::Color> AttachColor(const skjson::ObjectValue&, AnimatorScope*, const char prop_name[]);
-sk_sp<sksg::Path> AttachPath(const skjson::Value&, AnimatorScope*);
-sk_sp<sksg::Matrix> AttachMatrix(const skjson::ObjectValue&, AnimatorScope*, sk_sp<sksg::Matrix>);
-sk_sp<sksg::RenderNode> AttachOpacity(const skjson::ObjectValue&, AnimatorScope*,
- sk_sp<sksg::RenderNode>);
-
} // namespace internal
} // namespace skottie
diff --git a/modules/skottie/src/SkottieShapeLayer.cpp b/modules/skottie/src/SkottieShapeLayer.cpp
index 3ad7a50a1c..54f76753ea 100644
--- a/modules/skottie/src/SkottieShapeLayer.cpp
+++ b/modules/skottie/src/SkottieShapeLayer.cpp
@@ -9,7 +9,6 @@
#include "SkJSON.h"
#include "SkottieAdapter.h"
-#include "SkottieAnimator.h"
#include "SkottieJson.h"
#include "SkottieValue.h"
#include "SkPath.h"
@@ -31,24 +30,26 @@ namespace internal {
namespace {
sk_sp<sksg::GeometryNode> AttachPathGeometry(const skjson::ObjectValue& jpath,
+ const AnimationBuilder* abuilder,
AnimatorScope* ascope) {
- return AttachPath(jpath["ks"], ascope);
+ return abuilder->attachPath(jpath["ks"], ascope);
}
sk_sp<sksg::GeometryNode> AttachRRectGeometry(const skjson::ObjectValue& jrect,
+ const AnimationBuilder* abuilder,
AnimatorScope* ascope) {
auto rect_node = sksg::RRect::Make();
auto adapter = sk_make_sp<RRectAdapter>(rect_node);
- auto p_attached = BindProperty<VectorValue>(jrect["p"], ascope,
+ auto p_attached = abuilder->bindProperty<VectorValue>(jrect["p"], ascope,
[adapter](const VectorValue& p) {
adapter->setPosition(ValueTraits<VectorValue>::As<SkPoint>(p));
});
- auto s_attached = BindProperty<VectorValue>(jrect["s"], ascope,
+ auto s_attached = abuilder->bindProperty<VectorValue>(jrect["s"], ascope,
[adapter](const VectorValue& s) {
adapter->setSize(ValueTraits<VectorValue>::As<SkSize>(s));
});
- auto r_attached = BindProperty<ScalarValue>(jrect["r"], ascope,
+ auto r_attached = abuilder->bindProperty<ScalarValue>(jrect["r"], ascope,
[adapter](const ScalarValue& r) {
adapter->setRadius(SkSize::Make(r, r));
});
@@ -61,15 +62,16 @@ sk_sp<sksg::GeometryNode> AttachRRectGeometry(const skjson::ObjectValue& jrect,
}
sk_sp<sksg::GeometryNode> AttachEllipseGeometry(const skjson::ObjectValue& jellipse,
+ const AnimationBuilder* abuilder,
AnimatorScope* ascope) {
auto rect_node = sksg::RRect::Make();
auto adapter = sk_make_sp<RRectAdapter>(rect_node);
- auto p_attached = BindProperty<VectorValue>(jellipse["p"], ascope,
+ auto p_attached = abuilder->bindProperty<VectorValue>(jellipse["p"], ascope,
[adapter](const VectorValue& p) {
adapter->setPosition(ValueTraits<VectorValue>::As<SkPoint>(p));
});
- auto s_attached = BindProperty<VectorValue>(jellipse["s"], ascope,
+ auto s_attached = abuilder->bindProperty<VectorValue>(jellipse["s"], ascope,
[adapter](const VectorValue& s) {
const auto sz = ValueTraits<VectorValue>::As<SkSize>(s);
adapter->setSize(sz);
@@ -84,6 +86,7 @@ sk_sp<sksg::GeometryNode> AttachEllipseGeometry(const skjson::ObjectValue& jelli
}
sk_sp<sksg::GeometryNode> AttachPolystarGeometry(const skjson::ObjectValue& jstar,
+ const AnimationBuilder* abuilder,
AnimatorScope* ascope) {
static constexpr PolyStarAdapter::Type gTypes[] = {
PolyStarAdapter::Type::kStar, // "sy": 1
@@ -99,31 +102,31 @@ sk_sp<sksg::GeometryNode> AttachPolystarGeometry(const skjson::ObjectValue& jsta
auto path_node = sksg::Path::Make();
auto adapter = sk_make_sp<PolyStarAdapter>(path_node, gTypes[type]);
- BindProperty<VectorValue>(jstar["p"], ascope,
+ abuilder->bindProperty<VectorValue>(jstar["p"], ascope,
[adapter](const VectorValue& p) {
adapter->setPosition(ValueTraits<VectorValue>::As<SkPoint>(p));
});
- BindProperty<ScalarValue>(jstar["pt"], ascope,
+ abuilder->bindProperty<ScalarValue>(jstar["pt"], ascope,
[adapter](const ScalarValue& pt) {
adapter->setPointCount(pt);
});
- BindProperty<ScalarValue>(jstar["ir"], ascope,
+ abuilder->bindProperty<ScalarValue>(jstar["ir"], ascope,
[adapter](const ScalarValue& ir) {
adapter->setInnerRadius(ir);
});
- BindProperty<ScalarValue>(jstar["or"], ascope,
+ abuilder->bindProperty<ScalarValue>(jstar["or"], ascope,
[adapter](const ScalarValue& otr) {
adapter->setOuterRadius(otr);
});
- BindProperty<ScalarValue>(jstar["is"], ascope,
+ abuilder->bindProperty<ScalarValue>(jstar["is"], ascope,
[adapter](const ScalarValue& is) {
adapter->setInnerRoundness(is);
});
- BindProperty<ScalarValue>(jstar["os"], ascope,
+ abuilder->bindProperty<ScalarValue>(jstar["os"], ascope,
[adapter](const ScalarValue& os) {
adapter->setOuterRoundness(os);
});
- BindProperty<ScalarValue>(jstar["r"], ascope,
+ abuilder->bindProperty<ScalarValue>(jstar["r"], ascope,
[adapter](const ScalarValue& r) {
adapter->setRotation(r);
});
@@ -131,7 +134,8 @@ sk_sp<sksg::GeometryNode> AttachPolystarGeometry(const skjson::ObjectValue& jsta
return std::move(path_node);
}
-sk_sp<sksg::Gradient> AttachGradient(const skjson::ObjectValue& jgrad, AnimatorScope* ascope) {
+sk_sp<sksg::Gradient> AttachGradient(const skjson::ObjectValue& jgrad,
+ const AnimationBuilder* abuilder, AnimatorScope* ascope) {
const skjson::ObjectValue* stops = jgrad["g"];
if (!stops)
return nullptr;
@@ -155,15 +159,15 @@ sk_sp<sksg::Gradient> AttachGradient(const skjson::ObjectValue& jgrad, AnimatorS
gradient_node = std::move(radial_node);
}
- BindProperty<VectorValue>((*stops)["k"], ascope,
+ abuilder->bindProperty<VectorValue>((*stops)["k"], ascope,
[adapter](const VectorValue& stops) {
adapter->setColorStops(stops);
});
- BindProperty<VectorValue>(jgrad["s"], ascope,
+ abuilder->bindProperty<VectorValue>(jgrad["s"], ascope,
[adapter](const VectorValue& s) {
adapter->setStartPoint(ValueTraits<VectorValue>::As<SkPoint>(s));
});
- BindProperty<VectorValue>(jgrad["e"], ascope,
+ abuilder->bindProperty<VectorValue>(jgrad["e"], ascope,
[adapter](const VectorValue& e) {
adapter->setEndPoint(ValueTraits<VectorValue>::As<SkPoint>(e));
});
@@ -171,12 +175,13 @@ sk_sp<sksg::Gradient> AttachGradient(const skjson::ObjectValue& jgrad, AnimatorS
return gradient_node;
}
-sk_sp<sksg::PaintNode> AttachPaint(const skjson::ObjectValue& jpaint, AnimatorScope* ascope,
+sk_sp<sksg::PaintNode> AttachPaint(const skjson::ObjectValue& jpaint,
+ const AnimationBuilder* abuilder, AnimatorScope* ascope,
sk_sp<sksg::PaintNode> paint_node) {
if (paint_node) {
paint_node->setAntiAlias(true);
- BindProperty<ScalarValue>(jpaint["o"], ascope,
+ abuilder->bindProperty<ScalarValue>(jpaint["o"], ascope,
[paint_node](const ScalarValue& o) {
// BM opacity is [0..100]
paint_node->setOpacity(o * 0.01f);
@@ -186,14 +191,15 @@ sk_sp<sksg::PaintNode> AttachPaint(const skjson::ObjectValue& jpaint, AnimatorSc
return paint_node;
}
-sk_sp<sksg::PaintNode> AttachStroke(const skjson::ObjectValue& jstroke, AnimatorScope* ascope,
+sk_sp<sksg::PaintNode> AttachStroke(const skjson::ObjectValue& jstroke,
+ const AnimationBuilder* abuilder, AnimatorScope* ascope,
sk_sp<sksg::PaintNode> stroke_node) {
if (!stroke_node)
return nullptr;
stroke_node->setStyle(SkPaint::kStroke_Style);
- BindProperty<ScalarValue>(jstroke["w"], ascope,
+ abuilder->bindProperty<ScalarValue>(jstroke["w"], ascope,
[stroke_node](const ScalarValue& w) {
stroke_node->setStrokeWidth(w);
});
@@ -219,24 +225,30 @@ sk_sp<sksg::PaintNode> AttachStroke(const skjson::ObjectValue& jstroke, Animator
return stroke_node;
}
-sk_sp<sksg::PaintNode> AttachColorFill(const skjson::ObjectValue& jfill, AnimatorScope* ascope) {
- return AttachPaint(jfill, ascope, AttachColor(jfill, ascope, "c"));
+sk_sp<sksg::PaintNode> AttachColorFill(const skjson::ObjectValue& jfill,
+ const AnimationBuilder* abuilder, AnimatorScope* ascope) {
+ return AttachPaint(jfill, abuilder, ascope, abuilder->attachColor(jfill, ascope, "c"));
}
-sk_sp<sksg::PaintNode> AttachGradientFill(const skjson::ObjectValue& jfill, AnimatorScope* ascope) {
- return AttachPaint(jfill, ascope, AttachGradient(jfill, ascope));
+sk_sp<sksg::PaintNode> AttachGradientFill(const skjson::ObjectValue& jfill,
+ const AnimationBuilder* abuilder, AnimatorScope* ascope) {
+ return AttachPaint(jfill, abuilder, ascope, AttachGradient(jfill, abuilder, ascope));
}
sk_sp<sksg::PaintNode> AttachColorStroke(const skjson::ObjectValue& jstroke,
+ const AnimationBuilder* abuilder,
AnimatorScope* ascope) {
- return AttachStroke(jstroke, ascope, AttachPaint(jstroke, ascope,
- AttachColor(jstroke, ascope, "c")));
+ return AttachStroke(jstroke, abuilder, ascope,
+ AttachPaint(jstroke, abuilder, ascope,
+ abuilder->attachColor(jstroke, ascope, "c")));
}
sk_sp<sksg::PaintNode> AttachGradientStroke(const skjson::ObjectValue& jstroke,
+ const AnimationBuilder* abuilder,
AnimatorScope* ascope) {
- return AttachStroke(jstroke, ascope, AttachPaint(jstroke, ascope,
- AttachGradient(jstroke, ascope)));
+ return AttachStroke(jstroke, abuilder, ascope,
+ AttachPaint(jstroke, abuilder, ascope,
+ AttachGradient(jstroke, abuilder, ascope)));
}
sk_sp<sksg::Merge> Merge(std::vector<sk_sp<sksg::GeometryNode>>&& geos, sksg::Merge::Mode mode) {
@@ -252,7 +264,7 @@ sk_sp<sksg::Merge> Merge(std::vector<sk_sp<sksg::GeometryNode>>&& geos, sksg::Me
}
std::vector<sk_sp<sksg::GeometryNode>> AttachMergeGeometryEffect(
- const skjson::ObjectValue& jmerge, AnimatorScope*,
+ const skjson::ObjectValue& jmerge, const AnimationBuilder*, AnimatorScope*,
std::vector<sk_sp<sksg::GeometryNode>>&& geos) {
static constexpr sksg::Merge::Mode gModes[] = {
sksg::Merge::Mode::kMerge, // "mm": 1
@@ -272,7 +284,7 @@ std::vector<sk_sp<sksg::GeometryNode>> AttachMergeGeometryEffect(
}
std::vector<sk_sp<sksg::GeometryNode>> AttachTrimGeometryEffect(
- const skjson::ObjectValue& jtrim, AnimatorScope* ascope,
+ const skjson::ObjectValue& jtrim, const AnimationBuilder* abuilder, AnimatorScope* ascope,
std::vector<sk_sp<sksg::GeometryNode>>&& geos) {
enum class Mode {
@@ -297,15 +309,15 @@ std::vector<sk_sp<sksg::GeometryNode>> AttachTrimGeometryEffect(
trimmed.push_back(trimEffect);
const auto adapter = sk_make_sp<TrimEffectAdapter>(std::move(trimEffect));
- BindProperty<ScalarValue>(jtrim["s"], ascope,
+ abuilder->bindProperty<ScalarValue>(jtrim["s"], ascope,
[adapter](const ScalarValue& s) {
adapter->setStart(s);
});
- BindProperty<ScalarValue>(jtrim["e"], ascope,
+ abuilder->bindProperty<ScalarValue>(jtrim["e"], ascope,
[adapter](const ScalarValue& e) {
adapter->setEnd(e);
});
- BindProperty<ScalarValue>(jtrim["o"], ascope,
+ abuilder->bindProperty<ScalarValue>(jtrim["o"], ascope,
[adapter](const ScalarValue& o) {
adapter->setOffset(o);
});
@@ -315,7 +327,7 @@ std::vector<sk_sp<sksg::GeometryNode>> AttachTrimGeometryEffect(
}
std::vector<sk_sp<sksg::GeometryNode>> AttachRoundGeometryEffect(
- const skjson::ObjectValue& jtrim, AnimatorScope* ascope,
+ const skjson::ObjectValue& jtrim, const AnimationBuilder* abuilder, AnimatorScope* ascope,
std::vector<sk_sp<sksg::GeometryNode>>&& geos) {
std::vector<sk_sp<sksg::GeometryNode>> rounded;
@@ -325,7 +337,7 @@ std::vector<sk_sp<sksg::GeometryNode>> AttachRoundGeometryEffect(
const auto roundEffect = sksg::RoundEffect::Make(std::move(g));
rounded.push_back(roundEffect);
- BindProperty<ScalarValue>(jtrim["r"], ascope,
+ abuilder->bindProperty<ScalarValue>(jtrim["r"], ascope,
[roundEffect](const ScalarValue& r) {
roundEffect->setRadius(r);
});
@@ -334,7 +346,8 @@ std::vector<sk_sp<sksg::GeometryNode>> AttachRoundGeometryEffect(
return rounded;
}
-using GeometryAttacherT = sk_sp<sksg::GeometryNode> (*)(const skjson::ObjectValue&, AnimatorScope*);
+using GeometryAttacherT = sk_sp<sksg::GeometryNode> (*)(const skjson::ObjectValue&,
+ const AnimationBuilder*, AnimatorScope*);
static constexpr GeometryAttacherT gGeometryAttachers[] = {
AttachPathGeometry,
AttachRRectGeometry,
@@ -342,7 +355,8 @@ static constexpr GeometryAttacherT gGeometryAttachers[] = {
AttachPolystarGeometry,
};
-using PaintAttacherT = sk_sp<sksg::PaintNode> (*)(const skjson::ObjectValue&, AnimatorScope*);
+using PaintAttacherT = sk_sp<sksg::PaintNode> (*)(const skjson::ObjectValue&,
+ const AnimationBuilder*, AnimatorScope*);
static constexpr PaintAttacherT gPaintAttachers[] = {
AttachColorFill,
AttachColorStroke,
@@ -352,7 +366,7 @@ static constexpr PaintAttacherT gPaintAttachers[] = {
using GeometryEffectAttacherT =
std::vector<sk_sp<sksg::GeometryNode>> (*)(const skjson::ObjectValue&,
- AnimatorScope*,
+ const AnimationBuilder*, AnimatorScope*,
std::vector<sk_sp<sksg::GeometryNode>>&&);
static constexpr GeometryEffectAttacherT gGeometryEffectAttachers[] = {
AttachMergeGeometryEffect,
@@ -414,27 +428,29 @@ struct GeometryEffectRec {
};
struct AttachShapeContext {
- AttachShapeContext(AnimatorScope* ascope,
+ AttachShapeContext(const AnimationBuilder* abuilder,
+ AnimatorScope* ascope,
std::vector<sk_sp<sksg::GeometryNode>>* geos,
std::vector<GeometryEffectRec>* effects,
size_t committedAnimators)
- : fScope(ascope)
+ : fBuilder(abuilder)
+ , fScope(ascope)
, fGeometryStack(geos)
, fGeometryEffectStack(effects)
, fCommittedAnimators(committedAnimators) {}
+ const AnimationBuilder* fBuilder;
AnimatorScope* fScope;
std::vector<sk_sp<sksg::GeometryNode>>* fGeometryStack;
std::vector<GeometryEffectRec>* fGeometryEffectStack;
size_t fCommittedAnimators;
};
-sk_sp<sksg::RenderNode> AttachShape(const skjson::ArrayValue* jshape,
- AttachShapeContext* shapeCtx) {
+sk_sp<sksg::RenderNode> AttachShape(const skjson::ArrayValue* jshape, AttachShapeContext* ctx) {
if (!jshape)
return nullptr;
- SkDEBUGCODE(const auto initialGeometryEffects = shapeCtx->fGeometryEffectStack->size();)
+ SkDEBUGCODE(const auto initialGeometryEffects = ctx->fGeometryEffectStack->size();)
sk_sp<sksg::Group> shape_group = sksg::Group::Make();
sk_sp<sksg::RenderNode> shape_wrapper = shape_group;
@@ -466,14 +482,15 @@ sk_sp<sksg::RenderNode> AttachShape(const skjson::ArrayValue* jshape,
switch (info->fShapeType) {
case ShapeType::kTransform:
- if ((shape_matrix = AttachMatrix(*shape, shapeCtx->fScope, nullptr))) {
+ if ((shape_matrix = ctx->fBuilder->attachMatrix(*shape, ctx->fScope, nullptr))) {
shape_wrapper = sksg::Transform::Make(std::move(shape_wrapper), shape_matrix);
}
- shape_wrapper = AttachOpacity(*shape, shapeCtx->fScope, std::move(shape_wrapper));
+ shape_wrapper = ctx->fBuilder->attachOpacity(*shape, ctx->fScope,
+ std::move(shape_wrapper));
break;
case ShapeType::kGeometryEffect:
SkASSERT(info->fAttacherIndex < SK_ARRAY_COUNT(gGeometryEffectAttachers));
- shapeCtx->fGeometryEffectStack->push_back(
+ ctx->fGeometryEffectStack->push_back(
{ *shape, gGeometryEffectAttachers[info->fAttacherIndex] });
break;
default:
@@ -493,7 +510,8 @@ sk_sp<sksg::RenderNode> AttachShape(const skjson::ArrayValue* jshape,
case ShapeType::kGeometry: {
SkASSERT(rec->fInfo.fAttacherIndex < SK_ARRAY_COUNT(gGeometryAttachers));
if (auto geo = gGeometryAttachers[rec->fInfo.fAttacherIndex](rec->fJson,
- shapeCtx->fScope)) {
+ ctx->fBuilder,
+ ctx->fScope)) {
geos.push_back(std::move(geo));
}
} break;
@@ -502,38 +520,42 @@ sk_sp<sksg::RenderNode> AttachShape(const skjson::ArrayValue* jshape,
SkASSERT(rec->fInfo.fAttacherIndex < SK_ARRAY_COUNT(gGeometryEffectAttachers));
if (!geos.empty()) {
geos = gGeometryEffectAttachers[rec->fInfo.fAttacherIndex](rec->fJson,
- shapeCtx->fScope,
+ ctx->fBuilder,
+ ctx->fScope,
std::move(geos));
}
- SkASSERT(&shapeCtx->fGeometryEffectStack->back().fJson == &rec->fJson);
- SkASSERT(shapeCtx->fGeometryEffectStack->back().fAttach ==
+ SkASSERT(&ctx->fGeometryEffectStack->back().fJson == &rec->fJson);
+ SkASSERT(ctx->fGeometryEffectStack->back().fAttach ==
gGeometryEffectAttachers[rec->fInfo.fAttacherIndex]);
- shapeCtx->fGeometryEffectStack->pop_back();
+ ctx->fGeometryEffectStack->pop_back();
} break;
case ShapeType::kGroup: {
- AttachShapeContext groupShapeCtx(shapeCtx->fScope,
+ AttachShapeContext groupShapeCtx(ctx->fBuilder,
+ ctx->fScope,
&geos,
- shapeCtx->fGeometryEffectStack,
- shapeCtx->fCommittedAnimators);
+ ctx->fGeometryEffectStack,
+ ctx->fCommittedAnimators);
if (auto subgroup = AttachShape(rec->fJson["it"], &groupShapeCtx)) {
draws.push_back(std::move(subgroup));
- SkASSERT(groupShapeCtx.fCommittedAnimators >= shapeCtx->fCommittedAnimators);
- shapeCtx->fCommittedAnimators = groupShapeCtx.fCommittedAnimators;
+ SkASSERT(groupShapeCtx.fCommittedAnimators >= ctx->fCommittedAnimators);
+ ctx->fCommittedAnimators = groupShapeCtx.fCommittedAnimators;
}
} break;
case ShapeType::kPaint: {
SkASSERT(rec->fInfo.fAttacherIndex < SK_ARRAY_COUNT(gPaintAttachers));
- auto paint = gPaintAttachers[rec->fInfo.fAttacherIndex](rec->fJson, shapeCtx->fScope);
+ auto paint = gPaintAttachers[rec->fInfo.fAttacherIndex](rec->fJson,
+ ctx->fBuilder,
+ ctx->fScope);
if (!paint || geos.empty())
break;
auto drawGeos = geos;
// Apply all pending effects from the stack.
- for (auto it = shapeCtx->fGeometryEffectStack->rbegin();
- it != shapeCtx->fGeometryEffectStack->rend(); ++it) {
- drawGeos = it->fAttach(it->fJson, shapeCtx->fScope, std::move(drawGeos));
+ for (auto it = ctx->fGeometryEffectStack->rbegin();
+ it != ctx->fGeometryEffectStack->rend(); ++it) {
+ drawGeos = it->fAttach(it->fJson, ctx->fBuilder, ctx->fScope, std::move(drawGeos));
}
// If we still have multiple geos, reduce using 'merge'.
@@ -543,7 +565,7 @@ sk_sp<sksg::RenderNode> AttachShape(const skjson::ArrayValue* jshape,
SkASSERT(geo);
draws.push_back(sksg::Draw::Make(std::move(geo), std::move(paint)));
- shapeCtx->fCommittedAnimators = shapeCtx->fScope->size();
+ ctx->fCommittedAnimators = ctx->fScope->size();
} break;
default:
break;
@@ -551,11 +573,11 @@ sk_sp<sksg::RenderNode> AttachShape(const skjson::ArrayValue* jshape,
}
// By now we should have popped all local geometry effects.
- SkASSERT(shapeCtx->fGeometryEffectStack->size() == initialGeometryEffects);
+ SkASSERT(ctx->fGeometryEffectStack->size() == initialGeometryEffects);
// Push transformed local geometries to parent list, for subsequent paints.
for (const auto& geo : geos) {
- shapeCtx->fGeometryStack->push_back(shape_matrix
+ ctx->fGeometryStack->push_back(shape_matrix
? sksg::GeometryTransform::Make(std::move(geo), shape_matrix)
: std::move(geo));
}
@@ -571,10 +593,10 @@ sk_sp<sksg::RenderNode> AttachShape(const skjson::ArrayValue* jshape,
} // namespace
sk_sp<sksg::RenderNode> AnimationBuilder::attachShapeLayer(const skjson::ObjectValue& layer,
- AnimatorScope* ascope) {
+ AnimatorScope* ascope) const {
std::vector<sk_sp<sksg::GeometryNode>> geometryStack;
std::vector<GeometryEffectRec> geometryEffectStack;
- AttachShapeContext shapeCtx(ascope, &geometryStack, &geometryEffectStack, ascope->size());
+ AttachShapeContext shapeCtx(this, ascope, &geometryStack, &geometryEffectStack, ascope->size());
auto shapeNode = AttachShape(layer["shapes"], &shapeCtx);
// Trim uncommitted animators: AttachShape consumes effects on the fly, and greedily attaches
diff --git a/modules/skottie/src/SkottieTextLayer.cpp b/modules/skottie/src/SkottieTextLayer.cpp
index d39f57dd93..cb62a5b22e 100644
--- a/modules/skottie/src/SkottieTextLayer.cpp
+++ b/modules/skottie/src/SkottieTextLayer.cpp
@@ -206,7 +206,7 @@ void AnimationBuilder::parseFonts(const skjson::ObjectValue* jfonts,
}
sk_sp<sksg::RenderNode> AnimationBuilder::attachTextLayer(const skjson::ObjectValue& layer,
- AnimatorScope* ascope) {
+ AnimatorScope* ascope) const {
// General text node format:
// "t": {
// "a": [], // animators (TODO)
diff --git a/modules/skottie/src/SkottieValue.cpp b/modules/skottie/src/SkottieValue.cpp
index d564e515c4..910e8c3768 100644
--- a/modules/skottie/src/SkottieValue.cpp
+++ b/modules/skottie/src/SkottieValue.cpp
@@ -8,6 +8,8 @@
#include "SkottieValue.h"
#include "SkColor.h"
+#include "SkottieJson.h"
+#include "SkottiePriv.h"
#include "SkNx.h"
#include "SkPoint.h"
#include "SkSize.h"
@@ -15,6 +17,12 @@
namespace skottie {
template <>
+bool ValueTraits<ScalarValue>::FromJSON(const skjson::Value& jv, const internal::AnimationBuilder*,
+ ScalarValue* v) {
+ return Parse(jv, v);
+}
+
+template <>
bool ValueTraits<ScalarValue>::CanLerp(const ScalarValue&, const ScalarValue&) {
return true;
}
@@ -33,6 +41,12 @@ SkScalar ValueTraits<ScalarValue>::As<SkScalar>(const ScalarValue& v) {
}
template <>
+bool ValueTraits<VectorValue>::FromJSON(const skjson::Value& jv, const internal::AnimationBuilder*,
+ VectorValue* v) {
+ return Parse(jv, v);
+}
+
+template <>
bool ValueTraits<VectorValue>::CanLerp(const VectorValue& v1, const VectorValue& v2) {
return v1.size() == v2.size();
}
@@ -80,6 +94,67 @@ SkSize ValueTraits<VectorValue>::As<SkSize>(const VectorValue& vec) {
return SkSize::Make(pt.x(), pt.y());
}
+namespace {
+
+bool ParsePointVec(const skjson::Value& jv, std::vector<SkPoint>* pts) {
+ if (!jv.is<skjson::ArrayValue>())
+ return false;
+ const auto& av = jv.as<skjson::ArrayValue>();
+
+ pts->clear();
+ pts->reserve(av.size());
+
+ std::vector<float> vec;
+ for (size_t i = 0; i < av.size(); ++i) {
+ if (!Parse(av[i], &vec) || vec.size() != 2)
+ return false;
+ pts->push_back(SkPoint::Make(vec[0], vec[1]));
+ }
+
+ return true;
+}
+
+} // namespace
+
+template <>
+bool ValueTraits<ShapeValue>::FromJSON(const skjson::Value& jv,
+ const internal::AnimationBuilder* abuilder,
+ ShapeValue* v) {
+ SkASSERT(v->fVertices.empty());
+
+ // Some versions wrap values as single-element arrays.
+ if (const skjson::ArrayValue* av = jv) {
+ if (av->size() == 1) {
+ return FromJSON((*av)[0], abuilder, v);
+ }
+ }
+
+ if (!jv.is<skjson::ObjectValue>())
+ return false;
+ const auto& ov = jv.as<skjson::ObjectValue>();
+
+ std::vector<SkPoint> inPts, // Cubic Bezier "in" control points, relative to vertices.
+ outPts, // Cubic Bezier "out" control points, relative to vertices.
+ verts; // Cubic Bezier vertices.
+
+ if (!ParsePointVec(ov["i"], &inPts) ||
+ !ParsePointVec(ov["o"], &outPts) ||
+ !ParsePointVec(ov["v"], &verts) ||
+ inPts.size() != outPts.size() ||
+ inPts.size() != verts.size()) {
+
+ return false;
+ }
+
+ v->fVertices.reserve(inPts.size());
+ for (size_t i = 0; i < inPts.size(); ++i) {
+ v->fVertices.push_back(BezierVertex({inPts[i], outPts[i], verts[i]}));
+ }
+ v->fClosed = ParseDefault<bool>(ov["c"], false);
+
+ return true;
+}
+
template <>
bool ValueTraits<ShapeValue>::CanLerp(const ShapeValue& v1, const ShapeValue& v2) {
return v1.fVertices.size() == v2.fVertices.size()
diff --git a/modules/skottie/src/SkottieValue.h b/modules/skottie/src/SkottieValue.h
index 46e08cb74f..8e62985e8e 100644
--- a/modules/skottie/src/SkottieValue.h
+++ b/modules/skottie/src/SkottieValue.h
@@ -13,10 +13,17 @@
#include <vector>
-namespace skottie {
+namespace skjson { class Value; }
+
+namespace skottie {
+namespace internal {
+class AnimationBuilder;
+} // namespace internal
template <typename T>
struct ValueTraits {
+ static bool FromJSON(const skjson::Value&, const internal::AnimationBuilder*, T*);
+
template <typename U>
static U As(const T&);