/* * 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 kfs, std::vector cms, std::vector 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 fValues; TextValue* fTarget; using INHERITED = KeyframeAnimator; }; class TextExpressionAnimator final : public Animator { public: TextExpressionAnimator(sk_sp> 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> fExpressionEvaluator; TextValue* fTarget; }; class TextAnimatorBuilder final : public AnimatorBuilder { public: explicit TextAnimatorBuilder(TextValue* target) : INHERITED(Keyframe::Value::Type::kIndex) , fTarget(target) {} sk_sp 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( new TextKeyframeAnimator(std::move(fKFs), std::move(fCMs), std::move(fValues), fTarget)); } sk_sp makeFromExpression(ExpressionManager& em, const char* expr) override { sk_sp> expression_evaluator = em.createStringExpressionEvaluator(expr); return sk_make_sp(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 fValues; TextValue* fTarget; using INHERITED = AnimatorBuilder; }; } // namespace template <> bool AnimatablePropertyContainer::bind(const AnimationBuilder& abuilder, const skjson::ObjectValue* jprop, TextValue* v) { TextAnimatorBuilder builder(v); return this->bindImpl(abuilder, jprop, builder); } } // namespace skottie::internal