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