| /* |
| * Copyright 2020 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "modules/skottie/src/SkottieJson.h" |
| #include "modules/skottie/src/SkottieValue.h" |
| #include "modules/skottie/src/animator/KeyframeAnimator.h" |
| #include "modules/skottie/src/text/TextValue.h" |
| |
| namespace skottie::internal { |
| |
| namespace { |
| class TextKeyframeAnimator final : public KeyframeAnimator { |
| public: |
| TextKeyframeAnimator(std::vector<Keyframe> kfs, std::vector<SkCubicMap> cms, |
| std::vector<TextValue> vs, TextValue* target_value) |
| : INHERITED(std::move(kfs), std::move(cms)) |
| , fValues(std::move(vs)) |
| , fTarget(target_value) {} |
| |
| private: |
| StateChanged onSeek(float t) override { |
| const auto& lerp_info = this->getLERPInfo(t); |
| |
| // Text value keyframes are treated as selectors, not as interpolated values. |
| if (*fTarget != fValues[SkToSizeT(lerp_info.vrec0.idx)]) { |
| *fTarget = fValues[SkToSizeT(lerp_info.vrec0.idx)]; |
| return true; |
| } |
| |
| return false; |
| } |
| |
| const std::vector<TextValue> fValues; |
| TextValue* fTarget; |
| |
| using INHERITED = KeyframeAnimator; |
| }; |
| |
| class TextExpressionAnimator final : public Animator { |
| public: |
| TextExpressionAnimator(sk_sp<ExpressionEvaluator<SkString>> expression_evaluator, |
| TextValue* target_value) |
| : fExpressionEvaluator(std::move(expression_evaluator)) |
| , fTarget(target_value) {} |
| |
| private: |
| |
| StateChanged onSeek(float t) override { |
| SkString old_value = fTarget->fText; |
| |
| fTarget->fText = fExpressionEvaluator->evaluate(t); |
| |
| return fTarget->fText != old_value; |
| } |
| |
| sk_sp<ExpressionEvaluator<SkString>> fExpressionEvaluator; |
| TextValue* fTarget; |
| }; |
| |
| class TextAnimatorBuilder final : public AnimatorBuilder { |
| public: |
| explicit TextAnimatorBuilder(TextValue* target) |
| : INHERITED(Keyframe::Value::Type::kIndex) |
| , fTarget(target) {} |
| |
| sk_sp<KeyframeAnimator> makeFromKeyframes(const AnimationBuilder& abuilder, |
| const skjson::ArrayValue& jkfs) override { |
| SkASSERT(jkfs.size() > 0); |
| |
| fValues.reserve(jkfs.size()); |
| if (!this->parseKeyframes(abuilder, jkfs)) { |
| return nullptr; |
| } |
| fValues.shrink_to_fit(); |
| |
| return sk_sp<TextKeyframeAnimator>( |
| new TextKeyframeAnimator(std::move(fKFs), |
| std::move(fCMs), |
| std::move(fValues), |
| fTarget)); |
| } |
| |
| sk_sp<Animator> makeFromExpression(ExpressionManager& em, const char* expr) override { |
| sk_sp<ExpressionEvaluator<SkString>> expression_evaluator = |
| em.createStringExpressionEvaluator(expr); |
| return sk_make_sp<TextExpressionAnimator>(expression_evaluator, fTarget); |
| } |
| |
| bool parseValue(const AnimationBuilder& abuilder, const skjson::Value& jv) const override { |
| return Parse(jv, abuilder, fTarget); |
| } |
| |
| private: |
| bool parseKFValue(const AnimationBuilder& abuilder, |
| const skjson::ObjectValue&, |
| const skjson::Value& jv, |
| Keyframe::Value* v) override { |
| TextValue val; |
| if (!Parse(jv, abuilder, &val)) { |
| return false; |
| } |
| |
| // TODO: full deduping? |
| if (fValues.empty() || val != fValues.back()) { |
| fValues.push_back(std::move(val)); |
| } |
| |
| v->idx = SkToU32(fValues.size() - 1); |
| |
| return true; |
| } |
| |
| std::vector<TextValue> fValues; |
| TextValue* fTarget; |
| |
| using INHERITED = AnimatorBuilder; |
| }; |
| |
| } // namespace |
| |
| template <> |
| bool AnimatablePropertyContainer::bind<TextValue>(const AnimationBuilder& abuilder, |
| const skjson::ObjectValue* jprop, |
| TextValue* v) { |
| TextAnimatorBuilder builder(v); |
| return this->bindImpl(abuilder, jprop, builder); |
| } |
| |
| } // namespace skottie::internal |