ElementAnimationData.cpp (7836B)
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 #include "ElementAnimationData.h" 8 9 #include "mozilla/AnimationCollection.h" 10 #include "mozilla/AnimationUtils.h" 11 #include "mozilla/EffectSet.h" 12 #include "mozilla/TimelineCollection.h" 13 #include "mozilla/dom/CSSAnimation.h" 14 #include "mozilla/dom/CSSTransition.h" 15 #include "mozilla/dom/ScrollTimeline.h" 16 #include "mozilla/dom/ViewTimeline.h" 17 18 namespace mozilla { 19 20 const ElementAnimationData::PerElementOrPseudoData* 21 ElementAnimationData::GetPseudoData(const PseudoStyleRequest& aRequest) const { 22 MOZ_ASSERT(!aRequest.IsNotPseudo(), "Only for pseudo-elements"); 23 MOZ_ASSERT(AnimationUtils::IsSupportedPseudoForAnimations(aRequest.mType)); 24 25 auto entry = mPseudoData.Lookup(aRequest); 26 if (!entry) { 27 return nullptr; 28 } 29 MOZ_ASSERT(*entry, "Should always have a valid UniquePtr"); 30 return entry->get(); 31 } 32 33 ElementAnimationData::PerElementOrPseudoData& 34 ElementAnimationData::GetOrCreatePseudoData( 35 const PseudoStyleRequest& aRequest) { 36 MOZ_ASSERT(!aRequest.IsNotPseudo(), "Only for pseudo-elements"); 37 MOZ_ASSERT(AnimationUtils::IsSupportedPseudoForAnimations(aRequest.mType)); 38 39 UniquePtr<PerElementOrPseudoData>& data = mPseudoData.LookupOrInsertWith( 40 aRequest, [&] { return MakeUnique<PerElementOrPseudoData>(); }); 41 MOZ_ASSERT(data); 42 return *data; 43 } 44 45 void ElementAnimationData::Traverse(nsCycleCollectionTraversalCallback& cb) { 46 mElementData.Traverse(cb); 47 for (auto& data : mPseudoData.Values()) { 48 data->Traverse(cb); 49 } 50 } 51 52 void ElementAnimationData::ClearAllAnimationCollections() { 53 mElementData.mAnimations = nullptr; 54 mElementData.mTransitions = nullptr; 55 mElementData.mScrollTimelines = nullptr; 56 mElementData.mViewTimelines = nullptr; 57 ClearAllPseudos(false); 58 } 59 60 void ElementAnimationData::ClearAllPseudos(bool aOnlyViewTransitions) { 61 if (mPseudoData.IsEmpty()) { 62 return; 63 } 64 65 mIsClearingPseudoData = true; 66 for (auto iter = mPseudoData.Iter(); !iter.Done(); iter.Next()) { 67 const auto& data = iter.Data(); 68 MOZ_ASSERT(data); 69 70 if (aOnlyViewTransitions && !iter.Key().IsViewTransition()) { 71 continue; 72 } 73 74 // Note: We cannot remove EffectSet because we expect there is a valid 75 // EffectSet when unregistering the target. 76 // (See KeyframeEffect::UnregisterTarget() for more details). 77 // So we rely on EffectSet::Destroy() to clear it. 78 data->mAnimations = nullptr; 79 data->mTransitions = nullptr; 80 data->mScrollTimelines = nullptr; 81 data->mViewTimelines = nullptr; 82 83 if (data->IsEmpty()) { 84 iter.Remove(); 85 } 86 } 87 mIsClearingPseudoData = false; 88 } 89 90 void ElementAnimationData::MaybeClearEntry( 91 PseudoData::LookupResult<PseudoData&>&& aEntry) { 92 if (mIsClearingPseudoData || !aEntry || !aEntry.Data()->IsEmpty()) { 93 return; 94 } 95 UniquePtr<PerElementOrPseudoData> temp(std::move(*aEntry)); 96 aEntry.Remove(); 97 } 98 99 template <typename Fn> 100 void ElementAnimationData::WithDataForRemoval( 101 const PseudoStyleRequest& aRequest, Fn&& aFn) { 102 if (aRequest.IsNotPseudo()) { 103 aFn(mElementData); 104 return; 105 } 106 auto entry = mPseudoData.Lookup(aRequest); 107 if (!entry) { 108 return; 109 } 110 aFn(**entry); 111 MaybeClearEntry(std::move(entry)); 112 } 113 114 void ElementAnimationData::ClearEffectSetFor( 115 const PseudoStyleRequest& aRequest) { 116 WithDataForRemoval(aRequest, [](PerElementOrPseudoData& aData) { 117 aData.mEffectSet = nullptr; 118 }); 119 } 120 121 void ElementAnimationData::ClearTransitionCollectionFor( 122 const PseudoStyleRequest& aRequest) { 123 if (aRequest.IsNotPseudo()) { 124 mElementData.mTransitions = nullptr; 125 return; 126 } 127 128 auto entry = mPseudoData.Lookup(aRequest); 129 if (!entry || !entry.Data()->mTransitions) { 130 return; 131 } 132 // If a KeyframeEffect associated with only the animation in the collection, 133 // nullifying the collection may call ClearEffectSetFor(), which may clear the 134 // entry if all empty. Therefore, we move the collection out of the data 135 // first, and destroy the collection when leaving the function, to make sure 136 // |entry| is still valid when calling MaybeClearEntry(). 137 // Note: It seems MaybeClearEntry() here may be redundant because we always 138 // rely on ClearEffectSetFor() to clear the entry. However, we still call it 139 // just in case. 140 auto autoRemoved(std::move(entry.Data()->mTransitions)); 141 MaybeClearEntry(std::move(entry)); 142 } 143 144 void ElementAnimationData::ClearAnimationCollectionFor( 145 const PseudoStyleRequest& aRequest) { 146 if (aRequest.IsNotPseudo()) { 147 mElementData.mAnimations = nullptr; 148 return; 149 } 150 151 auto entry = mPseudoData.Lookup(aRequest); 152 if (!entry || !entry.Data()->mAnimations) { 153 return; 154 } 155 156 // If a KeyframeEffect associated with only the animation in the collection, 157 // nullifying the collection may call ClearEffectSetFor(), which may clear the 158 // entry if all empty. Therefore, we move the collection out of the data 159 // first, and destroy the collection when leaving the function, to make sure 160 // |entry| is still valid when calling MaybeClearEntry(). 161 // Note: It seems MaybeClearEntry() here may be redundant because we always 162 // rely on ClearEffectSetFor() to clear the entry. However, we still call it 163 // just in case. 164 auto autoRemoved(std::move(entry.Data()->mAnimations)); 165 MaybeClearEntry(std::move(entry)); 166 } 167 168 void ElementAnimationData::ClearScrollTimelineCollectionFor( 169 const PseudoStyleRequest& aRequest) { 170 WithDataForRemoval(aRequest, [](PerElementOrPseudoData& aData) { 171 aData.mScrollTimelines = nullptr; 172 }); 173 } 174 175 void ElementAnimationData::ClearViewTimelineCollectionFor( 176 const PseudoStyleRequest& aRequest) { 177 WithDataForRemoval(aRequest, [](PerElementOrPseudoData& aData) { 178 aData.mViewTimelines = nullptr; 179 }); 180 } 181 182 ElementAnimationData::PerElementOrPseudoData::PerElementOrPseudoData() = 183 default; 184 ElementAnimationData::PerElementOrPseudoData::~PerElementOrPseudoData() = 185 default; 186 187 void ElementAnimationData::PerElementOrPseudoData::Traverse( 188 nsCycleCollectionTraversalCallback& cb) { 189 // We only care about mEffectSet. The animation collections are managed by the 190 // pres context and go away when presentation of the document goes away. 191 if (mEffectSet) { 192 mEffectSet->Traverse(cb); 193 } 194 } 195 196 EffectSet& ElementAnimationData::PerElementOrPseudoData::DoEnsureEffectSet() { 197 MOZ_ASSERT(!mEffectSet); 198 mEffectSet = MakeUnique<EffectSet>(); 199 return *mEffectSet; 200 } 201 202 CSSTransitionCollection& 203 ElementAnimationData::PerElementOrPseudoData::DoEnsureTransitions( 204 dom::Element& aOwner, const PseudoStyleRequest& aRequest) { 205 MOZ_ASSERT(!mTransitions); 206 mTransitions = MakeUnique<CSSTransitionCollection>(aOwner, aRequest); 207 return *mTransitions; 208 } 209 210 CSSAnimationCollection& 211 ElementAnimationData::PerElementOrPseudoData::DoEnsureAnimations( 212 dom::Element& aOwner, const PseudoStyleRequest& aRequest) { 213 MOZ_ASSERT(!mAnimations); 214 mAnimations = MakeUnique<CSSAnimationCollection>(aOwner, aRequest); 215 return *mAnimations; 216 } 217 218 ScrollTimelineCollection& 219 ElementAnimationData::PerElementOrPseudoData::DoEnsureScrollTimelines( 220 dom::Element& aOwner, const PseudoStyleRequest& aRequest) { 221 MOZ_ASSERT(!mScrollTimelines); 222 mScrollTimelines = MakeUnique<ScrollTimelineCollection>(aOwner, aRequest); 223 return *mScrollTimelines; 224 } 225 226 ViewTimelineCollection& 227 ElementAnimationData::PerElementOrPseudoData::DoEnsureViewTimelines( 228 dom::Element& aOwner, const PseudoStyleRequest& aRequest) { 229 MOZ_ASSERT(!mViewTimelines); 230 mViewTimelines = MakeUnique<ViewTimelineCollection>(aOwner, aRequest); 231 return *mViewTimelines; 232 } 233 234 } // namespace mozilla