/* * 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/animator/Animator.h" #include "modules/skottie/src/SkottieJson.h" #include "modules/skottie/src/SkottiePriv.h" #include "modules/skottie/src/animator/KeyframeAnimator.h" namespace skottie::internal { Animator::StateChanged AnimatablePropertyContainer::onSeek(float t) { // The very first seek must trigger a sync, to ensure proper SG setup. bool changed = !fHasSynced; for (const auto& animator : fAnimators) { changed |= animator->seek(t); } if (changed) { this->onSync(); fHasSynced = true; } return changed; } void AnimatablePropertyContainer::attachDiscardableAdapter( sk_sp child) { if (!child) { return; } if (child->isStatic()) { child->seek(0); return; } fAnimators.push_back(child); } void AnimatablePropertyContainer::shrink_to_fit() { fAnimators.shrink_to_fit(); } bool AnimatablePropertyContainer::bindImpl(const AnimationBuilder& abuilder, const skjson::ObjectValue* jprop, AnimatorBuilder& builder) { if (!jprop) { return false; } const auto& jpropA = (*jprop)["a"]; const auto& jpropK = (*jprop)["k"]; // Handle expressions on the property. if (const skjson::StringValue* expr = (*jprop)["x"]) { if (!abuilder.expression_manager()) { abuilder.log(Logger::Level::kWarning, jprop, "Expression encountered but ExpressionManager not provided."); } else { builder.parseValue(abuilder, jpropK); sk_sp expression_animator = builder.makeFromExpression( *abuilder.expression_manager(), expr->begin()); if (expression_animator) { fAnimators.push_back(std::move(expression_animator)); return true; } } } // Older Json versions don't have an "a" animation marker. // For those, we attempt to parse both ways. if (!ParseDefault(jpropA, false)) { if (builder.parseValue(abuilder, jpropK)) { // Static property. return true; } if (!jpropA.is()) { abuilder.log(Logger::Level::kError, jprop, "Could not parse (explicit) static property."); return false; } } // Keyframed property. sk_sp animator; const skjson::ArrayValue* jkfs = jpropK; if (jkfs && jkfs->size() > 0) { animator = builder.makeFromKeyframes(abuilder, *jkfs); } if (!animator) { abuilder.log(Logger::Level::kError, jprop, "Could not parse keyframed property."); return false; } if (animator->isConstant()) { // If all keyframes are constant, there is no reason to treat this // as an animated property - apply immediately and discard the animator. animator->seek(0); } else { fAnimators.push_back(std::move(animator)); } return true; } } // namespace skottie::internal