/* * 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 "include/core/SkRefCnt.h" #include "modules/skottie/include/Skottie.h" #include "include/core/SkFontMgr.h" #include "include/core/SkFontStyle.h" #include "include/core/SkString.h" #include "include/core/SkTypeface.h" #include "modules/skottie/include/ExternalLayer.h" #include "modules/skottie/include/SkottieProperty.h" #include "modules/skottie/include/SlotManager.h" #include "modules/skottie/src/animator/Animator.h" #include "modules/skottie/src/text/Font.h" #include "src/base/SkUTF.h" #include "src/core/SkTHash.h" #include "modules/skshaper/include/SkShaper_factory.h" #include 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; class OpacityAdapter; using AnimatorScope = std::vector>; class SceneGraphRevalidator final : public SkNVRefCnt { public: void revalidate(); void setRoot(sk_sp); private: sk_sp fRoot; }; class AnimationBuilder final : public SkNoncopyable { public: AnimationBuilder(sk_sp, 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 { sk_sp fSceneRoot; AnimatorScope fAnimators; sk_sp fSlotManager; }; AnimationInfo parse(const skjson::ObjectValue&); struct FontInfo { SkString fFamily, fStyle, fPath; SkScalar fAscentPct; sk_sp fTypeface; CustomFont::Builder fCustomFontBuilder; 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_PRINTF_LIKE(4, 5); 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 skjson::ObjectValue* jtext) const; bool dispatchTransformProperty(const sk_sp&) const; sk_sp expression_manager() const; const skjson::ObjectValue* getSlotsRoot() const { return fSlotsRoot; } void parseFonts (const skjson::ObjectValue* jfonts, const skjson::ArrayValue* jchars); private: friend class CompositionBuilder; friend class CustomFont; friend class LayerBuilder; friend class AnimatablePropertyContainer; friend class SkSLEffectBase; struct AttachLayerContext; struct AttachShapeContext; struct FootageAssetInfo; struct LayerInfo; void parseAssets(const skjson::ArrayValue*); // 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; sk_sp fResourceProvider; sk_sp fFontMgr; sk_sp fPropertyObserver; sk_sp fLogger; sk_sp fMarkerObserver; sk_sp fPrecompInterceptor; sk_sp fExpressionManager; sk_sp fShapingFactory; sk_sp fRevalidator; sk_sp fSlotManager; Animation::Builder::Stats* fStats; const SkSize fCompSize; const float fDuration, fFrameRate; const uint32_t fFlags; mutable AnimatorScope* fCurrentAnimatorScope; mutable const char* fPropertyObserverContext = nullptr; 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; } } explicit operator bool() const { return !!fInfo; } const skjson::ObjectValue& operator*() const { return *fInfo->fAsset; } private: const AssetInfo* fInfo = nullptr; }; skia_private::THashMap fAssets; skia_private::THashMap fFonts; sk_sp fCustomGlyphMapper; mutable skia_private::THashMap fImageAssetCache; // Handle to "slots" JSON Object, used to grab slot values while building const skjson::ObjectValue* fSlotsRoot; using INHERITED = SkNoncopyable; }; } // namespace internal } // namespace skottie #endif // SkottiePriv_DEFINED