• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 Google LLC
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 SkResources_DEFINED
9 #define SkResources_DEFINED
10 
11 #include "include/core/SkData.h"
12 #include "include/core/SkMatrix.h"
13 #include "include/core/SkRefCnt.h"
14 #include "include/core/SkSamplingOptions.h"
15 #include "include/core/SkString.h"
16 #include "include/core/SkTypeface.h"
17 #include "include/core/SkTypes.h"
18 #include "include/private/base/SkMutex.h"
19 #include "src/core/SkTHash.h"
20 
21 #include <memory>
22 
23 class SkAnimCodecPlayer;
24 class SkImage;
25 
26 namespace skresources {
27 
28 /**
29  * Image asset proxy interface.
30  */
31 class SK_API ImageAsset : public SkRefCnt {
32 public:
33     /**
34      * Returns true if the image asset is animated.
35      */
36     virtual bool isMultiFrame() = 0;
37 
38     /**
39      * DEPRECATED: override getFrameData() instead.
40      *
41      * Returns the SkImage for a given frame.
42      *
43      * If the image asset is static, getFrame() is only called once, at animation load time.
44      * Otherwise, this gets invoked every time the animation time is adjusted (on every seek).
45      *
46      * Embedders should cache and serve the same SkImage whenever possible, for efficiency.
47      *
48      * @param t   Frame time code, in seconds, relative to the image layer timeline origin
49      *            (in-point).
50      */
51     virtual sk_sp<SkImage> getFrame(float t);
52 
53     struct FrameData {
54         // SkImage payload.
55         sk_sp<SkImage>       image;
56         // Resampling parameters.
57         SkSamplingOptions    sampling;
58         // Additional image transform to be applied before AE scaling rules.
59         SkMatrix             matrix = SkMatrix::I();
60         // Scaling strategy for aspect ratio adjustments.
61         SkMatrix::ScaleToFit scaling = SkMatrix::kCenter_ScaleToFit;
62     };
63 
64     /**
65      * Returns the payload for a given frame.
66      *
67      * If the image asset is static, getFrameData() is only called once, at animation load time.
68      * Otherwise, this gets invoked every time the animation time is adjusted (on every seek).
69      *
70      * Embedders should cache and serve the same SkImage whenever possible, for efficiency.
71      *
72      * @param t   Frame time code, in seconds, relative to the image layer timeline origin
73      *            (in-point).
74      */
75     virtual FrameData getFrameData(float t);
76 };
77 
78 class MultiFrameImageAsset final : public ImageAsset {
79 public:
80     /**
81     * By default, images are decoded on-the-fly, at rasterization time.
82     * Large images may cause jank as decoding is expensive (and can thrash internal caches).
83     *
84     * Pass |predecode| true to force-decode all images upfront, at the cost of potentially more RAM
85     * and slower animation build times.
86     */
87     static sk_sp<MultiFrameImageAsset> Make(sk_sp<SkData>, bool predecode = false);
88 
89     bool isMultiFrame() override;
90 
91     sk_sp<SkImage> getFrame(float t) override;
92 
93 private:
94     explicit MultiFrameImageAsset(std::unique_ptr<SkAnimCodecPlayer>, bool predecode);
95 
96     sk_sp<SkImage> generateFrame(float t);
97 
98     std::unique_ptr<SkAnimCodecPlayer> fPlayer;
99     sk_sp<SkImage>                     fCachedFrame;
100     bool                               fPreDecode;
101 
102     using INHERITED = ImageAsset;
103 };
104 
105 /**
106  * External track (e.g. audio playback) interface.
107  *
108  * Used to wrap data payload and playback controllers.
109  */
110 class ExternalTrackAsset : public SkRefCnt {
111 public:
112     /**
113      * Playback control callback, emitted for each corresponding Animation::seek().
114      *
115      * @param t  Frame time code, in seconds, relative to the layer's timeline origin
116      *           (in-point).
117      *
118      * Negative |t| values are used to signal off state (stop playback outside layer span).
119      */
120     virtual void seek(float t) = 0;
121 };
122 
123 /**
124  * ResourceProvider is an interface that lets rich-content modules defer loading of external
125  * resources (images, fonts, etc.) to embedding clients.
126  */
127 class SK_API ResourceProvider : public SkRefCnt {
128 public:
129     /**
130      * Load a generic resource (currently only nested animations) specified by |path| + |name|,
131      * and return as an SkData.
132      */
load(const char[],const char[])133     virtual sk_sp<SkData> load(const char[] /* resource_path */,
134                                const char[] /* resource_name */) const {
135         return nullptr;
136     }
137 
138     /**
139      * Load an image asset specified by |path| + |name|, and returns the corresponding
140      * ImageAsset proxy.
141      */
loadImageAsset(const char[],const char[],const char[])142     virtual sk_sp<ImageAsset> loadImageAsset(const char[] /* resource_path */,
143                                              const char[] /* resource_name */,
144                                              const char[] /* resource_id   */) const {
145         return nullptr;
146     }
147 
148     /**
149      * Load an external audio track specified by |path|/|name|/|id|.
150      */
loadAudioAsset(const char[],const char[],const char[])151     virtual sk_sp<ExternalTrackAsset> loadAudioAsset(const char[] /* resource_path */,
152                                                      const char[] /* resource_name */,
153                                                      const char[] /* resource_id   */) {
154         return nullptr;
155     }
156 
157     /**
158      * DEPRECATED: implement loadTypeface() instead.
159      *
160      * Load an external font and return as SkData.
161      *
162      * @param name  font name    ("fName" Lottie property)
163      * @param url   web font URL ("fPath" Lottie property)
164      *
165      * -- Note --
166      *
167      *   This mechanism assumes monolithic fonts (single data blob).  Some web font providers may
168      *   serve multiple font blobs, segmented for various unicode ranges, depending on user agent
169      *   capabilities (woff, woff2).  In that case, the embedder would need to advertise no user
170      *   agent capabilities when fetching the URL, in order to receive full font data.
171      */
loadFont(const char[],const char[])172     virtual sk_sp<SkData> loadFont(const char[] /* name */,
173                                    const char[] /* url  */) const {
174         return nullptr;
175     }
176 
177     /**
178      * Load an external font and return as SkTypeface.
179      *
180      * @param name  font name
181      * @param url   web font URL
182      */
loadTypeface(const char[],const char[])183     virtual sk_sp<SkTypeface> loadTypeface(const char[] /* name */,
184                                            const char[] /* url  */) const {
185         return nullptr;
186     }
187 };
188 
189 class FileResourceProvider final : public ResourceProvider {
190 public:
191     static sk_sp<FileResourceProvider> Make(SkString base_dir, bool predecode = false);
192 
193     sk_sp<SkData> load(const char resource_path[], const char resource_name[]) const override;
194 
195     sk_sp<ImageAsset> loadImageAsset(const char[], const char[], const char[]) const override;
196 
197 private:
198     FileResourceProvider(SkString, bool);
199 
200     const SkString fDir;
201     const bool     fPredecode;
202 
203     using INHERITED = ResourceProvider;
204 };
205 
206 class ResourceProviderProxyBase : public ResourceProvider {
207 protected:
208     explicit ResourceProviderProxyBase(sk_sp<ResourceProvider>);
209 
210     sk_sp<SkData> load(const char[], const char[]) const override;
211     sk_sp<ImageAsset> loadImageAsset(const char[], const char[], const char[]) const override;
212     sk_sp<SkTypeface> loadTypeface(const char[], const char[]) const override;
213     sk_sp<SkData> loadFont(const char[], const char[]) const override;
214     sk_sp<ExternalTrackAsset> loadAudioAsset(const char[], const char[], const char[]) override;
215 
216 private:
217     const sk_sp<ResourceProvider> fProxy;
218 };
219 
220 class SK_API CachingResourceProvider final : public ResourceProviderProxyBase {
221 public:
Make(sk_sp<ResourceProvider> rp)222     static sk_sp<CachingResourceProvider> Make(sk_sp<ResourceProvider> rp) {
223         return rp ? sk_sp<CachingResourceProvider>(new CachingResourceProvider(std::move(rp)))
224                   : nullptr;
225     }
226 
227 private:
228     explicit CachingResourceProvider(sk_sp<ResourceProvider>);
229 
230     sk_sp<ImageAsset> loadImageAsset(const char[], const char[], const char[]) const override;
231 
232     mutable SkMutex                                 fMutex;
233     mutable SkTHashMap<SkString, sk_sp<ImageAsset>> fImageCache;
234 
235     using INHERITED = ResourceProviderProxyBase;
236 };
237 
238 class DataURIResourceProviderProxy final : public ResourceProviderProxyBase {
239 public:
240     static sk_sp<DataURIResourceProviderProxy> Make(sk_sp<ResourceProvider> rp,
241                                                     bool predecode = false);
242 
243 private:
244     DataURIResourceProviderProxy(sk_sp<ResourceProvider>, bool);
245 
246     sk_sp<ImageAsset> loadImageAsset(const char[], const char[], const char[]) const override;
247     sk_sp<SkTypeface> loadTypeface(const char[], const char[]) const override;
248 
249     const bool fPredecode;
250 
251     using INHERITED = ResourceProviderProxyBase;
252 };
253 
254 } // namespace skresources
255 
256 #endif // SkResources_DEFINED
257