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/animator/Animator.h"
9
10#include "modules/skottie/src/SkottieJson.h"
11#include "modules/skottie/src/SkottiePriv.h"
12#include "modules/skottie/src/animator/KeyframeAnimator.h"
13
14namespace skottie::internal {
15
16Animator::StateChanged AnimatablePropertyContainer::onSeek(float t) {
17 // The very first seek must trigger a sync, to ensure proper SG setup.
18 bool changed = !fHasSynced;
19
20 for (const auto& animator : fAnimators) {
21 changed |= animator->seek(t);
22 }
23
24 if (changed) {
25 this->onSync();
26 fHasSynced = true;
27 }
28
29 return changed;
30}
31
32void AnimatablePropertyContainer::attachDiscardableAdapter(
33 sk_sp<AnimatablePropertyContainer> child) {
34 if (!child) {
35 return;
36 }
37
38 if (child->isStatic()) {
39 child->seek(0);
40 return;
41 }
42
43 fAnimators.push_back(child);
44}
45
46void AnimatablePropertyContainer::shrink_to_fit() {
47 fAnimators.shrink_to_fit();
48}
49
50bool AnimatablePropertyContainer::bindImpl(const AnimationBuilder& abuilder,
51 const skjson::ObjectValue* jprop,
52 KeyframeAnimatorBuilder& builder) {
53 if (!jprop) {
54 return false;
55 }
56
57 const auto& jpropA = (*jprop)["a"];
58 const auto& jpropK = (*jprop)["k"];
59
60 if (!(*jprop)["x"].is<skjson::NullValue>()) {
61 abuilder.log(Logger::Level::kWarning, nullptr, "Unsupported expression.");
62 }
63
64 // Older Json versions don't have an "a" animation marker.
65 // For those, we attempt to parse both ways.
66 if (!ParseDefault<bool>(jpropA, false)) {
67 if (builder.parseValue(abuilder, jpropK)) {
68 // Static property.
69 return true;
70 }
71
72 if (!jpropA.is<skjson::NullValue>()) {
73 abuilder.log(Logger::Level::kError, jprop,
74 "Could not parse (explicit) static property.");
75 return false;
76 }
77 }
78
79 // Keyframed property.
80 sk_sp<KeyframeAnimator> animator;
81 const skjson::ArrayValue* jkfs = jpropK;
82 if (jkfs && jkfs->size() > 0) {
83 animator = builder.make(abuilder, *jkfs);
84 }
85
86 if (!animator) {
87 abuilder.log(Logger::Level::kError, jprop, "Could not parse keyframed property.");
88 return false;
89 }
90
91 if (animator->isConstant()) {
92 // If all keyframes are constant, there is no reason to treat this
93 // as an animated property - apply immediately and discard the animator.
94 animator->seek(0);
95 } else {
96 fAnimators.push_back(std::move(animator));
97 }
98
99 return true;
100}
101
102} // namespace skottie::internal
103