Coverage Report

Created: 2024-05-20 07:14

/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