forked from mirrors/gecko-dev
Bug 1807003 - Centralize animation data in slots. r=smaug,firefox-animation-reviewers,boris
This should both be faster and simpler. Also will allow us in the future to animate more pseudos without having to add a gazillion properties. I think we should try to clear more stuff (maybe the whole animation data) on unbind, but that's a bit tangential. Differential Revision: https://phabricator.services.mozilla.com/D169860
This commit is contained in:
parent
45b09251e2
commit
6c32b964cd
24 changed files with 422 additions and 443 deletions
|
|
@ -233,20 +233,6 @@ class CSSAnimationKeyframeEffect : public KeyframeEffect {
|
|||
|
||||
} // namespace dom
|
||||
|
||||
template <>
|
||||
struct AnimationTypeTraits<dom::CSSAnimation> {
|
||||
static nsAtom* ElementPropertyAtom() { return nsGkAtoms::animationsProperty; }
|
||||
static nsAtom* BeforePropertyAtom() {
|
||||
return nsGkAtoms::animationsOfBeforeProperty;
|
||||
}
|
||||
static nsAtom* AfterPropertyAtom() {
|
||||
return nsGkAtoms::animationsOfAfterProperty;
|
||||
}
|
||||
static nsAtom* MarkerPropertyAtom() {
|
||||
return nsGkAtoms::animationsOfMarkerProperty;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_CSSAnimation_h
|
||||
|
|
|
|||
|
|
@ -225,22 +225,6 @@ class CSSTransition final : public Animation {
|
|||
|
||||
} // namespace dom
|
||||
|
||||
template <>
|
||||
struct AnimationTypeTraits<dom::CSSTransition> {
|
||||
static nsAtom* ElementPropertyAtom() {
|
||||
return nsGkAtoms::transitionsProperty;
|
||||
}
|
||||
static nsAtom* BeforePropertyAtom() {
|
||||
return nsGkAtoms::transitionsOfBeforeProperty;
|
||||
}
|
||||
static nsAtom* AfterPropertyAtom() {
|
||||
return nsGkAtoms::transitionsOfAfterProperty;
|
||||
}
|
||||
static nsAtom* MarkerPropertyAtom() {
|
||||
return nsGkAtoms::transitionsOfMarkerProperty;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_CSSTransition_h
|
||||
|
|
|
|||
|
|
@ -12,22 +12,10 @@
|
|||
#include "nsCycleCollectionNoteChild.h" // For CycleCollectionNoteChild
|
||||
#include "nsPresContext.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "ElementAnimationData.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/* static */
|
||||
void EffectSet::PropertyDtor(void* aObject, nsAtom* aPropertyName,
|
||||
void* aPropertyValue, void* aData) {
|
||||
EffectSet* effectSet = static_cast<EffectSet*>(aPropertyValue);
|
||||
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(!effectSet->mCalledPropertyDtor, "Should not call dtor twice");
|
||||
effectSet->mCalledPropertyDtor = true;
|
||||
#endif
|
||||
|
||||
delete effectSet;
|
||||
}
|
||||
|
||||
void EffectSet::Traverse(nsCycleCollectionTraversalCallback& aCallback) {
|
||||
for (const auto& key : mEffects) {
|
||||
CycleCollectionNoteChild(aCallback, key, "EffectSet::mEffects[]",
|
||||
|
|
@ -38,38 +26,16 @@ void EffectSet::Traverse(nsCycleCollectionTraversalCallback& aCallback) {
|
|||
/* static */
|
||||
EffectSet* EffectSet::GetEffectSet(const dom::Element* aElement,
|
||||
PseudoStyleType aPseudoType) {
|
||||
if (!aElement->MayHaveAnimations()) {
|
||||
return nullptr;
|
||||
if (auto* data = aElement->GetAnimationData()) {
|
||||
return data->GetEffectSetFor(aPseudoType);
|
||||
}
|
||||
|
||||
nsAtom* propName = GetEffectSetPropertyAtom(aPseudoType);
|
||||
return static_cast<EffectSet*>(aElement->GetProperty(propName));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* static */
|
||||
EffectSet* EffectSet::GetOrCreateEffectSet(dom::Element* aElement,
|
||||
PseudoStyleType aPseudoType) {
|
||||
EffectSet* effectSet = GetEffectSet(aElement, aPseudoType);
|
||||
if (effectSet) {
|
||||
return effectSet;
|
||||
}
|
||||
|
||||
nsAtom* propName = GetEffectSetPropertyAtom(aPseudoType);
|
||||
effectSet = new EffectSet();
|
||||
|
||||
nsresult rv = aElement->SetProperty(propName, effectSet,
|
||||
&EffectSet::PropertyDtor, true);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("SetProperty failed");
|
||||
// The set must be destroyed via PropertyDtor, otherwise
|
||||
// mCalledPropertyDtor assertion is triggered in destructor.
|
||||
EffectSet::PropertyDtor(aElement, propName, effectSet, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aElement->SetMayHaveAnimations();
|
||||
|
||||
return effectSet;
|
||||
return &aElement->EnsureAnimationData().EnsureEffectSetFor(aPseudoType);
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
|
@ -138,18 +104,9 @@ EffectSet* EffectSet::GetEffectSetForEffect(
|
|||
/* static */
|
||||
void EffectSet::DestroyEffectSet(dom::Element* aElement,
|
||||
PseudoStyleType aPseudoType) {
|
||||
nsAtom* propName = GetEffectSetPropertyAtom(aPseudoType);
|
||||
EffectSet* effectSet =
|
||||
static_cast<EffectSet*>(aElement->GetProperty(propName));
|
||||
if (!effectSet) {
|
||||
return;
|
||||
if (auto* data = aElement->GetAnimationData()) {
|
||||
data->ClearEffectSetFor(aPseudoType);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!effectSet->IsBeingEnumerated(),
|
||||
"Should not destroy an effect set while it is being enumerated");
|
||||
effectSet = nullptr;
|
||||
|
||||
aElement->RemoveProperty(propName);
|
||||
}
|
||||
|
||||
void EffectSet::UpdateAnimationGeneration(nsPresContext* aPresContext) {
|
||||
|
|
@ -157,40 +114,6 @@ void EffectSet::UpdateAnimationGeneration(nsPresContext* aPresContext) {
|
|||
aPresContext->RestyleManager()->GetAnimationGeneration();
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsAtom** EffectSet::GetEffectSetPropertyAtoms() {
|
||||
static nsAtom* effectSetPropertyAtoms[] = {
|
||||
nsGkAtoms::animationEffectsProperty,
|
||||
nsGkAtoms::animationEffectsForBeforeProperty,
|
||||
nsGkAtoms::animationEffectsForAfterProperty,
|
||||
nsGkAtoms::animationEffectsForMarkerProperty, nullptr};
|
||||
|
||||
return effectSetPropertyAtoms;
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsAtom* EffectSet::GetEffectSetPropertyAtom(PseudoStyleType aPseudoType) {
|
||||
switch (aPseudoType) {
|
||||
case PseudoStyleType::NotPseudo:
|
||||
return nsGkAtoms::animationEffectsProperty;
|
||||
|
||||
case PseudoStyleType::before:
|
||||
return nsGkAtoms::animationEffectsForBeforeProperty;
|
||||
|
||||
case PseudoStyleType::after:
|
||||
return nsGkAtoms::animationEffectsForAfterProperty;
|
||||
|
||||
case PseudoStyleType::marker:
|
||||
return nsGkAtoms::animationEffectsForMarkerProperty;
|
||||
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE(
|
||||
"Should not try to get animation effects for "
|
||||
"a pseudo other that :before, :after or ::marker");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void EffectSet::AddEffect(dom::KeyframeEffect& aEffect) {
|
||||
if (!mEffects.EnsureInserted(&aEffect)) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -32,28 +32,17 @@ 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,
|
||||
MOZ_ASSERT(!IsBeingEnumerated(),
|
||||
"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);
|
||||
|
|
@ -193,24 +182,20 @@ class EffectSet {
|
|||
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() {
|
||||
nsCSSPropertyIDSet PropertiesForAnimationsLevel() const {
|
||||
return mPropertiesForAnimationsLevel;
|
||||
}
|
||||
nsCSSPropertyIDSet PropertiesForAnimationsLevel() const {
|
||||
nsCSSPropertyIDSet& PropertiesForAnimationsLevel() {
|
||||
return mPropertiesForAnimationsLevel;
|
||||
}
|
||||
|
||||
private:
|
||||
static nsAtom* GetEffectSetPropertyAtom(PseudoStyleType aPseudoType);
|
||||
|
||||
OwningEffectSet mEffects;
|
||||
|
||||
// Refresh driver timestamp from the moment when the animations which produce
|
||||
|
|
@ -222,21 +207,13 @@ class EffectSet {
|
|||
// 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;
|
||||
uint64_t mAnimationGeneration = 0;
|
||||
|
||||
// Specifies the compositor-animatable properties that are overridden by
|
||||
// !important rules.
|
||||
|
|
@ -249,13 +226,19 @@ class EffectSet {
|
|||
#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;
|
||||
uint64_t mActiveIterators = 0;
|
||||
#endif
|
||||
|
||||
bool mMayHaveOpacityAnim;
|
||||
bool mMayHaveTransformAnim;
|
||||
// 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
|
||||
|
|
|
|||
80
dom/animation/ElementAnimationData.cpp
Normal file
80
dom/animation/ElementAnimationData.cpp
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "ElementAnimationData.h"
|
||||
#include "mozilla/AnimationCollection.h"
|
||||
#include "mozilla/EffectSet.h"
|
||||
#include "mozilla/dom/CSSTransition.h"
|
||||
#include "mozilla/dom/CSSAnimation.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
void ElementAnimationData::Traverse(nsCycleCollectionTraversalCallback& cb) {
|
||||
mElementData.Traverse(cb);
|
||||
mBeforeData.Traverse(cb);
|
||||
mAfterData.Traverse(cb);
|
||||
mMarkerData.Traverse(cb);
|
||||
}
|
||||
|
||||
void ElementAnimationData::ClearAllAnimationCollections() {
|
||||
for (auto* data : {&mElementData, &mBeforeData, &mAfterData, &mMarkerData}) {
|
||||
data->mAnimations = nullptr;
|
||||
data->mTransitions = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ElementAnimationData::PerElementOrPseudoData::PerElementOrPseudoData() =
|
||||
default;
|
||||
ElementAnimationData::PerElementOrPseudoData::~PerElementOrPseudoData() =
|
||||
default;
|
||||
|
||||
void ElementAnimationData::PerElementOrPseudoData::Traverse(
|
||||
nsCycleCollectionTraversalCallback& cb) {
|
||||
// We only care about mEffectSet. The animation collections are managed by the
|
||||
// pres context and go away when presentation of the document goes away.
|
||||
if (mEffectSet) {
|
||||
mEffectSet->Traverse(cb);
|
||||
}
|
||||
}
|
||||
|
||||
EffectSet& ElementAnimationData::PerElementOrPseudoData::DoEnsureEffectSet() {
|
||||
MOZ_ASSERT(!mEffectSet);
|
||||
mEffectSet = MakeUnique<EffectSet>();
|
||||
return *mEffectSet;
|
||||
}
|
||||
|
||||
CSSTransitionCollection&
|
||||
ElementAnimationData::PerElementOrPseudoData::DoEnsureTransitions(
|
||||
dom::Element& aOwner, PseudoStyleType aType) {
|
||||
MOZ_ASSERT(!mTransitions);
|
||||
mTransitions = MakeUnique<CSSTransitionCollection>(aOwner, aType);
|
||||
return *mTransitions;
|
||||
}
|
||||
|
||||
CSSAnimationCollection&
|
||||
ElementAnimationData::PerElementOrPseudoData::DoEnsureAnimations(
|
||||
dom::Element& aOwner, PseudoStyleType aType) {
|
||||
MOZ_ASSERT(!mAnimations);
|
||||
mAnimations = MakeUnique<CSSAnimationCollection>(aOwner, aType);
|
||||
return *mAnimations;
|
||||
}
|
||||
|
||||
void ElementAnimationData::PerElementOrPseudoData::DoClearEffectSet() {
|
||||
MOZ_ASSERT(mEffectSet);
|
||||
mEffectSet = nullptr;
|
||||
}
|
||||
|
||||
void ElementAnimationData::PerElementOrPseudoData::DoClearTransitions() {
|
||||
MOZ_ASSERT(mTransitions);
|
||||
mTransitions = nullptr;
|
||||
}
|
||||
|
||||
void ElementAnimationData::PerElementOrPseudoData::DoClearAnimations() {
|
||||
MOZ_ASSERT(mAnimations);
|
||||
mAnimations = nullptr;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
150
dom/animation/ElementAnimationData.h
Normal file
150
dom/animation/ElementAnimationData.h
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
/* -*- 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_ElementAnimationData_h
|
||||
#define mozilla_ElementAnimationData_h
|
||||
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/PseudoStyleType.h"
|
||||
|
||||
class nsCycleCollectionTraversalCallback;
|
||||
|
||||
namespace mozilla {
|
||||
enum class PseudoStyleType : uint8_t;
|
||||
class EffectSet;
|
||||
template <typename Animation>
|
||||
class AnimationCollection;
|
||||
namespace dom {
|
||||
class Element;
|
||||
class CSSAnimation;
|
||||
class CSSTransition;
|
||||
} // namespace dom
|
||||
using CSSAnimationCollection = AnimationCollection<dom::CSSAnimation>;
|
||||
using CSSTransitionCollection = AnimationCollection<dom::CSSTransition>;
|
||||
|
||||
// The animation data for a given element (and its pseudo-elements).
|
||||
class ElementAnimationData {
|
||||
struct PerElementOrPseudoData {
|
||||
UniquePtr<EffectSet> mEffectSet;
|
||||
UniquePtr<CSSAnimationCollection> mAnimations;
|
||||
UniquePtr<CSSTransitionCollection> mTransitions;
|
||||
|
||||
PerElementOrPseudoData();
|
||||
~PerElementOrPseudoData();
|
||||
|
||||
EffectSet& DoEnsureEffectSet();
|
||||
CSSTransitionCollection& DoEnsureTransitions(dom::Element&,
|
||||
PseudoStyleType);
|
||||
CSSAnimationCollection& DoEnsureAnimations(dom::Element&, PseudoStyleType);
|
||||
void DoClearEffectSet();
|
||||
void DoClearTransitions();
|
||||
void DoClearAnimations();
|
||||
|
||||
void Traverse(nsCycleCollectionTraversalCallback&);
|
||||
};
|
||||
|
||||
PerElementOrPseudoData mElementData;
|
||||
|
||||
// TODO(emilio): Maybe this should be a hash map eventually, once we allow
|
||||
// animating all pseudo-elements.
|
||||
PerElementOrPseudoData mBeforeData;
|
||||
PerElementOrPseudoData mAfterData;
|
||||
PerElementOrPseudoData mMarkerData;
|
||||
|
||||
const PerElementOrPseudoData& DataFor(PseudoStyleType aType) const {
|
||||
switch (aType) {
|
||||
case PseudoStyleType::NotPseudo:
|
||||
break;
|
||||
case PseudoStyleType::before:
|
||||
return mBeforeData;
|
||||
case PseudoStyleType::after:
|
||||
return mAfterData;
|
||||
case PseudoStyleType::marker:
|
||||
return mMarkerData;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE(
|
||||
"Should not try to get animation effects for "
|
||||
"a pseudo other that :before, :after or ::marker");
|
||||
break;
|
||||
}
|
||||
return mElementData;
|
||||
}
|
||||
|
||||
PerElementOrPseudoData& DataFor(PseudoStyleType aType) {
|
||||
const auto& data =
|
||||
const_cast<const ElementAnimationData*>(this)->DataFor(aType);
|
||||
return const_cast<PerElementOrPseudoData&>(data);
|
||||
}
|
||||
|
||||
public:
|
||||
void Traverse(nsCycleCollectionTraversalCallback&);
|
||||
|
||||
void ClearAllAnimationCollections();
|
||||
|
||||
EffectSet* GetEffectSetFor(PseudoStyleType aType) const {
|
||||
return DataFor(aType).mEffectSet.get();
|
||||
}
|
||||
|
||||
void ClearEffectSetFor(PseudoStyleType aType) {
|
||||
auto& data = DataFor(aType);
|
||||
if (data.mEffectSet) {
|
||||
data.DoClearEffectSet();
|
||||
}
|
||||
}
|
||||
|
||||
EffectSet& EnsureEffectSetFor(PseudoStyleType aType) {
|
||||
auto& data = DataFor(aType);
|
||||
if (auto* set = data.mEffectSet.get()) {
|
||||
return *set;
|
||||
}
|
||||
return data.DoEnsureEffectSet();
|
||||
}
|
||||
|
||||
CSSTransitionCollection* GetTransitionCollection(PseudoStyleType aType) {
|
||||
return DataFor(aType).mTransitions.get();
|
||||
}
|
||||
|
||||
void ClearTransitionCollectionFor(PseudoStyleType aType) {
|
||||
auto& data = DataFor(aType);
|
||||
if (data.mTransitions) {
|
||||
data.DoClearTransitions();
|
||||
}
|
||||
}
|
||||
|
||||
CSSTransitionCollection& EnsureTransitionCollection(dom::Element& aOwner,
|
||||
PseudoStyleType aType) {
|
||||
auto& data = DataFor(aType);
|
||||
if (auto* collection = data.mTransitions.get()) {
|
||||
return *collection;
|
||||
}
|
||||
return data.DoEnsureTransitions(aOwner, aType);
|
||||
}
|
||||
|
||||
CSSAnimationCollection* GetAnimationCollection(PseudoStyleType aType) {
|
||||
return DataFor(aType).mAnimations.get();
|
||||
}
|
||||
|
||||
void ClearAnimationCollectionFor(PseudoStyleType aType) {
|
||||
auto& data = DataFor(aType);
|
||||
if (data.mAnimations) {
|
||||
data.DoClearAnimations();
|
||||
}
|
||||
}
|
||||
|
||||
CSSAnimationCollection& EnsureAnimationCollection(dom::Element& aOwner,
|
||||
PseudoStyleType aType) {
|
||||
auto& data = DataFor(aType);
|
||||
if (auto* collection = data.mAnimations.get()) {
|
||||
return *collection;
|
||||
}
|
||||
return data.DoEnsureAnimations(aOwner, aType);
|
||||
}
|
||||
|
||||
ElementAnimationData() = default;
|
||||
};
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
|
@ -32,6 +32,7 @@ EXPORTS.mozilla += [
|
|||
"ComputedTiming.h",
|
||||
"EffectCompositor.h",
|
||||
"EffectSet.h",
|
||||
"ElementAnimationData.h",
|
||||
"Keyframe.h",
|
||||
"KeyframeEffectParams.h",
|
||||
"KeyframeUtils.h",
|
||||
|
|
@ -55,6 +56,7 @@ UNIFIED_SOURCES += [
|
|||
"DocumentTimeline.cpp",
|
||||
"EffectCompositor.cpp",
|
||||
"EffectSet.cpp",
|
||||
"ElementAnimationData.cpp",
|
||||
"KeyframeEffect.cpp",
|
||||
"KeyframeUtils.cpp",
|
||||
"PendingAnimationTracker.cpp",
|
||||
|
|
|
|||
|
|
@ -516,7 +516,7 @@ waitForAllPaints(() => {
|
|||
parentElement.appendChild(div);
|
||||
|
||||
await waitForAnimationReadyToRestyle(animation);
|
||||
ok(!SpecialPowers.wrap(animation).isRunningOnCompositor);
|
||||
ok(!SpecialPowers.wrap(animation).isRunningOnCompositor, "Should not be running in compositor");
|
||||
|
||||
const markers = await observeStyling(20);
|
||||
is(markers.length, 20,
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CharacterData)
|
|||
nsIContent::Unlink(tmp);
|
||||
|
||||
if (nsContentSlots* slots = tmp->GetExistingContentSlots()) {
|
||||
slots->Unlink();
|
||||
slots->Unlink(*tmp);
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "mozilla/DeclarationBlock.h"
|
||||
#include "mozilla/EffectCompositor.h"
|
||||
#include "mozilla/EffectSet.h"
|
||||
#include "mozilla/ElementAnimationData.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/EventListenerManager.h"
|
||||
|
|
@ -75,6 +76,7 @@
|
|||
#include "mozilla/dom/DocumentTimeline.h"
|
||||
#include "mozilla/dom/ElementBinding.h"
|
||||
#include "mozilla/dom/Flex.h"
|
||||
#include "mozilla/dom/FragmentOrElement.h"
|
||||
#include "mozilla/dom/FromParser.h"
|
||||
#include "mozilla/dom/Grid.h"
|
||||
#include "mozilla/dom/HTMLDivElement.h"
|
||||
|
|
@ -1863,8 +1865,14 @@ nsresult Element::BindToTree(BindContext& aContext, nsINode& aParent) {
|
|||
// FIXME(emilio): Why is this needed? The element shouldn't even be styled in
|
||||
// the first place, we should style it properly eventually.
|
||||
//
|
||||
// Also, if this _is_ needed, then it's wrong and should use GetComposedDoc()
|
||||
// to account for Shadow DOM.
|
||||
// This check is rather broken:
|
||||
//
|
||||
// * Should use GetComposedDoc() to account for shadow DOM.
|
||||
// * The GetEffectSet check is broken and only really works if pseudoType ==
|
||||
// PseudoStyleType::NotPseudo.
|
||||
//
|
||||
// Removing this chunk of code causes failures in test_restyles.html. Some of
|
||||
// them look benign, but another one at least looks like a real bug.
|
||||
if (aParent.IsInUncomposedDoc() && MayHaveAnimations()) {
|
||||
PseudoStyleType pseudoType = GetPseudoElementType();
|
||||
if ((pseudoType == PseudoStyleType::NotPseudo ||
|
||||
|
|
@ -1946,11 +1954,8 @@ void Element::UnbindFromTree(bool aNullParent) {
|
|||
Document::ExitFullscreenInDocTree(OwnerDoc());
|
||||
}
|
||||
|
||||
if (HasServoData()) {
|
||||
MOZ_ASSERT(document);
|
||||
MOZ_ASSERT(IsInNativeAnonymousSubtree());
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(HasServoData(), document);
|
||||
MOZ_ASSERT_IF(HasServoData(), IsInNativeAnonymousSubtree());
|
||||
if (document) {
|
||||
ClearServoData(document);
|
||||
}
|
||||
|
|
@ -1964,20 +1969,14 @@ void Element::UnbindFromTree(bool aNullParent) {
|
|||
// PendingAnimationTracker on the document and remove their animations,
|
||||
// and so they can find their pres context for dispatching cancel events.
|
||||
//
|
||||
// FIXME (Bug 522599): Need a test for this.
|
||||
if (MayHaveAnimations()) {
|
||||
RemoveProperty(nsGkAtoms::transitionsOfBeforeProperty);
|
||||
RemoveProperty(nsGkAtoms::transitionsOfAfterProperty);
|
||||
RemoveProperty(nsGkAtoms::transitionsOfMarkerProperty);
|
||||
RemoveProperty(nsGkAtoms::transitionsProperty);
|
||||
RemoveProperty(nsGkAtoms::animationsOfBeforeProperty);
|
||||
RemoveProperty(nsGkAtoms::animationsOfAfterProperty);
|
||||
RemoveProperty(nsGkAtoms::animationsOfMarkerProperty);
|
||||
RemoveProperty(nsGkAtoms::animationsProperty);
|
||||
// FIXME(bug 522599): Need a test for this.
|
||||
// FIXME(emilio): Why not clearing the effect set as well?
|
||||
if (auto* data = GetAnimationData()) {
|
||||
data->ClearAllAnimationCollections();
|
||||
if (document) {
|
||||
if (nsPresContext* presContext = document->GetPresContext()) {
|
||||
// We have to clear all pending restyle requests for the animations on
|
||||
// this element to avoid unnecessary restyles when we re-attached this
|
||||
// this element to avoid unnecessary restyles if/when we re-attach this
|
||||
// element.
|
||||
presContext->EffectCompositor()->ClearRestyleRequestsFor(this);
|
||||
}
|
||||
|
|
@ -4231,6 +4230,14 @@ void Element::ClearServoData(Document* aDoc) {
|
|||
}
|
||||
}
|
||||
|
||||
ElementAnimationData& Element::CreateAnimationData() {
|
||||
MOZ_ASSERT(!GetAnimationData());
|
||||
SetMayHaveAnimations();
|
||||
auto* slots = ExtendedDOMSlots();
|
||||
slots->mAnimations = MakeUnique<ElementAnimationData>();
|
||||
return *slots->mAnimations;
|
||||
}
|
||||
|
||||
void Element::SetCustomElementData(UniquePtr<CustomElementData> aData) {
|
||||
SetHasCustomElementData();
|
||||
|
||||
|
|
|
|||
|
|
@ -567,13 +567,32 @@ class Element : public FragmentOrElement {
|
|||
void ClearServoData() { ClearServoData(GetComposedDoc()); }
|
||||
void ClearServoData(Document* aDocument);
|
||||
|
||||
ElementAnimationData* GetAnimationData() const {
|
||||
if (!MayHaveAnimations()) {
|
||||
return nullptr;
|
||||
}
|
||||
const nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
|
||||
return slots ? slots->mAnimations.get() : nullptr;
|
||||
}
|
||||
|
||||
ElementAnimationData& EnsureAnimationData() {
|
||||
if (auto* anim = GetAnimationData()) {
|
||||
return *anim;
|
||||
}
|
||||
return CreateAnimationData();
|
||||
}
|
||||
|
||||
private:
|
||||
ElementAnimationData& CreateAnimationData();
|
||||
|
||||
public:
|
||||
/**
|
||||
* Gets the custom element data used by web components custom element.
|
||||
* Custom element data is created at the first attempt to enqueue a callback.
|
||||
*
|
||||
* @return The custom element data or null if none.
|
||||
*/
|
||||
inline CustomElementData* GetCustomElementData() const {
|
||||
CustomElementData* GetCustomElementData() const {
|
||||
if (!HasCustomElementData()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include "mozilla/EffectSet.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/EventListenerManager.h"
|
||||
#include "mozilla/ElementAnimationData.h"
|
||||
#include "mozilla/HTMLEditor.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/RestyleManager.h"
|
||||
|
|
@ -518,7 +519,7 @@ static_assert(sizeof(nsINode::nsSlots) <= MaxDOMSlotSizeAllowed,
|
|||
static_assert(sizeof(FragmentOrElement::nsDOMSlots) <= MaxDOMSlotSizeAllowed,
|
||||
"DOM slots cannot be grown without consideration");
|
||||
|
||||
void nsIContent::nsExtendedContentSlots::UnlinkExtendedSlots() {
|
||||
void nsIContent::nsExtendedContentSlots::UnlinkExtendedSlots(nsIContent&) {
|
||||
mContainingShadow = nullptr;
|
||||
mAssignedSlot = nullptr;
|
||||
}
|
||||
|
|
@ -578,8 +579,8 @@ void FragmentOrElement::nsDOMSlots::Traverse(
|
|||
aCb.NoteXPCOMChild(mPart.get());
|
||||
}
|
||||
|
||||
void FragmentOrElement::nsDOMSlots::Unlink() {
|
||||
nsIContent::nsContentSlots::Unlink();
|
||||
void FragmentOrElement::nsDOMSlots::Unlink(nsINode& aNode) {
|
||||
nsIContent::nsContentSlots::Unlink(aNode);
|
||||
mStyle = nullptr;
|
||||
if (mAttributeMap) {
|
||||
mAttributeMap->DropReference();
|
||||
|
|
@ -627,12 +628,10 @@ FragmentOrElement::nsExtendedDOMSlots::nsExtendedDOMSlots() = default;
|
|||
|
||||
FragmentOrElement::nsExtendedDOMSlots::~nsExtendedDOMSlots() = default;
|
||||
|
||||
void FragmentOrElement::nsExtendedDOMSlots::UnlinkExtendedSlots() {
|
||||
nsIContent::nsExtendedContentSlots::UnlinkExtendedSlots();
|
||||
void FragmentOrElement::nsExtendedDOMSlots::UnlinkExtendedSlots(
|
||||
nsIContent& aContent) {
|
||||
nsIContent::nsExtendedContentSlots::UnlinkExtendedSlots(aContent);
|
||||
|
||||
// Don't clear mXBLBinding, it'll be done in
|
||||
// BindingManager::RemovedFromDocument from FragmentOrElement::Unlink.
|
||||
//
|
||||
// mShadowRoot will similarly be cleared explicitly from
|
||||
// FragmentOrElement::Unlink.
|
||||
mSMILOverrideStyle = nullptr;
|
||||
|
|
@ -642,6 +641,10 @@ void FragmentOrElement::nsExtendedDOMSlots::UnlinkExtendedSlots() {
|
|||
mCustomElementData->Unlink();
|
||||
mCustomElementData = nullptr;
|
||||
}
|
||||
if (mAnimations) {
|
||||
mAnimations = nullptr;
|
||||
aContent.ClearMayHaveAnimations();
|
||||
}
|
||||
}
|
||||
|
||||
void FragmentOrElement::nsExtendedDOMSlots::TraverseExtendedSlots(
|
||||
|
|
@ -663,6 +666,9 @@ void FragmentOrElement::nsExtendedDOMSlots::TraverseExtendedSlots(
|
|||
if (mCustomElementData) {
|
||||
mCustomElementData->Traverse(aCb);
|
||||
}
|
||||
if (mAnimations) {
|
||||
mAnimations->Traverse(aCb);
|
||||
}
|
||||
}
|
||||
|
||||
size_t FragmentOrElement::nsExtendedDOMSlots::SizeOfExcludingThis(
|
||||
|
|
@ -1321,9 +1327,6 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(FragmentOrElement)
|
|||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FragmentOrElement)
|
||||
nsIContent::Unlink(tmp);
|
||||
|
||||
// The XBL binding is removed by RemoveFromBindingManagerRunnable
|
||||
// which is dispatched in UnbindFromTree.
|
||||
|
||||
if (tmp->HasProperties()) {
|
||||
if (tmp->IsElement()) {
|
||||
Element* elem = tmp->AsElement();
|
||||
|
|
@ -1337,13 +1340,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FragmentOrElement)
|
|||
tmp->RemoveProperty(props[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp->MayHaveAnimations()) {
|
||||
nsAtom** effectProps = EffectSet::GetEffectSetPropertyAtoms();
|
||||
for (uint32_t i = 0; effectProps[i]; ++i) {
|
||||
tmp->RemoveProperty(effectProps[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unlink child content (and unbind our subtree).
|
||||
|
|
@ -1802,14 +1798,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(FragmentOrElement)
|
|||
return NS_SUCCESS_INTERRUPTED_TRAVERSE;
|
||||
}
|
||||
|
||||
// Check that whenever we have effect properties, MayHaveAnimations is set.
|
||||
#ifdef DEBUG
|
||||
nsAtom** effectProps = EffectSet::GetEffectSetPropertyAtoms();
|
||||
for (uint32_t i = 0; effectProps[i]; ++i) {
|
||||
MOZ_ASSERT_IF(tmp->GetProperty(effectProps[i]), tmp->MayHaveAnimations());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (tmp->HasProperties()) {
|
||||
if (tmp->IsElement()) {
|
||||
Element* elem = tmp->AsElement();
|
||||
|
|
@ -1831,21 +1819,10 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(FragmentOrElement)
|
|||
cb.NoteXPCOMChild(property);
|
||||
}
|
||||
}
|
||||
if (tmp->MayHaveAnimations()) {
|
||||
nsAtom** effectProps = EffectSet::GetEffectSetPropertyAtoms();
|
||||
for (uint32_t i = 0; effectProps[i]; ++i) {
|
||||
EffectSet* effectSet =
|
||||
static_cast<EffectSet*>(tmp->GetProperty(effectProps[i]));
|
||||
if (effectSet) {
|
||||
effectSet->Traverse(cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Traverse attribute names.
|
||||
if (tmp->IsElement()) {
|
||||
Element* element = tmp->AsElement();
|
||||
// Traverse attribute names.
|
||||
uint32_t i;
|
||||
uint32_t attrs = element->GetAttrCount();
|
||||
for (i = 0; i < attrs; i++) {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ namespace mozilla {
|
|||
class DeclarationBlock;
|
||||
enum class ContentRelevancyReason;
|
||||
using ContentRelevancy = EnumSet<ContentRelevancyReason, uint8_t>;
|
||||
class ElementAnimationData;
|
||||
namespace dom {
|
||||
struct CustomElementData;
|
||||
class Element;
|
||||
|
|
@ -160,7 +161,7 @@ class FragmentOrElement : public nsIContent {
|
|||
~nsExtendedDOMSlots();
|
||||
|
||||
void TraverseExtendedSlots(nsCycleCollectionTraversalCallback&) final;
|
||||
void UnlinkExtendedSlots() final;
|
||||
void UnlinkExtendedSlots(nsIContent&) final;
|
||||
|
||||
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const final;
|
||||
|
||||
|
|
@ -195,6 +196,11 @@ class FragmentOrElement : public nsIContent {
|
|||
*/
|
||||
UniquePtr<CustomElementData> mCustomElementData;
|
||||
|
||||
/**
|
||||
* Web animations data.
|
||||
*/
|
||||
UniquePtr<ElementAnimationData> mAnimations;
|
||||
|
||||
/**
|
||||
* Last remembered size (in CSS pixels) for the element.
|
||||
* @see {@link https://drafts.csswg.org/css-sizing-4/#last-remembered}
|
||||
|
|
@ -221,7 +227,7 @@ class FragmentOrElement : public nsIContent {
|
|||
~nsDOMSlots();
|
||||
|
||||
void Traverse(nsCycleCollectionTraversalCallback&) final;
|
||||
void Unlink() final;
|
||||
void Unlink(nsINode&) final;
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -639,7 +639,7 @@ class nsIContent : public nsINode {
|
|||
virtual ~nsExtendedContentSlots();
|
||||
|
||||
virtual void TraverseExtendedSlots(nsCycleCollectionTraversalCallback&);
|
||||
virtual void UnlinkExtendedSlots();
|
||||
virtual void UnlinkExtendedSlots(nsIContent&);
|
||||
|
||||
virtual size_t SizeOfExcludingThis(
|
||||
mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
|
|
@ -674,10 +674,10 @@ class nsIContent : public nsINode {
|
|||
}
|
||||
}
|
||||
|
||||
void Unlink() override {
|
||||
nsINode::nsSlots::Unlink();
|
||||
void Unlink(nsINode& aNode) override {
|
||||
nsINode::nsSlots::Unlink(aNode);
|
||||
if (mExtendedSlots) {
|
||||
GetExtendedContentSlots()->UnlinkExtendedSlots();
|
||||
GetExtendedContentSlots()->UnlinkExtendedSlots(*aNode.AsContent());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ void nsINode::nsSlots::Traverse(nsCycleCollectionTraversalCallback& cb) {
|
|||
cb.NoteXPCOMChild(mChildNodes);
|
||||
}
|
||||
|
||||
void nsINode::nsSlots::Unlink() {
|
||||
void nsINode::nsSlots::Unlink(nsINode&) {
|
||||
if (mChildNodes) {
|
||||
mChildNodes->InvalidateCacheIfAvailable();
|
||||
ImplCycleCollectionUnlink(mChildNodes);
|
||||
|
|
@ -1490,9 +1490,8 @@ bool nsINode::Traverse(nsINode* tmp, nsCycleCollectionTraversalCallback& cb) {
|
|||
void nsINode::Unlink(nsINode* tmp) {
|
||||
tmp->ReleaseWrapper(tmp);
|
||||
|
||||
nsSlots* slots = tmp->GetExistingSlots();
|
||||
if (slots) {
|
||||
slots->Unlink();
|
||||
if (nsSlots* slots = tmp->GetExistingSlots()) {
|
||||
slots->Unlink(*tmp);
|
||||
}
|
||||
|
||||
if (tmp->NodeType() != DOCUMENT_NODE &&
|
||||
|
|
|
|||
|
|
@ -1281,7 +1281,7 @@ class nsINode : public mozilla::dom::EventTarget {
|
|||
virtual ~nsSlots();
|
||||
|
||||
virtual void Traverse(nsCycleCollectionTraversalCallback&);
|
||||
virtual void Unlink();
|
||||
virtual void Unlink(nsINode&);
|
||||
|
||||
/**
|
||||
* A list of mutation observers
|
||||
|
|
@ -1910,6 +1910,7 @@ class nsINode : public mozilla::dom::EventTarget {
|
|||
void ClearPointerLock() { ClearBoolFlag(ElementHasPointerLock); }
|
||||
bool MayHaveAnimations() const { return GetBoolFlag(ElementHasAnimations); }
|
||||
void SetMayHaveAnimations() { SetBoolFlag(ElementHasAnimations); }
|
||||
void ClearMayHaveAnimations() { ClearBoolFlag(ElementHasAnimations); }
|
||||
void SetHasValidDir() { SetBoolFlag(NodeHasValidDirAttribute); }
|
||||
void ClearHasValidDir() { ClearBoolFlag(NodeHasValidDirAttribute); }
|
||||
bool HasValidDir() const { return GetBoolFlag(NodeHasValidDirAttribute); }
|
||||
|
|
|
|||
|
|
@ -11535,15 +11535,13 @@ nsIFrame::CaretPosition::CaretPosition() : mContentOffset(0) {}
|
|||
nsIFrame::CaretPosition::~CaretPosition() = default;
|
||||
|
||||
bool nsIFrame::HasCSSAnimations() {
|
||||
auto collection =
|
||||
AnimationCollection<CSSAnimation>::GetAnimationCollection(this);
|
||||
return collection && collection->mAnimations.Length() > 0;
|
||||
auto* collection = AnimationCollection<CSSAnimation>::Get(this);
|
||||
return collection && !collection->mAnimations.IsEmpty();
|
||||
}
|
||||
|
||||
bool nsIFrame::HasCSSTransitions() {
|
||||
auto collection =
|
||||
AnimationCollection<CSSTransition>::GetAnimationCollection(this);
|
||||
return collection && collection->mAnimations.Length() > 0;
|
||||
auto* collection = AnimationCollection<CSSTransition>::Get(this);
|
||||
return collection && !collection->mAnimations.IsEmpty();
|
||||
}
|
||||
|
||||
void nsIFrame::AddSizeOfExcludingThisForTree(nsWindowSizes& aSizes) const {
|
||||
|
|
@ -11756,10 +11754,8 @@ void nsIFrame::UpdateVisibleDescendantsState() {
|
|||
}
|
||||
|
||||
void nsIFrame::UpdateAnimationVisibility() {
|
||||
auto* animationCollection =
|
||||
AnimationCollection<CSSAnimation>::GetAnimationCollection(this);
|
||||
auto* transitionCollection =
|
||||
AnimationCollection<CSSTransition>::GetAnimationCollection(this);
|
||||
auto* animationCollection = AnimationCollection<CSSAnimation>::Get(this);
|
||||
auto* transitionCollection = AnimationCollection<CSSTransition>::Get(this);
|
||||
|
||||
if ((!animationCollection || animationCollection->mAnimations.IsEmpty()) &&
|
||||
(!transitionCollection || transitionCollection->mAnimations.IsEmpty())) {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/AnimationCollection.h"
|
||||
#include <type_traits>
|
||||
|
||||
#include "mozilla/ElementAnimationData.h"
|
||||
#include "mozilla/RestyleManager.h"
|
||||
#include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch
|
||||
#include "mozilla/dom/CSSAnimation.h" // For dom::CSSAnimation
|
||||
|
|
@ -14,126 +16,59 @@
|
|||
namespace mozilla {
|
||||
|
||||
template <class AnimationType>
|
||||
/* static */ void AnimationCollection<AnimationType>::PropertyDtor(
|
||||
void* aObject, nsAtom* aPropertyName, void* aPropertyValue, void* aData) {
|
||||
AnimationCollection* collection =
|
||||
static_cast<AnimationCollection*>(aPropertyValue);
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(!collection->mCalledPropertyDtor, "can't call dtor twice");
|
||||
collection->mCalledPropertyDtor = true;
|
||||
#endif
|
||||
AnimationCollection<AnimationType>::~AnimationCollection() {
|
||||
MOZ_COUNT_DTOR(AnimationCollection);
|
||||
|
||||
PostRestyleMode postRestyle = collection->mCalledDestroy
|
||||
? PostRestyleMode::IfNeeded
|
||||
: PostRestyleMode::Never;
|
||||
const PostRestyleMode postRestyle =
|
||||
mCalledDestroy ? PostRestyleMode::IfNeeded : PostRestyleMode::Never;
|
||||
{
|
||||
nsAutoAnimationMutationBatch mb(collection->mElement->OwnerDoc());
|
||||
nsAutoAnimationMutationBatch mb(mElement.OwnerDoc());
|
||||
|
||||
for (size_t animIdx = collection->mAnimations.Length(); animIdx-- != 0;) {
|
||||
collection->mAnimations[animIdx]->CancelFromStyle(postRestyle);
|
||||
for (size_t animIdx = mAnimations.Length(); animIdx-- != 0;) {
|
||||
mAnimations[animIdx]->CancelFromStyle(postRestyle);
|
||||
}
|
||||
}
|
||||
delete collection;
|
||||
}
|
||||
|
||||
template <class AnimationType>
|
||||
/* static */ AnimationCollection<AnimationType>*
|
||||
AnimationCollection<AnimationType>::GetAnimationCollection(
|
||||
const dom::Element* aElement, PseudoStyleType aPseudoType) {
|
||||
if (!aElement->MayHaveAnimations()) {
|
||||
// Early return for the most common case.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsAtom* propName = GetPropertyAtomForPseudoType(aPseudoType);
|
||||
if (!propName) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return static_cast<AnimationCollection<AnimationType>*>(
|
||||
aElement->GetProperty(propName));
|
||||
}
|
||||
|
||||
template <class AnimationType>
|
||||
/* static */ AnimationCollection<AnimationType>*
|
||||
AnimationCollection<AnimationType>::GetAnimationCollection(
|
||||
const nsIFrame* aFrame) {
|
||||
Maybe<NonOwningAnimationTarget> pseudoElement =
|
||||
EffectCompositor::GetAnimationElementAndPseudoForFrame(aFrame);
|
||||
if (!pseudoElement) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!pseudoElement->mElement->MayHaveAnimations()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return GetAnimationCollection(pseudoElement->mElement,
|
||||
pseudoElement->mPseudoType);
|
||||
}
|
||||
|
||||
template <class AnimationType>
|
||||
/* static */ AnimationCollection<AnimationType>*
|
||||
AnimationCollection<AnimationType>::GetOrCreateAnimationCollection(
|
||||
dom::Element* aElement, PseudoStyleType aPseudoType,
|
||||
bool* aCreatedCollection) {
|
||||
MOZ_ASSERT(aCreatedCollection);
|
||||
*aCreatedCollection = false;
|
||||
|
||||
nsAtom* propName = GetPropertyAtomForPseudoType(aPseudoType);
|
||||
MOZ_ASSERT(propName,
|
||||
"Should only try to create animations for one of the"
|
||||
" recognized pseudo types");
|
||||
|
||||
auto collection = static_cast<AnimationCollection<AnimationType>*>(
|
||||
aElement->GetProperty(propName));
|
||||
if (!collection) {
|
||||
// FIXME: Consider arena-allocating?
|
||||
collection = new AnimationCollection<AnimationType>(aElement, propName);
|
||||
nsresult rv = aElement->SetProperty(
|
||||
propName, collection, &AnimationCollection<AnimationType>::PropertyDtor,
|
||||
false);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("SetProperty failed");
|
||||
// The collection must be destroyed via PropertyDtor, otherwise
|
||||
// mCalledPropertyDtor assertion is triggered in destructor.
|
||||
AnimationCollection<AnimationType>::PropertyDtor(aElement, propName,
|
||||
collection, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
*aCreatedCollection = true;
|
||||
aElement->SetMayHaveAnimations();
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
template <class AnimationType>
|
||||
/*static*/ nsAtom*
|
||||
AnimationCollection<AnimationType>::GetPropertyAtomForPseudoType(
|
||||
PseudoStyleType aPseudoType) {
|
||||
nsAtom* propName = nullptr;
|
||||
|
||||
if (aPseudoType == PseudoStyleType::NotPseudo) {
|
||||
propName = TraitsType::ElementPropertyAtom();
|
||||
} else if (aPseudoType == PseudoStyleType::before) {
|
||||
propName = TraitsType::BeforePropertyAtom();
|
||||
} else if (aPseudoType == PseudoStyleType::after) {
|
||||
propName = TraitsType::AfterPropertyAtom();
|
||||
} else if (aPseudoType == PseudoStyleType::marker) {
|
||||
propName = TraitsType::MarkerPropertyAtom();
|
||||
}
|
||||
|
||||
return propName;
|
||||
LinkedListElement<SelfType>::remove();
|
||||
}
|
||||
|
||||
template <class AnimationType>
|
||||
void AnimationCollection<AnimationType>::Destroy() {
|
||||
mCalledDestroy = true;
|
||||
auto* data = mElement.GetAnimationData();
|
||||
MOZ_ASSERT(data);
|
||||
if constexpr (std::is_same_v<AnimationType, dom::CSSAnimation>) {
|
||||
MOZ_ASSERT(data->GetAnimationCollection(mPseudo) == this);
|
||||
data->ClearAnimationCollectionFor(mPseudo);
|
||||
} else {
|
||||
MOZ_ASSERT(data->GetTransitionCollection(mPseudo) == this);
|
||||
data->ClearTransitionCollectionFor(mPseudo);
|
||||
}
|
||||
}
|
||||
|
||||
// This will call our destructor.
|
||||
mElement->RemoveProperty(mElementProperty);
|
||||
template <class AnimationType>
|
||||
AnimationCollection<AnimationType>* AnimationCollection<AnimationType>::Get(
|
||||
const dom::Element* aElement, const PseudoStyleType aType) {
|
||||
auto* data = aElement->GetAnimationData();
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
if constexpr (std::is_same_v<AnimationType, dom::CSSAnimation>) {
|
||||
return data->GetAnimationCollection(aType);
|
||||
} else {
|
||||
return data->GetTransitionCollection(aType);
|
||||
}
|
||||
}
|
||||
|
||||
template <class AnimationType>
|
||||
/* static */ AnimationCollection<AnimationType>*
|
||||
AnimationCollection<AnimationType>::Get(const nsIFrame* aFrame) {
|
||||
Maybe<NonOwningAnimationTarget> target =
|
||||
EffectCompositor::GetAnimationElementAndPseudoForFrame(aFrame);
|
||||
if (!target) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return Get(target->mElement, target->mPseudoType);
|
||||
}
|
||||
|
||||
// Explicit class instantiations
|
||||
|
|
|
|||
|
|
@ -21,73 +21,42 @@ namespace mozilla {
|
|||
namespace dom {
|
||||
class Element;
|
||||
}
|
||||
|
||||
// Traits class to define the specific atoms used when storing specializations
|
||||
// of AnimationCollection as a property on an Element (e.g. which atom
|
||||
// to use when storing an AnimationCollection<CSSAnimation> for a ::before
|
||||
// pseudo-element).
|
||||
template <class AnimationType>
|
||||
struct AnimationTypeTraits {};
|
||||
enum class PseudoStyleType : uint8_t;
|
||||
|
||||
template <class AnimationType>
|
||||
class AnimationCollection
|
||||
: public LinkedListElement<AnimationCollection<AnimationType>> {
|
||||
typedef AnimationCollection<AnimationType> SelfType;
|
||||
typedef AnimationTypeTraits<AnimationType> TraitsType;
|
||||
|
||||
AnimationCollection(dom::Element* aElement, nsAtom* aElementProperty)
|
||||
: mElement(aElement), mElementProperty(aElementProperty) {
|
||||
public:
|
||||
AnimationCollection(dom::Element& aOwner, PseudoStyleType aPseudoType)
|
||||
: mElement(aOwner), mPseudo(aPseudoType) {
|
||||
MOZ_COUNT_CTOR(AnimationCollection);
|
||||
}
|
||||
|
||||
public:
|
||||
~AnimationCollection() {
|
||||
MOZ_ASSERT(mCalledPropertyDtor,
|
||||
"must call destructor through element property dtor");
|
||||
MOZ_COUNT_DTOR(AnimationCollection);
|
||||
LinkedListElement<SelfType>::remove();
|
||||
}
|
||||
~AnimationCollection();
|
||||
|
||||
void Destroy();
|
||||
|
||||
static void PropertyDtor(void* aObject, nsAtom* aPropertyName,
|
||||
void* aPropertyValue, void* aData);
|
||||
|
||||
// Get the collection of animations for the given |aElement| and
|
||||
// |aPseudoType|.
|
||||
static AnimationCollection<AnimationType>* GetAnimationCollection(
|
||||
const dom::Element* aElement, PseudoStyleType aPseudoType);
|
||||
|
||||
// Given the frame |aFrame| with possibly animated content, finds its
|
||||
// associated collection of animations. If |aFrame| is a generated content
|
||||
// frame, this function may examine the parent frame to search for such
|
||||
// animations.
|
||||
static AnimationCollection<AnimationType>* GetAnimationCollection(
|
||||
const nsIFrame* aFrame);
|
||||
static AnimationCollection* Get(const nsIFrame* aFrame);
|
||||
static AnimationCollection* Get(const dom::Element* aElement,
|
||||
PseudoStyleType aPseudoType);
|
||||
|
||||
// Get the collection of animations for the given |aElement| and
|
||||
// |aPseudoType| or create it if it does not already exist.
|
||||
//
|
||||
// We'll set the outparam |aCreatedCollection| to true if we have
|
||||
// to create the collection and we successfully do so. Otherwise,
|
||||
// we'll set it to false.
|
||||
static AnimationCollection<AnimationType>* GetOrCreateAnimationCollection(
|
||||
dom::Element* aElement, PseudoStyleType aPseudoType,
|
||||
bool* aCreatedCollection);
|
||||
|
||||
dom::Element* mElement;
|
||||
|
||||
// the atom we use in mElement's prop table (must be a static atom,
|
||||
// i.e., in an atom list)
|
||||
nsAtom* mElementProperty;
|
||||
// The element. Weak reference is fine since it owns us.
|
||||
// FIXME(emilio): These are only needed for Destroy(), so maybe remove and
|
||||
// rely on the caller clearing us properly?
|
||||
dom::Element& mElement;
|
||||
const PseudoStyleType mPseudo;
|
||||
|
||||
nsTArray<RefPtr<AnimationType>> mAnimations;
|
||||
|
||||
private:
|
||||
static nsAtom* GetPropertyAtomForPseudoType(PseudoStyleType aPseudoType);
|
||||
|
||||
// We distinguish between destroying this by calling Destroy() vs directly
|
||||
// calling RemoveProperty on an element.
|
||||
// clearing the collection.
|
||||
//
|
||||
// The former case represents regular updating due to style changes and should
|
||||
// trigger subsequent restyles.
|
||||
|
|
@ -95,10 +64,6 @@ class AnimationCollection
|
|||
// The latter case represents document tear-down or other DOM surgery in
|
||||
// which case we should not trigger restyles.
|
||||
bool mCalledDestroy = false;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool mCalledPropertyDtor = false;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@ class CommonAnimationManager {
|
|||
void StopAnimationsForElement(dom::Element* aElement,
|
||||
PseudoStyleType aPseudoType) {
|
||||
MOZ_ASSERT(aElement);
|
||||
AnimationCollection<AnimationType>* collection =
|
||||
AnimationCollection<AnimationType>::GetAnimationCollection(aElement,
|
||||
aPseudoType);
|
||||
auto* collection =
|
||||
AnimationCollection<AnimationType>::Get(aElement, aPseudoType);
|
||||
if (!collection) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -620,42 +620,34 @@ bool Gecko_ElementHasAnimations(const Element* aElement) {
|
|||
|
||||
bool Gecko_ElementHasCSSAnimations(const Element* aElement) {
|
||||
PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
|
||||
nsAnimationManager::CSSAnimationCollection* collection =
|
||||
nsAnimationManager::CSSAnimationCollection ::GetAnimationCollection(
|
||||
aElement, pseudoType);
|
||||
|
||||
auto* collection =
|
||||
nsAnimationManager::CSSAnimationCollection::Get(aElement, pseudoType);
|
||||
return collection && !collection->mAnimations.IsEmpty();
|
||||
}
|
||||
|
||||
bool Gecko_ElementHasCSSTransitions(const Element* aElement) {
|
||||
PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
|
||||
nsTransitionManager::CSSTransitionCollection* collection =
|
||||
nsTransitionManager::CSSTransitionCollection ::GetAnimationCollection(
|
||||
aElement, pseudoType);
|
||||
|
||||
auto* collection =
|
||||
nsTransitionManager::CSSTransitionCollection::Get(aElement, pseudoType);
|
||||
return collection && !collection->mAnimations.IsEmpty();
|
||||
}
|
||||
|
||||
size_t Gecko_ElementTransitions_Length(const Element* aElement) {
|
||||
PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
|
||||
nsTransitionManager::CSSTransitionCollection* collection =
|
||||
nsTransitionManager::CSSTransitionCollection ::GetAnimationCollection(
|
||||
aElement, pseudoType);
|
||||
|
||||
auto* collection =
|
||||
nsTransitionManager::CSSTransitionCollection::Get(aElement, pseudoType);
|
||||
return collection ? collection->mAnimations.Length() : 0;
|
||||
}
|
||||
|
||||
static CSSTransition* GetCurrentTransitionAt(const Element* aElement,
|
||||
size_t aIndex) {
|
||||
PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
|
||||
nsTransitionManager::CSSTransitionCollection* collection =
|
||||
nsTransitionManager::CSSTransitionCollection ::GetAnimationCollection(
|
||||
aElement, pseudoType);
|
||||
auto* collection =
|
||||
nsTransitionManager::CSSTransitionCollection ::Get(aElement, pseudoType);
|
||||
if (!collection) {
|
||||
return nullptr;
|
||||
}
|
||||
nsTArray<RefPtr<CSSTransition>>& transitions = collection->mAnimations;
|
||||
return aIndex < transitions.Length() ? transitions[aIndex].get() : nullptr;
|
||||
return collection->mAnimations.SafeElementAt(aIndex);
|
||||
}
|
||||
|
||||
nsCSSPropertyID Gecko_ElementTransitions_PropertyAt(const Element* aElement,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "mozilla/AnimationEventDispatcher.h"
|
||||
#include "mozilla/EffectCompositor.h"
|
||||
#include "mozilla/ElementAnimationData.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/ServoStyleSet.h"
|
||||
#include "mozilla/dom/AnimationEffect.h"
|
||||
|
|
@ -374,9 +375,8 @@ void nsAnimationManager::DoUpdateAnimations(
|
|||
// Likewise, when we initially construct frames, we're not in a
|
||||
// style change, but also not in an animation restyle.
|
||||
|
||||
CSSAnimationCollection* collection =
|
||||
CSSAnimationCollection::GetAnimationCollection(aTarget.mElement,
|
||||
aTarget.mPseudoType);
|
||||
auto* collection =
|
||||
CSSAnimationCollection::Get(aTarget.mElement, aTarget.mPseudoType);
|
||||
if (!collection && aStyle.mAnimationNameCount == 1 &&
|
||||
aStyle.mAnimations[0].GetName() == nsGkAtoms::_empty) {
|
||||
return;
|
||||
|
|
@ -398,16 +398,10 @@ void nsAnimationManager::DoUpdateAnimations(
|
|||
}
|
||||
|
||||
if (!collection) {
|
||||
bool createdCollection = false;
|
||||
collection = CSSAnimationCollection::GetOrCreateAnimationCollection(
|
||||
aTarget.mElement, aTarget.mPseudoType, &createdCollection);
|
||||
if (!collection) {
|
||||
MOZ_ASSERT(!createdCollection, "outparam should agree with return value");
|
||||
NS_WARNING("allocating collection failed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (createdCollection) {
|
||||
collection =
|
||||
&aTarget.mElement->EnsureAnimationData().EnsureAnimationCollection(
|
||||
*aTarget.mElement, aTarget.mPseudoType);
|
||||
if (!collection->isInList()) {
|
||||
AddElementCollection(collection);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include "mozilla/MemoryReporting.h"
|
||||
#include "nsCSSPropertyIDSet.h"
|
||||
#include "mozilla/EffectSet.h"
|
||||
#include "mozilla/ElementAnimationData.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/ServoBindings.h"
|
||||
#include "mozilla/StyleAnimationValue.h"
|
||||
|
|
@ -64,8 +65,7 @@ bool nsTransitionManager::UpdateTransitions(dom::Element* aElement,
|
|||
return false;
|
||||
}
|
||||
|
||||
CSSTransitionCollection* collection =
|
||||
CSSTransitionCollection::GetAnimationCollection(aElement, aPseudoType);
|
||||
auto* collection = CSSTransitionCollection::Get(aElement, aPseudoType);
|
||||
return DoUpdateTransitions(*aNewStyle.StyleUIReset(), aElement, aPseudoType,
|
||||
collection, aOldStyle, aNewStyle);
|
||||
}
|
||||
|
|
@ -74,7 +74,7 @@ bool nsTransitionManager::DoUpdateTransitions(
|
|||
const nsStyleUIReset& aStyle, dom::Element* aElement,
|
||||
PseudoStyleType aPseudoType, CSSTransitionCollection*& aElementTransitions,
|
||||
const ComputedStyle& aOldStyle, const ComputedStyle& aNewStyle) {
|
||||
MOZ_ASSERT(!aElementTransitions || aElementTransitions->mElement == aElement,
|
||||
MOZ_ASSERT(!aElementTransitions || &aElementTransitions->mElement == aElement,
|
||||
"Element mismatch");
|
||||
|
||||
// Per http://lists.w3.org/Archives/Public/www-style/2009Aug/0109.html
|
||||
|
|
@ -291,7 +291,7 @@ bool nsTransitionManager::ConsiderInitiatingTransition(
|
|||
// IsShorthand itself will assert if aProperty is not a property.
|
||||
MOZ_ASSERT(!nsCSSProps::IsShorthand(aProperty), "property out of range");
|
||||
NS_ASSERTION(
|
||||
!aElementTransitions || aElementTransitions->mElement == aElement,
|
||||
!aElementTransitions || &aElementTransitions->mElement == aElement,
|
||||
"Element mismatch");
|
||||
|
||||
aProperty = nsCSSProps::Physicalize(aProperty, aNewStyle);
|
||||
|
|
@ -475,17 +475,10 @@ bool nsTransitionManager::ConsiderInitiatingTransition(
|
|||
animation->PlayFromStyle();
|
||||
|
||||
if (!aElementTransitions) {
|
||||
bool createdCollection = false;
|
||||
aElementTransitions =
|
||||
CSSTransitionCollection::GetOrCreateAnimationCollection(
|
||||
aElement, aPseudoType, &createdCollection);
|
||||
if (!aElementTransitions) {
|
||||
MOZ_ASSERT(!createdCollection, "outparam should agree with return value");
|
||||
NS_WARNING("allocating collection failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (createdCollection) {
|
||||
&aElement->EnsureAnimationData().EnsureTransitionCollection(
|
||||
*aElement, aPseudoType);
|
||||
if (!aElementTransitions->isInList()) {
|
||||
AddElementCollection(aElementTransitions);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2140,22 +2140,10 @@ STATIC_ATOMS = [
|
|||
Atom("onfetch", "onfetch"),
|
||||
# Content property names
|
||||
Atom("afterPseudoProperty", "afterPseudoProperty"), # nsXMLElement*
|
||||
Atom("animationsProperty", "AnimationsProperty"), # FrameAnimations*
|
||||
Atom("animationsOfBeforeProperty", "AnimationsOfBeforeProperty"), # FrameAnimations*
|
||||
Atom("animationsOfAfterProperty", "AnimationsOfAfterProperty"), # FrameAnimations*
|
||||
Atom("animationsOfMarkerProperty", "AnimationsOfMarkerProperty"), # FrameAnimations*
|
||||
Atom("animationEffectsProperty", "AnimationEffectsProperty"), # EffectSet*
|
||||
Atom("animationEffectsForBeforeProperty", "AnimationsEffectsForBeforeProperty"), # EffectSet*
|
||||
Atom("animationEffectsForAfterProperty", "AnimationsEffectsForAfterProperty"), # EffectSet*
|
||||
Atom("animationEffectsForMarkerProperty", "AnimationsEffectsForMarkerProperty"), # EffectSet*
|
||||
Atom("beforePseudoProperty", "beforePseudoProperty"), # nsXMLElement*
|
||||
Atom("cssPseudoElementBeforeProperty", "CSSPseudoElementBeforeProperty"), # CSSPseudoElement*
|
||||
Atom("cssPseudoElementAfterProperty", "CSSPseudoElementAfterProperty"), # CSSPseudoElement*
|
||||
Atom("cssPseudoElementMarkerProperty", "CSSPseudoElementMarkerProperty"), # CSSPseudoElement*
|
||||
Atom("transitionsProperty", "TransitionsProperty"), # FrameTransitions*
|
||||
Atom("transitionsOfBeforeProperty", "TransitionsOfBeforeProperty"), # FrameTransitions*
|
||||
Atom("transitionsOfAfterProperty", "TransitionsOfAfterProperty"), # FrameTransitions*
|
||||
Atom("transitionsOfMarkerProperty", "TransitionsOfMarkerProperty"), # FrameTransitions*
|
||||
Atom("genConInitializerProperty", "QuoteNodeProperty"),
|
||||
Atom("labelMouseDownPtProperty", "LabelMouseDownPtProperty"),
|
||||
Atom("lockedStyleStates", "lockedStyleStates"),
|
||||
|
|
|
|||
Loading…
Reference in a new issue