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_dom_CSSAnimation_h
8 #define mozilla_dom_CSSAnimation_h
10 #include "mozilla/dom/Animation.h"
11 #include "mozilla/dom/KeyframeEffect.h"
12 #include "mozilla/dom/MutationObservers.h"
13 #include "mozilla/StyleAnimationValue.h"
14 #include "AnimationCommon.h"
17 // Properties of CSS Animations that can be overridden by the Web Animations API
18 // in a manner that means we should ignore subsequent changes to markup for that
20 enum class CSSAnimationProperties
{
24 IterationCount
= 1 << 2,
28 Effect
= Keyframes
| Duration
| IterationCount
| Direction
| Delay
| FillMode
,
31 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CSSAnimationProperties
)
35 class CSSAnimation final
: public Animation
{
37 explicit CSSAnimation(nsIGlobalObject
* aGlobal
, nsAtom
* aAnimationName
)
38 : dom::Animation(aGlobal
),
39 mAnimationName(aAnimationName
),
40 mNeedsNewAnimationIndexWhenRun(false),
41 mPreviousPhase(ComputedTiming::AnimationPhase::Idle
),
42 mPreviousIteration(0) {
43 // We might need to drop this assertion once we add a script-accessible
44 // constructor but for animations generated from CSS markup the
45 // animation-name should never be empty.
46 MOZ_ASSERT(mAnimationName
!= nsGkAtoms::_empty
,
47 "animation-name should not be 'none'");
50 JSObject
* WrapObject(JSContext
* aCx
,
51 JS::Handle
<JSObject
*> aGivenProto
) override
;
53 CSSAnimation
* AsCSSAnimation() override
{ return this; }
54 const CSSAnimation
* AsCSSAnimation() const override
{ return this; }
56 // CSSAnimation interface
57 void GetAnimationName(nsString
& aRetVal
) const {
58 mAnimationName
->ToString(aRetVal
);
61 nsAtom
* AnimationName() const { return mAnimationName
; }
63 // Animation interface overrides
64 void SetEffect(AnimationEffect
* aEffect
) override
;
65 void SetStartTimeAsDouble(const Nullable
<double>& aStartTime
) override
;
66 Promise
* GetReady(ErrorResult
& aRv
) override
;
67 void Reverse(ErrorResult
& aRv
) override
;
69 // NOTE: tabbrowser.xml currently relies on the fact that reading the
70 // currentTime of a CSSAnimation does *not* flush style (whereas reading the
71 // playState does). If CSS Animations 2 specifies that reading currentTime
72 // also flushes style we will need to find another way to detect canceled
73 // animations in tabbrowser.xml. On the other hand, if CSS Animations 2
74 // specifies that reading playState does *not* flush style (and we drop the
75 // following override), then we should update tabbrowser.xml to check
76 // the playState instead.
77 AnimationPlayState
PlayStateFromJS() const override
;
78 bool PendingFromJS() const override
;
79 void PlayFromJS(ErrorResult
& aRv
) override
;
80 void PauseFromJS(ErrorResult
& aRv
) override
;
83 void PauseFromStyle();
84 void CancelFromStyle(PostRestyleMode aPostRestyle
) {
85 // When an animation is disassociated with style it enters an odd state
86 // where its composite order is undefined until it first transitions
87 // out of the idle state.
89 // Even if the composite order isn't defined we don't want it to be random
90 // in case we need to determine the order to dispatch events associated
91 // with an animation in this state. To solve this we treat the animation as
92 // if it had been added to the end of the global animation list so that
93 // its sort order is defined. We'll update this index again once the
94 // animation leaves the idle state.
95 mAnimationIndex
= sNextAnimationIndex
++;
96 mNeedsNewAnimationIndexWhenRun
= true;
98 Animation::Cancel(aPostRestyle
);
100 // We need to do this *after* calling Cancel() since
101 // Cancel() might synchronously trigger a cancel event for which
102 // we need an owning element to target the event at.
103 mOwningElement
= OwningElementRef();
106 void Tick() override
;
108 const StickyTimeDuration
& aActiveTime
= StickyTimeDuration());
110 bool HasLowerCompositeOrderThan(const CSSAnimation
& aOther
) const;
112 void SetAnimationIndex(uint64_t aIndex
) {
113 MOZ_ASSERT(IsTiedToMarkup());
114 if (IsRelevant() && mAnimationIndex
!= aIndex
) {
115 MutationObservers::NotifyAnimationChanged(this);
118 mAnimationIndex
= aIndex
;
121 // Sets the owning element which is used for determining the composite
122 // order of CSSAnimation objects generated from CSS markup.
124 // @see mOwningElement
125 void SetOwningElement(const OwningElementRef
& aElement
) {
126 mOwningElement
= aElement
;
128 // True for animations that are generated from CSS markup and continue to
129 // reflect changes to that markup.
130 bool IsTiedToMarkup() const { return mOwningElement
.IsSet(); }
132 void MaybeQueueCancelEvent(const StickyTimeDuration
& aActiveTime
) override
{
133 QueueEvents(aActiveTime
);
136 CSSAnimationProperties
GetOverriddenProperties() const {
137 return mOverriddenProperties
;
139 void AddOverriddenProperties(CSSAnimationProperties aProperties
) {
140 mOverriddenProperties
|= aProperties
;
144 virtual ~CSSAnimation() {
145 MOZ_ASSERT(!mOwningElement
.IsSet(),
146 "Owning element should be cleared "
147 "before a CSS animation is destroyed");
150 // Animation overrides
151 void UpdateTiming(SeekFlag aSeekFlag
,
152 SyncNotifyFlag aSyncNotifyFlag
) override
;
154 // Returns the duration from the start of the animation's source effect's
155 // active interval to the point where the animation actually begins playback.
156 // This is zero unless the animation's source effect has a negative delay in
157 // which case it is the absolute value of that delay.
158 // This is used for setting the elapsedTime member of CSS AnimationEvents.
159 TimeDuration
InitialAdvance() const {
160 return mEffect
? std::max(TimeDuration(),
161 mEffect
->SpecifiedTiming().Delay() * -1)
165 RefPtr
<nsAtom
> mAnimationName
;
167 // The (pseudo-)element whose computed animation-name refers to this
168 // animation (if any).
170 // This is used for determining the relative composite order of animations
171 // generated from CSS markup.
173 // Typically this will be the same as the target element of the keyframe
174 // effect associated with this animation. However, it can differ in the
175 // following circumstances:
177 // a) If script removes or replaces the effect of this animation,
178 // b) If this animation is cancelled (e.g. by updating the
179 // animation-name property or removing the owning element from the
181 // c) If this object is generated from script using the CSSAnimation
184 // For (b) and (c) the owning element will return !IsSet().
185 OwningElementRef mOwningElement
;
187 // When true, indicates that when this animation next leaves the idle state,
188 // its animation index should be updated.
189 bool mNeedsNewAnimationIndexWhenRun
;
191 // Phase and current iteration from the previous time we queued events.
192 // This is used to determine what new events to dispatch.
193 ComputedTiming::AnimationPhase mPreviousPhase
;
194 uint64_t mPreviousIteration
;
196 // Properties that would normally be defined by the cascade but which have
197 // since been explicitly set via the Web Animations API.
198 CSSAnimationProperties mOverriddenProperties
= CSSAnimationProperties::None
;
201 // A subclass of KeyframeEffect that reports when specific properties have been
202 // overridden via the Web Animations API.
203 class CSSAnimationKeyframeEffect
: public KeyframeEffect
{
205 CSSAnimationKeyframeEffect(Document
* aDocument
,
206 OwningAnimationTarget
&& aTarget
,
207 TimingParams
&& aTiming
,
208 const KeyframeEffectParams
& aOptions
)
209 : KeyframeEffect(aDocument
, std::move(aTarget
), std::move(aTiming
),
212 void GetTiming(EffectTiming
& aRetVal
) const override
;
213 void GetComputedTimingAsDict(ComputedEffectTiming
& aRetVal
) const override
;
214 void UpdateTiming(const OptionalEffectTiming
& aTiming
,
215 ErrorResult
& aRv
) override
;
216 void SetKeyframes(JSContext
* aContext
, JS::Handle
<JSObject
*> aKeyframes
,
217 ErrorResult
& aRv
) override
;
220 CSSAnimation
* GetOwningCSSAnimation() {
221 return mAnimation
? mAnimation
->AsCSSAnimation() : nullptr;
223 const CSSAnimation
* GetOwningCSSAnimation() const {
224 return mAnimation
? mAnimation
->AsCSSAnimation() : nullptr;
227 // Flushes styles if our owning animation is a CSSAnimation
228 void MaybeFlushUnanimatedStyle() const;
234 struct AnimationTypeTraits
<dom::CSSAnimation
> {
235 static nsAtom
* ElementPropertyAtom() { return nsGkAtoms::animationsProperty
; }
236 static nsAtom
* BeforePropertyAtom() {
237 return nsGkAtoms::animationsOfBeforeProperty
;
239 static nsAtom
* AfterPropertyAtom() {
240 return nsGkAtoms::animationsOfAfterProperty
;
242 static nsAtom
* MarkerPropertyAtom() {
243 return nsGkAtoms::animationsOfMarkerProperty
;
247 } // namespace mozilla
249 #endif // mozilla_dom_CSSAnimation_h