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