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