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 sk_sp<KeyframeAnimator> make(const AnimationBuilder& abuilder,
22 const skjson::ArrayValue& jkfs,
23 void* target_value) override {
24 SkASSERT(jkfs.size() > 0);
25
26 fValues.reserve(jkfs.size());
27 if (!this->parseKeyframes(abuilder, jkfs)) {
28 return nullptr;
29 }
30 fValues.shrink_to_fit();
31
32 return sk_sp<TextKeyframeAnimator>(
33 new TextKeyframeAnimator(std::move(fKFs),
34 std::move(fCMs),
35 std::move(fValues),
36 static_cast<TextValue*>(target_value)));
37 }
38
39 bool parseValue(const AnimationBuilder& abuilder,
40 const skjson::Value& jv, void* v) const override {
41 return Parse(jv, abuilder, static_cast<TextValue*>(v));
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 };
66
67private:
68 TextKeyframeAnimator(std::vector<Keyframe> kfs, std::vector<SkCubicMap> cms,
69 std::vector<TextValue> vs, TextValue* target_value)
70 : INHERITED(std::move(kfs), std::move(cms))
71 , fValues(std::move(vs))
72 , fTarget(target_value) {}
73
74 StateChanged onSeek(float t) override {
75 const auto& lerp_info = this->getLERPInfo(t);
76
77 // Text value keyframes are treated as selectors, not as interpolated values.
78 if (*fTarget != fValues[SkToSizeT(lerp_info.vrec0.idx)]) {
79 *fTarget = fValues[SkToSizeT(lerp_info.vrec0.idx)];
80 return true;
81 }
82
83 return false;
84 }
85
86 const std::vector<TextValue> fValues;
87 TextValue* fTarget;
88
89 using INHERITED = KeyframeAnimator;
90};
91
92} // namespace
93
94template <>
95bool AnimatablePropertyContainer::bind<TextValue>(const AnimationBuilder& abuilder,
96 const skjson::ObjectValue* jprop,
97 TextValue* v) {
98 TextKeyframeAnimator::Builder builder;
99 return this->bindImpl(abuilder, jprop, builder, v);
100}
101
102} // namespace skottie::internal
103