EffectSet.h (9134B)
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_EffectSet_h 8 #define mozilla_EffectSet_h 9 10 #include "mozilla/AnimationTarget.h" 11 #include "mozilla/EffectCompositor.h" 12 #include "mozilla/TimeStamp.h" 13 #include "mozilla/dom/KeyframeEffect.h" 14 #include "nsHashKeys.h" // For nsPtrHashKey 15 #include "nsTHashSet.h" 16 17 class nsPresContext; 18 enum class DisplayItemType : uint8_t; 19 20 namespace mozilla { 21 22 namespace dom { 23 class Element; 24 } // namespace dom 25 26 struct PseudoStyleRequest; 27 28 // A wrapper around a hashset of AnimationEffect objects to handle 29 // storing the set as a property of an element. 30 class EffectSet { 31 public: 32 EffectSet() 33 : mCascadeNeedsUpdate(false), 34 mMayHaveOpacityAnim(false), 35 mMayHaveTransformAnim(false) { 36 MOZ_COUNT_CTOR(EffectSet); 37 } 38 39 ~EffectSet() { 40 MOZ_ASSERT(!IsBeingEnumerated(), 41 "Effect set should not be destroyed while it is being " 42 "enumerated"); 43 MOZ_COUNT_DTOR(EffectSet); 44 } 45 46 // Methods for supporting cycle-collection 47 void Traverse(nsCycleCollectionTraversalCallback& aCallback); 48 49 static EffectSet* Get(const dom::Element* aElement, 50 const PseudoStyleRequest& aPseudoRequest); 51 static EffectSet* Get(const NonOwningAnimationTarget& aTarget) { 52 return Get(aTarget.mElement, aTarget.mPseudoRequest); 53 } 54 static EffectSet* Get(const OwningAnimationTarget& aTarget) { 55 return Get(aTarget.mElement, aTarget.mPseudoRequest); 56 } 57 58 static EffectSet* GetOrCreate(dom::Element* aElement, 59 const PseudoStyleRequest& aPseudoRequest); 60 static EffectSet* GetOrCreate(const OwningAnimationTarget& aTarget) { 61 return GetOrCreate(aTarget.mElement, aTarget.mPseudoRequest); 62 } 63 64 static EffectSet* GetForFrame(const nsIFrame* aFrame, 65 const nsCSSPropertyIDSet& aProperties); 66 static EffectSet* GetForFrame(const nsIFrame* aFrame, 67 DisplayItemType aDisplayItemType); 68 // Gets the EffectSet associated with the specified frame's content. 69 // 70 // Typically the specified frame should be a "style frame". 71 // 72 // That is because display:table content: 73 // 74 // - makes a distinction between the primary frame and style frame, 75 // - associates the EffectSet with the style frame's content, 76 // - applies transform animations to the primary frame. 77 // 78 // In such a situation, passing in the primary frame here will return nullptr 79 // despite the fact that it has a transform animation applied to it. 80 // 81 // GetForFrame, above, handles this by automatically looking up the 82 // EffectSet on the corresponding style frame when querying transform 83 // properties. Unless you are sure you know what you are doing, you should 84 // try using GetForFrame first. 85 // 86 // If you decide to use this, consider documenting why you are sure it is ok 87 // to use this. 88 static EffectSet* GetForStyleFrame(const nsIFrame* aStyleFrame); 89 90 static EffectSet* GetForEffect(const dom::KeyframeEffect* aEffect); 91 92 static void DestroyEffectSet(dom::Element* aElement, 93 const PseudoStyleRequest& aPseudoRequest); 94 static void DestroyEffectSet(const OwningAnimationTarget& aTarget) { 95 return DestroyEffectSet(aTarget.mElement, aTarget.mPseudoRequest); 96 } 97 98 void AddEffect(dom::KeyframeEffect& aEffect); 99 void RemoveEffect(dom::KeyframeEffect& aEffect); 100 101 void SetMayHaveOpacityAnimation() { mMayHaveOpacityAnim = true; } 102 bool MayHaveOpacityAnimation() const { return mMayHaveOpacityAnim; } 103 void SetMayHaveTransformAnimation() { mMayHaveTransformAnim = true; } 104 bool MayHaveTransformAnimation() const { return mMayHaveTransformAnim; } 105 106 private: 107 using OwningEffectSet = nsTHashSet<nsRefPtrHashKey<dom::KeyframeEffect>>; 108 109 public: 110 // A simple iterator to support iterating over the effects in this object in 111 // range-based for loops. 112 // 113 // This allows us to avoid exposing mEffects directly and saves the 114 // caller from having to dereference hashtable iterators using 115 // the rather complicated: iter.Get()->GetKey(). 116 // 117 // XXX Except for the active iterator checks, this could be replaced by the 118 // STL-style iterators of nsTHashSet directly now. 119 class Iterator { 120 public: 121 explicit Iterator(EffectSet& aEffectSet) 122 : Iterator(aEffectSet, aEffectSet.mEffects.begin()) {} 123 124 Iterator() = delete; 125 Iterator(const Iterator&) = delete; 126 Iterator(Iterator&&) = delete; 127 Iterator& operator=(const Iterator&) = delete; 128 Iterator& operator=(Iterator&&) = delete; 129 130 static Iterator EndIterator(EffectSet& aEffectSet) { 131 return {aEffectSet, aEffectSet.mEffects.end()}; 132 } 133 134 #ifdef DEBUG 135 ~Iterator() { 136 MOZ_ASSERT(mEffectSet.mActiveIterators > 0); 137 mEffectSet.mActiveIterators--; 138 } 139 #endif 140 141 bool operator!=(const Iterator& aOther) const { 142 return mHashIterator != aOther.mHashIterator; 143 } 144 145 Iterator& operator++() { 146 ++mHashIterator; 147 return *this; 148 } 149 150 dom::KeyframeEffect* operator*() { return *mHashIterator; } 151 152 private: 153 Iterator(EffectSet& aEffectSet, 154 OwningEffectSet::const_iterator aHashIterator) 155 : 156 #ifdef DEBUG 157 mEffectSet(aEffectSet), 158 #endif 159 mHashIterator(std::move(aHashIterator)) { 160 #ifdef DEBUG 161 mEffectSet.mActiveIterators++; 162 #endif 163 } 164 165 #ifdef DEBUG 166 EffectSet& mEffectSet; 167 #endif 168 OwningEffectSet::const_iterator mHashIterator; 169 }; 170 171 friend class Iterator; 172 173 Iterator begin() { return Iterator(*this); } 174 Iterator end() { return Iterator::EndIterator(*this); } 175 #ifdef DEBUG 176 bool IsBeingEnumerated() const { return mActiveIterators != 0; } 177 #endif 178 179 bool IsEmpty() const { return mEffects.IsEmpty(); } 180 181 size_t Count() const { return mEffects.Count(); } 182 183 const TimeStamp& LastOverflowAnimationSyncTime() const { 184 return mLastOverflowAnimationSyncTime; 185 } 186 void UpdateLastOverflowAnimationSyncTime(const TimeStamp& aRefreshTime) { 187 mLastOverflowAnimationSyncTime = aRefreshTime; 188 } 189 190 bool CascadeNeedsUpdate() const { return mCascadeNeedsUpdate; } 191 void MarkCascadeNeedsUpdate() { mCascadeNeedsUpdate = true; } 192 void MarkCascadeUpdated() { mCascadeNeedsUpdate = false; } 193 194 void UpdateAnimationGeneration(nsPresContext* aPresContext); 195 uint64_t GetAnimationGeneration() const { return mAnimationGeneration; } 196 197 const nsCSSPropertyIDSet& PropertiesWithImportantRules() const { 198 return mPropertiesWithImportantRules; 199 } 200 nsCSSPropertyIDSet& PropertiesWithImportantRules() { 201 return mPropertiesWithImportantRules; 202 } 203 const AnimatedPropertyIDSet& PropertiesForAnimationsLevel() const { 204 return mPropertiesForAnimationsLevel; 205 } 206 AnimatedPropertyIDSet& PropertiesForAnimationsLevel() { 207 return mPropertiesForAnimationsLevel; 208 } 209 210 private: 211 OwningEffectSet mEffects; 212 213 // Refresh driver timestamp from the moment when the animations which produce 214 // overflow change hints in this effect set were last updated. 215 216 // This is used for animations whose main-thread restyling is throttled either 217 // because they are running on the compositor or because they are not visible. 218 // We still need to update them on the main thread periodically, however (e.g. 219 // so scrollbars can be updated), so this tracks the last time we did that. 220 TimeStamp mLastOverflowAnimationSyncTime; 221 222 // RestyleManager keeps track of the number of animation restyles. 223 // 'mini-flushes' (see nsTransitionManager::UpdateAllThrottledStyles()). 224 // mAnimationGeneration is the sequence number of the last flush where a 225 // transition/animation changed. We keep a similar count on the 226 // corresponding layer so we can check that the layer is up to date with 227 // the animation manager. 228 uint64_t mAnimationGeneration = 0; 229 230 // Specifies the compositor-animatable properties that are overridden by 231 // !important rules. 232 nsCSSPropertyIDSet mPropertiesWithImportantRules; 233 // Specifies the properties for which the result will be added to the 234 // animations level of the cascade and hence should be skipped when we are 235 // composing the animation style for the transitions level of the cascede. 236 AnimatedPropertyIDSet mPropertiesForAnimationsLevel; 237 238 #ifdef DEBUG 239 // Track how many iterators are referencing this effect set when we are 240 // destroyed, we can assert that nothing is still pointing to us. 241 uint64_t mActiveIterators = 0; 242 #endif 243 244 // Dirty flag to represent when the mPropertiesWithImportantRules and 245 // mPropertiesForAnimationsLevel on effects in this set might need to be 246 // updated. 247 // 248 // Set to true any time the set of effects is changed or when 249 // one the effects goes in or out of the "in effect" state. 250 bool mCascadeNeedsUpdate = false; 251 252 bool mMayHaveOpacityAnim = false; 253 bool mMayHaveTransformAnim = false; 254 }; 255 256 } // namespace mozilla 257 258 #endif // mozilla_EffectSet_h