diff options
Diffstat (limited to 'dom/animation/ElementAnimationData.h')
-rw-r--r-- | dom/animation/ElementAnimationData.h | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/dom/animation/ElementAnimationData.h b/dom/animation/ElementAnimationData.h new file mode 100644 index 0000000000..9183f0f008 --- /dev/null +++ b/dom/animation/ElementAnimationData.h @@ -0,0 +1,262 @@ +/* -*- 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 <typename Animation> +class AnimationCollection; +template <typename TimelineType> +class TimelineCollection; +namespace dom { +class Element; +class CSSAnimation; +class CSSTransition; +class ProgressTimelineScheduler; +class ScrollTimeline; +class ViewTimeline; +} // namespace dom +using CSSAnimationCollection = AnimationCollection<dom::CSSAnimation>; +using CSSTransitionCollection = AnimationCollection<dom::CSSTransition>; +using ScrollTimelineCollection = TimelineCollection<dom::ScrollTimeline>; +using ViewTimelineCollection = TimelineCollection<dom::ViewTimeline>; + +// The animation data for a given element (and its pseudo-elements). +class ElementAnimationData { + struct PerElementOrPseudoData { + UniquePtr<EffectSet> mEffectSet; + UniquePtr<CSSAnimationCollection> mAnimations; + UniquePtr<CSSTransitionCollection> 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<ScrollTimelineCollection> mScrollTimelines; + UniquePtr<ViewTimelineCollection> 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<dom::ProgressTimelineScheduler> 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<const ElementAnimationData*>(this)->DataFor(aType); + return const_cast<PerElementOrPseudoData&>(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 |