/* -*- 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 "EffectSet.h" #include "mozilla/dom/Element.h" // For Element #include "mozilla/RestyleManagerHandle.h" #include "mozilla/RestyleManagerHandleInlines.h" #include "nsCSSPseudoElements.h" // For CSSPseudoElementType #include "nsCycleCollectionNoteChild.h" // For CycleCollectionNoteChild #include "nsPresContext.h" #include "nsLayoutUtils.h" namespace mozilla { /* static */ void EffectSet::PropertyDtor(void* aObject, nsIAtom* aPropertyName, void* aPropertyValue, void* aData) { EffectSet* effectSet = static_cast(aPropertyValue); #ifdef DEBUG MOZ_ASSERT(!effectSet->mCalledPropertyDtor, "Should not call dtor twice"); effectSet->mCalledPropertyDtor = true; #endif delete effectSet; } void EffectSet::Traverse(nsCycleCollectionTraversalCallback& aCallback) { for (auto iter = mEffects.Iter(); !iter.Done(); iter.Next()) { CycleCollectionNoteChild(aCallback, iter.Get()->GetKey(), "EffectSet::mEffects[]", aCallback.Flags()); } } /* static */ EffectSet* EffectSet::GetEffectSet(dom::Element* aElement, CSSPseudoElementType aPseudoType) { nsIAtom* propName = GetEffectSetPropertyAtom(aPseudoType); return static_cast(aElement->GetProperty(propName)); } /* static */ EffectSet* EffectSet::GetEffectSet(const nsIFrame* aFrame) { Maybe target = EffectCompositor::GetAnimationElementAndPseudoForFrame(aFrame); if (!target) { return nullptr; } if (!target->mElement->MayHaveAnimations()) { return nullptr; } return GetEffectSet(target->mElement, target->mPseudoType); } /* static */ EffectSet* EffectSet::GetOrCreateEffectSet(dom::Element* aElement, CSSPseudoElementType aPseudoType) { EffectSet* effectSet = GetEffectSet(aElement, aPseudoType); if (effectSet) { return effectSet; } nsIAtom* 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; } /* static */ void EffectSet::DestroyEffectSet(dom::Element* aElement, CSSPseudoElementType aPseudoType) { nsIAtom* propName = GetEffectSetPropertyAtom(aPseudoType); EffectSet* effectSet = static_cast(aElement->GetProperty(propName)); if (!effectSet) { return; } MOZ_ASSERT(!effectSet->IsBeingEnumerated(), "Should not destroy an effect set while it is being enumerated"); effectSet = nullptr; aElement->DeleteProperty(propName); } void EffectSet::UpdateAnimationGeneration(nsPresContext* aPresContext) { MOZ_ASSERT(aPresContext->RestyleManager()->IsGecko(), "stylo: Servo-backed style system should not be using " "EffectSet"); mAnimationGeneration = aPresContext->RestyleManager()->AsGecko()->GetAnimationGeneration(); } /* static */ nsIAtom** EffectSet::GetEffectSetPropertyAtoms() { static nsIAtom* effectSetPropertyAtoms[] = { nsGkAtoms::animationEffectsProperty, nsGkAtoms::animationEffectsForBeforeProperty, nsGkAtoms::animationEffectsForAfterProperty, nullptr }; return effectSetPropertyAtoms; } /* static */ nsIAtom* EffectSet::GetEffectSetPropertyAtom(CSSPseudoElementType aPseudoType) { switch (aPseudoType) { case CSSPseudoElementType::NotPseudo: return nsGkAtoms::animationEffectsProperty; case CSSPseudoElementType::before: return nsGkAtoms::animationEffectsForBeforeProperty; case CSSPseudoElementType::after: return nsGkAtoms::animationEffectsForAfterProperty; default: NS_NOTREACHED("Should not try to get animation effects for a pseudo " "other that :before or :after"); return nullptr; } } void EffectSet::AddEffect(dom::KeyframeEffectReadOnly& aEffect) { if (mEffects.Contains(&aEffect)) { return; } mEffects.PutEntry(&aEffect); MarkCascadeNeedsUpdate(); } void EffectSet::RemoveEffect(dom::KeyframeEffectReadOnly& aEffect) { if (!mEffects.Contains(&aEffect)) { return; } mEffects.RemoveEntry(&aEffect); MarkCascadeNeedsUpdate(); } } // namespace mozilla