1/*
2 * Copyright 2017 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#ifndef Skottie_DEFINED
9#define Skottie_DEFINED
10
11#include "include/core/SkFontMgr.h"
12#include "include/core/SkRefCnt.h"
13#include "include/core/SkSize.h"
14#include "include/core/SkString.h"
15#include "include/core/SkTypes.h"
16#include "modules/skottie/include/ExternalLayer.h"
17#include "modules/skottie/include/SkottieProperty.h"
18#include "modules/skresources/include/SkResources.h"
19
20#include <memory>
21#include <vector>
22
23class SkCanvas;
24struct SkRect;
25class SkStream;
26
27namespace skjson { class ObjectValue; }
28
29namespace sksg {
30
31class InvalidationController;
32class Scene;
33
34} // namespace sksg
35
36namespace skottie {
37
38namespace internal { class Animator; }
39
40using ImageAsset = skresources::ImageAsset;
41using ResourceProvider = skresources::ResourceProvider;
42
43/**
44 * A Logger subclass can be used to receive Animation::Builder parsing errors and warnings.
45 */
46class SK_API Logger : public SkRefCnt {
47public:
48 enum class Level {
49 kWarning,
50 kError,
51 };
52
53 virtual void log(Level, const char message[], const char* json = nullptr);
54};
55
56/**
57 * Interface for receiving AE composition markers at Animation build time.
58 */
59class SK_API MarkerObserver : public SkRefCnt {
60public:
61 // t0,t1 are in the Animation::seek() domain.
62 virtual void onMarker(const char name[], float t0, float t1) = 0;
63};
64
65class SK_API Animation : public SkNVRefCnt<Animation> {
66public:
67 class Builder final {
68 public:
69 enum Flags : uint32_t {
70 kDeferImageLoading = 0x01, // Normally, all static image frames are resolved at
71 // load time via ImageAsset::getFrame(0). With this flag,
72 // frames are only resolved when needed, at seek() time.
73 kPreferEmbeddedFonts = 0x02, // Attempt to use the embedded fonts (glyph paths,
74 // normally used as fallback) over native Skia typefaces.
75 };
76
77 explicit Builder(uint32_t flags = 0);
78 ~Builder();
79
80 struct Stats {
81 float fTotalLoadTimeMS = 0, // Total animation instantiation time.
82 fJsonParseTimeMS = 0, // Time spent building a JSON DOM.
83 fSceneParseTimeMS = 0; // Time spent constructing the animation scene graph.
84 size_t fJsonSize = 0, // Input JSON size.
85 fAnimatorCount = 0; // Number of dynamically animated properties.
86 };
87
88 /**
89 * Returns various animation build stats.
90 *
91 * @return Stats (see above).
92 */
93 const Stats& getStats() const { return fStats; }
94
95 /**
96 * Specify a loader for external resources (images, etc.).
97 */
98 Builder& setResourceProvider(sk_sp<ResourceProvider>);
99
100 /**
101 * Specify a font manager for loading animation fonts.
102 */
103 Builder& setFontManager(sk_sp<SkFontMgr>);
104
105 /**
106 * Specify a PropertyObserver to receive callbacks during parsing.
107 *
108 * See SkottieProperty.h for more details.
109 *
110 */
111 Builder& setPropertyObserver(sk_sp<PropertyObserver>);
112
113 /**
114 * Register a Logger with this builder.
115 */
116 Builder& setLogger(sk_sp<Logger>);
117
118 /**
119 * Register a MarkerObserver with this builder.
120 */
121 Builder& setMarkerObserver(sk_sp<MarkerObserver>);
122
123 /**
124 * Register a precomp layer interceptor.
125 * This allows substituting precomp layers with custom/externally managed content.
126 */
127 Builder& setPrecompInterceptor(sk_sp<PrecompInterceptor>);
128
129 /**
130 * Animation factories.
131 */
132 sk_sp<Animation> make(SkStream*);
133 sk_sp<Animation> make(const char* data, size_t length);
134 sk_sp<Animation> makeFromFile(const char path[]);
135
136 private:
137 const uint32_t fFlags;
138
139 sk_sp<ResourceProvider> fResourceProvider;
140 sk_sp<SkFontMgr> fFontMgr;
141 sk_sp<PropertyObserver> fPropertyObserver;
142 sk_sp<Logger> fLogger;
143 sk_sp<MarkerObserver > fMarkerObserver;
144 sk_sp<PrecompInterceptor> fPrecompInterceptor;
145 Stats fStats;
146 };
147
148 /**
149 * Animation factories.
150 *
151 * Use the Builder helper above for more options/control.
152 */
153 static sk_sp<Animation> Make(const char* data, size_t length);
154 static sk_sp<Animation> Make(SkStream*);
155 static sk_sp<Animation> MakeFromFile(const char path[]);
156
157 ~Animation();
158
159 enum RenderFlag : uint32_t {
160 // When rendering into a known transparent buffer, clients can pass
161 // this flag to avoid some unnecessary compositing overhead for
162 // animations using layer blend modes.
163 kSkipTopLevelIsolation = 0x01,
164 // By default, content is clipped to the intrinsic animation
165 // bounds (as determined by its size). If this flag is set,
166 // then the animation can draw outside of the bounds.
167 kDisableTopLevelClipping = 0x02,
168 };
169 using RenderFlags = uint32_t;
170
171 /**
172 * Draws the current animation frame.
173 *
174 * It is undefined behavior to call render() on a newly created Animation
175 * before specifying an initial frame via one of the seek() variants.
176 *
177 * @param canvas destination canvas
178 * @param dst optional destination rect
179 * @param flags optional RenderFlags
180 */
181 void render(SkCanvas* canvas, const SkRect* dst = nullptr) const;
182 void render(SkCanvas* canvas, const SkRect* dst, RenderFlags) const;
183
184 /**
185 * [Deprecated: use one of the other versions.]
186 *
187 * Updates the animation state for |t|.
188 *
189 * @param t normalized [0..1] frame selector (0 -> first frame, 1 -> final frame)
190 * @param ic optional invalidation controller (dirty region tracking)
191 *
192 */
193 void seek(SkScalar t, sksg::InvalidationController* ic = nullptr) {
194 this->seekFrameTime(t * this->duration(), ic);
195 }
196
197 /**
198 * Update the animation state to match |t|, specified as a frame index
199 * i.e. relative to duration() * fps().
200 *
201 * Fractional values are allowed and meaningful - e.g.
202 *
203 * 0.0 -> first frame
204 * 1.0 -> second frame
205 * 0.5 -> halfway between first and second frame
206 */
207 void seekFrame(double t, sksg::InvalidationController* ic = nullptr);
208
209 /** Update the animation state to match t, specifed in frame time
210 * i.e. relative to duration().
211 */
212 void seekFrameTime(double t, sksg::InvalidationController* = nullptr);
213
214 /**
215 * Returns the animation duration in seconds.
216 */
217 double duration() const { return fDuration; }
218
219 /**
220 * Returns the animation frame rate (frames / second).
221 */
222 double fps() const { return fFPS; }
223
224 /**
225 * Animation in point, in frame index units.
226 */
227 double inPoint() const { return fInPoint; }
228
229 /**
230 * Animation out point, in frame index units.
231 */
232 double outPoint() const { return fOutPoint; }
233
234 const SkString& version() const { return fVersion; }
235 const SkSize& size() const { return fSize; }
236
237private:
238 enum Flags : uint32_t {
239 kRequiresTopLevelIsolation = 1 << 0, // Needs to draw into a layer due to layer blending.
240 };
241
242 Animation(std::unique_ptr<sksg::Scene>,
243 std::vector<sk_sp<internal::Animator>>&&,
244 SkString ver, const SkSize& size,
245 double inPoint, double outPoint, double duration, double fps, uint32_t flags);
246
247 const std::unique_ptr<sksg::Scene> fScene;
248 const std::vector<sk_sp<internal::Animator>> fAnimators;
249 const SkString fVersion;
250 const SkSize fSize;
251 const double fInPoint,
252 fOutPoint,
253 fDuration,
254 fFPS;
255 const uint32_t fFlags;
256
257 typedef SkNVRefCnt<Animation> INHERITED;
258};
259
260} // namespace skottie
261
262#endif // Skottie_DEFINED
263