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 "SkFontMgr.h"
12 #include "SkRefCnt.h"
13 #include "SkSize.h"
14 #include "SkString.h"
15 #include "SkTypes.h"
16 
17 #include <memory>
18 
19 class SkCanvas;
20 class SkData;
21 class SkImage;
22 struct SkRect;
23 class SkStream;
24 
25 namespace skjson { class ObjectValue; }
26 
27 namespace sksg { class Scene;  }
28 
29 namespace skottie {
30 
31 class PropertyObserver;
32 
33 /**
34  * Image asset proxy interface.
35  */
36 class SK_API ImageAsset : public SkRefCnt {
37 public:
38     /**
39      * Returns true if the image asset is animated.
40      */
41     virtual bool isMultiFrame() = 0;
42 
43     /**
44      * Returns the SkImage for a given frame.
45      *
46      * If the image asset is static, getImage() is only called once, at animation load time.
47      * Otherwise, this gets invoked every time the animation time is adjusted (on every seek).
48      *
49      * Embedders should cache and serve the same SkImage whenever possible, for efficiency.
50      *
51      * @param t   Frame time code, in seconds, relative to the image layer timeline origin
52      *            (in-point).
53      */
54     virtual sk_sp<SkImage> getFrame(float t) = 0;
55 };
56 
57 /**
58  * ResourceProvider allows Skottie embedders to control loading of external
59  * Skottie resources -- e.g. images, fonts, nested animations.
60  */
61 class SK_API ResourceProvider : public SkRefCnt {
62 public:
63     /**
64      * Load a generic resource (currently only nested animations) specified by |path| + |name|,
65      * and return as an SkData.
66      */
67     virtual sk_sp<SkData> load(const char resource_path[],
68                                const char resource_name[]) const;
69 
70     /**
71      * Load an image asset specified by |path| + |name|, and returns the corresponding
72      * ImageAsset proxy.
73      */
74     virtual sk_sp<ImageAsset> loadImageAsset(const char resource_path[],
75                                              const char resource_name[]) const;
76 
77     /**
78      * Load an external font and return as SkData.
79      *
80      * @param name  font name    ("fName" Lottie property)
81      * @param url   web font URL ("fPath" Lottie property)
82      *
83      * -- Note --
84      *
85      *   This mechanism assumes monolithic fonts (single data blob).  Some web font providers may
86      *   serve multiple font blobs, segmented for various unicode ranges, depending on user agent
87      *   capabilities (woff, woff2).  In that case, the embedder would need to advertise no user
88      *   agent capabilities when fetching the URL, in order to receive full font data.
89      */
90     virtual sk_sp<SkData> loadFont(const char name[], const char url[]) const;
91 };
92 
93 /**
94  * A Logger subclass can be used to receive Animation::Builder parsing errors and warnings.
95  */
96 class SK_API Logger : public SkRefCnt {
97 public:
98     enum class Level {
99         kWarning,
100         kError,
101     };
102 
103     virtual void log(Level, const char message[], const char* json = nullptr);
104 };
105 
106 /**
107  * Interface for receiving AE composition markers at Animation build time.
108  */
109 class SK_API MarkerObserver : public SkRefCnt {
110 public:
111     // t0,t1 are in the Animation::seek() domain.
112     virtual void onMarker(const char name[], float t0, float t1) = 0;
113 };
114 
115 class SK_API Animation : public SkNVRefCnt<Animation> {
116 public:
117 
118     class Builder final {
119     public:
120         Builder();
121         ~Builder();
122 
123         struct Stats {
124             float  fTotalLoadTimeMS  = 0, // Total animation instantiation time.
125                    fJsonParseTimeMS  = 0, // Time spent building a JSON DOM.
126                    fSceneParseTimeMS = 0; // Time spent constructing the animation scene graph.
127             size_t fJsonSize         = 0, // Input JSON size.
128                    fAnimatorCount    = 0; // Number of dynamically animated properties.
129         };
130 
131         /**
132          * Returns various animation build stats.
133          *
134          * @return Stats (see above).
135          */
getStats()136         const Stats& getStats() const { return fStats; }
137 
138         /**
139          * Specify a loader for external resources (images, etc.).
140          */
141         Builder& setResourceProvider(sk_sp<ResourceProvider>);
142 
143         /**
144          * Specify a font manager for loading animation fonts.
145          */
146         Builder& setFontManager(sk_sp<SkFontMgr>);
147 
148         /**
149          * Specify a PropertyObserver to receive callbacks during parsing.
150          *
151          * See SkottieProperty.h for more details.
152          *
153          */
154         Builder& setPropertyObserver(sk_sp<PropertyObserver>);
155 
156         /**
157          * Register a Logger with this builder.
158          */
159         Builder& setLogger(sk_sp<Logger>);
160 
161         /**
162          * Register a MarkerObserver with this builder.
163          */
164         Builder& setMarkerObserver(sk_sp<MarkerObserver>);
165 
166         /**
167          * Animation factories.
168          */
169         sk_sp<Animation> make(SkStream*);
170         sk_sp<Animation> make(const char* data, size_t length);
171         sk_sp<Animation> makeFromFile(const char path[]);
172 
173     private:
174         sk_sp<ResourceProvider> fResourceProvider;
175         sk_sp<SkFontMgr>        fFontMgr;
176         sk_sp<PropertyObserver> fPropertyObserver;
177         sk_sp<Logger>           fLogger;
178         sk_sp<MarkerObserver>   fMarkerObserver;
179         Stats                   fStats;
180     };
181 
182     /**
183      * Animation factories.
184      *
185      * Use the Builder helper above for more options/control.
186      */
187     static sk_sp<Animation> Make(const char* data, size_t length);
188     static sk_sp<Animation> Make(SkStream*);
189     static sk_sp<Animation> MakeFromFile(const char path[]);
190 
191     ~Animation();
192 
193     /**
194      * Draws the current animation frame.
195      *
196      * @param canvas   destination canvas
197      * @param dst      optional destination rect
198      */
199     void render(SkCanvas* canvas, const SkRect* dst = nullptr) const;
200 
201     /**
202      * Updates the animation state for |t|.
203      *
204      * @param t   normalized [0..1] frame selector (0 -> first frame, 1 -> final frame)
205      *
206      */
207     void seek(SkScalar t);
208 
209     /**
210      * Returns the animation duration in seconds.
211      */
duration()212     SkScalar duration() const { return fDuration; }
213 
version()214     const SkString& version() const { return fVersion;   }
size()215     const SkSize&      size() const { return fSize;      }
216 
217     void setShowInval(bool show);
218 
219 private:
220     Animation(std::unique_ptr<sksg::Scene>, SkString ver, const SkSize& size,
221               SkScalar inPoint, SkScalar outPoint, SkScalar duration);
222 
223     std::unique_ptr<sksg::Scene> fScene;
224     const SkString               fVersion;
225     const SkSize                 fSize;
226     const SkScalar               fInPoint,
227                                  fOutPoint,
228                                  fDuration;
229 
230     typedef SkNVRefCnt<Animation> INHERITED;
231 };
232 
233 } // namespace skottie
234 
235 #endif // Skottie_DEFINED
236