Bug 1874684 - Part 37: Fix unified compilation. r=allstarschh
[gecko.git] / layout / style / AnimationCommon.h
blobd7a54c9751620e7a3199541f0ba0c5488568e92a
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
21 class nsPresContext;
23 namespace mozilla {
24 enum class PseudoStyleType : uint8_t;
26 namespace dom {
27 class Element;
30 template <class AnimationType>
31 class CommonAnimationManager {
32 public:
33 explicit CommonAnimationManager(nsPresContext* aPresContext)
34 : mPresContext(aPresContext) {}
36 // NOTE: This can return null after Disconnect().
37 nsPresContext* PresContext() const { return mPresContext; }
39 /**
40 * Notify the manager that the pres context is going away.
42 void Disconnect() {
43 // Content nodes might outlive the transition or animation manager.
44 RemoveAllElementCollections();
46 mPresContext = nullptr;
49 /**
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) {
56 MOZ_ASSERT(aElement);
57 auto* collection =
58 AnimationCollection<AnimationType>::Get(aElement, aPseudoType);
59 if (!collection) {
60 return;
63 nsAutoAnimationMutationBatch mb(aElement->OwnerDoc());
64 collection->Destroy();
67 protected:
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)
86 /**
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 {
101 public:
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);
147 private:
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
167 : PhaseType::After;
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) {
186 switch (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) {
201 switch (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 "
218 "CSSParser");
219 return TimingParams{aDuration, aDelay, aIterationCount,
220 StyleToDom(aDirection), StyleToDom(aFillMode)};
223 } // namespace mozilla
225 #endif /* !defined(mozilla_css_AnimationCommon_h) */