1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2017 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/include/Skottie.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFontMgr.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStream.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkFloatingPoint.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTPin.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/include/ExternalLayer.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/include/SkottieProperty.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/include/SlotManager.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/Adapter.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/Composition.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/SkottieJson.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/SkottiePriv.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/SkottieValue.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/Transform.h" // IWYU pragma: keep
29*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/animator/Animator.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/text/TextAdapter.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "modules/sksg/include/SkSGOpacityEffect.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "modules/sksg/include/SkSGRenderNode.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skshaper/include/SkShaper_factory.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTHash.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTraceEvent.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/utils/SkJSON.h"
37*c8dee2aaSAndroid Build Coastguard Worker
38*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
39*c8dee2aaSAndroid Build Coastguard Worker #include <chrono>
40*c8dee2aaSAndroid Build Coastguard Worker #include <cmath>
41*c8dee2aaSAndroid Build Coastguard Worker #include <cstdarg>
42*c8dee2aaSAndroid Build Coastguard Worker #include <cstdio>
43*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
44*c8dee2aaSAndroid Build Coastguard Worker #include <functional>
45*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
46*c8dee2aaSAndroid Build Coastguard Worker #include <ratio>
47*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
48*c8dee2aaSAndroid Build Coastguard Worker
49*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SK_DISABLE_LEGACY_SHAPER_FACTORY)
50*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skshaper/utils/FactoryHelpers.h"
51*c8dee2aaSAndroid Build Coastguard Worker #endif
52*c8dee2aaSAndroid Build Coastguard Worker
53*c8dee2aaSAndroid Build Coastguard Worker namespace sksg {
54*c8dee2aaSAndroid Build Coastguard Worker class Color;
55*c8dee2aaSAndroid Build Coastguard Worker }
56*c8dee2aaSAndroid Build Coastguard Worker
57*c8dee2aaSAndroid Build Coastguard Worker namespace skottie {
58*c8dee2aaSAndroid Build Coastguard Worker
59*c8dee2aaSAndroid Build Coastguard Worker namespace internal {
60*c8dee2aaSAndroid Build Coastguard Worker
setRoot(sk_sp<sksg::RenderNode> root)61*c8dee2aaSAndroid Build Coastguard Worker void SceneGraphRevalidator::setRoot(sk_sp<sksg::RenderNode> root) {
62*c8dee2aaSAndroid Build Coastguard Worker fRoot = std::move(root);
63*c8dee2aaSAndroid Build Coastguard Worker }
64*c8dee2aaSAndroid Build Coastguard Worker
revalidate()65*c8dee2aaSAndroid Build Coastguard Worker void SceneGraphRevalidator::revalidate() {
66*c8dee2aaSAndroid Build Coastguard Worker if (fRoot) {
67*c8dee2aaSAndroid Build Coastguard Worker fRoot->revalidate(nullptr, SkMatrix::I());
68*c8dee2aaSAndroid Build Coastguard Worker }
69*c8dee2aaSAndroid Build Coastguard Worker }
70*c8dee2aaSAndroid Build Coastguard Worker
log(Logger::Level lvl,const skjson::Value * json,const char fmt[],...) const71*c8dee2aaSAndroid Build Coastguard Worker void AnimationBuilder::log(Logger::Level lvl, const skjson::Value* json,
72*c8dee2aaSAndroid Build Coastguard Worker const char fmt[], ...) const {
73*c8dee2aaSAndroid Build Coastguard Worker if (!fLogger) {
74*c8dee2aaSAndroid Build Coastguard Worker return;
75*c8dee2aaSAndroid Build Coastguard Worker }
76*c8dee2aaSAndroid Build Coastguard Worker
77*c8dee2aaSAndroid Build Coastguard Worker char buff[1024];
78*c8dee2aaSAndroid Build Coastguard Worker va_list va;
79*c8dee2aaSAndroid Build Coastguard Worker va_start(va, fmt);
80*c8dee2aaSAndroid Build Coastguard Worker const auto len = vsnprintf(buff, sizeof(buff), fmt, va);
81*c8dee2aaSAndroid Build Coastguard Worker va_end(va);
82*c8dee2aaSAndroid Build Coastguard Worker
83*c8dee2aaSAndroid Build Coastguard Worker if (len < 0) {
84*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("!! Could not format log message !!\n");
85*c8dee2aaSAndroid Build Coastguard Worker return;
86*c8dee2aaSAndroid Build Coastguard Worker }
87*c8dee2aaSAndroid Build Coastguard Worker
88*c8dee2aaSAndroid Build Coastguard Worker if (len >= SkToInt(sizeof(buff))) {
89*c8dee2aaSAndroid Build Coastguard Worker static constexpr char kEllipsesStr[] = "...";
90*c8dee2aaSAndroid Build Coastguard Worker strcpy(buff + sizeof(buff) - sizeof(kEllipsesStr), kEllipsesStr);
91*c8dee2aaSAndroid Build Coastguard Worker }
92*c8dee2aaSAndroid Build Coastguard Worker
93*c8dee2aaSAndroid Build Coastguard Worker SkString jsonstr = json ? json->toString() : SkString();
94*c8dee2aaSAndroid Build Coastguard Worker
95*c8dee2aaSAndroid Build Coastguard Worker fLogger->log(lvl, buff, jsonstr.c_str());
96*c8dee2aaSAndroid Build Coastguard Worker }
97*c8dee2aaSAndroid Build Coastguard Worker
98*c8dee2aaSAndroid Build Coastguard Worker class OpacityAdapter final : public DiscardableAdapterBase<OpacityAdapter, sksg::OpacityEffect> {
99*c8dee2aaSAndroid Build Coastguard Worker public:
OpacityAdapter(const skjson::ObjectValue & jobject,sk_sp<sksg::RenderNode> child,const AnimationBuilder & abuilder)100*c8dee2aaSAndroid Build Coastguard Worker OpacityAdapter(const skjson::ObjectValue& jobject,
101*c8dee2aaSAndroid Build Coastguard Worker sk_sp<sksg::RenderNode> child,
102*c8dee2aaSAndroid Build Coastguard Worker const AnimationBuilder& abuilder)
103*c8dee2aaSAndroid Build Coastguard Worker : INHERITED(sksg::OpacityEffect::Make(std::move(child))) {
104*c8dee2aaSAndroid Build Coastguard Worker this->bind(abuilder, jobject["o"], fOpacity);
105*c8dee2aaSAndroid Build Coastguard Worker }
106*c8dee2aaSAndroid Build Coastguard Worker
107*c8dee2aaSAndroid Build Coastguard Worker private:
onSync()108*c8dee2aaSAndroid Build Coastguard Worker void onSync() override {
109*c8dee2aaSAndroid Build Coastguard Worker this->node()->setOpacity(fOpacity * 0.01f);
110*c8dee2aaSAndroid Build Coastguard Worker }
111*c8dee2aaSAndroid Build Coastguard Worker
112*c8dee2aaSAndroid Build Coastguard Worker ScalarValue fOpacity = 100;
113*c8dee2aaSAndroid Build Coastguard Worker
114*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = DiscardableAdapterBase<OpacityAdapter, sksg::OpacityEffect>;
115*c8dee2aaSAndroid Build Coastguard Worker };
116*c8dee2aaSAndroid Build Coastguard Worker
117*c8dee2aaSAndroid Build Coastguard Worker
attachOpacity(const skjson::ObjectValue & jobject,sk_sp<sksg::RenderNode> child_node) const118*c8dee2aaSAndroid Build Coastguard Worker sk_sp<sksg::RenderNode> AnimationBuilder::attachOpacity(const skjson::ObjectValue& jobject,
119*c8dee2aaSAndroid Build Coastguard Worker sk_sp<sksg::RenderNode> child_node) const {
120*c8dee2aaSAndroid Build Coastguard Worker if (!child_node)
121*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
122*c8dee2aaSAndroid Build Coastguard Worker
123*c8dee2aaSAndroid Build Coastguard Worker auto adapter = OpacityAdapter::Make(jobject, child_node, *this);
124*c8dee2aaSAndroid Build Coastguard Worker if (adapter->isStatic()) {
125*c8dee2aaSAndroid Build Coastguard Worker adapter->seek(0);
126*c8dee2aaSAndroid Build Coastguard Worker }
127*c8dee2aaSAndroid Build Coastguard Worker auto dispatched = this->dispatchOpacityProperty(adapter->node());
128*c8dee2aaSAndroid Build Coastguard Worker if (adapter->isStatic()) {
129*c8dee2aaSAndroid Build Coastguard Worker if (!dispatched && adapter->node()->getOpacity() >= 1) {
130*c8dee2aaSAndroid Build Coastguard Worker // No obeservable effects - we can discard.
131*c8dee2aaSAndroid Build Coastguard Worker return child_node;
132*c8dee2aaSAndroid Build Coastguard Worker }
133*c8dee2aaSAndroid Build Coastguard Worker } else {
134*c8dee2aaSAndroid Build Coastguard Worker fCurrentAnimatorScope->push_back(adapter);
135*c8dee2aaSAndroid Build Coastguard Worker }
136*c8dee2aaSAndroid Build Coastguard Worker
137*c8dee2aaSAndroid Build Coastguard Worker return adapter->node();
138*c8dee2aaSAndroid Build Coastguard Worker }
139*c8dee2aaSAndroid Build Coastguard Worker
AnimationBuilder(sk_sp<ResourceProvider> rp,sk_sp<SkFontMgr> fontmgr,sk_sp<PropertyObserver> pobserver,sk_sp<Logger> logger,sk_sp<MarkerObserver> mobserver,sk_sp<PrecompInterceptor> pi,sk_sp<ExpressionManager> expressionmgr,sk_sp<SkShapers::Factory> shapingFactory,Animation::Builder::Stats * stats,const SkSize & comp_size,float duration,float framerate,uint32_t flags)140*c8dee2aaSAndroid Build Coastguard Worker AnimationBuilder::AnimationBuilder(sk_sp<ResourceProvider> rp, sk_sp<SkFontMgr> fontmgr,
141*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PropertyObserver> pobserver, sk_sp<Logger> logger,
142*c8dee2aaSAndroid Build Coastguard Worker sk_sp<MarkerObserver> mobserver, sk_sp<PrecompInterceptor> pi,
143*c8dee2aaSAndroid Build Coastguard Worker sk_sp<ExpressionManager> expressionmgr,
144*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShapers::Factory> shapingFactory,
145*c8dee2aaSAndroid Build Coastguard Worker Animation::Builder::Stats* stats,
146*c8dee2aaSAndroid Build Coastguard Worker const SkSize& comp_size, float duration, float framerate,
147*c8dee2aaSAndroid Build Coastguard Worker uint32_t flags)
148*c8dee2aaSAndroid Build Coastguard Worker : fResourceProvider(std::move(rp))
149*c8dee2aaSAndroid Build Coastguard Worker , fFontMgr(std::move(fontmgr))
150*c8dee2aaSAndroid Build Coastguard Worker , fPropertyObserver(std::move(pobserver))
151*c8dee2aaSAndroid Build Coastguard Worker , fLogger(std::move(logger))
152*c8dee2aaSAndroid Build Coastguard Worker , fMarkerObserver(std::move(mobserver))
153*c8dee2aaSAndroid Build Coastguard Worker , fPrecompInterceptor(std::move(pi))
154*c8dee2aaSAndroid Build Coastguard Worker , fExpressionManager(std::move(expressionmgr))
155*c8dee2aaSAndroid Build Coastguard Worker , fShapingFactory(std::move(shapingFactory))
156*c8dee2aaSAndroid Build Coastguard Worker , fRevalidator(sk_make_sp<SceneGraphRevalidator>())
157*c8dee2aaSAndroid Build Coastguard Worker , fSlotManager(sk_make_sp<SlotManager>(fRevalidator))
158*c8dee2aaSAndroid Build Coastguard Worker , fStats(stats)
159*c8dee2aaSAndroid Build Coastguard Worker , fCompSize(comp_size)
160*c8dee2aaSAndroid Build Coastguard Worker , fDuration(duration)
161*c8dee2aaSAndroid Build Coastguard Worker , fFrameRate(framerate)
162*c8dee2aaSAndroid Build Coastguard Worker , fFlags(flags)
163*c8dee2aaSAndroid Build Coastguard Worker , fHasNontrivialBlending(false) {}
164*c8dee2aaSAndroid Build Coastguard Worker
parse(const skjson::ObjectValue & jroot)165*c8dee2aaSAndroid Build Coastguard Worker AnimationBuilder::AnimationInfo AnimationBuilder::parse(const skjson::ObjectValue& jroot) {
166*c8dee2aaSAndroid Build Coastguard Worker this->dispatchMarkers(jroot["markers"]);
167*c8dee2aaSAndroid Build Coastguard Worker
168*c8dee2aaSAndroid Build Coastguard Worker AutoScope ascope(this);
169*c8dee2aaSAndroid Build Coastguard Worker AutoPropertyTracker apt(this, jroot, PropertyObserver::NodeType::COMPOSITION);
170*c8dee2aaSAndroid Build Coastguard Worker
171*c8dee2aaSAndroid Build Coastguard Worker this->parseAssets(jroot["assets"]);
172*c8dee2aaSAndroid Build Coastguard Worker this->parseFonts(jroot["fonts"], jroot["chars"]);
173*c8dee2aaSAndroid Build Coastguard Worker fSlotsRoot = jroot["slots"];
174*c8dee2aaSAndroid Build Coastguard Worker
175*c8dee2aaSAndroid Build Coastguard Worker auto root = CompositionBuilder(*this, fCompSize, jroot).build(*this);
176*c8dee2aaSAndroid Build Coastguard Worker
177*c8dee2aaSAndroid Build Coastguard Worker auto animators = ascope.release();
178*c8dee2aaSAndroid Build Coastguard Worker fStats->fAnimatorCount = animators.size();
179*c8dee2aaSAndroid Build Coastguard Worker
180*c8dee2aaSAndroid Build Coastguard Worker // Point the revalidator to our final root, and perform initial revalidation.
181*c8dee2aaSAndroid Build Coastguard Worker fRevalidator->setRoot(root);
182*c8dee2aaSAndroid Build Coastguard Worker fRevalidator->revalidate();
183*c8dee2aaSAndroid Build Coastguard Worker
184*c8dee2aaSAndroid Build Coastguard Worker return { std::move(root), std::move(animators), std::move(fSlotManager)};
185*c8dee2aaSAndroid Build Coastguard Worker }
186*c8dee2aaSAndroid Build Coastguard Worker
parseAssets(const skjson::ArrayValue * jassets)187*c8dee2aaSAndroid Build Coastguard Worker void AnimationBuilder::parseAssets(const skjson::ArrayValue* jassets) {
188*c8dee2aaSAndroid Build Coastguard Worker if (!jassets) {
189*c8dee2aaSAndroid Build Coastguard Worker return;
190*c8dee2aaSAndroid Build Coastguard Worker }
191*c8dee2aaSAndroid Build Coastguard Worker
192*c8dee2aaSAndroid Build Coastguard Worker for (const skjson::ObjectValue* asset : *jassets) {
193*c8dee2aaSAndroid Build Coastguard Worker if (asset) {
194*c8dee2aaSAndroid Build Coastguard Worker fAssets.set(ParseDefault<SkString>((*asset)["id"], SkString()), { asset, false });
195*c8dee2aaSAndroid Build Coastguard Worker }
196*c8dee2aaSAndroid Build Coastguard Worker }
197*c8dee2aaSAndroid Build Coastguard Worker }
198*c8dee2aaSAndroid Build Coastguard Worker
dispatchMarkers(const skjson::ArrayValue * jmarkers) const199*c8dee2aaSAndroid Build Coastguard Worker void AnimationBuilder::dispatchMarkers(const skjson::ArrayValue* jmarkers) const {
200*c8dee2aaSAndroid Build Coastguard Worker if (!fMarkerObserver || !jmarkers) {
201*c8dee2aaSAndroid Build Coastguard Worker return;
202*c8dee2aaSAndroid Build Coastguard Worker }
203*c8dee2aaSAndroid Build Coastguard Worker
204*c8dee2aaSAndroid Build Coastguard Worker // For frame-number -> t conversions.
205*c8dee2aaSAndroid Build Coastguard Worker const auto frameRatio = 1 / (fFrameRate * fDuration);
206*c8dee2aaSAndroid Build Coastguard Worker
207*c8dee2aaSAndroid Build Coastguard Worker for (const skjson::ObjectValue* m : *jmarkers) {
208*c8dee2aaSAndroid Build Coastguard Worker if (!m) continue;
209*c8dee2aaSAndroid Build Coastguard Worker
210*c8dee2aaSAndroid Build Coastguard Worker const skjson::StringValue* name = (*m)["cm"];
211*c8dee2aaSAndroid Build Coastguard Worker const auto time = ParseDefault((*m)["tm"], -1.0f),
212*c8dee2aaSAndroid Build Coastguard Worker duration = ParseDefault((*m)["dr"], -1.0f);
213*c8dee2aaSAndroid Build Coastguard Worker
214*c8dee2aaSAndroid Build Coastguard Worker if (name && time >= 0 && duration >= 0) {
215*c8dee2aaSAndroid Build Coastguard Worker fMarkerObserver->onMarker(
216*c8dee2aaSAndroid Build Coastguard Worker name->begin(),
217*c8dee2aaSAndroid Build Coastguard Worker // "tm" is in frames
218*c8dee2aaSAndroid Build Coastguard Worker time * frameRatio,
219*c8dee2aaSAndroid Build Coastguard Worker // ... as is "dr"
220*c8dee2aaSAndroid Build Coastguard Worker (time + duration) * frameRatio
221*c8dee2aaSAndroid Build Coastguard Worker );
222*c8dee2aaSAndroid Build Coastguard Worker } else {
223*c8dee2aaSAndroid Build Coastguard Worker this->log(Logger::Level::kWarning, m, "Ignoring unexpected marker.");
224*c8dee2aaSAndroid Build Coastguard Worker }
225*c8dee2aaSAndroid Build Coastguard Worker }
226*c8dee2aaSAndroid Build Coastguard Worker }
227*c8dee2aaSAndroid Build Coastguard Worker
dispatchColorProperty(const sk_sp<sksg::Color> & c) const228*c8dee2aaSAndroid Build Coastguard Worker bool AnimationBuilder::dispatchColorProperty(const sk_sp<sksg::Color>& c) const {
229*c8dee2aaSAndroid Build Coastguard Worker bool dispatched = false;
230*c8dee2aaSAndroid Build Coastguard Worker if (fPropertyObserver) {
231*c8dee2aaSAndroid Build Coastguard Worker const char * node_name = fPropertyObserverContext;
232*c8dee2aaSAndroid Build Coastguard Worker fPropertyObserver->onColorProperty(node_name,
233*c8dee2aaSAndroid Build Coastguard Worker [&]() {
234*c8dee2aaSAndroid Build Coastguard Worker dispatched = true;
235*c8dee2aaSAndroid Build Coastguard Worker return std::make_unique<ColorPropertyHandle>(c, fRevalidator);
236*c8dee2aaSAndroid Build Coastguard Worker });
237*c8dee2aaSAndroid Build Coastguard Worker }
238*c8dee2aaSAndroid Build Coastguard Worker
239*c8dee2aaSAndroid Build Coastguard Worker return dispatched;
240*c8dee2aaSAndroid Build Coastguard Worker }
241*c8dee2aaSAndroid Build Coastguard Worker
dispatchOpacityProperty(const sk_sp<sksg::OpacityEffect> & o) const242*c8dee2aaSAndroid Build Coastguard Worker bool AnimationBuilder::dispatchOpacityProperty(const sk_sp<sksg::OpacityEffect>& o) const {
243*c8dee2aaSAndroid Build Coastguard Worker bool dispatched = false;
244*c8dee2aaSAndroid Build Coastguard Worker
245*c8dee2aaSAndroid Build Coastguard Worker if (fPropertyObserver) {
246*c8dee2aaSAndroid Build Coastguard Worker fPropertyObserver->onOpacityProperty(fPropertyObserverContext,
247*c8dee2aaSAndroid Build Coastguard Worker [&]() {
248*c8dee2aaSAndroid Build Coastguard Worker dispatched = true;
249*c8dee2aaSAndroid Build Coastguard Worker return std::make_unique<OpacityPropertyHandle>(o, fRevalidator);
250*c8dee2aaSAndroid Build Coastguard Worker });
251*c8dee2aaSAndroid Build Coastguard Worker }
252*c8dee2aaSAndroid Build Coastguard Worker
253*c8dee2aaSAndroid Build Coastguard Worker return dispatched;
254*c8dee2aaSAndroid Build Coastguard Worker }
255*c8dee2aaSAndroid Build Coastguard Worker
dispatchTextProperty(const sk_sp<TextAdapter> & t,const skjson::ObjectValue * jtext) const256*c8dee2aaSAndroid Build Coastguard Worker bool AnimationBuilder::dispatchTextProperty(const sk_sp<TextAdapter>& t,
257*c8dee2aaSAndroid Build Coastguard Worker const skjson::ObjectValue* jtext) const {
258*c8dee2aaSAndroid Build Coastguard Worker bool dispatched = false;
259*c8dee2aaSAndroid Build Coastguard Worker
260*c8dee2aaSAndroid Build Coastguard Worker if (jtext) {
261*c8dee2aaSAndroid Build Coastguard Worker if (const skjson::StringValue* slotID = (*jtext)["sid"]) {
262*c8dee2aaSAndroid Build Coastguard Worker fSlotManager->trackTextValue(SkString(slotID->begin()), t);
263*c8dee2aaSAndroid Build Coastguard Worker dispatched = true;
264*c8dee2aaSAndroid Build Coastguard Worker }
265*c8dee2aaSAndroid Build Coastguard Worker }
266*c8dee2aaSAndroid Build Coastguard Worker
267*c8dee2aaSAndroid Build Coastguard Worker if (fPropertyObserver) {
268*c8dee2aaSAndroid Build Coastguard Worker fPropertyObserver->onTextProperty(fPropertyObserverContext,
269*c8dee2aaSAndroid Build Coastguard Worker [&]() {
270*c8dee2aaSAndroid Build Coastguard Worker dispatched = true;
271*c8dee2aaSAndroid Build Coastguard Worker return std::make_unique<TextPropertyHandle>(t, fRevalidator);
272*c8dee2aaSAndroid Build Coastguard Worker });
273*c8dee2aaSAndroid Build Coastguard Worker }
274*c8dee2aaSAndroid Build Coastguard Worker
275*c8dee2aaSAndroid Build Coastguard Worker return dispatched;
276*c8dee2aaSAndroid Build Coastguard Worker }
277*c8dee2aaSAndroid Build Coastguard Worker
dispatchTransformProperty(const sk_sp<TransformAdapter2D> & t) const278*c8dee2aaSAndroid Build Coastguard Worker bool AnimationBuilder::dispatchTransformProperty(const sk_sp<TransformAdapter2D>& t) const {
279*c8dee2aaSAndroid Build Coastguard Worker bool dispatched = false;
280*c8dee2aaSAndroid Build Coastguard Worker
281*c8dee2aaSAndroid Build Coastguard Worker if (fPropertyObserver) {
282*c8dee2aaSAndroid Build Coastguard Worker fPropertyObserver->onTransformProperty(fPropertyObserverContext,
283*c8dee2aaSAndroid Build Coastguard Worker [&]() {
284*c8dee2aaSAndroid Build Coastguard Worker dispatched = true;
285*c8dee2aaSAndroid Build Coastguard Worker return std::make_unique<TransformPropertyHandle>(t, fRevalidator);
286*c8dee2aaSAndroid Build Coastguard Worker });
287*c8dee2aaSAndroid Build Coastguard Worker }
288*c8dee2aaSAndroid Build Coastguard Worker
289*c8dee2aaSAndroid Build Coastguard Worker return dispatched;
290*c8dee2aaSAndroid Build Coastguard Worker }
291*c8dee2aaSAndroid Build Coastguard Worker
expression_manager() const292*c8dee2aaSAndroid Build Coastguard Worker sk_sp<ExpressionManager> AnimationBuilder::expression_manager() const {
293*c8dee2aaSAndroid Build Coastguard Worker return fExpressionManager;
294*c8dee2aaSAndroid Build Coastguard Worker }
295*c8dee2aaSAndroid Build Coastguard Worker
updateContext(PropertyObserver * observer,const skjson::ObjectValue & obj)296*c8dee2aaSAndroid Build Coastguard Worker void AnimationBuilder::AutoPropertyTracker::updateContext(PropertyObserver* observer,
297*c8dee2aaSAndroid Build Coastguard Worker const skjson::ObjectValue& obj) {
298*c8dee2aaSAndroid Build Coastguard Worker const skjson::StringValue* name = obj["nm"];
299*c8dee2aaSAndroid Build Coastguard Worker fBuilder->fPropertyObserverContext = name ? name->begin() : fPrevContext;
300*c8dee2aaSAndroid Build Coastguard Worker }
301*c8dee2aaSAndroid Build Coastguard Worker
302*c8dee2aaSAndroid Build Coastguard Worker } // namespace internal
303*c8dee2aaSAndroid Build Coastguard Worker
Builder(uint32_t flags)304*c8dee2aaSAndroid Build Coastguard Worker Animation::Builder::Builder(uint32_t flags) : fFlags(flags) {}
305*c8dee2aaSAndroid Build Coastguard Worker Animation::Builder::Builder(const Builder&) = default;
306*c8dee2aaSAndroid Build Coastguard Worker Animation::Builder::Builder(Builder&&) = default;
307*c8dee2aaSAndroid Build Coastguard Worker Animation::Builder::~Builder() = default;
308*c8dee2aaSAndroid Build Coastguard Worker
setResourceProvider(sk_sp<ResourceProvider> rp)309*c8dee2aaSAndroid Build Coastguard Worker Animation::Builder& Animation::Builder::setResourceProvider(sk_sp<ResourceProvider> rp) {
310*c8dee2aaSAndroid Build Coastguard Worker fResourceProvider = std::move(rp);
311*c8dee2aaSAndroid Build Coastguard Worker return *this;
312*c8dee2aaSAndroid Build Coastguard Worker }
313*c8dee2aaSAndroid Build Coastguard Worker
setFontManager(sk_sp<SkFontMgr> fmgr)314*c8dee2aaSAndroid Build Coastguard Worker Animation::Builder& Animation::Builder::setFontManager(sk_sp<SkFontMgr> fmgr) {
315*c8dee2aaSAndroid Build Coastguard Worker fFontMgr = std::move(fmgr);
316*c8dee2aaSAndroid Build Coastguard Worker return *this;
317*c8dee2aaSAndroid Build Coastguard Worker }
318*c8dee2aaSAndroid Build Coastguard Worker
setPropertyObserver(sk_sp<PropertyObserver> pobserver)319*c8dee2aaSAndroid Build Coastguard Worker Animation::Builder& Animation::Builder::setPropertyObserver(sk_sp<PropertyObserver> pobserver) {
320*c8dee2aaSAndroid Build Coastguard Worker fPropertyObserver = std::move(pobserver);
321*c8dee2aaSAndroid Build Coastguard Worker return *this;
322*c8dee2aaSAndroid Build Coastguard Worker }
323*c8dee2aaSAndroid Build Coastguard Worker
setLogger(sk_sp<Logger> logger)324*c8dee2aaSAndroid Build Coastguard Worker Animation::Builder& Animation::Builder::setLogger(sk_sp<Logger> logger) {
325*c8dee2aaSAndroid Build Coastguard Worker fLogger = std::move(logger);
326*c8dee2aaSAndroid Build Coastguard Worker return *this;
327*c8dee2aaSAndroid Build Coastguard Worker }
328*c8dee2aaSAndroid Build Coastguard Worker
setMarkerObserver(sk_sp<MarkerObserver> mobserver)329*c8dee2aaSAndroid Build Coastguard Worker Animation::Builder& Animation::Builder::setMarkerObserver(sk_sp<MarkerObserver> mobserver) {
330*c8dee2aaSAndroid Build Coastguard Worker fMarkerObserver = std::move(mobserver);
331*c8dee2aaSAndroid Build Coastguard Worker return *this;
332*c8dee2aaSAndroid Build Coastguard Worker }
333*c8dee2aaSAndroid Build Coastguard Worker
setPrecompInterceptor(sk_sp<PrecompInterceptor> pi)334*c8dee2aaSAndroid Build Coastguard Worker Animation::Builder& Animation::Builder::setPrecompInterceptor(sk_sp<PrecompInterceptor> pi) {
335*c8dee2aaSAndroid Build Coastguard Worker fPrecompInterceptor = std::move(pi);
336*c8dee2aaSAndroid Build Coastguard Worker return *this;
337*c8dee2aaSAndroid Build Coastguard Worker }
338*c8dee2aaSAndroid Build Coastguard Worker
setExpressionManager(sk_sp<ExpressionManager> em)339*c8dee2aaSAndroid Build Coastguard Worker Animation::Builder& Animation::Builder::setExpressionManager(sk_sp<ExpressionManager> em) {
340*c8dee2aaSAndroid Build Coastguard Worker fExpressionManager = std::move(em);
341*c8dee2aaSAndroid Build Coastguard Worker return *this;
342*c8dee2aaSAndroid Build Coastguard Worker }
343*c8dee2aaSAndroid Build Coastguard Worker
setTextShapingFactory(sk_sp<SkShapers::Factory> factory)344*c8dee2aaSAndroid Build Coastguard Worker Animation::Builder& Animation::Builder::setTextShapingFactory(sk_sp<SkShapers::Factory> factory) {
345*c8dee2aaSAndroid Build Coastguard Worker fShapingFactory = std::move(factory);
346*c8dee2aaSAndroid Build Coastguard Worker return *this;
347*c8dee2aaSAndroid Build Coastguard Worker }
348*c8dee2aaSAndroid Build Coastguard Worker
make(SkStream * stream)349*c8dee2aaSAndroid Build Coastguard Worker sk_sp<Animation> Animation::Builder::make(SkStream* stream) {
350*c8dee2aaSAndroid Build Coastguard Worker if (!stream->hasLength()) {
351*c8dee2aaSAndroid Build Coastguard Worker // TODO: handle explicit buffering?
352*c8dee2aaSAndroid Build Coastguard Worker if (fLogger) {
353*c8dee2aaSAndroid Build Coastguard Worker fLogger->log(Logger::Level::kError, "Cannot parse streaming content.\n");
354*c8dee2aaSAndroid Build Coastguard Worker }
355*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
356*c8dee2aaSAndroid Build Coastguard Worker }
357*c8dee2aaSAndroid Build Coastguard Worker
358*c8dee2aaSAndroid Build Coastguard Worker auto data = SkData::MakeFromStream(stream, stream->getLength());
359*c8dee2aaSAndroid Build Coastguard Worker if (!data) {
360*c8dee2aaSAndroid Build Coastguard Worker if (fLogger) {
361*c8dee2aaSAndroid Build Coastguard Worker fLogger->log(Logger::Level::kError, "Failed to read the input stream.\n");
362*c8dee2aaSAndroid Build Coastguard Worker }
363*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
364*c8dee2aaSAndroid Build Coastguard Worker }
365*c8dee2aaSAndroid Build Coastguard Worker
366*c8dee2aaSAndroid Build Coastguard Worker return this->make(static_cast<const char*>(data->data()), data->size());
367*c8dee2aaSAndroid Build Coastguard Worker }
368*c8dee2aaSAndroid Build Coastguard Worker
make(const char * data,size_t data_len)369*c8dee2aaSAndroid Build Coastguard Worker sk_sp<Animation> Animation::Builder::make(const char* data, size_t data_len) {
370*c8dee2aaSAndroid Build Coastguard Worker TRACE_EVENT0("skottie", TRACE_FUNC);
371*c8dee2aaSAndroid Build Coastguard Worker
372*c8dee2aaSAndroid Build Coastguard Worker // Sanitize factory args.
373*c8dee2aaSAndroid Build Coastguard Worker class NullResourceProvider final : public ResourceProvider {
374*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> load(const char[], const char[]) const override { return nullptr; }
375*c8dee2aaSAndroid Build Coastguard Worker };
376*c8dee2aaSAndroid Build Coastguard Worker auto resolvedProvider = fResourceProvider
377*c8dee2aaSAndroid Build Coastguard Worker ? fResourceProvider : sk_make_sp<NullResourceProvider>();
378*c8dee2aaSAndroid Build Coastguard Worker
379*c8dee2aaSAndroid Build Coastguard Worker fStats = Stats{};
380*c8dee2aaSAndroid Build Coastguard Worker
381*c8dee2aaSAndroid Build Coastguard Worker fStats.fJsonSize = data_len;
382*c8dee2aaSAndroid Build Coastguard Worker const auto t0 = std::chrono::steady_clock::now();
383*c8dee2aaSAndroid Build Coastguard Worker
384*c8dee2aaSAndroid Build Coastguard Worker const skjson::DOM dom(data, data_len);
385*c8dee2aaSAndroid Build Coastguard Worker if (!dom.root().is<skjson::ObjectValue>()) {
386*c8dee2aaSAndroid Build Coastguard Worker // TODO: more error info.
387*c8dee2aaSAndroid Build Coastguard Worker if (fLogger) {
388*c8dee2aaSAndroid Build Coastguard Worker fLogger->log(Logger::Level::kError, "Failed to parse JSON input.\n");
389*c8dee2aaSAndroid Build Coastguard Worker }
390*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
391*c8dee2aaSAndroid Build Coastguard Worker }
392*c8dee2aaSAndroid Build Coastguard Worker const auto& json = dom.root().as<skjson::ObjectValue>();
393*c8dee2aaSAndroid Build Coastguard Worker
394*c8dee2aaSAndroid Build Coastguard Worker const auto t1 = std::chrono::steady_clock::now();
395*c8dee2aaSAndroid Build Coastguard Worker fStats.fJsonParseTimeMS = std::chrono::duration<float, std::milli>{t1-t0}.count();
396*c8dee2aaSAndroid Build Coastguard Worker
397*c8dee2aaSAndroid Build Coastguard Worker const auto version = ParseDefault<SkString>(json["v"], SkString());
398*c8dee2aaSAndroid Build Coastguard Worker const auto size = SkSize::Make(ParseDefault<float>(json["w"], 0.0f),
399*c8dee2aaSAndroid Build Coastguard Worker ParseDefault<float>(json["h"], 0.0f));
400*c8dee2aaSAndroid Build Coastguard Worker const auto fps = ParseDefault<float>(json["fr"], -1.0f),
401*c8dee2aaSAndroid Build Coastguard Worker inPoint = ParseDefault<float>(json["ip"], 0.0f),
402*c8dee2aaSAndroid Build Coastguard Worker outPoint = std::max(ParseDefault<float>(json["op"], SK_ScalarMax), inPoint),
403*c8dee2aaSAndroid Build Coastguard Worker duration = sk_ieee_float_divide(outPoint - inPoint, fps);
404*c8dee2aaSAndroid Build Coastguard Worker
405*c8dee2aaSAndroid Build Coastguard Worker if (size.isEmpty() || version.isEmpty() || fps <= 0 ||
406*c8dee2aaSAndroid Build Coastguard Worker !SkIsFinite(inPoint, outPoint, duration)) {
407*c8dee2aaSAndroid Build Coastguard Worker if (fLogger) {
408*c8dee2aaSAndroid Build Coastguard Worker const auto msg = SkStringPrintf(
409*c8dee2aaSAndroid Build Coastguard Worker "Invalid animation params (version: %s, size: [%f %f], frame rate: %f, "
410*c8dee2aaSAndroid Build Coastguard Worker "in-point: %f, out-point: %f)\n",
411*c8dee2aaSAndroid Build Coastguard Worker version.c_str(), size.width(), size.height(), fps, inPoint, outPoint);
412*c8dee2aaSAndroid Build Coastguard Worker fLogger->log(Logger::Level::kError, msg.c_str());
413*c8dee2aaSAndroid Build Coastguard Worker }
414*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
415*c8dee2aaSAndroid Build Coastguard Worker }
416*c8dee2aaSAndroid Build Coastguard Worker
417*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_DISABLE_LEGACY_SHAPER_FACTORY)
418*c8dee2aaSAndroid Build Coastguard Worker auto factory = fShapingFactory ? fShapingFactory : ::SkShapers::Primitive::Factory();
419*c8dee2aaSAndroid Build Coastguard Worker #else
420*c8dee2aaSAndroid Build Coastguard Worker auto factory = fShapingFactory ? fShapingFactory : ::SkShapers::BestAvailable();
421*c8dee2aaSAndroid Build Coastguard Worker #endif
422*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(resolvedProvider);
423*c8dee2aaSAndroid Build Coastguard Worker internal::AnimationBuilder builder(std::move(resolvedProvider), fFontMgr,
424*c8dee2aaSAndroid Build Coastguard Worker std::move(fPropertyObserver),
425*c8dee2aaSAndroid Build Coastguard Worker std::move(fLogger),
426*c8dee2aaSAndroid Build Coastguard Worker std::move(fMarkerObserver),
427*c8dee2aaSAndroid Build Coastguard Worker std::move(fPrecompInterceptor),
428*c8dee2aaSAndroid Build Coastguard Worker std::move(fExpressionManager),
429*c8dee2aaSAndroid Build Coastguard Worker std::move(factory),
430*c8dee2aaSAndroid Build Coastguard Worker &fStats, size, duration, fps, fFlags);
431*c8dee2aaSAndroid Build Coastguard Worker auto ainfo = builder.parse(json);
432*c8dee2aaSAndroid Build Coastguard Worker
433*c8dee2aaSAndroid Build Coastguard Worker fSlotManager = ainfo.fSlotManager;
434*c8dee2aaSAndroid Build Coastguard Worker
435*c8dee2aaSAndroid Build Coastguard Worker const auto t2 = std::chrono::steady_clock::now();
436*c8dee2aaSAndroid Build Coastguard Worker fStats.fSceneParseTimeMS = std::chrono::duration<float, std::milli>{t2-t1}.count();
437*c8dee2aaSAndroid Build Coastguard Worker fStats.fTotalLoadTimeMS = std::chrono::duration<float, std::milli>{t2-t0}.count();
438*c8dee2aaSAndroid Build Coastguard Worker
439*c8dee2aaSAndroid Build Coastguard Worker if (!ainfo.fSceneRoot && fLogger) {
440*c8dee2aaSAndroid Build Coastguard Worker fLogger->log(Logger::Level::kError, "Could not parse animation.\n");
441*c8dee2aaSAndroid Build Coastguard Worker }
442*c8dee2aaSAndroid Build Coastguard Worker
443*c8dee2aaSAndroid Build Coastguard Worker uint32_t flags = 0;
444*c8dee2aaSAndroid Build Coastguard Worker if (builder.hasNontrivialBlending()) {
445*c8dee2aaSAndroid Build Coastguard Worker flags |= Animation::Flags::kRequiresTopLevelIsolation;
446*c8dee2aaSAndroid Build Coastguard Worker }
447*c8dee2aaSAndroid Build Coastguard Worker
448*c8dee2aaSAndroid Build Coastguard Worker return sk_sp<Animation>(new Animation(std::move(ainfo.fSceneRoot),
449*c8dee2aaSAndroid Build Coastguard Worker std::move(ainfo.fAnimators),
450*c8dee2aaSAndroid Build Coastguard Worker std::move(version),
451*c8dee2aaSAndroid Build Coastguard Worker size,
452*c8dee2aaSAndroid Build Coastguard Worker inPoint,
453*c8dee2aaSAndroid Build Coastguard Worker outPoint,
454*c8dee2aaSAndroid Build Coastguard Worker duration,
455*c8dee2aaSAndroid Build Coastguard Worker fps,
456*c8dee2aaSAndroid Build Coastguard Worker flags));
457*c8dee2aaSAndroid Build Coastguard Worker }
458*c8dee2aaSAndroid Build Coastguard Worker
makeFromFile(const char path[])459*c8dee2aaSAndroid Build Coastguard Worker sk_sp<Animation> Animation::Builder::makeFromFile(const char path[]) {
460*c8dee2aaSAndroid Build Coastguard Worker const auto data = SkData::MakeFromFileName(path);
461*c8dee2aaSAndroid Build Coastguard Worker
462*c8dee2aaSAndroid Build Coastguard Worker return data ? this->make(static_cast<const char*>(data->data()), data->size())
463*c8dee2aaSAndroid Build Coastguard Worker : nullptr;
464*c8dee2aaSAndroid Build Coastguard Worker }
465*c8dee2aaSAndroid Build Coastguard Worker
Animation(sk_sp<sksg::RenderNode> scene_root,std::vector<sk_sp<internal::Animator>> && animators,SkString version,const SkSize & size,double inPoint,double outPoint,double duration,double fps,uint32_t flags)466*c8dee2aaSAndroid Build Coastguard Worker Animation::Animation(sk_sp<sksg::RenderNode> scene_root,
467*c8dee2aaSAndroid Build Coastguard Worker std::vector<sk_sp<internal::Animator>>&& animators,
468*c8dee2aaSAndroid Build Coastguard Worker SkString version, const SkSize& size,
469*c8dee2aaSAndroid Build Coastguard Worker double inPoint, double outPoint, double duration, double fps, uint32_t flags)
470*c8dee2aaSAndroid Build Coastguard Worker : fSceneRoot(std::move(scene_root))
471*c8dee2aaSAndroid Build Coastguard Worker , fAnimators(std::move(animators))
472*c8dee2aaSAndroid Build Coastguard Worker , fVersion(std::move(version))
473*c8dee2aaSAndroid Build Coastguard Worker , fSize(size)
474*c8dee2aaSAndroid Build Coastguard Worker , fInPoint(inPoint)
475*c8dee2aaSAndroid Build Coastguard Worker , fOutPoint(outPoint)
476*c8dee2aaSAndroid Build Coastguard Worker , fDuration(duration)
477*c8dee2aaSAndroid Build Coastguard Worker , fFPS(fps)
478*c8dee2aaSAndroid Build Coastguard Worker , fFlags(flags) {}
479*c8dee2aaSAndroid Build Coastguard Worker
480*c8dee2aaSAndroid Build Coastguard Worker Animation::~Animation() = default;
481*c8dee2aaSAndroid Build Coastguard Worker
render(SkCanvas * canvas,const SkRect * dstR) const482*c8dee2aaSAndroid Build Coastguard Worker void Animation::render(SkCanvas* canvas, const SkRect* dstR) const {
483*c8dee2aaSAndroid Build Coastguard Worker this->render(canvas, dstR, 0);
484*c8dee2aaSAndroid Build Coastguard Worker }
485*c8dee2aaSAndroid Build Coastguard Worker
render(SkCanvas * canvas,const SkRect * dstR,RenderFlags renderFlags) const486*c8dee2aaSAndroid Build Coastguard Worker void Animation::render(SkCanvas* canvas, const SkRect* dstR, RenderFlags renderFlags) const {
487*c8dee2aaSAndroid Build Coastguard Worker TRACE_EVENT0("skottie", TRACE_FUNC);
488*c8dee2aaSAndroid Build Coastguard Worker
489*c8dee2aaSAndroid Build Coastguard Worker if (!fSceneRoot)
490*c8dee2aaSAndroid Build Coastguard Worker return;
491*c8dee2aaSAndroid Build Coastguard Worker
492*c8dee2aaSAndroid Build Coastguard Worker SkAutoCanvasRestore restore(canvas, true);
493*c8dee2aaSAndroid Build Coastguard Worker
494*c8dee2aaSAndroid Build Coastguard Worker const SkRect srcR = SkRect::MakeSize(this->size());
495*c8dee2aaSAndroid Build Coastguard Worker if (dstR) {
496*c8dee2aaSAndroid Build Coastguard Worker canvas->concat(SkMatrix::RectToRect(srcR, *dstR, SkMatrix::kCenter_ScaleToFit));
497*c8dee2aaSAndroid Build Coastguard Worker }
498*c8dee2aaSAndroid Build Coastguard Worker
499*c8dee2aaSAndroid Build Coastguard Worker if (!(renderFlags & RenderFlag::kDisableTopLevelClipping)) {
500*c8dee2aaSAndroid Build Coastguard Worker canvas->clipRect(srcR);
501*c8dee2aaSAndroid Build Coastguard Worker }
502*c8dee2aaSAndroid Build Coastguard Worker
503*c8dee2aaSAndroid Build Coastguard Worker if ((fFlags & Flags::kRequiresTopLevelIsolation) &&
504*c8dee2aaSAndroid Build Coastguard Worker !(renderFlags & RenderFlag::kSkipTopLevelIsolation)) {
505*c8dee2aaSAndroid Build Coastguard Worker // The animation uses non-trivial blending, and needs
506*c8dee2aaSAndroid Build Coastguard Worker // to be rendered into a separate/transparent layer.
507*c8dee2aaSAndroid Build Coastguard Worker canvas->saveLayer(srcR, nullptr);
508*c8dee2aaSAndroid Build Coastguard Worker }
509*c8dee2aaSAndroid Build Coastguard Worker
510*c8dee2aaSAndroid Build Coastguard Worker fSceneRoot->render(canvas);
511*c8dee2aaSAndroid Build Coastguard Worker }
512*c8dee2aaSAndroid Build Coastguard Worker
seekFrame(double t,sksg::InvalidationController * ic)513*c8dee2aaSAndroid Build Coastguard Worker void Animation::seekFrame(double t, sksg::InvalidationController* ic) {
514*c8dee2aaSAndroid Build Coastguard Worker TRACE_EVENT0("skottie", TRACE_FUNC);
515*c8dee2aaSAndroid Build Coastguard Worker
516*c8dee2aaSAndroid Build Coastguard Worker if (!fSceneRoot)
517*c8dee2aaSAndroid Build Coastguard Worker return;
518*c8dee2aaSAndroid Build Coastguard Worker
519*c8dee2aaSAndroid Build Coastguard Worker // Per AE/Lottie semantics out_point is exclusive.
520*c8dee2aaSAndroid Build Coastguard Worker const auto kLastValidFrame = std::nextafterf(fOutPoint, fInPoint),
521*c8dee2aaSAndroid Build Coastguard Worker comp_time = SkTPin<float>(fInPoint + t, fInPoint, kLastValidFrame);
522*c8dee2aaSAndroid Build Coastguard Worker
523*c8dee2aaSAndroid Build Coastguard Worker for (const auto& anim : fAnimators) {
524*c8dee2aaSAndroid Build Coastguard Worker anim->seek(comp_time);
525*c8dee2aaSAndroid Build Coastguard Worker }
526*c8dee2aaSAndroid Build Coastguard Worker
527*c8dee2aaSAndroid Build Coastguard Worker fSceneRoot->revalidate(ic, SkMatrix::I());
528*c8dee2aaSAndroid Build Coastguard Worker }
529*c8dee2aaSAndroid Build Coastguard Worker
seekFrameTime(double t,sksg::InvalidationController * ic)530*c8dee2aaSAndroid Build Coastguard Worker void Animation::seekFrameTime(double t, sksg::InvalidationController* ic) {
531*c8dee2aaSAndroid Build Coastguard Worker this->seekFrame(t * fFPS, ic);
532*c8dee2aaSAndroid Build Coastguard Worker }
533*c8dee2aaSAndroid Build Coastguard Worker
Make(const char * data,size_t length)534*c8dee2aaSAndroid Build Coastguard Worker sk_sp<Animation> Animation::Make(const char* data, size_t length) {
535*c8dee2aaSAndroid Build Coastguard Worker return Builder().make(data, length);
536*c8dee2aaSAndroid Build Coastguard Worker }
537*c8dee2aaSAndroid Build Coastguard Worker
Make(SkStream * stream)538*c8dee2aaSAndroid Build Coastguard Worker sk_sp<Animation> Animation::Make(SkStream* stream) {
539*c8dee2aaSAndroid Build Coastguard Worker return Builder().make(stream);
540*c8dee2aaSAndroid Build Coastguard Worker }
541*c8dee2aaSAndroid Build Coastguard Worker
MakeFromFile(const char path[])542*c8dee2aaSAndroid Build Coastguard Worker sk_sp<Animation> Animation::MakeFromFile(const char path[]) {
543*c8dee2aaSAndroid Build Coastguard Worker return Builder().makeFromFile(path);
544*c8dee2aaSAndroid Build Coastguard Worker }
545*c8dee2aaSAndroid Build Coastguard Worker
546*c8dee2aaSAndroid Build Coastguard Worker } // namespace skottie
547