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:
Emilio Cobos Álvarez 2023-02-15 14:12:33 +00:00
parent 45b09251e2
commit 6c32b964cd
24 changed files with 422 additions and 443 deletions

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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

View 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

View 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

View file

@ -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",

View file

@ -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,

View file

@ -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

View file

@ -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();

View file

@ -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;
}

View file

@ -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++) {

View file

@ -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;

View file

@ -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());
}
}

View file

@ -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 &&

View file

@ -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); }

View file

@ -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())) {

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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,

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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"),