2 * Copyright (C) 2013 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include "core/animation/AnimationPlayer.h"
34 #include "core/animation/Animation.h"
35 #include "core/animation/AnimationTimeline.h"
36 #include "core/dom/Document.h"
37 #include "core/dom/ExceptionCode.h"
38 #include "core/events/AnimationPlayerEvent.h"
39 #include "core/frame/UseCounter.h"
40 #include "core/inspector/InspectorInstrumentation.h"
41 #include "core/inspector/InspectorTraceEvents.h"
42 #include "platform/TraceEvent.h"
43 #include "wtf/MathExtras.h"
49 static unsigned nextSequenceNumber()
51 static unsigned next
= 0;
57 PassRefPtrWillBeRawPtr
<AnimationPlayer
> AnimationPlayer::create(AnimationNode
* source
, AnimationTimeline
* timeline
)
60 // FIXME: Support creating players without a timeline.
64 RefPtrWillBeRawPtr
<AnimationPlayer
> player
= adoptRefWillBeNoop(new AnimationPlayer(timeline
->document()->contextDocument().get(), *timeline
, source
));
65 player
->suspendIfNeeded();
68 timeline
->playerAttached(*player
);
71 return player
.release();
74 AnimationPlayer::AnimationPlayer(ExecutionContext
* executionContext
, AnimationTimeline
& timeline
, AnimationNode
* content
)
75 : ActiveDOMObject(executionContext
)
78 , m_startTime(nullValue())
80 , m_sequenceNumber(nextSequenceNumber())
82 , m_timeline(&timeline
)
85 , m_isPausedForTesting(false)
88 , m_compositorState(nullptr)
89 , m_compositorPending(false)
90 , m_compositorGroup(0)
91 , m_currentTimePending(false)
92 , m_stateIsBeingUpdated(false)
95 if (m_content
->player()) {
96 m_content
->player()->cancel();
97 m_content
->player()->setSource(0);
99 m_content
->attach(this);
103 AnimationPlayer::~AnimationPlayer()
109 m_timeline
->playerDestroyed(this);
113 double AnimationPlayer::sourceEnd() const
115 return m_content
? m_content
->endTimeInternal() : 0;
118 bool AnimationPlayer::limited(double currentTime
) const
120 return (m_playbackRate
< 0 && currentTime
<= 0) || (m_playbackRate
> 0 && currentTime
>= sourceEnd());
123 void AnimationPlayer::setCurrentTime(double newCurrentTime
)
125 UseCounter::count(executionContext(), UseCounter::AnimationPlayerSetCurrentTime
);
127 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
);
129 m_currentTimePending
= false;
130 setCurrentTimeInternal(newCurrentTime
/ 1000, TimingUpdateOnDemand
);
132 if (calculatePlayState() == Finished
)
133 m_startTime
= calculateStartTime(newCurrentTime
);
136 void AnimationPlayer::setCurrentTimeInternal(double newCurrentTime
, TimingUpdateReason reason
)
138 ASSERT(std::isfinite(newCurrentTime
));
140 bool oldHeld
= m_held
;
141 bool outdated
= false;
142 bool isLimited
= limited(newCurrentTime
);
143 m_held
= m_paused
|| !m_playbackRate
|| isLimited
|| std::isnan(m_startTime
);
145 if (!oldHeld
|| m_holdTime
!= newCurrentTime
)
147 m_holdTime
= newCurrentTime
;
148 if (m_paused
|| !m_playbackRate
) {
149 m_startTime
= nullValue();
150 } else if (isLimited
&& std::isnan(m_startTime
) && reason
== TimingUpdateForAnimationFrame
) {
151 m_startTime
= calculateStartTime(newCurrentTime
);
154 m_holdTime
= nullValue();
155 m_startTime
= calculateStartTime(newCurrentTime
);
165 // Update timing to reflect updated animation clock due to tick
166 void AnimationPlayer::updateCurrentTimingState(TimingUpdateReason reason
)
169 // Add hystersis due to floating point error accumulation
170 if (!isNull(m_startTime
) && m_timeline
&& !limited(calculateCurrentTime() + 0.001 * m_playbackRate
) && playStateInternal() == Finished
) {
172 setCurrentTimeInternal(calculateCurrentTime(), reason
);
175 setCurrentTimeInternal(m_holdTime
, reason
);
178 if (!limited(calculateCurrentTime()))
181 m_holdTime
= m_playbackRate
< 0 ? 0 : sourceEnd();
184 double AnimationPlayer::startTime(bool& isNull
) const
186 double result
= startTime();
187 isNull
= std::isnan(result
);
191 double AnimationPlayer::startTime() const
193 UseCounter::count(executionContext(), UseCounter::AnimationPlayerGetStartTime
);
194 return m_startTime
* 1000;
197 double AnimationPlayer::currentTime(bool& isNull
)
199 double result
= currentTime();
200 isNull
= std::isnan(result
);
204 double AnimationPlayer::currentTime()
206 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
);
208 UseCounter::count(executionContext(), UseCounter::AnimationPlayerGetCurrentTime
);
209 if (m_currentTimePending
|| playStateInternal() == Idle
)
210 return std::numeric_limits
<double>::quiet_NaN();
212 return currentTimeInternal() * 1000;
215 double AnimationPlayer::currentTimeInternal() const
217 double result
= m_held
? m_holdTime
: calculateCurrentTime();
219 const_cast<AnimationPlayer
*>(this)->updateCurrentTimingState(TimingUpdateOnDemand
);
220 ASSERT(result
== (m_held
? m_holdTime
: calculateCurrentTime()));
225 void AnimationPlayer::preCommit(int compositorGroup
, bool startOnCompositor
)
227 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
, DoNotSetCompositorPending
);
229 bool softChange
= m_compositorState
&& (paused() || m_compositorState
->playbackRate
!= m_playbackRate
);
230 bool hardChange
= m_compositorState
&& (m_compositorState
->sourceChanged
|| m_compositorState
->startTime
!= m_startTime
);
232 // FIXME: softChange && !hardChange should generate a Pause/ThenStart,
233 // not a Cancel, but we can't communicate these to the compositor yet.
235 bool changed
= softChange
|| hardChange
;
236 bool shouldCancel
= (!playing() && m_compositorState
) || changed
;
237 bool shouldStart
= playing() && (!m_compositorState
|| changed
);
240 cancelAnimationOnCompositor();
241 m_compositorState
= nullptr;
244 if (m_compositorState
&& m_compositorState
->pendingAction
== Start
) {
245 // Still waiting for a start time.
249 ASSERT(!m_compositorState
|| !std::isnan(m_compositorState
->startTime
));
252 m_currentTimePending
= false;
256 m_compositorGroup
= compositorGroup
;
257 if (startOnCompositor
) {
258 if (maybeStartAnimationOnCompositor())
259 m_compositorState
= adoptPtr(new CompositorState(*this));
261 cancelIncompatibleAnimationsOnCompositor();
266 void AnimationPlayer::postCommit(double timelineTime
)
268 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
, DoNotSetCompositorPending
);
270 m_compositorPending
= false;
272 if (!m_compositorState
|| m_compositorState
->pendingAction
== None
)
275 switch (m_compositorState
->pendingAction
) {
277 if (!std::isnan(m_compositorState
->startTime
)) {
278 ASSERT(m_startTime
== m_compositorState
->startTime
);
279 m_compositorState
->pendingAction
= None
;
284 ASSERT(std::isnan(m_startTime
));
285 m_compositorState
->pendingAction
= None
;
286 setCurrentTimeInternal((timelineTime
- m_compositorState
->startTime
) * m_playbackRate
, TimingUpdateForAnimationFrame
);
287 m_currentTimePending
= false;
290 ASSERT_NOT_REACHED();
294 void AnimationPlayer::notifyCompositorStartTime(double timelineTime
)
296 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
, DoNotSetCompositorPending
);
298 if (m_compositorState
) {
299 ASSERT(m_compositorState
->pendingAction
== Start
);
300 ASSERT(std::isnan(m_compositorState
->startTime
));
302 double initialCompositorHoldTime
= m_compositorState
->holdTime
;
303 m_compositorState
->pendingAction
= None
;
304 m_compositorState
->startTime
= timelineTime
+ currentTimeInternal() / -m_playbackRate
;
306 if (m_startTime
== timelineTime
) {
307 // The start time was set to the incoming compositor start time.
308 // Unlikely, but possible.
309 // FIXME: Depending on what changed above this might still be pending.
311 m_currentTimePending
= false;
315 if (!std::isnan(m_startTime
) || currentTimeInternal() != initialCompositorHoldTime
) {
316 // A new start time or current time was set while starting.
317 setCompositorPending(true);
322 notifyStartTime(timelineTime
);
325 void AnimationPlayer::notifyStartTime(double timelineTime
)
328 ASSERT(std::isnan(m_startTime
));
331 if (m_playbackRate
== 0) {
332 setStartTimeInternal(timelineTime
);
334 setStartTimeInternal(timelineTime
+ currentTimeInternal() / -m_playbackRate
);
337 // FIXME: This avoids marking this player as outdated needlessly when a start time
338 // is notified, but we should refactor how outdating works to avoid this.
341 m_currentTimePending
= false;
345 bool AnimationPlayer::affects(const Element
& element
, CSSPropertyID property
) const
347 if (!m_content
|| !m_content
->isAnimation())
350 const Animation
* animation
= toAnimation(m_content
.get());
351 return (animation
->target() == &element
) && animation
->affects(property
);
354 double AnimationPlayer::calculateStartTime(double currentTime
) const
356 return m_timeline
->effectiveTime() - currentTime
/ m_playbackRate
;
359 double AnimationPlayer::calculateCurrentTime() const
361 if (isNull(m_startTime
) || !m_timeline
)
363 return (m_timeline
->effectiveTime() - m_startTime
) * m_playbackRate
;
366 void AnimationPlayer::setStartTime(double startTime
)
368 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
);
370 UseCounter::count(executionContext(), UseCounter::AnimationPlayerSetStartTime
);
371 if (m_paused
|| playStateInternal() == Idle
)
373 if (startTime
== m_startTime
)
376 m_currentTimePending
= false;
377 setStartTimeInternal(startTime
/ 1000);
380 void AnimationPlayer::setStartTimeInternal(double newStartTime
)
383 ASSERT(std::isfinite(newStartTime
));
384 ASSERT(newStartTime
!= m_startTime
);
386 bool hadStartTime
= hasStartTime();
387 double previousCurrentTime
= currentTimeInternal();
388 m_startTime
= newStartTime
;
389 if (m_held
&& m_playbackRate
) {
390 // If held, the start time would still be derrived from the hold time.
391 // Force a new, limited, current time.
393 double currentTime
= calculateCurrentTime();
394 if (m_playbackRate
> 0 && currentTime
> sourceEnd()) {
395 currentTime
= sourceEnd();
396 } else if (m_playbackRate
< 0 && currentTime
< 0) {
399 setCurrentTimeInternal(currentTime
, TimingUpdateOnDemand
);
401 updateCurrentTimingState(TimingUpdateOnDemand
);
402 double newCurrentTime
= currentTimeInternal();
404 if (previousCurrentTime
!= newCurrentTime
) {
406 } else if (!hadStartTime
&& m_timeline
) {
407 // Even though this player is not outdated, time to effect change is
408 // infinity until start time is set.
413 void AnimationPlayer::setSource(AnimationNode
* newSource
)
415 if (m_content
== newSource
)
418 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
, SetCompositorPendingWithSourceChanged
);
420 double storedCurrentTime
= currentTimeInternal();
423 m_content
= newSource
;
425 // FIXME: This logic needs to be updated once groups are implemented
426 if (newSource
->player()) {
427 newSource
->player()->cancel();
428 newSource
->player()->setSource(0);
430 newSource
->attach(this);
433 setCurrentTimeInternal(storedCurrentTime
, TimingUpdateOnDemand
);
436 const char* AnimationPlayer::playStateString(AnimationPlayState playState
)
450 ASSERT_NOT_REACHED();
455 AnimationPlayer::AnimationPlayState
AnimationPlayer::playStateInternal() const
460 AnimationPlayer::AnimationPlayState
AnimationPlayer::calculatePlayState()
462 if (m_playState
== Idle
)
464 if (m_currentTimePending
|| (isNull(m_startTime
) && !m_paused
&& m_playbackRate
!= 0))
473 void AnimationPlayer::pause()
478 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
);
481 m_currentTimePending
= true;
484 setCurrentTimeInternal(currentTimeInternal(), TimingUpdateOnDemand
);
487 void AnimationPlayer::unpause()
492 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
);
494 m_currentTimePending
= true;
498 void AnimationPlayer::unpauseInternal()
503 setCurrentTimeInternal(currentTimeInternal(), TimingUpdateOnDemand
);
506 void AnimationPlayer::play()
508 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
);
511 m_startTime
= nullValue();
513 if (playStateInternal() == Idle
) {
514 // We may not go into the pending state, but setting it to something other
515 // than Idle here will force an update.
516 ASSERT(isNull(m_startTime
));
517 m_playState
= Pending
;
526 double currentTime
= this->currentTimeInternal();
527 if (m_playbackRate
> 0 && (currentTime
< 0 || currentTime
>= sourceEnd()))
528 setCurrentTimeInternal(0, TimingUpdateOnDemand
);
529 else if (m_playbackRate
< 0 && (currentTime
<= 0 || currentTime
> sourceEnd()))
530 setCurrentTimeInternal(sourceEnd(), TimingUpdateOnDemand
);
533 void AnimationPlayer::reverse()
535 if (!m_playbackRate
) {
539 setPlaybackRateInternal(-m_playbackRate
);
543 void AnimationPlayer::finish(ExceptionState
& exceptionState
)
545 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
);
547 if (!m_playbackRate
|| playStateInternal() == Idle
) {
550 if (m_playbackRate
> 0 && sourceEnd() == std::numeric_limits
<double>::infinity()) {
551 exceptionState
.throwDOMException(InvalidStateError
, "AnimationPlayer has source content whose end time is infinity.");
555 double newCurrentTime
= m_playbackRate
< 0 ? 0 : sourceEnd();
556 setCurrentTimeInternal(newCurrentTime
, TimingUpdateOnDemand
);
558 m_startTime
= calculateStartTime(newCurrentTime
);
561 m_currentTimePending
= false;
562 ASSERT(playStateInternal() != Idle
);
566 ScriptPromise
AnimationPlayer::finished(ScriptState
* scriptState
)
568 if (!m_finishedPromise
) {
569 m_finishedPromise
= new AnimationPlayerPromise(scriptState
->executionContext(), this, AnimationPlayerPromise::Finished
);
570 if (playStateInternal() == Finished
)
571 m_finishedPromise
->resolve(this);
573 return m_finishedPromise
->promise(scriptState
->world());
576 ScriptPromise
AnimationPlayer::ready(ScriptState
* scriptState
)
578 if (!m_readyPromise
) {
579 m_readyPromise
= new AnimationPlayerPromise(scriptState
->executionContext(), this, AnimationPlayerPromise::Ready
);
580 if (playStateInternal() != Pending
)
581 m_readyPromise
->resolve(this);
583 return m_readyPromise
->promise(scriptState
->world());
586 const AtomicString
& AnimationPlayer::interfaceName() const
588 return EventTargetNames::AnimationPlayer
;
591 ExecutionContext
* AnimationPlayer::executionContext() const
593 return ActiveDOMObject::executionContext();
596 bool AnimationPlayer::hasPendingActivity() const
598 return m_pendingFinishedEvent
|| (!m_finished
&& hasEventListeners(EventTypeNames::finish
));
601 void AnimationPlayer::stop()
603 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
);
606 m_pendingFinishedEvent
= nullptr;
609 bool AnimationPlayer::dispatchEvent(PassRefPtrWillBeRawPtr
<Event
> event
)
611 if (m_pendingFinishedEvent
== event
)
612 m_pendingFinishedEvent
= nullptr;
613 return EventTargetWithInlineData::dispatchEvent(event
);
616 double AnimationPlayer::playbackRate() const
618 UseCounter::count(executionContext(), UseCounter::AnimationPlayerGetPlaybackRate
);
619 return m_playbackRate
;
622 void AnimationPlayer::setPlaybackRate(double playbackRate
)
624 UseCounter::count(executionContext(), UseCounter::AnimationPlayerSetPlaybackRate
);
625 if (playbackRate
== m_playbackRate
)
628 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
);
630 setPlaybackRateInternal(playbackRate
);
633 void AnimationPlayer::setPlaybackRateInternal(double playbackRate
)
635 ASSERT(std::isfinite(playbackRate
));
636 ASSERT(playbackRate
!= m_playbackRate
);
638 if (!limited() && !paused() && hasStartTime())
639 m_currentTimePending
= true;
641 double storedCurrentTime
= currentTimeInternal();
642 if ((m_playbackRate
< 0 && playbackRate
>= 0) || (m_playbackRate
> 0 && playbackRate
<= 0))
645 m_playbackRate
= playbackRate
;
646 m_startTime
= std::numeric_limits
<double>::quiet_NaN();
647 setCurrentTimeInternal(storedCurrentTime
, TimingUpdateOnDemand
);
650 void AnimationPlayer::setOutdated()
654 m_timeline
->setOutdatedAnimationPlayer(this);
657 bool AnimationPlayer::canStartAnimationOnCompositor()
659 // FIXME: Timeline playback rates should be compositable
660 if (m_playbackRate
== 0 || (std::isinf(sourceEnd()) && m_playbackRate
< 0) || (timeline() && timeline()->playbackRate() != 1))
663 return m_timeline
&& m_content
&& m_content
->isAnimation() && playing();
666 bool AnimationPlayer::maybeStartAnimationOnCompositor()
668 if (!canStartAnimationOnCompositor())
671 bool reversed
= m_playbackRate
< 0;
673 double startTime
= timeline()->zeroTime() + startTimeInternal();
675 startTime
-= sourceEnd() / fabs(m_playbackRate
);
678 double timeOffset
= 0;
679 if (std::isnan(startTime
)) {
680 timeOffset
= reversed
? sourceEnd() - currentTimeInternal() : currentTimeInternal();
681 timeOffset
= timeOffset
/ fabs(m_playbackRate
);
683 ASSERT(m_compositorGroup
!= 0);
684 return toAnimation(m_content
.get())->maybeStartAnimationOnCompositor(m_compositorGroup
, startTime
, timeOffset
, m_playbackRate
);
687 void AnimationPlayer::setCompositorPending(bool sourceChanged
)
689 // FIXME: Animation could notify this directly?
690 if (!hasActiveAnimationsOnCompositor()) {
691 m_compositorState
.release();
693 if (sourceChanged
&& m_compositorState
) {
694 m_compositorState
->sourceChanged
= true;
696 if (m_compositorPending
|| m_isPausedForTesting
) {
700 if (sourceChanged
|| !m_compositorState
701 || !playing() || m_compositorState
->playbackRate
!= m_playbackRate
702 || m_compositorState
->startTime
!= m_startTime
) {
703 m_compositorPending
= true;
704 timeline()->document()->compositorPendingAnimations().add(this);
708 void AnimationPlayer::cancelAnimationOnCompositor()
710 if (hasActiveAnimationsOnCompositor())
711 toAnimation(m_content
.get())->cancelAnimationOnCompositor();
714 void AnimationPlayer::restartAnimationOnCompositor()
716 if (hasActiveAnimationsOnCompositor())
717 toAnimation(m_content
.get())->restartAnimationOnCompositor();
720 void AnimationPlayer::cancelIncompatibleAnimationsOnCompositor()
722 if (m_content
&& m_content
->isAnimation())
723 toAnimation(m_content
.get())->cancelIncompatibleAnimationsOnCompositor();
726 bool AnimationPlayer::hasActiveAnimationsOnCompositor()
728 if (!m_content
|| !m_content
->isAnimation())
731 return toAnimation(m_content
.get())->hasActiveAnimationsOnCompositor();
734 bool AnimationPlayer::update(TimingUpdateReason reason
)
739 PlayStateUpdateScope
updateScope(*this, reason
, DoNotSetCompositorPending
);
742 bool idle
= playStateInternal() == Idle
;
745 double inheritedTime
= idle
|| isNull(m_timeline
->currentTimeInternal()) ? nullValue() : currentTimeInternal();
746 // Special case for end-exclusivity when playing backwards.
747 if (inheritedTime
== 0 && m_playbackRate
< 0)
749 m_content
->updateInheritedTime(inheritedTime
, reason
);
752 if ((idle
|| limited()) && !m_finished
) {
753 if (reason
== TimingUpdateForAnimationFrame
&& (idle
|| hasStartTime())) {
754 const AtomicString
& eventType
= EventTypeNames::finish
;
755 if (executionContext() && hasEventListeners(eventType
)) {
756 double eventCurrentTime
= currentTimeInternal() * 1000;
757 m_pendingFinishedEvent
= AnimationPlayerEvent::create(eventType
, eventCurrentTime
, timeline()->currentTime());
758 m_pendingFinishedEvent
->setTarget(this);
759 m_pendingFinishedEvent
->setCurrentTarget(this);
760 m_timeline
->document()->enqueueAnimationFrameEvent(m_pendingFinishedEvent
);
769 double AnimationPlayer::timeToEffectChange()
772 if (m_held
|| !hasStartTime())
773 return std::numeric_limits
<double>::infinity();
775 return -currentTimeInternal() / m_playbackRate
;
776 double result
= m_playbackRate
> 0
777 ? m_content
->timeToForwardsEffectChange() / m_playbackRate
778 : m_content
->timeToReverseEffectChange() / -m_playbackRate
;
779 return !hasActiveAnimationsOnCompositor() && m_content
->phase() == AnimationNode::PhaseActive
784 void AnimationPlayer::cancel()
786 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
);
788 if (playStateInternal() == Idle
)
791 m_holdTime
= currentTimeInternal();
795 m_startTime
= nullValue();
796 m_currentTimePending
= false;
798 // after cancelation, transitions must be downgraded or they'll fail
799 // to be considered when retriggering themselves. This can happen if
800 // the transition is captured through getAnimationPlayers then played.
801 if (m_content
&& m_content
->isAnimation())
802 toAnimation(m_content
.get())->downgradeToNormalAnimation();
805 void AnimationPlayer::beginUpdatingState()
807 // Nested calls are not allowed!
808 ASSERT(!m_stateIsBeingUpdated
);
809 m_stateIsBeingUpdated
= true;
812 void AnimationPlayer::endUpdatingState()
814 ASSERT(m_stateIsBeingUpdated
);
815 m_stateIsBeingUpdated
= false;
818 AnimationPlayer::PlayStateUpdateScope::PlayStateUpdateScope(AnimationPlayer
& player
, TimingUpdateReason reason
, CompositorPendingChange compositorPendingChange
)
820 , m_initialPlayState(m_player
->playStateInternal())
821 , m_compositorPendingChange(compositorPendingChange
)
823 m_player
->beginUpdatingState();
824 m_player
->updateCurrentTimingState(reason
);
827 AnimationPlayer::PlayStateUpdateScope::~PlayStateUpdateScope()
829 AnimationPlayState oldPlayState
= m_initialPlayState
;
830 AnimationPlayState newPlayState
= m_player
->calculatePlayState();
832 m_player
->m_playState
= newPlayState
;
833 if (oldPlayState
!= newPlayState
) {
834 bool wasActive
= oldPlayState
== Pending
|| oldPlayState
== Running
;
835 bool isActive
= newPlayState
== Pending
|| newPlayState
== Running
;
836 if (!wasActive
&& isActive
)
837 TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("blink.animations," TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Animation", m_player
, "data", InspectorAnimationEvent::data(*m_player
));
838 else if (wasActive
&& !isActive
)
839 TRACE_EVENT_NESTABLE_ASYNC_END1("blink.animations," TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Animation", m_player
, "endData", InspectorAnimationStateEvent::data(*m_player
));
841 TRACE_EVENT_NESTABLE_ASYNC_INSTANT1("blink.animations," TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Animation", m_player
, "data", InspectorAnimationStateEvent::data(*m_player
));
844 // Ordering is important, the ready promise should resolve/reject before
845 // the finished promise.
846 if (m_player
->m_readyPromise
&& newPlayState
!= oldPlayState
) {
847 if (newPlayState
== Idle
) {
848 if (m_player
->m_readyPromise
->state() == AnimationPlayerPromise::Pending
) {
849 m_player
->m_readyPromise
->reject(DOMException::create(AbortError
));
851 m_player
->m_readyPromise
->reset();
852 m_player
->m_readyPromise
->resolve(m_player
);
853 } else if (oldPlayState
== Pending
) {
854 m_player
->m_readyPromise
->resolve(m_player
);
855 } else if (newPlayState
== Pending
) {
856 ASSERT(m_player
->m_readyPromise
->state() != AnimationPlayerPromise::Pending
);
857 m_player
->m_readyPromise
->reset();
861 if (m_player
->m_finishedPromise
&& newPlayState
!= oldPlayState
) {
862 if (newPlayState
== Idle
) {
863 if (m_player
->m_finishedPromise
->state() == AnimationPlayerPromise::Pending
) {
864 m_player
->m_finishedPromise
->reject(DOMException::create(AbortError
));
866 m_player
->m_finishedPromise
->reset();
867 } else if (newPlayState
== Finished
) {
868 m_player
->m_finishedPromise
->resolve(m_player
);
869 } else if (oldPlayState
== Finished
) {
870 m_player
->m_finishedPromise
->reset();
874 if (oldPlayState
!= newPlayState
&& (oldPlayState
== Idle
|| newPlayState
== Idle
)) {
875 m_player
->setOutdated();
879 // Verify that current time is up to date.
880 m_player
->currentTimeInternal();
883 switch (m_compositorPendingChange
) {
884 case SetCompositorPending
:
885 m_player
->setCompositorPending();
887 case SetCompositorPendingWithSourceChanged
:
888 m_player
->setCompositorPending(true);
890 case DoNotSetCompositorPending
:
893 ASSERT_NOT_REACHED();
896 m_player
->endUpdatingState();
898 if (oldPlayState
!= newPlayState
&& newPlayState
== Running
)
899 InspectorInstrumentation::didCreateAnimationPlayer(m_player
->timeline()->document(), *m_player
);
904 bool AnimationPlayer::canFree() const
907 return hasOneRef() && m_content
->isAnimation() && m_content
->hasOneRef();
911 bool AnimationPlayer::addEventListener(const AtomicString
& eventType
, PassRefPtr
<EventListener
> listener
, bool useCapture
)
913 if (eventType
== EventTypeNames::finish
)
914 UseCounter::count(executionContext(), UseCounter::AnimationPlayerFinishEvent
);
915 return EventTargetWithInlineData::addEventListener(eventType
, listener
, useCapture
);
918 void AnimationPlayer::pauseForTesting(double pauseTime
)
920 RELEASE_ASSERT(!paused());
921 setCurrentTimeInternal(pauseTime
, TimingUpdateOnDemand
);
922 if (hasActiveAnimationsOnCompositor())
923 toAnimation(m_content
.get())->pauseAnimationForTestingOnCompositor(currentTimeInternal());
924 m_isPausedForTesting
= true;
928 DEFINE_TRACE(AnimationPlayer
)
930 visitor
->trace(m_content
);
931 visitor
->trace(m_timeline
);
932 visitor
->trace(m_pendingFinishedEvent
);
933 visitor
->trace(m_finishedPromise
);
934 visitor
->trace(m_readyPromise
);
935 EventTargetWithInlineData::trace(visitor
);
936 ActiveDOMObject::trace(visitor
);