1 /*
2 * Copyright 2020 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "modules/skottie/src/SkottieJson.h"
9 #include "modules/skottie/src/SkottieValue.h"
10 #include "modules/skottie/src/animator/KeyframeAnimator.h"
11 #include "modules/skottie/src/text/TextValue.h"
12
13 namespace skottie::internal {
14
15 namespace {
16 class TextKeyframeAnimator final : public KeyframeAnimator {
17 public:
TextKeyframeAnimator(std::vector<Keyframe> kfs,std::vector<SkCubicMap> cms,std::vector<TextValue> vs,TextValue * target_value)18 TextKeyframeAnimator(std::vector<Keyframe> kfs, std::vector<SkCubicMap> cms,
19 std::vector<TextValue> vs, TextValue* target_value)
20 : INHERITED(std::move(kfs), std::move(cms))
21 , fValues(std::move(vs))
22 , fTarget(target_value) {}
23
24 private:
onSeek(float t)25 StateChanged onSeek(float t) override {
26 const auto& lerp_info = this->getLERPInfo(t);
27
28 // Text value keyframes are treated as selectors, not as interpolated values.
29 if (*fTarget != fValues[SkToSizeT(lerp_info.vrec0.idx)]) {
30 *fTarget = fValues[SkToSizeT(lerp_info.vrec0.idx)];
31 return true;
32 }
33
34 return false;
35 }
36
37 const std::vector<TextValue> fValues;
38 TextValue* fTarget;
39
40 using INHERITED = KeyframeAnimator;
41 };
42
43 class TextExpressionAnimator final : public Animator {
44 public:
TextExpressionAnimator(sk_sp<ExpressionEvaluator<SkString>> expression_evaluator,TextValue * target_value)45 TextExpressionAnimator(sk_sp<ExpressionEvaluator<SkString>> expression_evaluator,
46 TextValue* target_value)
47 : fExpressionEvaluator(std::move(expression_evaluator))
48 , fTarget(target_value) {}
49
50 private:
51
onSeek(float t)52 StateChanged onSeek(float t) override {
53 SkString old_value = fTarget->fText;
54
55 fTarget->fText = fExpressionEvaluator->evaluate(t);
56
57 return fTarget->fText != old_value;
58 }
59
60 sk_sp<ExpressionEvaluator<SkString>> fExpressionEvaluator;
61 TextValue* fTarget;
62 };
63
64 class TextAnimatorBuilder final : public AnimatorBuilder {
65 public:
TextAnimatorBuilder(TextValue * target)66 explicit TextAnimatorBuilder(TextValue* target)
67 : INHERITED(Keyframe::Value::Type::kIndex)
68 , fTarget(target) {}
69
makeFromKeyframes(const AnimationBuilder & abuilder,const skjson::ArrayValue & jkfs)70 sk_sp<KeyframeAnimator> makeFromKeyframes(const AnimationBuilder& abuilder,
71 const skjson::ArrayValue& jkfs) override {
72 SkASSERT(jkfs.size() > 0);
73
74 fValues.reserve(jkfs.size());
75 if (!this->parseKeyframes(abuilder, jkfs)) {
76 return nullptr;
77 }
78 fValues.shrink_to_fit();
79
80 return sk_sp<TextKeyframeAnimator>(
81 new TextKeyframeAnimator(std::move(fKFs),
82 std::move(fCMs),
83 std::move(fValues),
84 fTarget));
85 }
86
makeFromExpression(ExpressionManager & em,const char * expr)87 sk_sp<Animator> makeFromExpression(ExpressionManager& em, const char* expr) override {
88 sk_sp<ExpressionEvaluator<SkString>> expression_evaluator =
89 em.createStringExpressionEvaluator(expr);
90 return sk_make_sp<TextExpressionAnimator>(expression_evaluator, fTarget);
91 }
92
parseValue(const AnimationBuilder & abuilder,const skjson::Value & jv) const93 bool parseValue(const AnimationBuilder& abuilder, const skjson::Value& jv) const override {
94 return Parse(jv, abuilder, fTarget);
95 }
96
97 private:
parseKFValue(const AnimationBuilder & abuilder,const skjson::ObjectValue &,const skjson::Value & jv,Keyframe::Value * v)98 bool parseKFValue(const AnimationBuilder& abuilder,
99 const skjson::ObjectValue&,
100 const skjson::Value& jv,
101 Keyframe::Value* v) override {
102 TextValue val;
103 if (!Parse(jv, abuilder, &val)) {
104 return false;
105 }
106
107 // TODO: full deduping?
108 if (fValues.empty() || val != fValues.back()) {
109 fValues.push_back(std::move(val));
110 }
111
112 v->idx = SkToU32(fValues.size() - 1);
113
114 return true;
115 }
116
117 std::vector<TextValue> fValues;
118 TextValue* fTarget;
119
120 using INHERITED = AnimatorBuilder;
121 };
122
123 } // namespace
124
125 template <>
bind(const AnimationBuilder & abuilder,const skjson::ObjectValue * jprop,TextValue * v)126 bool AnimatablePropertyContainer::bind<TextValue>(const AnimationBuilder& abuilder,
127 const skjson::ObjectValue* jprop,
128 TextValue* v) {
129 TextAnimatorBuilder builder(v);
130 return this->bindImpl(abuilder, jprop, builder);
131 }
132
133 } // namespace skottie::internal
134