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 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