/* -*- 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_EffectSet_h #define mozilla_EffectSet_h #include "mozilla/DebugOnly.h" #include "mozilla/EffectCompositor.h" #include "mozilla/EnumeratedArray.h" #include "mozilla/TimeStamp.h" #include "mozilla/dom/KeyframeEffect.h" #include "nsHashKeys.h" // For nsPtrHashKey #include "nsTHashSet.h" class nsPresContext; enum class DisplayItemType : uint8_t; namespace mozilla { namespace dom { class Element; } // namespace dom enum class PseudoStyleType : uint8_t; // A wrapper around a hashset of AnimationEffect objects to handle // storing the set as a property of an element. class EffectSet { public: EffectSet() : mCascadeNeedsUpdate(false), mMayHaveOpacityAnim(false), mMayHaveTransformAnim(false) { MOZ_COUNT_CTOR(EffectSet); } ~EffectSet() { MOZ_ASSERT(!IsBeingEnumerated(), "Effect set should not be destroyed while it is being " "enumerated"); MOZ_COUNT_DTOR(EffectSet); } // Methods for supporting cycle-collection void Traverse(nsCycleCollectionTraversalCallback& aCallback); static EffectSet* Get(const dom::Element* aElement, PseudoStyleType aPseudoType); static EffectSet* GetOrCreate(dom::Element* aElement, PseudoStyleType aPseudoType); static EffectSet* GetForFrame(const nsIFrame* aFrame, const nsCSSPropertyIDSet& aProperties); static EffectSet* GetForFrame(const nsIFrame* aFrame, DisplayItemType aDisplayItemType); // Gets the EffectSet associated with the specified frame's content. // // Typically the specified frame should be a "style frame". // // That is because display:table content: // // - makes a distinction between the primary frame and style frame, // - associates the EffectSet with the style frame's content, // - applies transform animations to the primary frame. // // In such a situation, passing in the primary frame here will return nullptr // despite the fact that it has a transform animation applied to it. // // GetForFrame, above, handles this by automatically looking up the // EffectSet on the corresponding style frame when querying transform // properties. Unless you are sure you know what you are doing, you should // try using GetForFrame first. // // If you decide to use this, consider documenting why you are sure it is ok // to use this. static EffectSet* GetForStyleFrame(const nsIFrame* aStyleFrame); static EffectSet* GetForEffect(const dom::KeyframeEffect* aEffect); static void DestroyEffectSet(dom::Element* aElement, PseudoStyleType aPseudoType); void AddEffect(dom::KeyframeEffect& aEffect); void RemoveEffect(dom::KeyframeEffect& aEffect); void SetMayHaveOpacityAnimation() { mMayHaveOpacityAnim = true; } bool MayHaveOpacityAnimation() const { return mMayHaveOpacityAnim; } void SetMayHaveTransformAnimation() { mMayHaveTransformAnim = true; } bool MayHaveTransformAnimation() const { return mMayHaveTransformAnim; } private: using OwningEffectSet = nsTHashSet>; public: // A simple iterator to support iterating over the effects in this object in // range-based for loops. // // This allows us to avoid exposing mEffects directly and saves the // caller from having to dereference hashtable iterators using // the rather complicated: iter.Get()->GetKey(). // // XXX Except for the active iterator checks, this could be replaced by the // STL-style iterators of nsTHashSet directly now. class Iterator { public: explicit Iterator(EffectSet& aEffectSet) : Iterator(aEffectSet, aEffectSet.mEffects.begin()) {} Iterator() = delete; Iterator(const Iterator&) = delete; Iterator(Iterator&&) = delete; Iterator& operator=(const Iterator&) = delete; Iterator& operator=(Iterator&&) = delete; static Iterator EndIterator(EffectSet& aEffectSet) { return {aEffectSet, aEffectSet.mEffects.end()}; } #ifdef DEBUG ~Iterator() { MOZ_ASSERT(mEffectSet.mActiveIterators > 0); mEffectSet.mActiveIterators--; } #endif bool operator!=(const Iterator& aOther) const { return mHashIterator != aOther.mHashIterator; } Iterator& operator++() { ++mHashIterator; return *this; } dom::KeyframeEffect* operator*() { return *mHashIterator; } private: Iterator(EffectSet& aEffectSet, OwningEffectSet::const_iterator aHashIterator) : #ifdef DEBUG mEffectSet(aEffectSet), #endif mHashIterator(std::move(aHashIterator)) { #ifdef DEBUG mEffectSet.mActiveIterators++; #endif } #ifdef DEBUG EffectSet& mEffectSet; #endif OwningEffectSet::const_iterator mHashIterator; }; friend class Iterator; Iterator begin() { return Iterator(*this); } Iterator end() { return Iterator::EndIterator(*this); } #ifdef DEBUG bool IsBeingEnumerated() const { return mActiveIterators != 0; } #endif bool IsEmpty() const { return mEffects.IsEmpty(); } size_t Count() const { return mEffects.Count(); } const TimeStamp& LastOverflowAnimationSyncTime() const { return mLastOverflowAnimationSyncTime; } void UpdateLastOverflowAnimationSyncTime(const TimeStamp& aRefreshTime) { mLastOverflowAnimationSyncTime = aRefreshTime; } bool CascadeNeedsUpdate() const { return mCascadeNeedsUpdate; } void MarkCascadeNeedsUpdate() { mCascadeNeedsUpdate = true; } void MarkCascadeUpdated() { mCascadeNeedsUpdate = false; } void UpdateAnimationGeneration(nsPresContext* aPresContext); uint64_t GetAnimationGeneration() const { return mAnimationGeneration; } const nsCSSPropertyIDSet& PropertiesWithImportantRules() const { return mPropertiesWithImportantRules; } nsCSSPropertyIDSet& PropertiesWithImportantRules() { return mPropertiesWithImportantRules; } nsCSSPropertyIDSet PropertiesForAnimationsLevel() const { return mPropertiesForAnimationsLevel; } nsCSSPropertyIDSet& PropertiesForAnimationsLevel() { return mPropertiesForAnimationsLevel; } private: OwningEffectSet mEffects; // Refresh driver timestamp from the moment when the animations which produce // overflow change hints in this effect set were last updated. // This is used for animations whose main-thread restyling is throttled either // because they are running on the compositor or because they are not visible. // We still need to update them on the main thread periodically, however (e.g. // so scrollbars can be updated), so this tracks the last time we did that. TimeStamp mLastOverflowAnimationSyncTime; // RestyleManager keeps track of the number of animation restyles. // 'mini-flushes' (see nsTransitionManager::UpdateAllThrottledStyles()). // mAnimationGeneration is the sequence number of the last flush where a // transition/animation changed. We keep a similar count on the // corresponding layer so we can check that the layer is up to date with // the animation manager. uint64_t mAnimationGeneration = 0; // Specifies the compositor-animatable properties that are overridden by // !important rules. nsCSSPropertyIDSet mPropertiesWithImportantRules; // Specifies the properties for which the result will be added to the // animations level of the cascade and hence should be skipped when we are // composing the animation style for the transitions level of the cascede. nsCSSPropertyIDSet mPropertiesForAnimationsLevel; #ifdef DEBUG // Track how many iterators are referencing this effect set when we are // destroyed, we can assert that nothing is still pointing to us. uint64_t mActiveIterators = 0; #endif // Dirty flag to represent when the mPropertiesWithImportantRules and // mPropertiesForAnimationsLevel on effects in this set might need to be // updated. // // Set to true any time the set of effects is changed or when // one the effects goes in or out of the "in effect" state. bool mCascadeNeedsUpdate = false; bool mMayHaveOpacityAnim = false; bool mMayHaveTransformAnim = false; }; } // namespace mozilla #endif // mozilla_EffectSet_h