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/Animator.h"
11#include "modules/skottie/src/animator/KeyframeAnimator.h"
12
13namespace skottie::internal {
14
15namespace  {
16
17    // Scalar specialization: stores scalar values (floats) inline in keyframes.
18class ScalarKeyframeAnimator final : public KeyframeAnimator {
19public:
20    ScalarKeyframeAnimator(std::vector<Keyframe> kfs,
21                           std::vector<SkCubicMap> cms,
22                           ScalarValue* target_value)
23        : INHERITED(std::move(kfs), std::move(cms))
24        , fTarget(target_value) {}
25
26private:
27
28    StateChanged onSeek(float t) override {
29        const auto& lerp_info = this->getLERPInfo(t);
30        const auto  old_value = *fTarget;
31
32        *fTarget = Lerp(lerp_info.vrec0.flt, lerp_info.vrec1.flt, lerp_info.weight);
33
34        return *fTarget != old_value;
35    }
36
37    ScalarValue* fTarget;
38
39    using INHERITED = KeyframeAnimator;
40};
41
42    // Scalar specialization: stores scalar values (floats).
43class ScalarExpressionAnimator final : public Animator {
44public:
45    ScalarExpressionAnimator(sk_sp<ExpressionEvaluator<ScalarValue>> expression_evaluator,
46        ScalarValue* target_value)
47        : fExpressionEvaluator(std::move(expression_evaluator))
48        , fTarget(target_value) {}
49
50private:
51
52    StateChanged onSeek(float t) override {
53        auto old_value = *fTarget;
54
55        *fTarget = fExpressionEvaluator->evaluate(t);
56
57        return *fTarget != old_value;
58    }
59
60    sk_sp<ExpressionEvaluator<ScalarValue>> fExpressionEvaluator;
61    ScalarValue* fTarget;
62};
63
64class ScalarAnimatorBuilder final : public AnimatorBuilder {
65    public:
66        explicit ScalarAnimatorBuilder(ScalarValue* target)
67            : INHERITED(Keyframe::Value::Type::kScalar)
68            , fTarget(target) {}
69
70        sk_sp<KeyframeAnimator> makeFromKeyframes(const AnimationBuilder& abuilder,
71                                     const skjson::ArrayValue& jkfs) override {
72            SkASSERT(jkfs.size() > 0);
73            if (!this->parseKeyframes(abuilder, jkfs)) {
74                return nullptr;
75            }
76
77            return sk_sp<ScalarKeyframeAnimator>(
78                        new ScalarKeyframeAnimator(std::move(fKFs), std::move(fCMs), fTarget));
79        }
80
81        sk_sp<Animator> makeFromExpression(ExpressionManager& em, const char* expr) override {
82            sk_sp<ExpressionEvaluator<ScalarValue>> expression_evaluator =
83                em.createNumberExpressionEvaluator(expr);
84            return sk_make_sp<ScalarExpressionAnimator>(expression_evaluator, fTarget);
85        }
86
87
88        bool parseValue(const AnimationBuilder&, const skjson::Value& jv) const override {
89            return Parse(jv, fTarget);
90        }
91
92    private:
93        bool parseKFValue(const AnimationBuilder&,
94                          const skjson::ObjectValue&,
95                          const skjson::Value& jv,
96                          Keyframe::Value* v) override {
97            return Parse(jv, &v->flt);
98        }
99
100        ScalarValue* fTarget;
101
102        using INHERITED = AnimatorBuilder;
103    };
104
105} // namespace
106
107template <>
108bool AnimatablePropertyContainer::bind<ScalarValue>(const AnimationBuilder& abuilder,
109                                                    const skjson::ObjectValue* jprop,
110                                                    ScalarValue* v) {
111    ScalarAnimatorBuilder builder(v);
112
113    return this->bindImpl(abuilder, jprop, builder);
114}
115
116} // namespace skottie::internal
117