зеркало из https://github.com/mozilla/gecko-dev.git
273 строки
9.2 KiB
C++
273 строки
9.2 KiB
C++
/* -*- 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 "nsTHashtable.h" // For nsTHashtable
|
|
|
|
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),
|
|
mAnimationGeneration(0)
|
|
#ifdef DEBUG
|
|
,
|
|
mActiveIterators(0),
|
|
mCalledPropertyDtor(false)
|
|
#endif
|
|
,
|
|
mMayHaveOpacityAnim(false),
|
|
mMayHaveTransformAnim(false) {
|
|
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, nsAtom* aPropertyName,
|
|
void* aPropertyValue, void* aData);
|
|
|
|
// Methods for supporting cycle-collection
|
|
void Traverse(nsCycleCollectionTraversalCallback& aCallback);
|
|
|
|
static EffectSet* GetEffectSet(const dom::Element* aElement,
|
|
PseudoStyleType aPseudoType);
|
|
static EffectSet* GetOrCreateEffectSet(dom::Element* aElement,
|
|
PseudoStyleType aPseudoType);
|
|
|
|
static EffectSet* GetEffectSetForFrame(const nsIFrame* aFrame,
|
|
const nsCSSPropertyIDSet& aProperties);
|
|
static EffectSet* GetEffectSetForFrame(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.
|
|
//
|
|
// GetEffectSetForFrame, 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 GetEffectSetForFrame first.
|
|
//
|
|
// If you decide to use this, consider documenting why you are sure it is ok
|
|
// to use this.
|
|
static EffectSet* GetEffectSetForStyleFrame(const nsIFrame* aStyleFrame);
|
|
|
|
static EffectSet* GetEffectSetForEffect(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:
|
|
typedef nsTHashtable<nsRefPtrHashKey<dom::KeyframeEffect>> 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(aEffectSet.mEffects.Iter()),
|
|
mIsEndIterator(false) {
|
|
#ifdef DEBUG
|
|
mEffectSet.mActiveIterators++;
|
|
#endif
|
|
}
|
|
|
|
Iterator(Iterator&& aOther)
|
|
: mEffectSet(aOther.mEffectSet),
|
|
mHashIterator(std::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::KeyframeEffect* 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(); }
|
|
|
|
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; }
|
|
|
|
static nsAtom** GetEffectSetPropertyAtoms();
|
|
|
|
const nsCSSPropertyIDSet& PropertiesWithImportantRules() const {
|
|
return mPropertiesWithImportantRules;
|
|
}
|
|
nsCSSPropertyIDSet& PropertiesWithImportantRules() {
|
|
return mPropertiesWithImportantRules;
|
|
}
|
|
nsCSSPropertyIDSet& PropertiesForAnimationsLevel() {
|
|
return mPropertiesForAnimationsLevel;
|
|
}
|
|
nsCSSPropertyIDSet PropertiesForAnimationsLevel() const {
|
|
return mPropertiesForAnimationsLevel;
|
|
}
|
|
|
|
private:
|
|
static nsAtom* GetEffectSetPropertyAtom(PseudoStyleType aPseudoType);
|
|
|
|
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;
|
|
|
|
// 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
|
|
|
|
bool mMayHaveOpacityAnim;
|
|
bool mMayHaveTransformAnim;
|
|
};
|
|
|
|
} // namespace mozilla
|
|
|
|
#endif // mozilla_EffectSet_h
|