ElementAnimationData.h (7515B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_ElementAnimationData_h 8 #define mozilla_ElementAnimationData_h 9 10 #include "mozilla/PseudoStyleType.h" 11 #include "mozilla/UniquePtr.h" 12 #include "nsTHashMap.h" 13 14 class nsCycleCollectionTraversalCallback; 15 16 namespace mozilla { 17 class EffectSet; 18 template <typename Animation> 19 class AnimationCollection; 20 template <typename TimelineType> 21 class TimelineCollection; 22 namespace dom { 23 class Element; 24 class CSSAnimation; 25 class CSSTransition; 26 class ScrollTimeline; 27 class ViewTimeline; 28 } // namespace dom 29 using CSSAnimationCollection = AnimationCollection<dom::CSSAnimation>; 30 using CSSTransitionCollection = AnimationCollection<dom::CSSTransition>; 31 using ScrollTimelineCollection = TimelineCollection<dom::ScrollTimeline>; 32 using ViewTimelineCollection = TimelineCollection<dom::ViewTimeline>; 33 34 // The animation data for a given element (and its pseudo-elements). 35 class ElementAnimationData { 36 struct PerElementOrPseudoData { 37 UniquePtr<EffectSet> mEffectSet; 38 UniquePtr<CSSAnimationCollection> mAnimations; 39 UniquePtr<CSSTransitionCollection> mTransitions; 40 41 // Note: scroll-timeline-name is applied to elements which could be 42 // scroll containers, or replaced elements. view-timeline-name is applied to 43 // all elements. However, the named timeline is referenceable in 44 // animation-timeline by the tree order scope. 45 // Spec: https://drafts.csswg.org/scroll-animations-1/#timeline-scope. 46 // 47 // So it should be fine to create timeline objects only on the elements and 48 // pseudo elements which support animations. 49 // 50 // Note: TimelineCollection owns and manages the named progress timeline 51 // generated by specifying scroll-timeline-name property and 52 // view-timeline-name property on this element. However, the anonymous 53 // progress timelines (e.g. animation-timeline:scroll()) are owned by 54 // Animation objects only. 55 UniquePtr<ScrollTimelineCollection> mScrollTimelines; 56 UniquePtr<ViewTimelineCollection> mViewTimelines; 57 58 PerElementOrPseudoData(); 59 ~PerElementOrPseudoData(); 60 61 EffectSet& DoEnsureEffectSet(); 62 CSSTransitionCollection& DoEnsureTransitions(dom::Element&, 63 const PseudoStyleRequest&); 64 CSSAnimationCollection& DoEnsureAnimations(dom::Element&, 65 const PseudoStyleRequest&); 66 ScrollTimelineCollection& DoEnsureScrollTimelines( 67 dom::Element&, const PseudoStyleRequest&); 68 ViewTimelineCollection& DoEnsureViewTimelines(dom::Element&, 69 const PseudoStyleRequest&); 70 71 bool IsEmpty() const { 72 return !mEffectSet && !mAnimations && !mTransitions && 73 !mScrollTimelines && !mViewTimelines; 74 } 75 76 void Traverse(nsCycleCollectionTraversalCallback&); 77 }; 78 79 PerElementOrPseudoData mElementData; 80 81 using PseudoData = 82 nsTHashMap<PseudoStyleRequestHashKey, UniquePtr<PerElementOrPseudoData>>; 83 PseudoData mPseudoData; 84 // Avoid remove hash entry while other people are still using it. 85 bool mIsClearingPseudoData = false; 86 87 const PerElementOrPseudoData* GetData( 88 const PseudoStyleRequest& aRequest) const { 89 if (aRequest.mType != PseudoStyleType::NotPseudo) { 90 return GetPseudoData(aRequest); 91 } 92 return &mElementData; 93 } 94 95 PerElementOrPseudoData& GetOrCreateData(const PseudoStyleRequest& aRequest) { 96 if (aRequest.mType != PseudoStyleType::NotPseudo) { 97 return GetOrCreatePseudoData(aRequest); 98 } 99 return mElementData; 100 } 101 102 const PerElementOrPseudoData* GetPseudoData( 103 const PseudoStyleRequest& aRequest) const; 104 PerElementOrPseudoData& GetOrCreatePseudoData( 105 const PseudoStyleRequest& aRequest); 106 void MaybeClearEntry(PseudoData::LookupResult<PseudoData&>&& aEntry); 107 108 // |aFn| is the removal function which accepts only |PerElementOrPseudoData&| 109 // as the parameter. 110 template <typename Fn> 111 void WithDataForRemoval(const PseudoStyleRequest& aRequest, Fn&& aFn); 112 113 public: 114 void Traverse(nsCycleCollectionTraversalCallback&); 115 116 void ClearAllAnimationCollections(); 117 void ClearAllPseudos(bool aOnlyViewTransitions); 118 void ClearViewTransitionPseudos() { ClearAllPseudos(true); } 119 120 EffectSet* GetEffectSetFor(const PseudoStyleRequest& aRequest) const { 121 if (auto* data = GetData(aRequest)) { 122 return data->mEffectSet.get(); 123 } 124 return nullptr; 125 } 126 127 void ClearEffectSetFor(const PseudoStyleRequest& aRequest); 128 129 EffectSet& EnsureEffectSetFor(const PseudoStyleRequest& aRequest) { 130 auto& data = GetOrCreateData(aRequest); 131 if (auto* set = data.mEffectSet.get()) { 132 return *set; 133 } 134 return data.DoEnsureEffectSet(); 135 } 136 137 CSSTransitionCollection* GetTransitionCollection( 138 const PseudoStyleRequest& aRequest) const { 139 if (auto* data = GetData(aRequest)) { 140 return data->mTransitions.get(); 141 } 142 return nullptr; 143 } 144 145 void ClearTransitionCollectionFor(const PseudoStyleRequest& aRequest); 146 147 CSSTransitionCollection& EnsureTransitionCollection( 148 dom::Element& aOwner, const PseudoStyleRequest& aRequest) { 149 auto& data = GetOrCreateData(aRequest); 150 if (auto* collection = data.mTransitions.get()) { 151 return *collection; 152 } 153 return data.DoEnsureTransitions(aOwner, aRequest); 154 } 155 156 CSSAnimationCollection* GetAnimationCollection( 157 const PseudoStyleRequest& aRequest) const { 158 if (auto* data = GetData(aRequest)) { 159 return data->mAnimations.get(); 160 } 161 return nullptr; 162 } 163 164 void ClearAnimationCollectionFor(const PseudoStyleRequest& aRequest); 165 166 CSSAnimationCollection& EnsureAnimationCollection( 167 dom::Element& aOwner, const PseudoStyleRequest& aRequest) { 168 auto& data = GetOrCreateData(aRequest); 169 if (auto* collection = data.mAnimations.get()) { 170 return *collection; 171 } 172 return data.DoEnsureAnimations(aOwner, aRequest); 173 } 174 175 ScrollTimelineCollection* GetScrollTimelineCollection( 176 const PseudoStyleRequest& aRequest) const { 177 if (auto* data = GetData(aRequest)) { 178 return data->mScrollTimelines.get(); 179 } 180 return nullptr; 181 } 182 183 void ClearScrollTimelineCollectionFor(const PseudoStyleRequest& aRequest); 184 185 ScrollTimelineCollection& EnsureScrollTimelineCollection( 186 dom::Element& aOwner, const PseudoStyleRequest& aRequest) { 187 auto& data = GetOrCreateData(aRequest); 188 if (auto* collection = data.mScrollTimelines.get()) { 189 return *collection; 190 } 191 return data.DoEnsureScrollTimelines(aOwner, aRequest); 192 } 193 194 ViewTimelineCollection* GetViewTimelineCollection( 195 const PseudoStyleRequest& aRequest) const { 196 if (auto* data = GetData(aRequest)) { 197 return data->mViewTimelines.get(); 198 } 199 return nullptr; 200 } 201 202 void ClearViewTimelineCollectionFor(const PseudoStyleRequest& aRequest); 203 204 ViewTimelineCollection& EnsureViewTimelineCollection( 205 dom::Element& aOwner, const PseudoStyleRequest& aRequest) { 206 auto& data = GetOrCreateData(aRequest); 207 if (auto* collection = data.mViewTimelines.get()) { 208 return *collection; 209 } 210 return data.DoEnsureViewTimelines(aOwner, aRequest); 211 } 212 213 ElementAnimationData() = default; 214 }; 215 216 } // namespace mozilla 217 218 #endif