diff options
Diffstat (limited to '')
-rw-r--r-- | dom/animation/EffectSet.h | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/dom/animation/EffectSet.h b/dom/animation/EffectSet.h new file mode 100644 index 0000000000..c743676794 --- /dev/null +++ b/dom/animation/EffectSet.h @@ -0,0 +1,246 @@ +/* -*- 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<nsRefPtrHashKey<dom::KeyframeEffect>>; + + 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 |