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 { 16class TextKeyframeAnimator final : public KeyframeAnimator { 17public: 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 24private: 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 43class TextExpressionAnimator final : public Animator { 44public: 45 TextExpressionAnimator(sk_sp<ExpressionEvaluator<SkString>> expression_evaluator, 46 TextValue* target_value) 47 : fExpressionEvaluator(std::move(expression_evaluator)) 48 , fTarget(target_value) {} 49 50private: 51 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 64class TextAnimatorBuilder final : public AnimatorBuilder { 65public: 66 explicit TextAnimatorBuilder(TextValue* target) 67 : INHERITED(Keyframe::Value::Type::kIndex) 68 , fTarget(target) {} 69 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 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 93 bool parseValue(const AnimationBuilder& abuilder, const skjson::Value& jv) const override { 94 return Parse(jv, abuilder, fTarget); 95 } 96 97private: 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 125template <> 126bool 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