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/Animation.h"
34 #include "core/animation/AnimationTimeline.h"
35 #include "core/animation/KeyframeEffect.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/RuntimeEnabledFeatures.h"
43 #include "platform/TraceEvent.h"
44 #include "public/platform/Platform.h"
45 #include "public/platform/WebCompositorAnimationPlayer.h"
46 #include "public/platform/WebCompositorSupport.h"
47 #include "wtf/MathExtras.h"
53 static unsigned nextSequenceNumber()
55 static unsigned next
= 0;
61 Animation
* Animation::create(AnimationEffect
* effect
, AnimationTimeline
* timeline
)
64 // FIXME: Support creating animations without a timeline.
68 Animation
* animation
= new Animation(timeline
->document()->contextDocument().get(), *timeline
, effect
);
69 animation
->suspendIfNeeded();
72 timeline
->animationAttached(*animation
);
73 animation
->attachCompositorTimeline();
79 Animation::Animation(ExecutionContext
* executionContext
, AnimationTimeline
& timeline
, AnimationEffect
* content
)
80 : ActiveDOMObject(executionContext
)
83 , m_startTime(nullValue())
85 , m_startClip(-std::numeric_limits
<double>::infinity())
86 , m_endClip(std::numeric_limits
<double>::infinity())
87 , m_sequenceNumber(nextSequenceNumber())
89 , m_timeline(&timeline
)
92 , m_isPausedForTesting(false)
93 , m_isCompositedAnimationDisabledForTesting(false)
96 , m_compositorState(nullptr)
97 , m_compositorPending(false)
98 , m_compositorGroup(0)
99 , m_currentTimePending(false)
100 , m_stateIsBeingUpdated(false)
103 if (m_content
->animation()) {
104 m_content
->animation()->cancel();
105 m_content
->animation()->setEffect(0);
107 m_content
->attach(this);
109 InspectorInstrumentation::didCreateAnimation(m_timeline
->document(), m_sequenceNumber
);
112 Animation::~Animation()
114 destroyCompositorPlayer();
117 double Animation::effectEnd() const
119 return m_content
? m_content
->endTimeInternal() : 0;
122 bool Animation::limited(double currentTime
) const
124 return (m_playbackRate
< 0 && currentTime
<= 0) || (m_playbackRate
> 0 && currentTime
>= effectEnd());
127 void Animation::setCurrentTime(double newCurrentTime
)
129 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
);
131 m_currentTimePending
= false;
132 setCurrentTimeInternal(newCurrentTime
/ 1000, TimingUpdateOnDemand
);
134 if (calculatePlayState() == Finished
)
135 m_startTime
= calculateStartTime(newCurrentTime
);
138 void Animation::setCurrentTimeInternal(double newCurrentTime
, TimingUpdateReason reason
)
140 ASSERT(std::isfinite(newCurrentTime
));
142 bool oldHeld
= m_held
;
143 bool outdated
= false;
144 bool isLimited
= limited(newCurrentTime
);
145 m_held
= m_paused
|| !m_playbackRate
|| isLimited
|| std::isnan(m_startTime
);
147 if (!oldHeld
|| m_holdTime
!= newCurrentTime
)
149 m_holdTime
= newCurrentTime
;
150 if (m_paused
|| !m_playbackRate
) {
151 m_startTime
= nullValue();
152 } else if (isLimited
&& std::isnan(m_startTime
) && reason
== TimingUpdateForAnimationFrame
) {
153 m_startTime
= calculateStartTime(newCurrentTime
);
156 m_holdTime
= nullValue();
157 m_startTime
= calculateStartTime(newCurrentTime
);
167 // Update timing to reflect updated animation clock due to tick
168 void Animation::updateCurrentTimingState(TimingUpdateReason reason
)
171 double newCurrentTime
= m_holdTime
;
172 if (playStateInternal() == Finished
&& !isNull(m_startTime
) && m_timeline
) {
173 // Add hystersis due to floating point error accumulation
174 if (!limited(calculateCurrentTime() + 0.001 * m_playbackRate
)) {
175 // The current time became unlimited, eg. due to a backwards
176 // seek of the timeline.
177 newCurrentTime
= calculateCurrentTime();
178 } else if (!limited(m_holdTime
)) {
179 // The hold time became unlimited, eg. due to the effect
181 newCurrentTime
= clampTo
<double>(calculateCurrentTime(), 0, effectEnd());
184 setCurrentTimeInternal(newCurrentTime
, reason
);
185 } else if (limited(calculateCurrentTime())) {
187 m_holdTime
= m_playbackRate
< 0 ? 0 : effectEnd();
191 double Animation::startTime(bool& isNull
) const
193 double result
= startTime();
194 isNull
= std::isnan(result
);
198 double Animation::startTime() const
200 return m_startTime
* 1000;
203 double Animation::currentTime(bool& isNull
)
205 double result
= currentTime();
206 isNull
= std::isnan(result
);
210 double Animation::currentTime()
212 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
);
214 if (m_currentTimePending
|| playStateInternal() == Idle
)
215 return std::numeric_limits
<double>::quiet_NaN();
217 return currentTimeInternal() * 1000;
220 double Animation::currentTimeInternal() const
222 double result
= m_held
? m_holdTime
: calculateCurrentTime();
224 const_cast<Animation
*>(this)->updateCurrentTimingState(TimingUpdateOnDemand
);
225 ASSERT(result
== (m_held
? m_holdTime
: calculateCurrentTime()));
230 double Animation::unlimitedCurrentTimeInternal() const
233 currentTimeInternal();
235 return playStateInternal() == Paused
|| isNull(m_startTime
)
236 ? currentTimeInternal()
237 : calculateCurrentTime();
240 bool Animation::preCommit(int compositorGroup
, bool startOnCompositor
)
242 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
, DoNotSetCompositorPending
);
244 bool softChange
= m_compositorState
&& (paused() || m_compositorState
->playbackRate
!= m_playbackRate
);
245 bool hardChange
= m_compositorState
&& (m_compositorState
->effectChanged
|| m_compositorState
->startTime
!= m_startTime
);
247 // FIXME: softChange && !hardChange should generate a Pause/ThenStart,
248 // not a Cancel, but we can't communicate these to the compositor yet.
250 bool changed
= softChange
|| hardChange
;
251 bool shouldCancel
= (!playing() && m_compositorState
) || changed
;
252 bool shouldStart
= playing() && (!m_compositorState
|| changed
);
254 if (shouldCancel
&& shouldStart
&& m_compositorState
&& m_compositorState
->pendingAction
== Start
) {
255 // Restarting but still waiting for a start time.
260 cancelAnimationOnCompositor();
261 m_compositorState
= nullptr;
264 ASSERT(!m_compositorState
|| !std::isnan(m_compositorState
->startTime
));
267 m_currentTimePending
= false;
271 m_compositorGroup
= compositorGroup
;
272 if (startOnCompositor
) {
273 if (isCandidateForAnimationOnCompositor())
274 createCompositorPlayer();
276 if (maybeStartAnimationOnCompositor())
277 m_compositorState
= adoptPtr(new CompositorState(*this));
279 cancelIncompatibleAnimationsOnCompositor();
286 void Animation::postCommit(double timelineTime
)
288 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
, DoNotSetCompositorPending
);
290 m_compositorPending
= false;
292 if (!m_compositorState
|| m_compositorState
->pendingAction
== None
)
295 switch (m_compositorState
->pendingAction
) {
297 if (!std::isnan(m_compositorState
->startTime
)) {
298 ASSERT(m_startTime
== m_compositorState
->startTime
);
299 m_compositorState
->pendingAction
= None
;
304 ASSERT(std::isnan(m_startTime
));
305 m_compositorState
->pendingAction
= None
;
306 setCurrentTimeInternal((timelineTime
- m_compositorState
->startTime
) * m_playbackRate
, TimingUpdateForAnimationFrame
);
307 m_currentTimePending
= false;
310 ASSERT_NOT_REACHED();
314 void Animation::notifyCompositorStartTime(double timelineTime
)
316 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
, DoNotSetCompositorPending
);
318 if (m_compositorState
) {
319 ASSERT(m_compositorState
->pendingAction
== Start
);
320 ASSERT(std::isnan(m_compositorState
->startTime
));
322 double initialCompositorHoldTime
= m_compositorState
->holdTime
;
323 m_compositorState
->pendingAction
= None
;
324 m_compositorState
->startTime
= timelineTime
+ currentTimeInternal() / -m_playbackRate
;
326 if (m_startTime
== timelineTime
) {
327 // The start time was set to the incoming compositor start time.
328 // Unlikely, but possible.
329 // FIXME: Depending on what changed above this might still be pending.
331 m_currentTimePending
= false;
335 if (!std::isnan(m_startTime
) || currentTimeInternal() != initialCompositorHoldTime
) {
336 // A new start time or current time was set while starting.
337 setCompositorPending(true);
342 notifyStartTime(timelineTime
);
345 void Animation::notifyStartTime(double timelineTime
)
348 ASSERT(std::isnan(m_startTime
));
351 if (m_playbackRate
== 0) {
352 setStartTimeInternal(timelineTime
);
354 setStartTimeInternal(timelineTime
+ currentTimeInternal() / -m_playbackRate
);
357 // FIXME: This avoids marking this animation as outdated needlessly when a start time
358 // is notified, but we should refactor how outdating works to avoid this.
360 m_currentTimePending
= false;
364 bool Animation::affects(const Element
& element
, CSSPropertyID property
) const
366 if (!m_content
|| !m_content
->isKeyframeEffect())
369 const KeyframeEffect
* effect
= toKeyframeEffect(m_content
.get());
370 return (effect
->target() == &element
) && effect
->affects(PropertyHandle(property
));
373 double Animation::calculateStartTime(double currentTime
) const
375 return m_timeline
->effectiveTime() - currentTime
/ m_playbackRate
;
378 double Animation::calculateCurrentTime() const
380 if (isNull(m_startTime
) || !m_timeline
)
382 return (m_timeline
->effectiveTime() - m_startTime
) * m_playbackRate
;
385 void Animation::setStartTime(double startTime
)
387 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
);
389 if (m_paused
|| playStateInternal() == Idle
)
391 if (startTime
== m_startTime
)
394 m_currentTimePending
= false;
395 setStartTimeInternal(startTime
/ 1000);
398 void Animation::setStartTimeInternal(double newStartTime
)
401 ASSERT(std::isfinite(newStartTime
));
402 ASSERT(newStartTime
!= m_startTime
);
404 bool hadStartTime
= hasStartTime();
405 double previousCurrentTime
= currentTimeInternal();
406 m_startTime
= newStartTime
;
407 if (m_held
&& m_playbackRate
) {
408 // If held, the start time would still be derrived from the hold time.
409 // Force a new, limited, current time.
411 double currentTime
= calculateCurrentTime();
412 if (m_playbackRate
> 0 && currentTime
> effectEnd()) {
413 currentTime
= effectEnd();
414 } else if (m_playbackRate
< 0 && currentTime
< 0) {
417 setCurrentTimeInternal(currentTime
, TimingUpdateOnDemand
);
419 updateCurrentTimingState(TimingUpdateOnDemand
);
420 double newCurrentTime
= currentTimeInternal();
422 if (previousCurrentTime
!= newCurrentTime
) {
424 } else if (!hadStartTime
&& m_timeline
) {
425 // Even though this animation is not outdated, time to effect change is
426 // infinity until start time is set.
431 bool Animation::clipped(double time
)
433 ASSERT(!isNull(time
));
434 return time
<= m_startClip
|| time
> m_endClip
+ effectEnd();
437 void Animation::setEffect(AnimationEffect
* newEffect
)
439 if (m_content
== newEffect
)
441 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
, SetCompositorPendingWithEffectChanged
);
443 double storedCurrentTime
= currentTimeInternal();
446 m_content
= newEffect
;
448 // FIXME: This logic needs to be updated once groups are implemented
449 if (newEffect
->animation()) {
450 newEffect
->animation()->cancel();
451 newEffect
->animation()->setEffect(0);
453 newEffect
->attach(this);
456 setCurrentTimeInternal(storedCurrentTime
, TimingUpdateOnDemand
);
459 const char* Animation::playStateString(AnimationPlayState playState
)
473 ASSERT_NOT_REACHED();
478 Animation::AnimationPlayState
Animation::playStateInternal() const
483 Animation::AnimationPlayState
Animation::calculatePlayState()
485 if (m_playState
== Idle
)
487 if (m_currentTimePending
|| (isNull(m_startTime
) && !m_paused
&& m_playbackRate
!= 0))
496 void Animation::pause()
501 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
);
504 m_currentTimePending
= true;
507 setCurrentTimeInternal(currentTimeInternal(), TimingUpdateOnDemand
);
510 void Animation::unpause()
515 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
);
517 m_currentTimePending
= true;
521 void Animation::unpauseInternal()
526 setCurrentTimeInternal(currentTimeInternal(), TimingUpdateOnDemand
);
529 void Animation::play()
531 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
);
534 m_startTime
= nullValue();
536 if (playStateInternal() == Idle
) {
537 // We may not go into the pending state, but setting it to something other
538 // than Idle here will force an update.
539 ASSERT(isNull(m_startTime
));
540 m_playState
= Pending
;
549 double currentTime
= this->currentTimeInternal();
550 if (m_playbackRate
> 0 && (currentTime
< 0 || currentTime
>= effectEnd())) {
551 m_startTime
= nullValue();
552 setCurrentTimeInternal(0, TimingUpdateOnDemand
);
553 } else if (m_playbackRate
< 0 && (currentTime
<= 0 || currentTime
> effectEnd())) {
554 m_startTime
= nullValue();
555 setCurrentTimeInternal(effectEnd(), TimingUpdateOnDemand
);
559 void Animation::reverse()
561 if (!m_playbackRate
) {
565 setPlaybackRateInternal(-m_playbackRate
);
569 void Animation::finish(ExceptionState
& exceptionState
)
571 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
);
573 if (!m_playbackRate
|| playStateInternal() == Idle
) {
576 if (m_playbackRate
> 0 && effectEnd() == std::numeric_limits
<double>::infinity()) {
577 exceptionState
.throwDOMException(InvalidStateError
, "Animation has effect whose end time is infinity.");
581 double newCurrentTime
= m_playbackRate
< 0 ? 0 : effectEnd();
582 setCurrentTimeInternal(newCurrentTime
, TimingUpdateOnDemand
);
584 m_startTime
= calculateStartTime(newCurrentTime
);
587 m_currentTimePending
= false;
588 ASSERT(playStateInternal() != Idle
);
592 ScriptPromise
Animation::finished(ScriptState
* scriptState
)
594 if (!m_finishedPromise
) {
595 m_finishedPromise
= new AnimationPromise(scriptState
->executionContext(), this, AnimationPromise::Finished
);
596 if (playStateInternal() == Finished
)
597 m_finishedPromise
->resolve(this);
599 return m_finishedPromise
->promise(scriptState
->world());
602 ScriptPromise
Animation::ready(ScriptState
* scriptState
)
604 if (!m_readyPromise
) {
605 m_readyPromise
= new AnimationPromise(scriptState
->executionContext(), this, AnimationPromise::Ready
);
606 if (playStateInternal() != Pending
)
607 m_readyPromise
->resolve(this);
609 return m_readyPromise
->promise(scriptState
->world());
612 const AtomicString
& Animation::interfaceName() const
614 return EventTargetNames::AnimationPlayer
;
617 ExecutionContext
* Animation::executionContext() const
619 return ActiveDOMObject::executionContext();
622 bool Animation::hasPendingActivity() const
624 return m_pendingFinishedEvent
|| (!m_finished
&& hasEventListeners(EventTypeNames::finish
));
627 void Animation::stop()
629 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
);
632 m_pendingFinishedEvent
= nullptr;
635 bool Animation::dispatchEventInternal(PassRefPtrWillBeRawPtr
<Event
> event
)
637 if (m_pendingFinishedEvent
== event
)
638 m_pendingFinishedEvent
= nullptr;
639 return EventTargetWithInlineData::dispatchEventInternal(event
);
642 double Animation::playbackRate() const
644 return m_playbackRate
;
647 void Animation::setPlaybackRate(double playbackRate
)
649 if (playbackRate
== m_playbackRate
)
652 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
);
654 setPlaybackRateInternal(playbackRate
);
657 void Animation::setPlaybackRateInternal(double playbackRate
)
659 ASSERT(std::isfinite(playbackRate
));
660 ASSERT(playbackRate
!= m_playbackRate
);
662 if (!limited() && !paused() && hasStartTime())
663 m_currentTimePending
= true;
665 double storedCurrentTime
= currentTimeInternal();
666 if ((m_playbackRate
< 0 && playbackRate
>= 0) || (m_playbackRate
> 0 && playbackRate
<= 0))
669 m_playbackRate
= playbackRate
;
670 m_startTime
= std::numeric_limits
<double>::quiet_NaN();
671 setCurrentTimeInternal(storedCurrentTime
, TimingUpdateOnDemand
);
674 void Animation::clearOutdated()
680 m_timeline
->clearOutdatedAnimation(this);
683 void Animation::setOutdated()
689 m_timeline
->setOutdatedAnimation(this);
692 bool Animation::canStartAnimationOnCompositor() const
694 if (m_isCompositedAnimationDisabledForTesting
)
697 // FIXME: Timeline playback rates should be compositable
698 if (m_playbackRate
== 0 || (std::isinf(effectEnd()) && m_playbackRate
< 0) || (timeline() && timeline()->playbackRate() != 1))
701 return m_timeline
&& m_content
&& m_content
->isKeyframeEffect() && playing();
704 bool Animation::isCandidateForAnimationOnCompositor() const
706 if (!canStartAnimationOnCompositor())
709 return toKeyframeEffect(m_content
.get())->isCandidateForAnimationOnCompositor(m_playbackRate
);
712 bool Animation::maybeStartAnimationOnCompositor()
714 if (!canStartAnimationOnCompositor())
717 bool reversed
= m_playbackRate
< 0;
719 double startTime
= timeline()->zeroTime() + startTimeInternal();
721 startTime
-= effectEnd() / fabs(m_playbackRate
);
724 double timeOffset
= 0;
725 if (std::isnan(startTime
)) {
726 timeOffset
= reversed
? effectEnd() - currentTimeInternal() : currentTimeInternal();
727 timeOffset
= timeOffset
/ fabs(m_playbackRate
);
729 ASSERT(m_compositorGroup
!= 0);
730 return toKeyframeEffect(m_content
.get())->maybeStartAnimationOnCompositor(m_compositorGroup
, startTime
, timeOffset
, m_playbackRate
);
733 void Animation::setCompositorPending(bool effectChanged
)
735 // FIXME: KeyframeEffect could notify this directly?
736 if (!hasActiveAnimationsOnCompositor()) {
737 destroyCompositorPlayer();
738 m_compositorState
.release();
740 if (effectChanged
&& m_compositorState
) {
741 m_compositorState
->effectChanged
= true;
743 if (m_compositorPending
|| m_isPausedForTesting
) {
747 if (!m_compositorState
|| m_compositorState
->effectChanged
748 || !playing() || m_compositorState
->playbackRate
!= m_playbackRate
749 || m_compositorState
->startTime
!= m_startTime
) {
750 m_compositorPending
= true;
752 ASSERT(timeline()->document());
753 timeline()->document()->compositorPendingAnimations().add(this);
757 void Animation::cancelAnimationOnCompositor()
759 if (hasActiveAnimationsOnCompositor())
760 toKeyframeEffect(m_content
.get())->cancelAnimationOnCompositor();
762 destroyCompositorPlayer();
765 void Animation::restartAnimationOnCompositor()
767 if (hasActiveAnimationsOnCompositor())
768 toKeyframeEffect(m_content
.get())->restartAnimationOnCompositor();
771 void Animation::cancelIncompatibleAnimationsOnCompositor()
773 if (m_content
&& m_content
->isKeyframeEffect())
774 toKeyframeEffect(m_content
.get())->cancelIncompatibleAnimationsOnCompositor();
777 bool Animation::hasActiveAnimationsOnCompositor()
779 if (!m_content
|| !m_content
->isKeyframeEffect())
782 return toKeyframeEffect(m_content
.get())->hasActiveAnimationsOnCompositor();
785 bool Animation::update(TimingUpdateReason reason
)
790 PlayStateUpdateScope
updateScope(*this, reason
, DoNotSetCompositorPending
);
793 bool idle
= playStateInternal() == Idle
;
796 double inheritedTime
= idle
|| isNull(m_timeline
->currentTimeInternal())
798 : currentTimeInternal();
800 if (!isNull(inheritedTime
)) {
801 double timeForClipping
= m_held
&& (!limited(inheritedTime
) || isNull(m_startTime
))
802 // Use hold time when there is no start time.
804 // Use calculated current time when the animation is limited.
805 : calculateCurrentTime();
806 if (clipped(timeForClipping
))
807 inheritedTime
= nullValue();
809 // Special case for end-exclusivity when playing backwards.
810 if (inheritedTime
== 0 && m_playbackRate
< 0)
812 m_content
->updateInheritedTime(inheritedTime
, reason
);
815 if ((idle
|| limited()) && !m_finished
) {
816 if (reason
== TimingUpdateForAnimationFrame
&& (idle
|| hasStartTime())) {
818 // TODO(dstockwell): Fire the cancel event.
820 const AtomicString
& eventType
= EventTypeNames::finish
;
821 if (executionContext() && hasEventListeners(eventType
)) {
822 double eventCurrentTime
= currentTimeInternal() * 1000;
823 m_pendingFinishedEvent
= AnimationPlayerEvent::create(eventType
, eventCurrentTime
, timeline()->currentTime());
824 m_pendingFinishedEvent
->setTarget(this);
825 m_pendingFinishedEvent
->setCurrentTarget(this);
826 m_timeline
->document()->enqueueAnimationFrameEvent(m_pendingFinishedEvent
);
833 return !m_finished
|| std::isfinite(timeToEffectChange());
836 double Animation::timeToEffectChange()
840 return std::numeric_limits
<double>::infinity();
842 double currentTime
= calculateCurrentTime();
844 if (limited(currentTime
)) {
845 if (m_playbackRate
> 0 && m_endClip
+ effectEnd() > currentTime
)
846 return m_endClip
+ effectEnd() - currentTime
;
847 if (m_playbackRate
< 0 && m_startClip
<= currentTime
)
848 return m_startClip
- currentTime
;
850 return std::numeric_limits
<double>::infinity();
854 return -currentTimeInternal() / m_playbackRate
;
855 double result
= m_playbackRate
> 0
856 ? m_content
->timeToForwardsEffectChange() / m_playbackRate
857 : m_content
->timeToReverseEffectChange() / -m_playbackRate
;
859 return !hasActiveAnimationsOnCompositor() && m_content
->phase() == AnimationEffect::PhaseActive
861 : clipTimeToEffectChange(result
);
864 double Animation::clipTimeToEffectChange(double result
) const
866 double currentTime
= calculateCurrentTime();
867 if (m_playbackRate
> 0) {
868 if (currentTime
<= m_startClip
)
869 result
= std::min(result
, (m_startClip
- currentTime
) / m_playbackRate
);
870 else if (currentTime
< m_endClip
+ effectEnd())
871 result
= std::min(result
, (m_endClip
+ effectEnd() - currentTime
) / m_playbackRate
);
873 if (currentTime
>= m_endClip
+ effectEnd())
874 result
= std::min(result
, (currentTime
- m_endClip
+ effectEnd()) / -m_playbackRate
);
875 else if (currentTime
> m_startClip
)
876 result
= std::min(result
, (currentTime
- m_startClip
) / -m_playbackRate
);
881 void Animation::cancel()
883 PlayStateUpdateScope
updateScope(*this, TimingUpdateOnDemand
);
885 if (playStateInternal() == Idle
)
888 m_holdTime
= currentTimeInternal();
892 m_startTime
= nullValue();
893 m_currentTimePending
= false;
896 InspectorInstrumentation::didCancelAnimation(timeline()->document(), this);
899 void Animation::beginUpdatingState()
901 // Nested calls are not allowed!
902 ASSERT(!m_stateIsBeingUpdated
);
903 m_stateIsBeingUpdated
= true;
906 void Animation::endUpdatingState()
908 ASSERT(m_stateIsBeingUpdated
);
909 m_stateIsBeingUpdated
= false;
912 void Animation::createCompositorPlayer()
914 if (RuntimeEnabledFeatures::compositorAnimationTimelinesEnabled() && Platform::current()->isThreadedAnimationEnabled() && !m_compositorPlayer
) {
915 ASSERT(Platform::current()->compositorSupport());
916 m_compositorPlayer
= adoptPtr(Platform::current()->compositorSupport()->createAnimationPlayer());
917 ASSERT(m_compositorPlayer
);
918 m_compositorPlayer
->setAnimationDelegate(this);
919 attachCompositorTimeline();
922 attachCompositedLayers();
925 void Animation::destroyCompositorPlayer()
927 detachCompositedLayers();
929 if (m_compositorPlayer
) {
930 detachCompositorTimeline();
931 m_compositorPlayer
->setAnimationDelegate(nullptr);
933 m_compositorPlayer
.clear();
936 void Animation::attachCompositorTimeline()
938 if (m_compositorPlayer
) {
939 WebCompositorAnimationTimeline
* timeline
= m_timeline
? m_timeline
->compositorTimeline() : nullptr;
941 timeline
->playerAttached(*this);
945 void Animation::detachCompositorTimeline()
947 if (m_compositorPlayer
) {
948 WebCompositorAnimationTimeline
* timeline
= m_timeline
? m_timeline
->compositorTimeline() : nullptr;
950 timeline
->playerDestroyed(*this);
954 void Animation::attachCompositedLayers()
956 if (!RuntimeEnabledFeatures::compositorAnimationTimelinesEnabled() || !m_compositorPlayer
)
960 ASSERT(m_content
->isKeyframeEffect());
962 if (toKeyframeEffect(m_content
.get())->canAttachCompositedLayers())
963 toKeyframeEffect(m_content
.get())->attachCompositedLayers();
966 void Animation::detachCompositedLayers()
968 if (m_compositorPlayer
&& m_compositorPlayer
->isLayerAttached())
969 m_compositorPlayer
->detachLayer();
972 void Animation::notifyAnimationStarted(double monotonicTime
, int group
)
974 ASSERT(RuntimeEnabledFeatures::compositorAnimationTimelinesEnabled());
975 timeline()->document()->compositorPendingAnimations().notifyCompositorAnimationStarted(monotonicTime
, group
);
978 Animation::PlayStateUpdateScope::PlayStateUpdateScope(Animation
& animation
, TimingUpdateReason reason
, CompositorPendingChange compositorPendingChange
)
979 : m_animation(animation
)
980 , m_initialPlayState(m_animation
->playStateInternal())
981 , m_compositorPendingChange(compositorPendingChange
)
983 m_animation
->beginUpdatingState();
984 m_animation
->updateCurrentTimingState(reason
);
987 Animation::PlayStateUpdateScope::~PlayStateUpdateScope()
989 AnimationPlayState oldPlayState
= m_initialPlayState
;
990 AnimationPlayState newPlayState
= m_animation
->calculatePlayState();
992 m_animation
->m_playState
= newPlayState
;
993 if (oldPlayState
!= newPlayState
) {
994 bool wasActive
= oldPlayState
== Pending
|| oldPlayState
== Running
;
995 bool isActive
= newPlayState
== Pending
|| newPlayState
== Running
;
996 if (!wasActive
&& isActive
)
997 TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("blink.animations,devtools.timeline", "Animation", m_animation
, "data", InspectorAnimationEvent::data(*m_animation
));
998 else if (wasActive
&& !isActive
)
999 TRACE_EVENT_NESTABLE_ASYNC_END1("blink.animations,devtools.timeline", "Animation", m_animation
, "endData", InspectorAnimationStateEvent::data(*m_animation
));
1001 TRACE_EVENT_NESTABLE_ASYNC_INSTANT1("blink.animations,devtools.timeline", "Animation", m_animation
, "data", InspectorAnimationStateEvent::data(*m_animation
));
1004 // Ordering is important, the ready promise should resolve/reject before
1005 // the finished promise.
1006 if (m_animation
->m_readyPromise
&& newPlayState
!= oldPlayState
) {
1007 if (newPlayState
== Idle
) {
1008 if (m_animation
->m_readyPromise
->state() == AnimationPromise::Pending
) {
1009 m_animation
->m_readyPromise
->reject(DOMException::create(AbortError
));
1011 m_animation
->m_readyPromise
->reset();
1012 m_animation
->m_readyPromise
->resolve(m_animation
);
1013 } else if (oldPlayState
== Pending
) {
1014 m_animation
->m_readyPromise
->resolve(m_animation
);
1015 } else if (newPlayState
== Pending
) {
1016 ASSERT(m_animation
->m_readyPromise
->state() != AnimationPromise::Pending
);
1017 m_animation
->m_readyPromise
->reset();
1021 if (m_animation
->m_finishedPromise
&& newPlayState
!= oldPlayState
) {
1022 if (newPlayState
== Idle
) {
1023 if (m_animation
->m_finishedPromise
->state() == AnimationPromise::Pending
) {
1024 m_animation
->m_finishedPromise
->reject(DOMException::create(AbortError
));
1026 m_animation
->m_finishedPromise
->reset();
1027 } else if (newPlayState
== Finished
) {
1028 m_animation
->m_finishedPromise
->resolve(m_animation
);
1029 } else if (oldPlayState
== Finished
) {
1030 m_animation
->m_finishedPromise
->reset();
1034 if (oldPlayState
!= newPlayState
&& (oldPlayState
== Idle
|| newPlayState
== Idle
)) {
1035 m_animation
->setOutdated();
1039 // Verify that current time is up to date.
1040 m_animation
->currentTimeInternal();
1043 switch (m_compositorPendingChange
) {
1044 case SetCompositorPending
:
1045 m_animation
->setCompositorPending();
1047 case SetCompositorPendingWithEffectChanged
:
1048 m_animation
->setCompositorPending(true);
1050 case DoNotSetCompositorPending
:
1053 ASSERT_NOT_REACHED();
1056 m_animation
->endUpdatingState();
1058 if (oldPlayState
!= newPlayState
&& newPlayState
== Running
)
1059 InspectorInstrumentation::didStartAnimation(m_animation
->timeline()->document(), m_animation
);
1062 bool Animation::addEventListener(const AtomicString
& eventType
, PassRefPtrWillBeRawPtr
<EventListener
> listener
, bool useCapture
)
1064 if (eventType
== EventTypeNames::finish
)
1065 UseCounter::count(executionContext(), UseCounter::AnimationFinishEvent
);
1066 return EventTargetWithInlineData::addEventListener(eventType
, listener
, useCapture
);
1069 void Animation::pauseForTesting(double pauseTime
)
1071 RELEASE_ASSERT(!paused());
1072 setCurrentTimeInternal(pauseTime
, TimingUpdateOnDemand
);
1073 if (hasActiveAnimationsOnCompositor())
1074 toKeyframeEffect(m_content
.get())->pauseAnimationForTestingOnCompositor(currentTimeInternal());
1075 m_isPausedForTesting
= true;
1079 void Animation::disableCompositedAnimationForTesting()
1081 m_isCompositedAnimationDisabledForTesting
= true;
1082 cancelAnimationOnCompositor();
1085 DEFINE_TRACE(Animation
)
1087 visitor
->trace(m_content
);
1088 visitor
->trace(m_timeline
);
1089 visitor
->trace(m_pendingFinishedEvent
);
1090 visitor
->trace(m_finishedPromise
);
1091 visitor
->trace(m_readyPromise
);
1092 RefCountedGarbageCollectedEventTargetWithInlineData
<Animation
>::trace(visitor
);
1093 ActiveDOMObject::trace(visitor
);