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
13namespace skottie::internal {
14
15namespace {
16
17class TextKeyframeAnimator final : public KeyframeAnimator {
18public:
19 class Builder final : public KeyframeAnimatorBuilder {
20 public:
21 explicit Builder(TextValue* target) : fTarget(target) {}
22
23 sk_sp<KeyframeAnimator> make(const AnimationBuilder& abuilder,
24 const skjson::ArrayValue& jkfs) override {
25 SkASSERT(jkfs.size() > 0);
26
27 fValues.reserve(jkfs.size());
28 if (!this->parseKeyframes(abuilder, jkfs)) {
29 return nullptr;
30 }
31 fValues.shrink_to_fit();
32
33 return sk_sp<TextKeyframeAnimator>(
34 new TextKeyframeAnimator(std::move(fKFs),
35 std::move(fCMs),
36 std::move(fValues),
37 fTarget));
38 }
39
40 bool parseValue(const AnimationBuilder& abuilder, const skjson::Value& jv) const override {
41 return Parse(jv, abuilder, fTarget);
42 }
43
44 private:
45 bool parseKFValue(const AnimationBuilder& abuilder,
46 const skjson::ObjectValue&,
47 const skjson::Value& jv,
48 Keyframe::Value* v) override {
49 TextValue val;
50 if (!Parse(jv, abuilder, &val)) {
51 return false;
52 }
53
54 // TODO: full deduping?
55 if (fValues.empty() || val != fValues.back()) {
56 fValues.push_back(std::move(val));
57 }
58
59 v->idx = SkToU32(fValues.size() - 1);
60
61 return true;
62 }
63
64 std::vector<TextValue> fValues;
65 TextValue* fTarget;
66 };
67
68private:
69 TextKeyframeAnimator(std::vector<Keyframe> kfs, std::vector<SkCubicMap> cms,
70 std::vector<TextValue> vs, TextValue* target_value)
71 : INHERITED(std::move(kfs), std::move(cms))
72 , fValues(std::move(vs))
73 , fTarget(target_value) {}
74
75 StateChanged onSeek(float t) override {
76 const auto& lerp_info = this->getLERPInfo(t);
77
78 // Text value keyframes are treated as selectors, not as interpolated values.
79 if (*fTarget != fValues[SkToSizeT(lerp_info.vrec0.idx)]) {
80 *fTarget = fValues[SkToSizeT(lerp_info.vrec0.idx)];
81 return true;
82 }
83
84 return false;
85 }
86
87 const std::vector<TextValue> fValues;
88 TextValue* fTarget;
89
90 using INHERITED = KeyframeAnimator;
91};
92
93} // namespace
94
95template <>
96bool AnimatablePropertyContainer::bind<TextValue>(const AnimationBuilder& abuilder,
97 const skjson::ObjectValue* jprop,
98 TextValue* v) {
99 TextKeyframeAnimator::Builder builder(v);
100 return this->bindImpl(abuilder, jprop, builder);
101}
102
103} // namespace skottie::internal
104