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 
82 private:
83     struct AttachLayerContext;
84     struct AttachShapeContext;
85     struct ImageAssetInfo;
86     struct LayerInfo;
87 
88     void parseAssets(const skjson::ArrayValue*);
89     void parseFonts (const skjson::ObjectValue* jfonts,
90                      const skjson::ArrayValue* jchars);
91 
92     void dispatchMarkers(const skjson::ArrayValue*) const;
93 
94     sk_sp<sksg::RenderNode> attachComposition(const skjson::ObjectValue&, AnimatorScope*) const;
95     sk_sp<sksg::RenderNode> attachLayer(const skjson::ObjectValue*, AttachLayerContext*) const;
96     sk_sp<sksg::RenderNode> attachLayerEffects(const skjson::ArrayValue& jeffects, AnimatorScope*,
97                                                sk_sp<sksg::RenderNode>) const;
98 
99     sk_sp<sksg::RenderNode> attachShape(const skjson::ArrayValue*, AttachShapeContext*) const;
100     sk_sp<sksg::RenderNode> attachAssetRef(const skjson::ObjectValue&, AnimatorScope*,
101         const std::function<sk_sp<sksg::RenderNode>(const skjson::ObjectValue&,
102                                                     AnimatorScope* ctx)>&) const;
103     const ImageAssetInfo* loadImageAsset(const skjson::ObjectValue&) const;
104     sk_sp<sksg::RenderNode> attachImageAsset(const skjson::ObjectValue&, const LayerInfo&,
105                                              AnimatorScope*) const;
106 
107     sk_sp<sksg::RenderNode> attachNestedAnimation(const char* name, AnimatorScope* ascope) const;
108 
109     sk_sp<sksg::RenderNode> attachImageLayer  (const skjson::ObjectValue&, const LayerInfo&,
110                                                AnimatorScope*) const;
111     sk_sp<sksg::RenderNode> attachNullLayer   (const skjson::ObjectValue&, const LayerInfo&,
112                                                AnimatorScope*) const;
113     sk_sp<sksg::RenderNode> attachPrecompLayer(const skjson::ObjectValue&, const LayerInfo&,
114                                                AnimatorScope*) const;
115     sk_sp<sksg::RenderNode> attachShapeLayer  (const skjson::ObjectValue&, const LayerInfo&,
116                                                AnimatorScope*) const;
117     sk_sp<sksg::RenderNode> attachSolidLayer  (const skjson::ObjectValue&, const LayerInfo&,
118                                                AnimatorScope*) const;
119     sk_sp<sksg::RenderNode> attachTextLayer   (const skjson::ObjectValue&, const LayerInfo&,
120                                                AnimatorScope*) const;
121 
122     bool dispatchColorProperty(const sk_sp<sksg::Color>&) const;
123     bool dispatchOpacityProperty(const sk_sp<sksg::OpacityEffect>&) const;
124     bool dispatchTransformProperty(const sk_sp<TransformAdapter2D>&) const;
125 
126     // Delay resolving the fontmgr until it is actually needed.
127     struct LazyResolveFontMgr {
LazyResolveFontMgrLazyResolveFontMgr128         LazyResolveFontMgr(sk_sp<SkFontMgr> fontMgr) : fFontMgr(std::move(fontMgr)) {}
129 
getLazyResolveFontMgr130         const sk_sp<SkFontMgr>& get() {
131             if (!fFontMgr) {
132                 fFontMgr = SkFontMgr::RefDefault();
133                 SkASSERT(fFontMgr);
134             }
135             return fFontMgr;
136         }
137 
getMaybeNullLazyResolveFontMgr138         const sk_sp<SkFontMgr>& getMaybeNull() const { return fFontMgr; }
139 
140     private:
141         sk_sp<SkFontMgr> fFontMgr;
142     };
143 
144     class AutoPropertyTracker {
145     public:
AutoPropertyTracker(const AnimationBuilder * builder,const skjson::ObjectValue & obj)146         AutoPropertyTracker(const AnimationBuilder* builder, const skjson::ObjectValue& obj)
147             : fBuilder(builder)
148             , fPrevContext(builder->fPropertyObserverContext) {
149             if (fBuilder->fPropertyObserver) {
150                 this->updateContext(builder->fPropertyObserver.get(), obj);
151             }
152         }
153 
~AutoPropertyTracker()154         ~AutoPropertyTracker() {
155             if (fBuilder->fPropertyObserver) {
156                 fBuilder->fPropertyObserverContext = fPrevContext;
157             }
158         }
159     private:
160         void updateContext(PropertyObserver*, const skjson::ObjectValue&);
161 
162         const AnimationBuilder* fBuilder;
163         const char*             fPrevContext;
164     };
165 
166     sk_sp<ResourceProvider>    fResourceProvider;
167     LazyResolveFontMgr         fLazyFontMgr;
168     sk_sp<PropertyObserver>    fPropertyObserver;
169     sk_sp<Logger>              fLogger;
170     sk_sp<MarkerObserver>      fMarkerObserver;
171     Animation::Builder::Stats* fStats;
172     const float                fDuration,
173                                fFrameRate;
174 
175     mutable const char*        fPropertyObserverContext;
176 
177     struct LayerInfo {
178         float fInPoint,
179               fOutPoint;
180     };
181 
182     struct AssetInfo {
183         const skjson::ObjectValue* fAsset;
184         mutable bool               fIsAttaching; // Used for cycle detection
185     };
186 
187     struct FontInfo {
188         SkString                  fFamily,
189                                   fStyle;
190         SkScalar                  fAscent;
191         sk_sp<SkTypeface>         fTypeface;
192 
193         bool matches(const char family[], const char style[]) const;
194     };
195 
196     struct ImageAssetInfo {
197         sk_sp<ImageAsset> fAsset;
198         SkISize           fSize;
199     };
200 
201     SkTHashMap<SkString, AssetInfo>              fAssets;
202     SkTHashMap<SkString, FontInfo>               fFonts;
203     mutable SkTHashMap<SkString, ImageAssetInfo> fImageAssetCache;
204 
205     using INHERITED = SkNoncopyable;
206 };
207 
208 } // namespace internal
209 } // namespace skottie
210 
211 #endif // SkottiePriv_DEFINED
212