1 /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "AnimationPlayer.h"
7 #include "AnimationUtils.h"
8 #include "mozilla/dom/AnimationPlayerBinding.h"
9 #include "AnimationCommon.h" // For AnimationPlayerCollection,
10 // CommonAnimationManager
11 #include "nsIDocument.h" // For nsIDocument
12 #include "nsIPresShell.h" // For nsIPresShell
13 #include "nsLayoutUtils.h" // For PostRestyleEvent (remove after bug 1073336)
18 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AnimationPlayer
, mTimeline
, mSource
)
20 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AnimationPlayer
, AddRef
)
21 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AnimationPlayer
, Release
)
24 AnimationPlayer::WrapObject(JSContext
* aCx
)
26 return dom::AnimationPlayerBinding::Wrap(aCx
, this);
30 AnimationPlayer::GetStartTime() const
32 return AnimationUtils::TimeDurationToDouble(mStartTime
);
35 Nullable
<TimeDuration
>
36 AnimationPlayer::GetCurrentTime() const
38 Nullable
<TimeDuration
> result
;
39 if (!mHoldTime
.IsNull()) {
42 Nullable
<TimeDuration
> timelineTime
= mTimeline
->GetCurrentTime();
43 if (!timelineTime
.IsNull() && !mStartTime
.IsNull()) {
44 result
.SetValue(timelineTime
.Value() - mStartTime
.Value());
51 AnimationPlayer::PlayState() const
53 Nullable
<TimeDuration
> currentTime
= GetCurrentTime();
54 if (currentTime
.IsNull()) {
55 return AnimationPlayState::Idle
;
59 return AnimationPlayState::Paused
;
62 if (currentTime
.Value() >= SourceContentEnd()) {
63 return AnimationPlayState::Finished
;
66 return AnimationPlayState::Running
;
70 AnimationPlayer::Play(UpdateFlags aFlags
)
72 // FIXME: When we implement finishing behavior (bug 1074630) we should
73 // not return early if mIsPaused is false since we may still need to seek.
74 // (However, we will need to pass a flag so that when we start playing due to
75 // a change in animation-play-state we *don't* trigger finishing behavior.)
81 Nullable
<TimeDuration
> timelineTime
= mTimeline
->GetCurrentTime();
82 if (timelineTime
.IsNull()) {
83 // FIXME: We should just sit in the pending state in this case.
84 // We will introduce the pending state in Bug 927349.
88 // Update start time to an appropriate offset from the current timeline time
89 MOZ_ASSERT(!mHoldTime
.IsNull(), "Hold time should not be null when paused");
90 mStartTime
.SetValue(timelineTime
.Value() - mHoldTime
.Value());
93 if (aFlags
== eUpdateStyle
) {
99 AnimationPlayer::Pause(UpdateFlags aFlags
)
105 mIsRunningOnCompositor
= false;
107 // Bug 927349 - check for null result here and go to pending state
108 mHoldTime
= GetCurrentTime();
109 mStartTime
.SetNull();
111 if (aFlags
== eUpdateStyle
) {
117 AnimationPlayer::GetCurrentTimeAsDouble() const
119 return AnimationUtils::TimeDurationToDouble(GetCurrentTime());
123 AnimationPlayer::PlayFromJS()
129 AnimationPlayer::PauseFromJS()
135 AnimationPlayer::SetSource(Animation
* aSource
)
138 mSource
->SetParentTime(Nullable
<TimeDuration
>());
142 mSource
->SetParentTime(GetCurrentTime());
147 AnimationPlayer::Tick()
150 mSource
->SetParentTime(GetCurrentTime());
155 AnimationPlayer::IsRunning() const
157 if (IsPaused() || !GetSource() || GetSource()->IsFinishedTransition()) {
161 ComputedTiming computedTiming
= GetSource()->GetComputedTiming();
162 return computedTiming
.mPhase
== ComputedTiming::AnimationPhase_Active
;
166 AnimationPlayer::CanThrottle() const
169 mSource
->IsFinishedTransition() ||
170 mSource
->Properties().IsEmpty()) {
174 if (!mIsRunningOnCompositor
) {
178 if (PlayState() != AnimationPlayState::Finished
) {
179 // Unfinished animations can be throttled.
183 // The animation has finished but, if this is the first sample since
184 // finishing, we need an unthrottled sample so we can apply the correct
185 // end-of-animation behavior on the main thread (either removing the
186 // animation style or applying the fill mode).
187 return mIsPreviousStateFinished
;
191 AnimationPlayer::ComposeStyle(nsRefPtr
<css::AnimValuesStyleRule
>& aStyleRule
,
192 nsCSSPropertySet
& aSetProperties
,
193 bool& aNeedsRefreshes
)
195 if (!mSource
|| mSource
->IsFinishedTransition()) {
199 AnimationPlayState playState
= PlayState();
200 if (playState
== AnimationPlayState::Running
) {
201 aNeedsRefreshes
= true;
204 mSource
->ComposeStyle(aStyleRule
, aSetProperties
);
206 mIsPreviousStateFinished
= (playState
== AnimationPlayState::Finished
);
210 AnimationPlayer::FlushStyle() const
212 nsIDocument
* doc
= GetRenderedDocument();
214 doc
->FlushPendingNotifications(Flush_Style
);
219 AnimationPlayer::MaybePostRestyle() const
225 Element
* targetElement
;
226 nsCSSPseudoElements::Type pseudoType
;
227 mSource
->GetTarget(targetElement
, pseudoType
);
228 if (!targetElement
) {
232 // FIXME: This is a bit heavy-handed but in bug 1073336 we hope to
233 // introduce a better means for players to update style.
234 nsLayoutUtils::PostRestyleEvent(targetElement
,
236 nsChangeHint_AllReflowHints
);
240 AnimationPlayer::PostUpdate()
242 AnimationPlayerCollection
* collection
= GetCollection();
244 collection
->NotifyPlayerUpdated();
249 AnimationPlayer::SourceContentEnd() const
252 return StickyTimeDuration(0);
255 return mSource
->Timing().mDelay
256 + mSource
->GetComputedTiming().mActiveDuration
;
260 AnimationPlayer::GetRenderedDocument() const
266 Element
* targetElement
;
267 nsCSSPseudoElements::Type pseudoType
;
268 mSource
->GetTarget(targetElement
, pseudoType
);
269 if (!targetElement
) {
273 return targetElement
->GetComposedDoc();
277 AnimationPlayer::GetPresContext() const
279 nsIDocument
* doc
= GetRenderedDocument();
283 nsIPresShell
* shell
= doc
->GetShell();
287 return shell
->GetPresContext();
290 AnimationPlayerCollection
*
291 AnimationPlayer::GetCollection() const
293 css::CommonAnimationManager
* manager
= GetAnimationManager();
297 MOZ_ASSERT(mSource
, "A player with an animation manager must have a source");
299 Element
* targetElement
;
300 nsCSSPseudoElements::Type targetPseudoType
;
301 mSource
->GetTarget(targetElement
, targetPseudoType
);
302 MOZ_ASSERT(targetElement
,
303 "A player with an animation manager must have a target");
305 return manager
->GetAnimationPlayers(targetElement
, targetPseudoType
, false);
309 } // namespace mozilla