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