/src/skia/modules/skresources/include/SkResources.h
Line | Count | Source (jump to first uncovered line) |
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 SkCodec; |
25 | | class SkImage; |
26 | | |
27 | | namespace skresources { |
28 | | |
29 | | /** |
30 | | * Image asset proxy interface. |
31 | | */ |
32 | | class SK_API ImageAsset : public SkRefCnt { |
33 | | public: |
34 | | /** |
35 | | * Returns true if the image asset is animated. |
36 | | */ |
37 | | virtual bool isMultiFrame() = 0; |
38 | | |
39 | | /** |
40 | | * DEPRECATED: override getFrameData() instead. |
41 | | * |
42 | | * Returns the SkImage for a given frame. |
43 | | * |
44 | | * If the image asset is static, getFrame() is only called once, at animation load time. |
45 | | * Otherwise, this gets invoked every time the animation time is adjusted (on every seek). |
46 | | * |
47 | | * Embedders should cache and serve the same SkImage whenever possible, for efficiency. |
48 | | * |
49 | | * @param t Frame time code, in seconds, relative to the image layer timeline origin |
50 | | * (in-point). |
51 | | */ |
52 | | virtual sk_sp<SkImage> getFrame(float t); |
53 | | |
54 | | // Describes how the frame image is to be scaled to the animation-declared asset size. |
55 | | enum class SizeFit { |
56 | | // See SkMatrix::ScaleToFit |
57 | | kFill = SkMatrix::kFill_ScaleToFit, |
58 | | kStart = SkMatrix::kStart_ScaleToFit, |
59 | | kCenter = SkMatrix::kCenter_ScaleToFit, |
60 | | kEnd = SkMatrix::kEnd_ScaleToFit, |
61 | | |
62 | | // No scaling. |
63 | | kNone, |
64 | | }; |
65 | | |
66 | | struct FrameData { |
67 | | // SkImage payload. |
68 | | sk_sp<SkImage> image; |
69 | | // Resampling parameters. |
70 | | SkSamplingOptions sampling; |
71 | | // Additional image transform to be applied before AE scaling rules. |
72 | | SkMatrix matrix = SkMatrix::I(); |
73 | | // Strategy for image size -> AE asset size scaling. |
74 | | SizeFit scaling = SizeFit::kCenter; |
75 | | }; |
76 | | |
77 | | /** |
78 | | * Returns the payload for a given frame. |
79 | | * |
80 | | * If the image asset is static, getFrameData() is only called once, at animation load time. |
81 | | * Otherwise, this gets invoked every time the animation time is adjusted (on every seek). |
82 | | * |
83 | | * Embedders should cache and serve the same SkImage whenever possible, for efficiency. |
84 | | * |
85 | | * @param t Frame time code, in seconds, relative to the image layer timeline origin |
86 | | * (in-point). |
87 | | */ |
88 | | virtual FrameData getFrameData(float t); |
89 | | }; |
90 | | |
91 | | enum class ImageDecodeStrategy { |
92 | | // Images are decoded on-the-fly, at rasterization time. |
93 | | // Large images may cause jank as decoding is expensive (and can thrash internal caches). |
94 | | kLazyDecode, |
95 | | // Force-decode all images upfront, at the cost of potentially more RAM and slower |
96 | | // animation build times. |
97 | | kPreDecode, |
98 | | }; |
99 | | |
100 | | class MultiFrameImageAsset final : public ImageAsset { |
101 | | public: |
102 | | // Clients must call SkCodec::Register() to load the required decoding image codecs before |
103 | | // calling Make. For example: |
104 | | // SkCodec::Register(SkPngDecoder::Decoder()); |
105 | | static sk_sp<MultiFrameImageAsset> Make(sk_sp<SkData>, |
106 | | ImageDecodeStrategy = ImageDecodeStrategy::kLazyDecode); |
107 | | // If the client has already decoded the data, they can use this constructor. |
108 | | static sk_sp<MultiFrameImageAsset> Make(std::unique_ptr<SkCodec>, |
109 | | ImageDecodeStrategy = ImageDecodeStrategy::kLazyDecode); |
110 | | |
111 | | |
112 | | bool isMultiFrame() override; |
113 | | |
114 | | sk_sp<SkImage> getFrame(float t) override; |
115 | | |
116 | | private: |
117 | | explicit MultiFrameImageAsset(std::unique_ptr<SkAnimCodecPlayer>, ImageDecodeStrategy); |
118 | | |
119 | | sk_sp<SkImage> generateFrame(float t); |
120 | | |
121 | | std::unique_ptr<SkAnimCodecPlayer> fPlayer; |
122 | | sk_sp<SkImage> fCachedFrame; |
123 | | ImageDecodeStrategy fStrategy; |
124 | | |
125 | | using INHERITED = ImageAsset; |
126 | | }; |
127 | | |
128 | | /** |
129 | | * External track (e.g. audio playback) interface. |
130 | | * |
131 | | * Used to wrap data payload and playback controllers. |
132 | | */ |
133 | | class ExternalTrackAsset : public SkRefCnt { |
134 | | public: |
135 | | /** |
136 | | * Playback control callback, emitted for each corresponding Animation::seek(). |
137 | | * |
138 | | * @param t Frame time code, in seconds, relative to the layer's timeline origin |
139 | | * (in-point). |
140 | | * |
141 | | * Negative |t| values are used to signal off state (stop playback outside layer span). |
142 | | */ |
143 | | virtual void seek(float t) = 0; |
144 | | }; |
145 | | |
146 | | /** |
147 | | * ResourceProvider is an interface that lets rich-content modules defer loading of external |
148 | | * resources (images, fonts, etc.) to embedding clients. |
149 | | */ |
150 | | class SK_API ResourceProvider : public SkRefCnt { |
151 | | public: |
152 | | /** |
153 | | * Load a generic resource (currently only nested animations) specified by |path| + |name|, |
154 | | * and return as an SkData. |
155 | | */ |
156 | | virtual sk_sp<SkData> load(const char[] /* resource_path */, |
157 | 0 | const char[] /* resource_name */) const { |
158 | 0 | return nullptr; |
159 | 0 | } |
160 | | |
161 | | /** |
162 | | * Load an image asset specified by |path| + |name|, and returns the corresponding |
163 | | * ImageAsset proxy. |
164 | | */ |
165 | | virtual sk_sp<ImageAsset> loadImageAsset(const char[] /* resource_path */, |
166 | | const char[] /* resource_name */, |
167 | 0 | const char[] /* resource_id */) const { |
168 | 0 | return nullptr; |
169 | 0 | } |
170 | | |
171 | | /** |
172 | | * Load an external audio track specified by |path|/|name|/|id|. |
173 | | */ |
174 | | virtual sk_sp<ExternalTrackAsset> loadAudioAsset(const char[] /* resource_path */, |
175 | | const char[] /* resource_name */, |
176 | 0 | const char[] /* resource_id */) { |
177 | 0 | return nullptr; |
178 | 0 | } |
179 | | |
180 | | /** |
181 | | * DEPRECATED: implement loadTypeface() instead. |
182 | | * |
183 | | * Load an external font and return as SkData. |
184 | | * |
185 | | * @param name font name ("fName" Lottie property) |
186 | | * @param url web font URL ("fPath" Lottie property) |
187 | | * |
188 | | * -- Note -- |
189 | | * |
190 | | * This mechanism assumes monolithic fonts (single data blob). Some web font providers may |
191 | | * serve multiple font blobs, segmented for various unicode ranges, depending on user agent |
192 | | * capabilities (woff, woff2). In that case, the embedder would need to advertise no user |
193 | | * agent capabilities when fetching the URL, in order to receive full font data. |
194 | | */ |
195 | | virtual sk_sp<SkData> loadFont(const char[] /* name */, |
196 | 0 | const char[] /* url */) const { |
197 | 0 | return nullptr; |
198 | 0 | } |
199 | | |
200 | | /** |
201 | | * Load an external font and return as SkTypeface. |
202 | | * |
203 | | * @param name font name |
204 | | * @param url web font URL |
205 | | */ |
206 | | virtual sk_sp<SkTypeface> loadTypeface(const char[] /* name */, |
207 | 0 | const char[] /* url */) const { |
208 | 0 | return nullptr; |
209 | 0 | } |
210 | | }; |
211 | | |
212 | | class FileResourceProvider final : public ResourceProvider { |
213 | | public: |
214 | | // To decode images, clients must call SkCodecs::Register() before calling Make. |
215 | | static sk_sp<FileResourceProvider> Make(SkString base_dir, |
216 | | ImageDecodeStrategy = ImageDecodeStrategy::kLazyDecode); |
217 | | |
218 | | sk_sp<SkData> load(const char resource_path[], const char resource_name[]) const override; |
219 | | |
220 | | sk_sp<ImageAsset> loadImageAsset(const char[], const char[], const char[]) const override; |
221 | | |
222 | | private: |
223 | | FileResourceProvider(SkString, ImageDecodeStrategy); |
224 | | |
225 | | const SkString fDir; |
226 | | const ImageDecodeStrategy fStrategy; |
227 | | |
228 | | using INHERITED = ResourceProvider; |
229 | | }; |
230 | | |
231 | | class ResourceProviderProxyBase : public ResourceProvider { |
232 | | protected: |
233 | | explicit ResourceProviderProxyBase(sk_sp<ResourceProvider>); |
234 | | |
235 | | sk_sp<SkData> load(const char[], const char[]) const override; |
236 | | sk_sp<ImageAsset> loadImageAsset(const char[], const char[], const char[]) const override; |
237 | | sk_sp<SkTypeface> loadTypeface(const char[], const char[]) const override; |
238 | | sk_sp<SkData> loadFont(const char[], const char[]) const override; |
239 | | sk_sp<ExternalTrackAsset> loadAudioAsset(const char[], const char[], const char[]) override; |
240 | | |
241 | | protected: |
242 | | const sk_sp<ResourceProvider> fProxy; |
243 | | }; |
244 | | |
245 | | class SK_API CachingResourceProvider final : public ResourceProviderProxyBase { |
246 | | public: |
247 | 0 | static sk_sp<CachingResourceProvider> Make(sk_sp<ResourceProvider> rp) { |
248 | 0 | return rp ? sk_sp<CachingResourceProvider>(new CachingResourceProvider(std::move(rp))) |
249 | 0 | : nullptr; |
250 | 0 | } |
251 | | |
252 | | private: |
253 | | explicit CachingResourceProvider(sk_sp<ResourceProvider>); |
254 | | |
255 | | sk_sp<ImageAsset> loadImageAsset(const char[], const char[], const char[]) const override; |
256 | | |
257 | | mutable SkMutex fMutex; |
258 | | mutable skia_private::THashMap<SkString, sk_sp<ImageAsset>> fImageCache; |
259 | | |
260 | | using INHERITED = ResourceProviderProxyBase; |
261 | | }; |
262 | | |
263 | | class SK_API DataURIResourceProviderProxy final : public ResourceProviderProxyBase { |
264 | | public: |
265 | | // If font data is supplied via base64 encoding, this needs a provided SkFontMgr to process |
266 | | // that font data into an SkTypeface. To decode images, clients must call SkCodecs::Register() |
267 | | // before calling Make. |
268 | | static sk_sp<DataURIResourceProviderProxy> Make( |
269 | | sk_sp<ResourceProvider> rp, |
270 | | ImageDecodeStrategy = ImageDecodeStrategy::kLazyDecode, |
271 | | sk_sp<const SkFontMgr> fontMgr = nullptr); |
272 | | |
273 | | private: |
274 | | DataURIResourceProviderProxy(sk_sp<ResourceProvider>, |
275 | | ImageDecodeStrategy, |
276 | | sk_sp<const SkFontMgr> fontMgr); |
277 | | |
278 | | sk_sp<ImageAsset> loadImageAsset(const char[], const char[], const char[]) const override; |
279 | | sk_sp<SkTypeface> loadTypeface(const char[], const char[]) const override; |
280 | | |
281 | | const ImageDecodeStrategy fStrategy; |
282 | | sk_sp<const SkFontMgr> fFontMgr; |
283 | | |
284 | | using INHERITED = ResourceProviderProxyBase; |
285 | | }; |
286 | | |
287 | | } // namespace skresources |
288 | | |
289 | | #endif // SkResources_DEFINED |