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/sksg/include/SkSGScene.h" 19 #include "src/utils/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 class TransformAdapter2D; 41 class TransformAdapter3D; 42 43 namespace internal { 44 45 class TextAdapter; 46 47 using AnimatorScope = sksg::AnimatorList; 48 49 class AnimationBuilder final : public SkNoncopyable { 50 public: 51 AnimationBuilder(sk_sp<ResourceProvider>, sk_sp<SkFontMgr>, sk_sp<PropertyObserver>, 52 sk_sp<Logger>, sk_sp<MarkerObserver>, 53 Animation::Builder::Stats*, const SkSize& size, 54 float duration, float framerate); 55 56 std::unique_ptr<sksg::Scene> parse(const skjson::ObjectValue&); 57 58 struct FontInfo { 59 SkString fFamily, 60 fStyle; 61 SkScalar fAscentPct; 62 sk_sp<SkTypeface> fTypeface; 63 64 bool matches(const char family[], const char style[]) const; 65 }; 66 const FontInfo* findFont(const SkString& name) const; 67 68 // This is the workhorse for property binding: depending on whether the property is animated, 69 // it will either apply immediately or instantiate and attach a keyframe animator. 70 template <typename T> 71 bool bindProperty(const skjson::Value&, 72 std::function<void(const T&)>&&, 73 const T* default_igore = nullptr) const; 74 75 template <typename T> bindProperty(const skjson::Value & jv,std::function<void (const T &)> && apply,const T & default_ignore)76 bool bindProperty(const skjson::Value& jv, 77 std::function<void(const T&)>&& apply, 78 const T& default_ignore) const { 79 return this->bindProperty(jv, std::move(apply), &default_ignore); 80 } 81 82 void log(Logger::Level, const skjson::Value*, const char fmt[], ...) const; 83 84 sk_sp<sksg::Color> attachColor(const skjson::ObjectValue&, const char prop_name[]) const; 85 sk_sp<sksg::Transform> attachMatrix2D(const skjson::ObjectValue&, sk_sp<sksg::Transform>) const; 86 sk_sp<sksg::Transform> attachMatrix3D(const skjson::ObjectValue&, sk_sp<sksg::Transform>, 87 sk_sp<TransformAdapter3D> = nullptr, 88 bool precompose_parent = false) const; 89 sk_sp<sksg::RenderNode> attachOpacity(const skjson::ObjectValue&, 90 sk_sp<sksg::RenderNode>) const; 91 sk_sp<sksg::Path> attachPath(const skjson::Value&) const; 92 hasNontrivialBlending()93 bool hasNontrivialBlending() const { return fHasNontrivialBlending; } 94 95 class AutoScope final { 96 public: AutoScope(const AnimationBuilder * builder)97 explicit AutoScope(const AnimationBuilder* builder) : AutoScope(builder, AnimatorScope()) {} 98 AutoScope(const AnimationBuilder * builder,AnimatorScope && scope)99 AutoScope(const AnimationBuilder* builder, AnimatorScope&& scope) 100 : fBuilder(builder) 101 , fCurrentScope(std::move(scope)) 102 , fPrevScope(fBuilder->fCurrentAnimatorScope) { 103 fBuilder->fCurrentAnimatorScope = &fCurrentScope; 104 } 105 release()106 AnimatorScope release() { 107 fBuilder->fCurrentAnimatorScope = fPrevScope; 108 SkDEBUGCODE(fBuilder = nullptr); 109 110 return std::move(fCurrentScope); 111 } 112 ~AutoScope()113 ~AutoScope() { SkASSERT(!fBuilder); } 114 115 private: 116 const AnimationBuilder* fBuilder; 117 AnimatorScope fCurrentScope; 118 AnimatorScope* fPrevScope; 119 }; 120 121 template <typename T, typename... Args> attachDiscardableAdapter(Args &&...args)122 sk_sp<sksg::RenderNode> attachDiscardableAdapter(Args&&... args) const { 123 AutoScope ascope(this); 124 auto adapter = T::Make(std::forward<Args>(args)...); 125 auto adapter_animators = ascope.release(); 126 127 if (!adapter) { return nullptr; } 128 129 const auto& node = adapter->renderNode(); 130 if (adapter_animators.empty()) { 131 // Fire off a synthetic tick to force a single SG sync before discarding the adapter. 132 adapter->tick(0); 133 } else { 134 adapter->setAnimators(std::move(adapter_animators)); 135 fCurrentAnimatorScope->push_back(std::move(adapter)); 136 } 137 138 return node; 139 } 140 141 class AutoPropertyTracker { 142 public: AutoPropertyTracker(const AnimationBuilder * builder,const skjson::ObjectValue & obj)143 AutoPropertyTracker(const AnimationBuilder* builder, const skjson::ObjectValue& obj) 144 : fBuilder(builder) 145 , fPrevContext(builder->fPropertyObserverContext) { 146 if (fBuilder->fPropertyObserver) { 147 this->updateContext(builder->fPropertyObserver.get(), obj); 148 } 149 } 150 ~AutoPropertyTracker()151 ~AutoPropertyTracker() { 152 if (fBuilder->fPropertyObserver) { 153 fBuilder->fPropertyObserverContext = fPrevContext; 154 } 155 } 156 private: 157 void updateContext(PropertyObserver*, const skjson::ObjectValue&); 158 159 const AnimationBuilder* fBuilder; 160 const char* fPrevContext; 161 }; 162 163 private: 164 struct AttachLayerContext; 165 struct AttachShapeContext; 166 struct ImageAssetInfo; 167 struct LayerInfo; 168 169 void parseAssets(const skjson::ArrayValue*); 170 void parseFonts (const skjson::ObjectValue* jfonts, 171 const skjson::ArrayValue* jchars); 172 173 void dispatchMarkers(const skjson::ArrayValue*) const; 174 175 sk_sp<sksg::RenderNode> attachComposition(const skjson::ObjectValue&) const; 176 sk_sp<sksg::RenderNode> attachLayer(const skjson::ObjectValue*, 177 AttachLayerContext*) const; 178 179 sk_sp<sksg::RenderNode> attachBlendMode(const skjson::ObjectValue&, 180 sk_sp<sksg::RenderNode>) const; 181 182 sk_sp<sksg::RenderNode> attachShape(const skjson::ArrayValue*, AttachShapeContext*) const; 183 sk_sp<sksg::RenderNode> attachAssetRef(const skjson::ObjectValue&, 184 const std::function<sk_sp<sksg::RenderNode>(const skjson::ObjectValue&)>&) const; 185 const ImageAssetInfo* loadImageAsset(const skjson::ObjectValue&) const; 186 sk_sp<sksg::RenderNode> attachImageAsset(const skjson::ObjectValue&, LayerInfo*) const; 187 188 sk_sp<sksg::RenderNode> attachNestedAnimation(const char* name) const; 189 190 sk_sp<sksg::RenderNode> attachImageLayer (const skjson::ObjectValue&, LayerInfo*) const; 191 sk_sp<sksg::RenderNode> attachNullLayer (const skjson::ObjectValue&, LayerInfo*) const; 192 sk_sp<sksg::RenderNode> attachPrecompLayer(const skjson::ObjectValue&, LayerInfo*) const; 193 sk_sp<sksg::RenderNode> attachShapeLayer (const skjson::ObjectValue&, LayerInfo*) const; 194 sk_sp<sksg::RenderNode> attachSolidLayer (const skjson::ObjectValue&, LayerInfo*) const; 195 sk_sp<sksg::RenderNode> attachTextLayer (const skjson::ObjectValue&, LayerInfo*) const; 196 197 bool dispatchColorProperty(const sk_sp<sksg::Color>&) const; 198 bool dispatchOpacityProperty(const sk_sp<sksg::OpacityEffect>&) const; 199 bool dispatchTextProperty(const sk_sp<TextAdapter>&) const; 200 bool dispatchTransformProperty(const sk_sp<TransformAdapter2D>&) const; 201 202 // Delay resolving the fontmgr until it is actually needed. 203 struct LazyResolveFontMgr { LazyResolveFontMgrLazyResolveFontMgr204 LazyResolveFontMgr(sk_sp<SkFontMgr> fontMgr) : fFontMgr(std::move(fontMgr)) {} 205 getLazyResolveFontMgr206 const sk_sp<SkFontMgr>& get() { 207 if (!fFontMgr) { 208 fFontMgr = SkFontMgr::RefDefault(); 209 SkASSERT(fFontMgr); 210 } 211 return fFontMgr; 212 } 213 getMaybeNullLazyResolveFontMgr214 const sk_sp<SkFontMgr>& getMaybeNull() const { return fFontMgr; } 215 216 private: 217 sk_sp<SkFontMgr> fFontMgr; 218 }; 219 220 sk_sp<ResourceProvider> fResourceProvider; 221 LazyResolveFontMgr fLazyFontMgr; 222 sk_sp<PropertyObserver> fPropertyObserver; 223 sk_sp<Logger> fLogger; 224 sk_sp<MarkerObserver> fMarkerObserver; 225 Animation::Builder::Stats* fStats; 226 const SkSize fSize; 227 const float fDuration, 228 fFrameRate; 229 mutable AnimatorScope* fCurrentAnimatorScope; 230 mutable const char* fPropertyObserverContext; 231 mutable bool fHasNontrivialBlending : 1; 232 233 struct LayerInfo { 234 SkSize fSize; 235 const float fInPoint, 236 fOutPoint; 237 }; 238 239 struct AssetInfo { 240 const skjson::ObjectValue* fAsset; 241 mutable bool fIsAttaching; // Used for cycle detection 242 }; 243 244 struct ImageAssetInfo { 245 sk_sp<ImageAsset> fAsset; 246 SkISize fSize; 247 }; 248 249 SkTHashMap<SkString, AssetInfo> fAssets; 250 SkTHashMap<SkString, FontInfo> fFonts; 251 mutable SkTHashMap<SkString, ImageAssetInfo> fImageAssetCache; 252 253 using INHERITED = SkNoncopyable; 254 }; 255 256 struct AnimationBuilder::AttachLayerContext { 257 explicit AttachLayerContext(const skjson::ArrayValue&); 258 ~AttachLayerContext(); 259 260 struct TransformRec { 261 sk_sp<sksg::Transform> fTransformNode; 262 AnimatorScope fTransformScope; 263 }; 264 265 const skjson::ArrayValue& fLayerList; 266 SkTHashMap<int, TransformRec> fLayerTransformMap; 267 sk_sp<sksg::RenderNode> fCurrentMatte; 268 sk_sp<sksg::Transform> fCameraTransform; 269 270 size_t fMotionBlurSamples = 1; 271 float fMotionBlurAngle = 0, 272 fMotionBlurPhase = 0; 273 274 enum class TransformType { kLayer, kCamera }; 275 276 TransformRec attachLayerTransform(const skjson::ObjectValue& jlayer, 277 const AnimationBuilder* abuilder, 278 TransformType type = TransformType::kLayer); 279 280 bool hasMotionBlur(const skjson::ObjectValue& jlayer) const; 281 282 private: 283 sk_sp<sksg::Transform> attachParentLayerTransform(const skjson::ObjectValue& jlayer, 284 const AnimationBuilder* abuilder, 285 int layer_index); 286 287 sk_sp<sksg::Transform> attachTransformNode(const skjson::ObjectValue& jlayer, 288 const AnimationBuilder* abuilder, 289 sk_sp<sksg::Transform> parent_transform, 290 TransformType type) const; 291 292 TransformRec* attachLayerTransformImpl(const skjson::ObjectValue& jlayer, 293 const AnimationBuilder* abuilder, 294 TransformType type, int layer_index); 295 }; 296 297 } // namespace internal 298 } // namespace skottie 299 300 #endif // SkottiePriv_DEFINED 301