/* * Copyright 2018 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkottiePriv_DEFINED #define SkottiePriv_DEFINED #include "modules/skottie/include/Skottie.h" #include "include/core/SkFontStyle.h" #include "include/core/SkString.h" #include "include/core/SkTypeface.h" #include "include/private/SkTHash.h" #include "include/utils/SkCustomTypeface.h" #include "modules/skottie/include/SkottieProperty.h" #include "modules/skottie/src/animator/Animator.h" #include "modules/sksg/include/SkSGScene.h" #include "src/utils/SkUTF.h" #include class SkFontMgr; namespace skjson { class ArrayValue; class ObjectValue; class Value; } // namespace skjson namespace sksg { class Color; class Path; class RenderNode; class Transform; } // namespace sksg namespace skottie { namespace internal { // Close-enough to AE. static constexpr float kBlurSizeToSigma = 0.3f; class TextAdapter; class TransformAdapter2D; class TransformAdapter3D; using AnimatorScope = std::vector>; class AnimationBuilder final : public SkNoncopyable { public: AnimationBuilder(sk_sp, sk_sp, sk_sp, sk_sp, sk_sp, sk_sp, sk_sp, Animation::Builder::Stats*, const SkSize& comp_size, float duration, float framerate, uint32_t flags); struct AnimationInfo { std::unique_ptr fScene; AnimatorScope fAnimators; }; AnimationInfo parse(const skjson::ObjectValue&); struct FontInfo { SkString fFamily, fStyle, fPath; SkScalar fAscentPct; sk_sp fTypeface; SkCustomTypefaceBuilder fCustomBuilder; bool matches(const char family[], const char style[]) const; }; const FontInfo* findFont(const SkString& name) const; void log(Logger::Level, const skjson::Value*, const char fmt[], ...) const; sk_sp attachMatrix2D(const skjson::ObjectValue&, sk_sp, bool auto_orient = false) const; sk_sp attachMatrix3D(const skjson::ObjectValue&, sk_sp, bool auto_orient = false) const; sk_sp attachCamera(const skjson::ObjectValue& jlayer, const skjson::ObjectValue& jtransform, sk_sp, const SkSize&) const; sk_sp attachOpacity(const skjson::ObjectValue&, sk_sp) const; sk_sp attachPath(const skjson::Value&) const; bool hasNontrivialBlending() const { return fHasNontrivialBlending; } class AutoScope final { public: explicit AutoScope(const AnimationBuilder* builder) : AutoScope(builder, AnimatorScope()) {} AutoScope(const AnimationBuilder* builder, AnimatorScope&& scope) : fBuilder(builder) , fCurrentScope(std::move(scope)) , fPrevScope(fBuilder->fCurrentAnimatorScope) { fBuilder->fCurrentAnimatorScope = &fCurrentScope; } AnimatorScope release() { fBuilder->fCurrentAnimatorScope = fPrevScope; SkDEBUGCODE(fBuilder = nullptr); return std::move(fCurrentScope); } ~AutoScope() { SkASSERT(!fBuilder); } private: const AnimationBuilder* fBuilder; AnimatorScope fCurrentScope; AnimatorScope* fPrevScope; }; template void attachDiscardableAdapter(sk_sp adapter) const { if (adapter->isStatic()) { // Fire off a synthetic tick to force a single SG sync before discarding. adapter->seek(0); } else { fCurrentAnimatorScope->push_back(std::move(adapter)); } } template auto attachDiscardableAdapter(Args&&... args) const -> typename std::decay(args)...)->node())>::type { using NodeType = typename std::decay(args)...)->node())>::type; NodeType node; if (auto adapter = T::Make(std::forward(args)...)) { node = adapter->node(); this->attachDiscardableAdapter(std::move(adapter)); } return node; } class AutoPropertyTracker { public: AutoPropertyTracker(const AnimationBuilder* builder, const skjson::ObjectValue& obj, const PropertyObserver::NodeType node_type) : fBuilder(builder) , fPrevContext(builder->fPropertyObserverContext), fNodeType(node_type) { if (fBuilder->fPropertyObserver) { auto observer = builder->fPropertyObserver.get(); this->updateContext(observer, obj); observer->onEnterNode(fBuilder->fPropertyObserverContext, fNodeType); } } ~AutoPropertyTracker() { if (fBuilder->fPropertyObserver) { fBuilder->fPropertyObserver->onLeavingNode(fBuilder->fPropertyObserverContext, fNodeType); fBuilder->fPropertyObserverContext = fPrevContext; } } private: void updateContext(PropertyObserver*, const skjson::ObjectValue&); const AnimationBuilder* fBuilder; const char* fPrevContext; const PropertyObserver::NodeType fNodeType; }; bool dispatchColorProperty(const sk_sp&) const; bool dispatchOpacityProperty(const sk_sp&) const; bool dispatchTextProperty(const sk_sp&) const; bool dispatchTransformProperty(const sk_sp&) const; sk_sp expression_manager() const; private: friend class CompositionBuilder; friend class LayerBuilder; struct AttachLayerContext; struct AttachShapeContext; struct FootageAssetInfo; struct LayerInfo; void parseAssets(const skjson::ArrayValue*); void parseFonts (const skjson::ObjectValue* jfonts, const skjson::ArrayValue* jchars); // Return true iff all fonts were resolved. bool resolveNativeTypefaces(); bool resolveEmbeddedTypefaces(const skjson::ArrayValue& jchars); void dispatchMarkers(const skjson::ArrayValue*) const; sk_sp attachBlendMode(const skjson::ObjectValue&, sk_sp) const; sk_sp attachShape(const skjson::ArrayValue*, AttachShapeContext*, bool suppress_draws = false) const; const FootageAssetInfo* loadFootageAsset(const skjson::ObjectValue&) const; sk_sp attachFootageAsset(const skjson::ObjectValue&, LayerInfo*) const; sk_sp attachExternalPrecompLayer(const skjson::ObjectValue&, const LayerInfo&) const; sk_sp attachFootageLayer(const skjson::ObjectValue&, LayerInfo*) const; sk_sp attachNullLayer (const skjson::ObjectValue&, LayerInfo*) const; sk_sp attachPrecompLayer(const skjson::ObjectValue&, LayerInfo*) const; sk_sp attachShapeLayer (const skjson::ObjectValue&, LayerInfo*) const; sk_sp attachSolidLayer (const skjson::ObjectValue&, LayerInfo*) const; sk_sp attachTextLayer (const skjson::ObjectValue&, LayerInfo*) const; sk_sp attachAudioLayer (const skjson::ObjectValue&, LayerInfo*) const; // Delay resolving the fontmgr until it is actually needed. struct LazyResolveFontMgr { LazyResolveFontMgr(sk_sp fontMgr) : fFontMgr(std::move(fontMgr)) {} const sk_sp& get() { if (!fFontMgr) { fFontMgr = SkFontMgr::RefDefault(); SkASSERT(fFontMgr); } return fFontMgr; } const sk_sp& getMaybeNull() const { return fFontMgr; } private: sk_sp fFontMgr; }; sk_sp fResourceProvider; LazyResolveFontMgr fLazyFontMgr; sk_sp fPropertyObserver; sk_sp fLogger; sk_sp fMarkerObserver; sk_sp fPrecompInterceptor; sk_sp fExpressionManager; Animation::Builder::Stats* fStats; const SkSize fCompSize; const float fDuration, fFrameRate; const uint32_t fFlags; mutable AnimatorScope* fCurrentAnimatorScope; mutable const char* fPropertyObserverContext; mutable bool fHasNontrivialBlending : 1; struct LayerInfo { SkSize fSize; const float fInPoint, fOutPoint; }; struct AssetInfo { const skjson::ObjectValue* fAsset; mutable bool fIsAttaching; // Used for cycle detection }; struct FootageAssetInfo { sk_sp fAsset; SkISize fSize; }; class ScopedAssetRef { public: ScopedAssetRef(const AnimationBuilder* abuilder, const skjson::ObjectValue& jlayer); ~ScopedAssetRef() { if (fInfo) { fInfo->fIsAttaching = false; } } operator bool() const { return !!fInfo; } const skjson::ObjectValue& operator*() const { return *fInfo->fAsset; } private: const AssetInfo* fInfo = nullptr; }; SkTHashMap fAssets; SkTHashMap fFonts; mutable SkTHashMap fImageAssetCache; using INHERITED = SkNoncopyable; }; } // namespace internal } // namespace skottie #endif // SkottiePriv_DEFINED