/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_ElementAnimationData_h #define mozilla_ElementAnimationData_h #include "mozilla/PseudoStyleRequest.h" #include "mozilla/UniquePtr.h" #include "nsTHashMap.h" class nsCycleCollectionTraversalCallback; namespace mozilla { class EffectSet; template class AnimationCollection; template class TimelineCollection; namespace dom { class Element; class CSSAnimation; class CSSTransition; class ScrollTimeline; class ViewTimeline; } // namespace dom using CSSAnimationCollection = AnimationCollection; using CSSTransitionCollection = AnimationCollection; using ScrollTimelineCollection = TimelineCollection; using ViewTimelineCollection = TimelineCollection; // The animation data for a given element (and its pseudo-elements). class ElementAnimationData { struct PerElementOrPseudoData { UniquePtr mEffectSet; UniquePtr mAnimations; UniquePtr mTransitions; // Note: scroll-timeline-name is applied to elements which could be // scroll containers, or replaced elements. view-timeline-name is applied to // all elements. However, the named timeline is referenceable in // animation-timeline by the tree order scope. // Spec: https://drafts.csswg.org/scroll-animations-1/#timeline-scope. // // So it should be fine to create timeline objects only on the elements and // pseudo elements which support animations. // // Note: TimelineCollection owns and manages the named progress timeline // generated by specifying scroll-timeline-name property and // view-timeline-name property on this element. However, the anonymous // progress timelines (e.g. animation-timeline:scroll()) are owned by // Animation objects only. UniquePtr mScrollTimelines; UniquePtr mViewTimelines; PerElementOrPseudoData(); ~PerElementOrPseudoData(); EffectSet& DoEnsureEffectSet(); CSSTransitionCollection& DoEnsureTransitions(dom::Element&, const PseudoStyleRequest&); CSSAnimationCollection& DoEnsureAnimations(dom::Element&, const PseudoStyleRequest&); ScrollTimelineCollection& DoEnsureScrollTimelines( dom::Element&, const PseudoStyleRequest&); ViewTimelineCollection& DoEnsureViewTimelines(dom::Element&, const PseudoStyleRequest&); bool IsEmpty() const { return !mEffectSet && !mAnimations && !mTransitions && !mScrollTimelines && !mViewTimelines; } void Traverse(nsCycleCollectionTraversalCallback&); }; PerElementOrPseudoData mElementData; using PseudoData = nsTHashMap>; PseudoData mPseudoData; // Avoid remove hash entry while other people are still using it. bool mIsClearingPseudoData = false; const PerElementOrPseudoData* GetData( const PseudoStyleRequest& aRequest) const { if (aRequest.mType != PseudoStyleType::NotPseudo) { return GetPseudoData(aRequest); } return &mElementData; } PerElementOrPseudoData& GetOrCreateData(const PseudoStyleRequest& aRequest) { if (aRequest.mType != PseudoStyleType::NotPseudo) { return GetOrCreatePseudoData(aRequest); } return mElementData; } const PerElementOrPseudoData* GetPseudoData( const PseudoStyleRequest& aRequest) const; PerElementOrPseudoData& GetOrCreatePseudoData( const PseudoStyleRequest& aRequest); void MaybeClearEntry(PseudoData::LookupResult&& aEntry); // |aFn| is the removal function which accepts only |PerElementOrPseudoData&| // as the parameter. template void WithDataForRemoval(const PseudoStyleRequest& aRequest, Fn&& aFn); public: void Traverse(nsCycleCollectionTraversalCallback&); void ClearAllAnimationCollections(); void ClearAllPseudos(bool aOnlyViewTransitions); void ClearViewTransitionPseudos() { ClearAllPseudos(true); } EffectSet* GetEffectSetFor(const PseudoStyleRequest& aRequest) const { if (auto* data = GetData(aRequest)) { return data->mEffectSet.get(); } return nullptr; } void ClearEffectSetFor(const PseudoStyleRequest& aRequest); EffectSet& EnsureEffectSetFor(const PseudoStyleRequest& aRequest) { auto& data = GetOrCreateData(aRequest); if (auto* set = data.mEffectSet.get()) { return *set; } return data.DoEnsureEffectSet(); } CSSTransitionCollection* GetTransitionCollection( const PseudoStyleRequest& aRequest) const { if (auto* data = GetData(aRequest)) { return data->mTransitions.get(); } return nullptr; } void ClearTransitionCollectionFor(const PseudoStyleRequest& aRequest); CSSTransitionCollection& EnsureTransitionCollection( dom::Element& aOwner, const PseudoStyleRequest& aRequest) { auto& data = GetOrCreateData(aRequest); if (auto* collection = data.mTransitions.get()) { return *collection; } return data.DoEnsureTransitions(aOwner, aRequest); } CSSAnimationCollection* GetAnimationCollection( const PseudoStyleRequest& aRequest) const { if (auto* data = GetData(aRequest)) { return data->mAnimations.get(); } return nullptr; } void ClearAnimationCollectionFor(const PseudoStyleRequest& aRequest); CSSAnimationCollection& EnsureAnimationCollection( dom::Element& aOwner, const PseudoStyleRequest& aRequest) { auto& data = GetOrCreateData(aRequest); if (auto* collection = data.mAnimations.get()) { return *collection; } return data.DoEnsureAnimations(aOwner, aRequest); } ScrollTimelineCollection* GetScrollTimelineCollection( const PseudoStyleRequest& aRequest) const { if (auto* data = GetData(aRequest)) { return data->mScrollTimelines.get(); } return nullptr; } void ClearScrollTimelineCollectionFor(const PseudoStyleRequest& aRequest); ScrollTimelineCollection& EnsureScrollTimelineCollection( dom::Element& aOwner, const PseudoStyleRequest& aRequest) { auto& data = GetOrCreateData(aRequest); if (auto* collection = data.mScrollTimelines.get()) { return *collection; } return data.DoEnsureScrollTimelines(aOwner, aRequest); } ViewTimelineCollection* GetViewTimelineCollection( const PseudoStyleRequest& aRequest) const { if (auto* data = GetData(aRequest)) { return data->mViewTimelines.get(); } return nullptr; } void ClearViewTimelineCollectionFor(const PseudoStyleRequest& aRequest); ViewTimelineCollection& EnsureViewTimelineCollection( dom::Element& aOwner, const PseudoStyleRequest& aRequest) { auto& data = GetOrCreateData(aRequest); if (auto* collection = data.mViewTimelines.get()) { return *collection; } return data.DoEnsureViewTimelines(aOwner, aRequest); } ElementAnimationData() = default; }; } // namespace mozilla #endif