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 "modules/skottie/include/SkottieProperty.h"
18#include "modules/skottie/src/animator/Animator.h"
19#include "modules/sksg/include/SkSGScene.h"
20#include "src/utils/SkUTF.h"
21
22#include <functional>
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>,
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 SkScalar fAscentPct;
70 sk_sp<SkTypeface> fTypeface;
71
72 bool matches(const char family[], const char style[]) const;
73 };
74 const FontInfo* findFont(const SkString& name) const;
75
76 void log(Logger::Level, const skjson::Value*, const char fmt[], ...) const;
77
78 sk_sp<sksg::Transform> attachMatrix2D(const skjson::ObjectValue&, sk_sp<sksg::Transform>) const;
79 sk_sp<sksg::Transform> attachMatrix3D(const skjson::ObjectValue&, sk_sp<sksg::Transform>) const;
80
81 sk_sp<sksg::Transform> attachCamera(const skjson::ObjectValue& jlayer,
82 const skjson::ObjectValue& jtransform,
83 sk_sp<sksg::Transform>,
84 const SkSize&) const;
85
86 sk_sp<sksg::RenderNode> attachOpacity(const skjson::ObjectValue&,
87 sk_sp<sksg::RenderNode>) const;
88 sk_sp<sksg::Path> attachPath(const skjson::Value&) const;
89
90 bool hasNontrivialBlending() const { return fHasNontrivialBlending; }
91
92 class AutoScope final {
93 public:
94 explicit AutoScope(const AnimationBuilder* builder) : AutoScope(builder, AnimatorScope()) {}
95
96 AutoScope(const AnimationBuilder* builder, AnimatorScope&& scope)
97 : fBuilder(builder)
98 , fCurrentScope(std::move(scope))
99 , fPrevScope(fBuilder->fCurrentAnimatorScope) {
100 fBuilder->fCurrentAnimatorScope = &fCurrentScope;
101 }
102
103 AnimatorScope release() {
104 fBuilder->fCurrentAnimatorScope = fPrevScope;
105 SkDEBUGCODE(fBuilder = nullptr);
106
107 return std::move(fCurrentScope);
108 }
109
110 ~AutoScope() { SkASSERT(!fBuilder); }
111
112 private:
113 const AnimationBuilder* fBuilder;
114 AnimatorScope fCurrentScope;
115 AnimatorScope* fPrevScope;
116 };
117
118 template <typename T>
119 void attachDiscardableAdapter(sk_sp<T> adapter) const {
120 if (adapter->isStatic()) {
121 // Fire off a synthetic tick to force a single SG sync before discarding.
122 adapter->seek(0);
123 } else {
124 fCurrentAnimatorScope->push_back(std::move(adapter));
125 }
126 }
127
128 template <typename T, typename... Args>
129 auto attachDiscardableAdapter(Args&&... args) const ->
130 typename std::decay<decltype(T::Make(std::forward<Args>(args)...)->node())>::type
131 {
132 using NodeType =
133 typename std::decay<decltype(T::Make(std::forward<Args>(args)...)->node())>::type;
134
135 NodeType node;
136 if (auto adapter = T::Make(std::forward<Args>(args)...)) {
137 node = adapter->node();
138 this->attachDiscardableAdapter(std::move(adapter));
139 }
140 return node;
141 }
142
143 class AutoPropertyTracker {
144 public:
145 AutoPropertyTracker(const AnimationBuilder* builder, const skjson::ObjectValue& obj)
146 : fBuilder(builder)
147 , fPrevContext(builder->fPropertyObserverContext) {
148 if (fBuilder->fPropertyObserver) {
149 auto observer = builder->fPropertyObserver.get();
150 this->updateContext(observer, obj);
151 observer->onEnterNode(fBuilder->fPropertyObserverContext);
152 }
153 }
154
155 ~AutoPropertyTracker() {
156 if (fBuilder->fPropertyObserver) {
157 fBuilder->fPropertyObserver->onLeavingNode(fBuilder->fPropertyObserverContext);
158 fBuilder->fPropertyObserverContext = fPrevContext;
159 }
160 }
161 private:
162 void updateContext(PropertyObserver*, const skjson::ObjectValue&);
163
164 const AnimationBuilder* fBuilder;
165 const char* fPrevContext;
166 };
167
168 bool dispatchColorProperty(const sk_sp<sksg::Color>&) const;
169 bool dispatchOpacityProperty(const sk_sp<sksg::OpacityEffect>&) const;
170 bool dispatchTextProperty(const sk_sp<TextAdapter>&) const;
171 bool dispatchTransformProperty(const sk_sp<TransformAdapter2D>&) const;
172
173private:
174 friend class CompositionBuilder;
175 friend class LayerBuilder;
176
177 struct AttachLayerContext;
178 struct AttachShapeContext;
179 struct ImageAssetInfo;
180 struct LayerInfo;
181
182 void parseAssets(const skjson::ArrayValue*);
183 void parseFonts (const skjson::ObjectValue* jfonts,
184 const skjson::ArrayValue* jchars);
185
186 void dispatchMarkers(const skjson::ArrayValue*) const;
187
188 sk_sp<sksg::RenderNode> attachBlendMode(const skjson::ObjectValue&,
189 sk_sp<sksg::RenderNode>) const;
190
191 sk_sp<sksg::RenderNode> attachShape(const skjson::ArrayValue*, AttachShapeContext*) const;
192 sk_sp<sksg::RenderNode> attachAssetRef(const skjson::ObjectValue&,
193 const std::function<sk_sp<sksg::RenderNode>(const skjson::ObjectValue&)>&) const;
194 const ImageAssetInfo* loadImageAsset(const skjson::ObjectValue&) const;
195 sk_sp<sksg::RenderNode> attachImageAsset(const skjson::ObjectValue&, LayerInfo*) const;
196
197 sk_sp<sksg::RenderNode> attachNestedAnimation(const char* name) const;
198
199 sk_sp<sksg::RenderNode> attachImageLayer (const skjson::ObjectValue&, LayerInfo*) const;
200 sk_sp<sksg::RenderNode> attachNullLayer (const skjson::ObjectValue&, LayerInfo*) const;
201 sk_sp<sksg::RenderNode> attachPrecompLayer(const skjson::ObjectValue&, LayerInfo*) const;
202 sk_sp<sksg::RenderNode> attachShapeLayer (const skjson::ObjectValue&, LayerInfo*) const;
203 sk_sp<sksg::RenderNode> attachSolidLayer (const skjson::ObjectValue&, LayerInfo*) const;
204 sk_sp<sksg::RenderNode> attachTextLayer (const skjson::ObjectValue&, LayerInfo*) const;
205
206 // Delay resolving the fontmgr until it is actually needed.
207 struct LazyResolveFontMgr {
208 LazyResolveFontMgr(sk_sp<SkFontMgr> fontMgr) : fFontMgr(std::move(fontMgr)) {}
209
210 const sk_sp<SkFontMgr>& get() {
211 if (!fFontMgr) {
212 fFontMgr = SkFontMgr::RefDefault();
213 SkASSERT(fFontMgr);
214 }
215 return fFontMgr;
216 }
217
218 const sk_sp<SkFontMgr>& getMaybeNull() const { return fFontMgr; }
219
220 private:
221 sk_sp<SkFontMgr> fFontMgr;
222 };
223
224 sk_sp<ResourceProvider> fResourceProvider;
225 LazyResolveFontMgr fLazyFontMgr;
226 sk_sp<PropertyObserver> fPropertyObserver;
227 sk_sp<Logger> fLogger;
228 sk_sp<MarkerObserver> fMarkerObserver;
229 Animation::Builder::Stats* fStats;
230 const SkSize fCompSize;
231 const float fDuration,
232 fFrameRate;
233 const uint32_t fFlags;
234 mutable AnimatorScope* fCurrentAnimatorScope;
235 mutable const char* fPropertyObserverContext;
236 mutable bool fHasNontrivialBlending : 1;
237
238 struct LayerInfo {
239 SkSize fSize;
240 const float fInPoint,
241 fOutPoint;
242 };
243
244 struct AssetInfo {
245 const skjson::ObjectValue* fAsset;
246 mutable bool fIsAttaching; // Used for cycle detection
247 };
248
249 struct ImageAssetInfo {
250 sk_sp<ImageAsset> fAsset;
251 SkISize fSize;
252 };
253
254 SkTHashMap<SkString, AssetInfo> fAssets;
255 SkTHashMap<SkString, FontInfo> fFonts;
256 mutable SkTHashMap<SkString, ImageAssetInfo> fImageAssetCache;
257
258 using INHERITED = SkNoncopyable;
259};
260
261} // namespace internal
262} // namespace skottie
263
264#endif // SkottiePriv_DEFINED
265