summaryrefslogtreecommitdiffstats
path: root/dom/animation/EffectSet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/animation/EffectSet.cpp')
-rw-r--r--dom/animation/EffectSet.cpp210
1 files changed, 210 insertions, 0 deletions
diff --git a/dom/animation/EffectSet.cpp b/dom/animation/EffectSet.cpp
new file mode 100644
index 0000000000..550d0cf1b0
--- /dev/null
+++ b/dom/animation/EffectSet.cpp
@@ -0,0 +1,210 @@
+/* -*- 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/RestyleManager.h"
+#include "mozilla/LayerAnimationInfo.h"
+#include "nsCSSPseudoElements.h" // For PseudoStyleType
+#include "nsCycleCollectionNoteChild.h" // For CycleCollectionNoteChild
+#include "nsPresContext.h"
+#include "nsLayoutUtils.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[]",
+ aCallback.Flags());
+ }
+}
+
+/* static */
+EffectSet* EffectSet::GetEffectSet(const dom::Element* aElement,
+ PseudoStyleType aPseudoType) {
+ if (!aElement->MayHaveAnimations()) {
+ return nullptr;
+ }
+
+ nsAtom* propName = GetEffectSetPropertyAtom(aPseudoType);
+ return static_cast<EffectSet*>(aElement->GetProperty(propName));
+}
+
+/* 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;
+}
+
+/* static */
+EffectSet* EffectSet::GetEffectSetForFrame(
+ const nsIFrame* aFrame, const nsCSSPropertyIDSet& aProperties) {
+ MOZ_ASSERT(aFrame);
+
+ // Transform animations are run on the primary frame (but stored on the
+ // content associated with the style frame).
+ const nsIFrame* frameToQuery = nullptr;
+ if (aProperties.IsSubsetOf(nsCSSPropertyIDSet::TransformLikeProperties())) {
+ // Make sure to return nullptr if we're looking for transform animations on
+ // the inner table frame.
+ if (!aFrame->IsFrameOfType(nsIFrame::eSupportsCSSTransforms)) {
+ return nullptr;
+ }
+ frameToQuery = nsLayoutUtils::GetStyleFrame(aFrame);
+ } else {
+ MOZ_ASSERT(
+ !aProperties.Intersects(nsCSSPropertyIDSet::TransformLikeProperties()),
+ "We should have only transform properties or no transform properties");
+ // We don't need to explicitly return nullptr when |aFrame| is NOT the style
+ // frame since there will be no effect set in that case.
+ frameToQuery = aFrame;
+ }
+
+ Maybe<NonOwningAnimationTarget> target =
+ EffectCompositor::GetAnimationElementAndPseudoForFrame(frameToQuery);
+ if (!target) {
+ return nullptr;
+ }
+
+ return GetEffectSet(target->mElement, target->mPseudoType);
+}
+
+/* static */
+EffectSet* EffectSet::GetEffectSetForFrame(const nsIFrame* aFrame,
+ DisplayItemType aDisplayItemType) {
+ return EffectSet::GetEffectSetForFrame(
+ aFrame, LayerAnimationInfo::GetCSSPropertiesFor(aDisplayItemType));
+}
+
+/* static */
+EffectSet* EffectSet::GetEffectSetForStyleFrame(const nsIFrame* aStyleFrame) {
+ Maybe<NonOwningAnimationTarget> target =
+ EffectCompositor::GetAnimationElementAndPseudoForFrame(aStyleFrame);
+
+ if (!target) {
+ return nullptr;
+ }
+
+ return GetEffectSet(target->mElement, target->mPseudoType);
+}
+
+/* static */
+EffectSet* EffectSet::GetEffectSetForEffect(
+ const dom::KeyframeEffect* aEffect) {
+ NonOwningAnimationTarget target = aEffect->GetAnimationTarget();
+ if (!target) {
+ return nullptr;
+ }
+
+ return EffectSet::GetEffectSet(target.mElement, target.mPseudoType);
+}
+
+/* static */
+void EffectSet::DestroyEffectSet(dom::Element* aElement,
+ PseudoStyleType aPseudoType) {
+ nsAtom* propName = GetEffectSetPropertyAtom(aPseudoType);
+ EffectSet* effectSet =
+ static_cast<EffectSet*>(aElement->GetProperty(propName));
+ if (!effectSet) {
+ return;
+ }
+
+ 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) {
+ mAnimationGeneration =
+ 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;
+ }
+
+ MarkCascadeNeedsUpdate();
+}
+
+void EffectSet::RemoveEffect(dom::KeyframeEffect& aEffect) {
+ if (!mEffects.EnsureRemoved(&aEffect)) {
+ return;
+ }
+
+ MarkCascadeNeedsUpdate();
+}
+
+} // namespace mozilla