diff options
Diffstat (limited to 'dom/animation/EffectSet.h')
-rw-r--r-- | dom/animation/EffectSet.h | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/dom/animation/EffectSet.h b/dom/animation/EffectSet.h new file mode 100644 index 000000000..9ba31ef91 --- /dev/null +++ b/dom/animation/EffectSet.h @@ -0,0 +1,261 @@ +/* -*- 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/AnimValuesStyleRule.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/EffectCompositor.h" +#include "mozilla/EnumeratedArray.h" +#include "mozilla/TimeStamp.h" +#include "mozilla/dom/KeyframeEffectReadOnly.h" +#include "nsHashKeys.h" // For nsPtrHashKey +#include "nsTHashtable.h" // For nsTHashtable + +class nsPresContext; + +namespace mozilla { + +namespace dom { +class Element; +} // namespace dom + +enum class CSSPseudoElementType : 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) + , mAnimationGeneration(0) +#ifdef DEBUG + , mActiveIterators(0) + , mCalledPropertyDtor(false) +#endif + { + MOZ_COUNT_CTOR(EffectSet); + } + + ~EffectSet() + { + MOZ_ASSERT(mCalledPropertyDtor, + "must call destructor through element property dtor"); + MOZ_ASSERT(mActiveIterators == 0, + "Effect set should not be destroyed while it is being " + "enumerated"); + MOZ_COUNT_DTOR(EffectSet); + } + static void PropertyDtor(void* aObject, nsIAtom* aPropertyName, + void* aPropertyValue, void* aData); + + // Methods for supporting cycle-collection + void Traverse(nsCycleCollectionTraversalCallback& aCallback); + + static EffectSet* GetEffectSet(dom::Element* aElement, + CSSPseudoElementType aPseudoType); + static EffectSet* GetEffectSet(const nsIFrame* aFrame); + static EffectSet* GetOrCreateEffectSet(dom::Element* aElement, + CSSPseudoElementType aPseudoType); + static void DestroyEffectSet(dom::Element* aElement, + CSSPseudoElementType aPseudoType); + + void AddEffect(dom::KeyframeEffectReadOnly& aEffect); + void RemoveEffect(dom::KeyframeEffectReadOnly& aEffect); + +private: + typedef nsTHashtable<nsRefPtrHashKey<dom::KeyframeEffectReadOnly>> + OwningEffectSet; + +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(). + class Iterator + { + public: + explicit Iterator(EffectSet& aEffectSet) + : mEffectSet(aEffectSet) + , mHashIterator(mozilla::Move(aEffectSet.mEffects.Iter())) + , mIsEndIterator(false) + { +#ifdef DEBUG + mEffectSet.mActiveIterators++; +#endif + } + + Iterator(Iterator&& aOther) + : mEffectSet(aOther.mEffectSet) + , mHashIterator(mozilla::Move(aOther.mHashIterator)) + , mIsEndIterator(aOther.mIsEndIterator) + { +#ifdef DEBUG + mEffectSet.mActiveIterators++; +#endif + } + + static Iterator EndIterator(EffectSet& aEffectSet) + { + Iterator result(aEffectSet); + result.mIsEndIterator = true; + return result; + } + + ~Iterator() + { +#ifdef DEBUG + MOZ_ASSERT(mEffectSet.mActiveIterators > 0); + mEffectSet.mActiveIterators--; +#endif + } + + bool operator!=(const Iterator& aOther) const { + if (Done() || aOther.Done()) { + return Done() != aOther.Done(); + } + return mHashIterator.Get() != aOther.mHashIterator.Get(); + } + + Iterator& operator++() { + MOZ_ASSERT(!Done()); + mHashIterator.Next(); + return *this; + } + + dom::KeyframeEffectReadOnly* operator* () + { + MOZ_ASSERT(!Done()); + return mHashIterator.Get()->GetKey(); + } + + private: + Iterator() = delete; + Iterator(const Iterator&) = delete; + Iterator& operator=(const Iterator&) = delete; + Iterator& operator=(const Iterator&&) = delete; + + bool Done() const { + return mIsEndIterator || mHashIterator.Done(); + } + + EffectSet& mEffectSet; + OwningEffectSet::Iterator mHashIterator; + bool mIsEndIterator; + }; + + 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(); } + + RefPtr<AnimValuesStyleRule>& AnimationRule(EffectCompositor::CascadeLevel + aCascadeLevel) + { + return mAnimationRule[aCascadeLevel]; + } + + const TimeStamp& AnimationRuleRefreshTime(EffectCompositor::CascadeLevel + aCascadeLevel) const + { + return mAnimationRuleRefreshTime[aCascadeLevel]; + } + void UpdateAnimationRuleRefreshTime(EffectCompositor::CascadeLevel + aCascadeLevel, + const TimeStamp& aRefreshTime) + { + mAnimationRuleRefreshTime[aCascadeLevel] = aRefreshTime; + } + + bool CascadeNeedsUpdate() const { return mCascadeNeedsUpdate; } + void MarkCascadeNeedsUpdate() { mCascadeNeedsUpdate = true; } + void MarkCascadeUpdated() { mCascadeNeedsUpdate = false; } + + void UpdateAnimationGeneration(nsPresContext* aPresContext); + uint64_t GetAnimationGeneration() const { return mAnimationGeneration; } + + static nsIAtom** GetEffectSetPropertyAtoms(); + + nsCSSPropertyIDSet& PropertiesWithImportantRules() + { + return mPropertiesWithImportantRules; + } + nsCSSPropertyIDSet& PropertiesForAnimationsLevel() + { + return mPropertiesForAnimationsLevel; + } + +private: + static nsIAtom* GetEffectSetPropertyAtom(CSSPseudoElementType aPseudoType); + + OwningEffectSet mEffects; + + // These style rules contain the style data for currently animating + // values. They only match when styling with animation. When we + // style without animation, we need to not use them so that we can + // detect any new changes; if necessary we restyle immediately + // afterwards with animation. + EnumeratedArray<EffectCompositor::CascadeLevel, + EffectCompositor::CascadeLevel( + EffectCompositor::kCascadeLevelCount), + RefPtr<AnimValuesStyleRule>> mAnimationRule; + + // A parallel array to mAnimationRule that records the refresh driver + // timestamp when the rule was last updated. This is used for certain + // animations which are updated only periodically (e.g. transform animations + // running on the compositor that affect the scrollable overflow region). + EnumeratedArray<EffectCompositor::CascadeLevel, + EffectCompositor::CascadeLevel( + EffectCompositor::kCascadeLevelCount), + TimeStamp> mAnimationRuleRefreshTime; + + // 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; + + // 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; + + // 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; + + bool mCalledPropertyDtor; +#endif +}; + +} // namespace mozilla + +#endif // mozilla_EffectSet_h |