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