/* -*- 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/UniquePtr.h" #include "mozilla/PseudoStyleType.h" class nsCycleCollectionTraversalCallback; namespace mozilla { enum class PseudoStyleType : uint8_t; class EffectSet; template class AnimationCollection; template class TimelineCollection; namespace dom { class Element; class CSSAnimation; class CSSTransition; class ProgressTimelineScheduler; 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. UniquePtr mScrollTimelines; UniquePtr mViewTimelines; // This is different from |mScrollTimelines|. We use this to schedule all // scroll-driven animations (which use anonymous/named scroll timelines or // anonymous/name view timelines) for a specific scroll source (which is the // element with nsIScrollableFrame). // // 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. // // Note: // 1. For named scroll timelines. The element which specifies // scroll-timeline-name is the scroll source. However, for named view // timelines, the element which specifies view-timeline-name may not be // the scroll source because we use its nearest scroll container as the // scroll source. // 2. For anonymous progress timelines, we don't keep their timeline obejcts // in TimelineCollection. // So, per 1) and 2), we use |mProgressTimelineScheduler| for the scroll // source element to schedule scroll-driven animations. UniquePtr mProgressTimelineScheduler; PerElementOrPseudoData(); ~PerElementOrPseudoData(); EffectSet& DoEnsureEffectSet(); CSSTransitionCollection& DoEnsureTransitions(dom::Element&, PseudoStyleType); CSSAnimationCollection& DoEnsureAnimations(dom::Element&, PseudoStyleType); ScrollTimelineCollection& DoEnsureScrollTimelines(dom::Element&, PseudoStyleType); ViewTimelineCollection& DoEnsureViewTimelines(dom::Element&, PseudoStyleType); dom::ProgressTimelineScheduler& DoEnsureProgressTimelineScheduler( dom::Element&, PseudoStyleType); void DoClearEffectSet(); void DoClearTransitions(); void DoClearAnimations(); void DoClearScrollTimelines(); void DoClearViewTimelines(); void DoClearProgressTimelineScheduler(); void Traverse(nsCycleCollectionTraversalCallback&); }; PerElementOrPseudoData mElementData; // TODO(emilio): Maybe this should be a hash map eventually, once we allow // animating all pseudo-elements. PerElementOrPseudoData mBeforeData; PerElementOrPseudoData mAfterData; PerElementOrPseudoData mMarkerData; const PerElementOrPseudoData& DataFor(PseudoStyleType aType) const { switch (aType) { case PseudoStyleType::NotPseudo: break; case PseudoStyleType::before: return mBeforeData; case PseudoStyleType::after: return mAfterData; case PseudoStyleType::marker: return mMarkerData; default: MOZ_ASSERT_UNREACHABLE( "Should not try to get animation effects for " "a pseudo other that :before, :after or ::marker"); break; } return mElementData; } PerElementOrPseudoData& DataFor(PseudoStyleType aType) { const auto& data = const_cast(this)->DataFor(aType); return const_cast(data); } public: void Traverse(nsCycleCollectionTraversalCallback&); void ClearAllAnimationCollections(); EffectSet* GetEffectSetFor(PseudoStyleType aType) const { return DataFor(aType).mEffectSet.get(); } void ClearEffectSetFor(PseudoStyleType aType) { auto& data = DataFor(aType); if (data.mEffectSet) { data.DoClearEffectSet(); } } EffectSet& EnsureEffectSetFor(PseudoStyleType aType) { auto& data = DataFor(aType); if (auto* set = data.mEffectSet.get()) { return *set; } return data.DoEnsureEffectSet(); } CSSTransitionCollection* GetTransitionCollection(PseudoStyleType aType) { return DataFor(aType).mTransitions.get(); } void ClearTransitionCollectionFor(PseudoStyleType aType) { auto& data = DataFor(aType); if (data.mTransitions) { data.DoClearTransitions(); } } CSSTransitionCollection& EnsureTransitionCollection(dom::Element& aOwner, PseudoStyleType aType) { auto& data = DataFor(aType); if (auto* collection = data.mTransitions.get()) { return *collection; } return data.DoEnsureTransitions(aOwner, aType); } CSSAnimationCollection* GetAnimationCollection(PseudoStyleType aType) { return DataFor(aType).mAnimations.get(); } void ClearAnimationCollectionFor(PseudoStyleType aType) { auto& data = DataFor(aType); if (data.mAnimations) { data.DoClearAnimations(); } } CSSAnimationCollection& EnsureAnimationCollection(dom::Element& aOwner, PseudoStyleType aType) { auto& data = DataFor(aType); if (auto* collection = data.mAnimations.get()) { return *collection; } return data.DoEnsureAnimations(aOwner, aType); } ScrollTimelineCollection* GetScrollTimelineCollection(PseudoStyleType aType) { return DataFor(aType).mScrollTimelines.get(); } void ClearScrollTimelineCollectionFor(PseudoStyleType aType) { auto& data = DataFor(aType); if (data.mScrollTimelines) { data.DoClearScrollTimelines(); } } ScrollTimelineCollection& EnsureScrollTimelineCollection( dom::Element& aOwner, PseudoStyleType aType) { auto& data = DataFor(aType); if (auto* collection = data.mScrollTimelines.get()) { return *collection; } return data.DoEnsureScrollTimelines(aOwner, aType); } ViewTimelineCollection* GetViewTimelineCollection(PseudoStyleType aType) { return DataFor(aType).mViewTimelines.get(); } void ClearViewTimelineCollectionFor(PseudoStyleType aType) { auto& data = DataFor(aType); if (data.mViewTimelines) { data.DoClearViewTimelines(); } } ViewTimelineCollection& EnsureViewTimelineCollection(dom::Element& aOwner, PseudoStyleType aType) { auto& data = DataFor(aType); if (auto* collection = data.mViewTimelines.get()) { return *collection; } return data.DoEnsureViewTimelines(aOwner, aType); } dom::ProgressTimelineScheduler* GetProgressTimelineScheduler( PseudoStyleType aType) { return DataFor(aType).mProgressTimelineScheduler.get(); } void ClearProgressTimelineScheduler(PseudoStyleType aType) { auto& data = DataFor(aType); if (data.mProgressTimelineScheduler) { data.DoClearProgressTimelineScheduler(); } } dom::ProgressTimelineScheduler& EnsureProgressTimelineScheduler( dom::Element& aOwner, PseudoStyleType aType) { auto& data = DataFor(aType); if (auto* collection = data.mProgressTimelineScheduler.get()) { return *collection; } return data.DoEnsureProgressTimelineScheduler(aOwner, aType); } ElementAnimationData() = default; }; } // namespace mozilla #endif