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,
29 Effect
= Keyframes
| Duration
| IterationCount
| Direction
| Delay
|
30 FillMode
| Composition
,
33 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CSSAnimationProperties
)
37 class CSSAnimation final
: public Animation
{
39 explicit CSSAnimation(nsIGlobalObject
* aGlobal
, nsAtom
* aAnimationName
)
40 : dom::Animation(aGlobal
),
41 mAnimationName(aAnimationName
),
42 mNeedsNewAnimationIndexWhenRun(false),
43 mPreviousPhase(ComputedTiming::AnimationPhase::Idle
),
44 mPreviousIteration(0) {
45 // We might need to drop this assertion once we add a script-accessible
46 // constructor but for animations generated from CSS markup the
47 // animation-name should never be empty.
48 MOZ_ASSERT(mAnimationName
!= nsGkAtoms::_empty
,
49 "animation-name should not be 'none'");
52 JSObject
* WrapObject(JSContext
* aCx
,
53 JS::Handle
<JSObject
*> aGivenProto
) override
;
55 CSSAnimation
* AsCSSAnimation() override
{ return this; }
56 const CSSAnimation
* AsCSSAnimation() const override
{ return this; }
58 // CSSAnimation interface
59 void GetAnimationName(nsString
& aRetVal
) const {
60 mAnimationName
->ToString(aRetVal
);
63 nsAtom
* AnimationName() const { return mAnimationName
; }
65 // Animation interface overrides
66 void SetEffect(AnimationEffect
* aEffect
) override
;
67 void SetStartTimeAsDouble(const Nullable
<double>& aStartTime
) override
;
68 Promise
* GetReady(ErrorResult
& aRv
) override
;
69 void Reverse(ErrorResult
& aRv
) override
;
71 // NOTE: tabbrowser.xml currently relies on the fact that reading the
72 // currentTime of a CSSAnimation does *not* flush style (whereas reading the
73 // playState does). If CSS Animations 2 specifies that reading currentTime
74 // also flushes style we will need to find another way to detect canceled
75 // animations in tabbrowser.xml. On the other hand, if CSS Animations 2
76 // specifies that reading playState does *not* flush style (and we drop the
77 // following override), then we should update tabbrowser.xml to check
78 // the playState instead.
79 AnimationPlayState
PlayStateFromJS() const override
;
80 bool PendingFromJS() const override
;
81 void PlayFromJS(ErrorResult
& aRv
) override
;
82 void PauseFromJS(ErrorResult
& aRv
) override
;
85 void PauseFromStyle();
86 void CancelFromStyle(PostRestyleMode aPostRestyle
) {
87 // When an animation is disassociated with style it enters an odd state
88 // where its composite order is undefined until it first transitions
89 // out of the idle state.
91 // Even if the composite order isn't defined we don't want it to be random
92 // in case we need to determine the order to dispatch events associated
93 // with an animation in this state. To solve this we treat the animation as
94 // if it had been added to the end of the global animation list so that
95 // its sort order is defined. We'll update this index again once the
96 // animation leaves the idle state.
97 mAnimationIndex
= sNextAnimationIndex
++;
98 mNeedsNewAnimationIndexWhenRun
= true;
100 Animation::Cancel(aPostRestyle
);
102 // We need to do this *after* calling Cancel() since
103 // Cancel() might synchronously trigger a cancel event for which
104 // we need an owning element to target the event at.
105 mOwningElement
= OwningElementRef();
108 void Tick(TickState
&) override
;
110 const StickyTimeDuration
& aActiveTime
= StickyTimeDuration());
112 bool HasLowerCompositeOrderThan(const CSSAnimation
& aOther
) const;
114 void SetAnimationIndex(uint64_t aIndex
) {
115 MOZ_ASSERT(IsTiedToMarkup());
116 if (IsRelevant() && mAnimationIndex
!= aIndex
) {
117 MutationObservers::NotifyAnimationChanged(this);
120 mAnimationIndex
= aIndex
;
123 // Sets the owning element which is used for determining the composite
124 // order of CSSAnimation objects generated from CSS markup.
126 // @see mOwningElement
127 void SetOwningElement(const OwningElementRef
& aElement
) {
128 mOwningElement
= aElement
;
130 // True for animations that are generated from CSS markup and continue to
131 // reflect changes to that markup.
132 bool IsTiedToMarkup() const { return mOwningElement
.IsSet(); }
134 void MaybeQueueCancelEvent(const StickyTimeDuration
& aActiveTime
) override
{
135 QueueEvents(aActiveTime
);
138 CSSAnimationProperties
GetOverriddenProperties() const {
139 return mOverriddenProperties
;
141 void AddOverriddenProperties(CSSAnimationProperties aProperties
) {
142 mOverriddenProperties
|= aProperties
;
146 virtual ~CSSAnimation() {
147 MOZ_ASSERT(!mOwningElement
.IsSet(),
148 "Owning element should be cleared "
149 "before a CSS animation is destroyed");
152 // Animation overrides
153 void UpdateTiming(SeekFlag aSeekFlag
,
154 SyncNotifyFlag aSyncNotifyFlag
) override
;
156 // Returns the duration from the start of the animation's source effect's
157 // active interval to the point where the animation actually begins playback.
158 // This is zero unless the animation's source effect has a negative delay in
159 // which case it is the absolute value of that delay.
160 // This is used for setting the elapsedTime member of CSS AnimationEvents.
161 TimeDuration
InitialAdvance() const {
162 return mEffect
? std::max(TimeDuration(),
163 mEffect
->NormalizedTiming().Delay() * -1)
167 RefPtr
<nsAtom
> mAnimationName
;
169 // The (pseudo-)element whose computed animation-name refers to this
170 // animation (if any).
172 // This is used for determining the relative composite order of animations
173 // generated from CSS markup.
175 // Typically this will be the same as the target element of the keyframe
176 // effect associated with this animation. However, it can differ in the
177 // following circumstances:
179 // a) If script removes or replaces the effect of this animation,
180 // b) If this animation is cancelled (e.g. by updating the
181 // animation-name property or removing the owning element from the
183 // c) If this object is generated from script using the CSSAnimation
186 // For (b) and (c) the owning element will return !IsSet().
187 OwningElementRef mOwningElement
;
189 // When true, indicates that when this animation next leaves the idle state,
190 // its animation index should be updated.
191 bool mNeedsNewAnimationIndexWhenRun
;
193 // Phase and current iteration from the previous time we queued events.
194 // This is used to determine what new events to dispatch.
195 ComputedTiming::AnimationPhase mPreviousPhase
;
196 uint64_t mPreviousIteration
;
198 // Properties that would normally be defined by the cascade but which have
199 // since been explicitly set via the Web Animations API.
200 CSSAnimationProperties mOverriddenProperties
= CSSAnimationProperties::None
;
203 // A subclass of KeyframeEffect that reports when specific properties have been
204 // overridden via the Web Animations API.
205 class CSSAnimationKeyframeEffect
: public KeyframeEffect
{
207 CSSAnimationKeyframeEffect(Document
* aDocument
,
208 OwningAnimationTarget
&& aTarget
,
209 TimingParams
&& aTiming
,
210 const KeyframeEffectParams
& aOptions
)
211 : KeyframeEffect(aDocument
, std::move(aTarget
), std::move(aTiming
),
214 void GetTiming(EffectTiming
& aRetVal
) const override
;
215 void GetComputedTimingAsDict(ComputedEffectTiming
& aRetVal
) const override
;
216 void UpdateTiming(const OptionalEffectTiming
& aTiming
,
217 ErrorResult
& aRv
) override
;
218 void SetKeyframes(JSContext
* aContext
, JS::Handle
<JSObject
*> aKeyframes
,
219 ErrorResult
& aRv
) override
;
220 void SetComposite(const CompositeOperation
& aComposite
) override
;
223 CSSAnimation
* GetOwningCSSAnimation() {
224 return mAnimation
? mAnimation
->AsCSSAnimation() : nullptr;
226 const CSSAnimation
* GetOwningCSSAnimation() const {
227 return mAnimation
? mAnimation
->AsCSSAnimation() : nullptr;
230 // Flushes styles if our owning animation is a CSSAnimation
231 void MaybeFlushUnanimatedStyle() const;
236 } // namespace mozilla
238 #endif // mozilla_dom_CSSAnimation_h