1/*
2 * Copyright 2018 Google Inc.
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 SkottiePriv_DEFINED
9#define SkottiePriv_DEFINED
10
11#include "modules/skottie/include/Skottie.h"
12
13#include "include/core/SkFontStyle.h"
14#include "include/core/SkString.h"
15#include "include/core/SkTypeface.h"
16#include "include/private/SkTHash.h"
17#include "include/utils/SkCustomTypeface.h"
18#include "modules/skottie/include/SkottieProperty.h"
19#include "modules/skottie/src/animator/Animator.h"
20#include "modules/sksg/include/SkSGScene.h"
21#include "src/utils/SkUTF.h"
22
23#include <vector>
24
25class SkFontMgr;
26
27namespace skjson {
28class ArrayValue;
29class ObjectValue;
30class Value;
31} // namespace skjson
32
33namespace sksg {
34class Color;
35class Path;
36class RenderNode;
37class Transform;
38} // namespace sksg
39
40namespace skottie {
41namespace internal {
42
43// Close-enough to AE.
44static constexpr float kBlurSizeToSigma = 0.3f;
45
46class TextAdapter;
47class TransformAdapter2D;
48class TransformAdapter3D;
49
50using AnimatorScope = std::vector<sk_sp<Animator>>;
51
52class AnimationBuilder final : public SkNoncopyable {
53public:
54 AnimationBuilder(sk_sp<ResourceProvider>, sk_sp<SkFontMgr>, sk_sp<PropertyObserver>,
55 sk_sp<Logger>, sk_sp<MarkerObserver>, sk_sp<PrecompInterceptor>,
56 Animation::Builder::Stats*, const SkSize& comp_size,
57 float duration, float framerate, uint32_t flags);
58
59 struct AnimationInfo {
60 std::unique_ptr<sksg::Scene> fScene;
61 AnimatorScope fAnimators;
62 };
63
64 AnimationInfo parse(const skjson::ObjectValue&);
65
66 struct FontInfo {
67 SkString fFamily,
68 fStyle,
69 fPath;
70 SkScalar fAscentPct;
71 sk_sp<SkTypeface> fTypeface;
72 SkCustomTypefaceBuilder fCustomBuilder;
73
74 bool matches(const char family[], const char style[]) const;
75 };
76 const FontInfo* findFont(const SkString& name) const;
77
78 void log(Logger::Level, const skjson::Value*, const char fmt[], ...) const;
79
80 sk_sp<sksg::Transform> attachMatrix2D(const skjson::ObjectValue&, sk_sp<sksg::Transform>,
81 bool auto_orient = false) const;
82 sk_sp<sksg::Transform> attachMatrix3D(const skjson::ObjectValue&, sk_sp<sksg::Transform>,
83 bool auto_orient = false) const;
84
85 sk_sp<sksg::Transform> attachCamera(const skjson::ObjectValue& jlayer,
86 const skjson::ObjectValue& jtransform,
87 sk_sp<sksg::Transform>,
88 const SkSize&) const;
89
90 sk_sp<sksg::RenderNode> attachOpacity(const skjson::ObjectValue&,
91 sk_sp<sksg::RenderNode>) const;
92 sk_sp<sksg::Path> attachPath(const skjson::Value&) const;
93
94 bool hasNontrivialBlending() const { return fHasNontrivialBlending; }
95
96 class AutoScope final {
97 public:
98 explicit AutoScope(const AnimationBuilder* builder) : AutoScope(builder, AnimatorScope()) {}
99
100 AutoScope(const AnimationBuilder* builder, AnimatorScope&& scope)
101 : fBuilder(builder)
102 , fCurrentScope(std::move(scope))
103 , fPrevScope(fBuilder->fCurrentAnimatorScope) {
104 fBuilder->fCurrentAnimatorScope = &fCurrentScope;
105 }
106
107 AnimatorScope release() {
108 fBuilder->fCurrentAnimatorScope = fPrevScope;
109 SkDEBUGCODE(fBuilder = nullptr);
110
111 return std::move(fCurrentScope);
112 }
113
114 ~AutoScope() { SkASSERT(!fBuilder); }
115
116 private:
117 const AnimationBuilder* fBuilder;
118 AnimatorScope fCurrentScope;
119 AnimatorScope* fPrevScope;
120 };
121
122 template <typename T>
123 void attachDiscardableAdapter(sk_sp<T> adapter) const {
124 if (adapter->isStatic()) {
125 // Fire off a synthetic tick to force a single SG sync before discarding.
126 adapter->seek(0);
127 } else {
128 fCurrentAnimatorScope->push_back(std::move(adapter));
129 }
130 }
131
132 template <typename T, typename... Args>
133 auto attachDiscardableAdapter(Args&&... args) const ->
134 typename std::decay<decltype(T::Make(std::forward<Args>(args)...)->node())>::type
135 {
136 using NodeType =
137 typename std::decay<decltype(T::Make(std::forward<Args>(args)...)->node())>::type;
138
139 NodeType node;
140 if (auto adapter = T::Make(std::forward<Args>(args)...)) {
141 node = adapter->node();
142 this->attachDiscardableAdapter(std::move(adapter));
143 }
144 return node;
145 }
146
147 class AutoPropertyTracker {
148 public:
149 AutoPropertyTracker(const AnimationBuilder* builder, const skjson::ObjectValue& obj)
150 : fBuilder(builder)
151 , fPrevContext(builder->fPropertyObserverContext) {
152 if (fBuilder->fPropertyObserver) {
153 auto observer = builder->fPropertyObserver.get();
154 this->updateContext(observer, obj);
155 observer->onEnterNode(fBuilder->fPropertyObserverContext);
156 }
157 }
158
159 ~AutoPropertyTracker() {
160 if (fBuilder->fPropertyObserver) {
161 fBuilder->fPropertyObserver->onLeavingNode(fBuilder->fPropertyObserverContext);
162 fBuilder->fPropertyObserverContext = fPrevContext;
163 }
164 }
165 private:
166 void updateContext(PropertyObserver*, const skjson::ObjectValue&);
167
168 const AnimationBuilder* fBuilder;
169 const char* fPrevContext;
170 };
171
172 bool dispatchColorProperty(const sk_sp<sksg::Color>&) const;
173 bool dispatchOpacityProperty(const sk_sp<sksg::OpacityEffect>&) const;
174 bool dispatchTextProperty(const sk_sp<TextAdapter>&) const;
175 bool dispatchTransformProperty(const sk_sp<TransformAdapter2D>&) const;
176
177private:
178 friend class CompositionBuilder;
179 friend class LayerBuilder;
180
181 struct AttachLayerContext;
182 struct AttachShapeContext;
183 struct FootageAssetInfo;
184 struct LayerInfo;
185
186 void parseAssets(const skjson::ArrayValue*);
187 void parseFonts (const skjson::ObjectValue* jfonts,
188 const skjson::ArrayValue* jchars);
189
190 // Return true iff all fonts were resolved.
191 bool resolveNativeTypefaces();
192 bool resolveEmbeddedTypefaces(const skjson::ArrayValue& jchars);
193
194 void dispatchMarkers(const skjson::ArrayValue*) const;
195
196 sk_sp<sksg::RenderNode> attachBlendMode(const skjson::ObjectValue&,
197 sk_sp<sksg::RenderNode>) const;
198
199 sk_sp<sksg::RenderNode> attachShape(const skjson::ArrayValue*, AttachShapeContext*,
200 bool suppress_draws = false) const;
201 const FootageAssetInfo* loadFootageAsset(const skjson::ObjectValue&) const;
202 sk_sp<sksg::RenderNode> attachFootageAsset(const skjson::ObjectValue&, LayerInfo*) const;
203
204 sk_sp<sksg::RenderNode> attachExternalPrecompLayer(const skjson::ObjectValue&,
205 const LayerInfo&) const;
206
207 sk_sp<sksg::RenderNode> attachFootageLayer(const skjson::ObjectValue&, LayerInfo*) const;
208 sk_sp<sksg::RenderNode> attachNullLayer (const skjson::ObjectValue&, LayerInfo*) const;
209 sk_sp<sksg::RenderNode> attachPrecompLayer(const skjson::ObjectValue&, LayerInfo*) const;
210 sk_sp<sksg::RenderNode> attachShapeLayer (const skjson::ObjectValue&, LayerInfo*) const;
211 sk_sp<sksg::RenderNode> attachSolidLayer (const skjson::ObjectValue&, LayerInfo*) const;
212 sk_sp<sksg::RenderNode> attachTextLayer (const skjson::ObjectValue&, LayerInfo*) const;
213 sk_sp<sksg::RenderNode> attachAudioLayer (const skjson::ObjectValue&, LayerInfo*) const;
214
215 // Delay resolving the fontmgr until it is actually needed.
216 struct LazyResolveFontMgr {
217 LazyResolveFontMgr(sk_sp<SkFontMgr> fontMgr) : fFontMgr(std::move(fontMgr)) {}
218
219 const sk_sp<SkFontMgr>& get() {
220 if (!fFontMgr) {
221 fFontMgr = SkFontMgr::RefDefault();
222 SkASSERT(fFontMgr);
223 }
224 return fFontMgr;
225 }
226
227 const sk_sp<SkFontMgr>& getMaybeNull() const { return fFontMgr; }
228
229 private:
230 sk_sp<SkFontMgr> fFontMgr;
231 };
232
233 sk_sp<ResourceProvider> fResourceProvider;
234 LazyResolveFontMgr fLazyFontMgr;
235 sk_sp<PropertyObserver> fPropertyObserver;
236 sk_sp<Logger> fLogger;
237 sk_sp<MarkerObserver> fMarkerObserver;
238 sk_sp<PrecompInterceptor> fPrecompInterceptor;
239 Animation::Builder::Stats* fStats;
240 const SkSize fCompSize;
241 const float fDuration,
242 fFrameRate;
243 const uint32_t fFlags;
244 mutable AnimatorScope* fCurrentAnimatorScope;
245 mutable const char* fPropertyObserverContext;
246 mutable bool fHasNontrivialBlending : 1;
247
248 struct LayerInfo {
249 SkSize fSize;
250 const float fInPoint,
251 fOutPoint;
252 };
253
254 struct AssetInfo {
255 const skjson::ObjectValue* fAsset;
256 mutable bool fIsAttaching; // Used for cycle detection
257 };
258
259 struct FootageAssetInfo {
260 sk_sp<ImageAsset> fAsset;
261 SkISize fSize;
262 };
263
264 class ScopedAssetRef {
265 public:
266 ScopedAssetRef(const AnimationBuilder* abuilder, const skjson::ObjectValue& jlayer);
267
268 ~ScopedAssetRef() {
269 if (fInfo) {
270 fInfo->fIsAttaching = false;
271 }
272 }
273
274 operator bool() const { return !!fInfo; }
275
276 const skjson::ObjectValue& operator*() const { return *fInfo->fAsset; }
277
278 private:
279 const AssetInfo* fInfo = nullptr;
280 };
281
282 SkTHashMap<SkString, AssetInfo> fAssets;
283 SkTHashMap<SkString, FontInfo> fFonts;
284 mutable SkTHashMap<SkString, FootageAssetInfo> fImageAssetCache;
285
286 using INHERITED = SkNoncopyable;
287};
288
289} // namespace internal
290} // namespace skottie
291
292#endif // SkottiePriv_DEFINED
293