1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_css_AnimationCommon_h
8 #define mozilla_css_AnimationCommon_h
10 #include "mozilla/AnimationCollection.h"
11 #include "mozilla/LinkedList.h"
12 #include "mozilla/dom/Animation.h"
13 #include "mozilla/dom/BaseKeyframeTypesBinding.h"
14 #include "mozilla/Assertions.h"
15 #include "mozilla/Maybe.h"
16 #include "mozilla/TimingParams.h"
17 #include "mozilla/dom/Nullable.h"
18 #include "nsContentUtils.h"
19 #include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch
24 enum class PseudoStyleType
: uint8_t;
30 template <class AnimationType
>
31 class CommonAnimationManager
{
33 explicit CommonAnimationManager(nsPresContext
* aPresContext
)
34 : mPresContext(aPresContext
) {}
36 // NOTE: This can return null after Disconnect().
37 nsPresContext
* PresContext() const { return mPresContext
; }
40 * Notify the manager that the pres context is going away.
43 // Content nodes might outlive the transition or animation manager.
44 RemoveAllElementCollections();
46 mPresContext
= nullptr;
50 * Stop animations on the element. This method takes the real element
51 * rather than the element for the generated content for animations on
52 * ::before, ::after and ::marker.
54 void StopAnimationsForElement(dom::Element
* aElement
,
55 PseudoStyleType aPseudoType
) {
58 AnimationCollection
<AnimationType
>::Get(aElement
, aPseudoType
);
63 nsAutoAnimationMutationBatch
mb(aElement
->OwnerDoc());
64 collection
->Destroy();
68 virtual ~CommonAnimationManager() {
69 MOZ_ASSERT(!mPresContext
, "Disconnect should have been called");
72 void AddElementCollection(AnimationCollection
<AnimationType
>* aCollection
) {
73 mElementCollections
.insertBack(aCollection
);
75 void RemoveAllElementCollections() {
76 while (AnimationCollection
<AnimationType
>* head
=
77 mElementCollections
.getFirst()) {
78 head
->Destroy(); // Note: this removes 'head' from mElementCollections.
82 LinkedList
<AnimationCollection
<AnimationType
>> mElementCollections
;
83 nsPresContext
* mPresContext
; // weak (non-null from ctor to Disconnect)
87 * Utility class for referencing the element that created a CSS animation or
88 * transition. It is non-owning (i.e. it uses a raw pointer) since it is only
89 * expected to be set by the owned animation while it actually being managed
90 * by the owning element.
92 * This class also abstracts the comparison of an element/pseudo-class pair
93 * for the sake of composite ordering since this logic is common to both CSS
94 * animations and transitions.
96 * (We call this OwningElementRef instead of just OwningElement so that we can
97 * call the getter on CSSAnimation/CSSTransition OwningElement() without
98 * clashing with this object's contructor.)
100 class OwningElementRef final
{
102 OwningElementRef() = default;
104 explicit OwningElementRef(const NonOwningAnimationTarget
& aTarget
)
105 : mTarget(aTarget
) {}
107 OwningElementRef(dom::Element
& aElement
, PseudoStyleType aPseudoType
)
108 : mTarget(&aElement
, aPseudoType
) {}
110 bool Equals(const OwningElementRef
& aOther
) const {
111 return mTarget
== aOther
.mTarget
;
114 bool LessThan(Maybe
<uint32_t>& aChildIndex
, const OwningElementRef
& aOther
,
115 Maybe
<uint32_t>& aOtherChildIndex
) const {
116 MOZ_ASSERT(mTarget
.mElement
&& aOther
.mTarget
.mElement
,
117 "Elements to compare should not be null");
119 if (mTarget
.mElement
!= aOther
.mTarget
.mElement
) {
120 return nsContentUtils::PositionIsBefore(mTarget
.mElement
,
121 aOther
.mTarget
.mElement
,
122 &aChildIndex
, &aOtherChildIndex
);
125 return mTarget
.mPseudoType
== PseudoStyleType::NotPseudo
||
126 (mTarget
.mPseudoType
== PseudoStyleType::before
&&
127 aOther
.mTarget
.mPseudoType
== PseudoStyleType::after
) ||
128 (mTarget
.mPseudoType
== PseudoStyleType::marker
&&
129 aOther
.mTarget
.mPseudoType
== PseudoStyleType::before
) ||
130 (mTarget
.mPseudoType
== PseudoStyleType::marker
&&
131 aOther
.mTarget
.mPseudoType
== PseudoStyleType::after
);
134 bool IsSet() const { return !!mTarget
.mElement
; }
136 void GetElement(dom::Element
*& aElement
, PseudoStyleType
& aPseudoType
) const {
137 aElement
= mTarget
.mElement
;
138 aPseudoType
= mTarget
.mPseudoType
;
141 const NonOwningAnimationTarget
& Target() const { return mTarget
; }
143 nsPresContext
* GetPresContext() const {
144 return nsContentUtils::GetContextForContent(mTarget
.mElement
);
148 NonOwningAnimationTarget mTarget
;
151 // Return the TransitionPhase or AnimationPhase to use when the animation
152 // doesn't have a target effect.
153 template <typename PhaseType
>
154 PhaseType
GetAnimationPhaseWithoutEffect(const dom::Animation
& aAnimation
) {
155 MOZ_ASSERT(!aAnimation
.GetEffect(),
156 "Should only be called when we do not have an effect");
158 dom::Nullable
<TimeDuration
> currentTime
=
159 aAnimation
.GetCurrentTimeAsDuration();
160 if (currentTime
.IsNull()) {
161 return PhaseType::Idle
;
164 // If we don't have a target effect, the duration will be zero so the phase is
165 // 'before' if the current time is less than zero.
166 return currentTime
.Value() < TimeDuration() ? PhaseType::Before
170 inline dom::PlaybackDirection
StyleToDom(StyleAnimationDirection aDirection
) {
171 switch (aDirection
) {
172 case StyleAnimationDirection::Normal
:
173 return dom::PlaybackDirection::Normal
;
174 case StyleAnimationDirection::Reverse
:
175 return dom::PlaybackDirection::Reverse
;
176 case StyleAnimationDirection::Alternate
:
177 return dom::PlaybackDirection::Alternate
;
178 case StyleAnimationDirection::AlternateReverse
:
179 return dom::PlaybackDirection::Alternate_reverse
;
181 MOZ_ASSERT_UNREACHABLE("Wrong style value?");
182 return dom::PlaybackDirection::Normal
;
185 inline dom::FillMode
StyleToDom(StyleAnimationFillMode aFillMode
) {
187 case StyleAnimationFillMode::None
:
188 return dom::FillMode::None
;
189 case StyleAnimationFillMode::Both
:
190 return dom::FillMode::Both
;
191 case StyleAnimationFillMode::Forwards
:
192 return dom::FillMode::Forwards
;
193 case StyleAnimationFillMode::Backwards
:
194 return dom::FillMode::Backwards
;
196 MOZ_ASSERT_UNREACHABLE("Wrong style value?");
197 return dom::FillMode::None
;
200 inline dom::CompositeOperation
StyleToDom(StyleAnimationComposition aStyle
) {
202 case StyleAnimationComposition::Replace
:
203 return dom::CompositeOperation::Replace
;
204 case StyleAnimationComposition::Add
:
205 return dom::CompositeOperation::Add
;
206 case StyleAnimationComposition::Accumulate
:
207 return dom::CompositeOperation::Accumulate
;
209 MOZ_ASSERT_UNREACHABLE("Invalid style composite operation?");
210 return dom::CompositeOperation::Replace
;
213 inline TimingParams
TimingParamsFromCSSParams(
214 float aDuration
, float aDelay
, float aIterationCount
,
215 StyleAnimationDirection aDirection
, StyleAnimationFillMode aFillMode
) {
216 MOZ_ASSERT(aIterationCount
>= 0.0 && !std::isnan(aIterationCount
),
217 "aIterations should be nonnegative & finite, as ensured by "
219 return TimingParams
{aDuration
, aDelay
, aIterationCount
,
220 StyleToDom(aDirection
), StyleToDom(aFillMode
)};
223 } // namespace mozilla
225 #endif /* !defined(mozilla_css_AnimationCommon_h) */