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 "Skottie.h"
12 
13 #include "SkFontStyle.h"
14 #include "SkottieProperty.h"
15 #include "SkSGScene.h"
16 #include "SkString.h"
17 #include "SkTHash.h"
18 #include "SkTypeface.h"
19 #include "SkUTF.h"
20 
21 #include <functional>
22 
23 class SkFontMgr;
24 
25 namespace skjson {
26 class ArrayValue;
27 class ObjectValue;
28 class Value;
29 } // namespace skjson
30 
31 namespace sksg {
32 class Color;
33 class Path;
34 class RenderNode;
35 class Transform;
36 } // namespace sksg
37 
38 namespace skottie {
39 
40 namespace internal {
41 
42 using AnimatorScope = sksg::AnimatorList;
43 
44 class AnimationBuilder final : public SkNoncopyable {
45 public:
46     AnimationBuilder(sk_sp<ResourceProvider>, sk_sp<SkFontMgr>, sk_sp<PropertyObserver>,
47                      sk_sp<Logger>, sk_sp<MarkerObserver>,
48                      Animation::Builder::Stats*, float duration, float framerate);
49 
50     std::unique_ptr<sksg::Scene> parse(const skjson::ObjectValue&);
51 
52     sk_sp<SkTypeface> findFont(const SkString& name) const;
53 
54     // This is the workhorse for property binding: depending on whether the property is animated,
55     // it will either apply immediately or instantiate and attach a keyframe animator.
56     template <typename T>
57     bool bindProperty(const skjson::Value&,
58                       AnimatorScope*,
59                       std::function<void(const T&)>&&,
60                       const T* default_igore = nullptr) const;
61 
62     template <typename T>
bindProperty(const skjson::Value & jv,AnimatorScope * ascope,std::function<void (const T &)> && apply,const T & default_ignore)63     bool bindProperty(const skjson::Value& jv,
64                       AnimatorScope* ascope,
65                       std::function<void(const T&)>&& apply,
66                       const T& default_ignore) const {
67         return this->bindProperty(jv, ascope, std::move(apply), &default_ignore);
68     }
69 
70     void log(Logger::Level, const skjson::Value*, const char fmt[], ...) const;
71 
72     sk_sp<sksg::Color> attachColor(const skjson::ObjectValue&, AnimatorScope*,
73                                    const char prop_name[]) const;
74     sk_sp<sksg::Transform> attachMatrix2D(const skjson::ObjectValue&, AnimatorScope*,
75                                           sk_sp<sksg::Transform>) const;
76     sk_sp<sksg::Transform> attachMatrix3D(const skjson::ObjectValue&, AnimatorScope*,
77                                           sk_sp<sksg::Transform>) const;
78     sk_sp<sksg::RenderNode> attachOpacity(const skjson::ObjectValue&, AnimatorScope*,
79                                       sk_sp<sksg::RenderNode>) const;
80     sk_sp<sksg::Path> attachPath(const skjson::Value&, AnimatorScope*) const;
81 
hasNontrivialBlending()82     bool hasNontrivialBlending() const { return fHasNontrivialBlending; }
83 
84 private:
85     struct AttachLayerContext;
86     struct AttachShapeContext;
87     struct ImageAssetInfo;
88     struct LayerInfo;
89 
90     void parseAssets(const skjson::ArrayValue*);
91     void parseFonts (const skjson::ObjectValue* jfonts,
92                      const skjson::ArrayValue* jchars);
93 
94     void dispatchMarkers(const skjson::ArrayValue*) const;
95 
96     sk_sp<sksg::RenderNode> attachComposition(const skjson::ObjectValue&, AnimatorScope*) const;
97     sk_sp<sksg::RenderNode> attachLayer(const skjson::ObjectValue*, AttachLayerContext*) const;
98     sk_sp<sksg::RenderNode> attachLayerEffects(const skjson::ArrayValue& jeffects, AnimatorScope*,
99                                                sk_sp<sksg::RenderNode>) const;
100 
101     sk_sp<sksg::RenderNode> attachBlendMode(const skjson::ObjectValue&,
102                                             sk_sp<sksg::RenderNode>) const;
103 
104     sk_sp<sksg::RenderNode> attachShape(const skjson::ArrayValue*, AttachShapeContext*) const;
105     sk_sp<sksg::RenderNode> attachAssetRef(const skjson::ObjectValue&, AnimatorScope*,
106         const std::function<sk_sp<sksg::RenderNode>(const skjson::ObjectValue&,
107                                                     AnimatorScope* ctx)>&) const;
108     const ImageAssetInfo* loadImageAsset(const skjson::ObjectValue&) const;
109     sk_sp<sksg::RenderNode> attachImageAsset(const skjson::ObjectValue&, const LayerInfo&,
110                                              AnimatorScope*) const;
111 
112     sk_sp<sksg::RenderNode> attachNestedAnimation(const char* name, AnimatorScope* ascope) const;
113 
114     sk_sp<sksg::RenderNode> attachImageLayer  (const skjson::ObjectValue&, const LayerInfo&,
115                                                AnimatorScope*) const;
116     sk_sp<sksg::RenderNode> attachNullLayer   (const skjson::ObjectValue&, const LayerInfo&,
117                                                AnimatorScope*) const;
118     sk_sp<sksg::RenderNode> attachPrecompLayer(const skjson::ObjectValue&, const LayerInfo&,
119                                                AnimatorScope*) const;
120     sk_sp<sksg::RenderNode> attachShapeLayer  (const skjson::ObjectValue&, const LayerInfo&,
121                                                AnimatorScope*) const;
122     sk_sp<sksg::RenderNode> attachSolidLayer  (const skjson::ObjectValue&, const LayerInfo&,
123                                                AnimatorScope*) const;
124     sk_sp<sksg::RenderNode> attachTextLayer   (const skjson::ObjectValue&, const LayerInfo&,
125                                                AnimatorScope*) const;
126 
127     bool dispatchColorProperty(const sk_sp<sksg::Color>&) const;
128     bool dispatchOpacityProperty(const sk_sp<sksg::OpacityEffect>&) const;
129     bool dispatchTransformProperty(const sk_sp<TransformAdapter2D>&) const;
130 
131     // Delay resolving the fontmgr until it is actually needed.
132     struct LazyResolveFontMgr {
LazyResolveFontMgrLazyResolveFontMgr133         LazyResolveFontMgr(sk_sp<SkFontMgr> fontMgr) : fFontMgr(std::move(fontMgr)) {}
134 
getLazyResolveFontMgr135         const sk_sp<SkFontMgr>& get() {
136             if (!fFontMgr) {
137                 fFontMgr = SkFontMgr::RefDefault();
138                 SkASSERT(fFontMgr);
139             }
140             return fFontMgr;
141         }
142 
getMaybeNullLazyResolveFontMgr143         const sk_sp<SkFontMgr>& getMaybeNull() const { return fFontMgr; }
144 
145     private:
146         sk_sp<SkFontMgr> fFontMgr;
147     };
148 
149     class AutoPropertyTracker {
150     public:
AutoPropertyTracker(const AnimationBuilder * builder,const skjson::ObjectValue & obj)151         AutoPropertyTracker(const AnimationBuilder* builder, const skjson::ObjectValue& obj)
152             : fBuilder(builder)
153             , fPrevContext(builder->fPropertyObserverContext) {
154             if (fBuilder->fPropertyObserver) {
155                 this->updateContext(builder->fPropertyObserver.get(), obj);
156             }
157         }
158 
~AutoPropertyTracker()159         ~AutoPropertyTracker() {
160             if (fBuilder->fPropertyObserver) {
161                 fBuilder->fPropertyObserverContext = fPrevContext;
162             }
163         }
164     private:
165         void updateContext(PropertyObserver*, const skjson::ObjectValue&);
166 
167         const AnimationBuilder* fBuilder;
168         const char*             fPrevContext;
169     };
170 
171     sk_sp<ResourceProvider>    fResourceProvider;
172     LazyResolveFontMgr         fLazyFontMgr;
173     sk_sp<PropertyObserver>    fPropertyObserver;
174     sk_sp<Logger>              fLogger;
175     sk_sp<MarkerObserver>      fMarkerObserver;
176     Animation::Builder::Stats* fStats;
177     const float                fDuration,
178                                fFrameRate;
179     mutable const char*        fPropertyObserverContext;
180     mutable bool               fHasNontrivialBlending : 1;
181 
182 
183     struct LayerInfo {
184         float fInPoint,
185               fOutPoint;
186     };
187 
188     struct AssetInfo {
189         const skjson::ObjectValue* fAsset;
190         mutable bool               fIsAttaching; // Used for cycle detection
191     };
192 
193     struct FontInfo {
194         SkString                  fFamily,
195                                   fStyle;
196         SkScalar                  fAscent;
197         sk_sp<SkTypeface>         fTypeface;
198 
199         bool matches(const char family[], const char style[]) const;
200     };
201 
202     struct ImageAssetInfo {
203         sk_sp<ImageAsset> fAsset;
204         SkISize           fSize;
205     };
206 
207     SkTHashMap<SkString, AssetInfo>              fAssets;
208     SkTHashMap<SkString, FontInfo>               fFonts;
209     mutable SkTHashMap<SkString, ImageAssetInfo> fImageAssetCache;
210 
211     using INHERITED = SkNoncopyable;
212 };
213 
214 } // namespace internal
215 } // namespace skottie
216 
217 #endif // SkottiePriv_DEFINED
218