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/events/AnimationPlayerEvent.h"
38 #include "core/frame/UseCounter.h"
39 #include "platform/TraceEvent.h"
40 #include "wtf/MathExtras.h"
46 static unsigned nextSequenceNumber()
48 static unsigned next = 0;
54 PassRefPtrWillBeRawPtr<AnimationPlayer> AnimationPlayer::create(ExecutionContext* executionContext, AnimationTimeline& timeline, AnimationNode* content)
56 RefPtrWillBeRawPtr<AnimationPlayer> player = adoptRefWillBeNoop(new AnimationPlayer(executionContext, timeline, content));
58 timeline.document()->compositorPendingAnimations().add(player.get());
59 player->suspendIfNeeded();
60 return player.release();
63 AnimationPlayer::AnimationPlayer(ExecutionContext* executionContext, AnimationTimeline& timeline, AnimationNode* content)
64 : ActiveDOMObject(executionContext)
66 , m_startTime(nullValue())
68 , m_sequenceNumber(nextSequenceNumber())
70 , m_timeline(&timeline)
73 , m_isPausedForTesting(false)
76 , m_compositorState(nullptr)
77 , m_compositorPending(true)
78 , m_currentTimePending(false)
82 if (m_content->player()) {
83 m_content->player()->cancel();
84 m_content->player()->setSource(0);
86 m_content->attach(this);
90 AnimationPlayer::~AnimationPlayer()
96 m_timeline->playerDestroyed(this);
100 double AnimationPlayer::sourceEnd() const
102 return m_content ? m_content->endTimeInternal() : 0;
105 bool AnimationPlayer::limited(double currentTime) const
107 return (m_playbackRate < 0 && currentTime <= 0) || (m_playbackRate > 0 && currentTime >= sourceEnd());
110 void AnimationPlayer::setCurrentTimeInternal(double newCurrentTime, TimingUpdateReason reason)
112 ASSERT(std::isfinite(newCurrentTime));
114 bool oldHeld = m_held;
115 bool outdated = false;
116 bool isLimited = limited(newCurrentTime);
117 m_held = m_paused || !m_playbackRate || isLimited || std::isnan(m_startTime);
119 if (!oldHeld || m_holdTime != newCurrentTime)
121 m_holdTime = newCurrentTime;
122 if (m_paused || !m_playbackRate) {
123 m_startTime = nullValue();
124 } else if (isLimited && std::isnan(m_startTime) && reason == TimingUpdateForAnimationFrame) {
125 m_startTime = calculateStartTime(newCurrentTime);
128 m_holdTime = nullValue();
129 m_startTime = calculateStartTime(newCurrentTime);
139 // Update timing to reflect updated animation clock due to tick
140 void AnimationPlayer::updateCurrentTimingState(TimingUpdateReason reason)
143 setCurrentTimeInternal(m_holdTime, reason);
146 if (!limited(calculateCurrentTime()))
149 m_holdTime = m_playbackRate < 0 ? 0 : sourceEnd();
152 double AnimationPlayer::startTime(bool& isNull) const
154 double result = startTime();
155 isNull = std::isnan(result);
159 double AnimationPlayer::startTime() const
161 UseCounter::count(executionContext(), UseCounter::AnimationPlayerGetStartTime);
162 return m_startTime * 1000;
165 double AnimationPlayer::currentTime(bool& isNull)
167 double result = currentTime();
168 isNull = std::isnan(result);
172 double AnimationPlayer::currentTime()
174 UseCounter::count(executionContext(), UseCounter::AnimationPlayerGetCurrentTime);
175 if (m_currentTimePending || m_idle)
176 return std::numeric_limits<double>::quiet_NaN();
177 return currentTimeInternal() * 1000;
180 double AnimationPlayer::currentTimeInternal()
182 updateCurrentTimingState(TimingUpdateOnDemand);
185 return calculateCurrentTime();
188 void AnimationPlayer::preCommit(bool startOnCompositor)
190 if (m_compositorState && m_compositorState->pendingAction == Start) {
191 // Still waiting for a start time.
195 bool softChange = m_compositorState && (paused() || m_compositorState->playbackRate != m_playbackRate);
196 bool hardChange = m_compositorState && (m_compositorState->sourceChanged || (m_compositorState->startTime != m_startTime && !std::isnan(m_compositorState->startTime) && !std::isnan(m_startTime)));
198 // FIXME: softChange && !hardChange should generate a Pause/ThenStart,
199 // not a Cancel, but we can't communicate these to the compositor yet.
201 bool changed = softChange || hardChange;
202 bool shouldCancel = (!playing() && m_compositorState) || changed;
203 bool shouldStart = playing() && (!m_compositorState || changed);
206 cancelAnimationOnCompositor();
207 m_compositorState = nullptr;
212 m_currentTimePending = false;
215 if (shouldStart && startOnCompositor && maybeStartAnimationOnCompositor()) {
216 m_compositorState = adoptPtr(new CompositorState(*this));
220 void AnimationPlayer::postCommit(double timelineTime)
222 m_compositorPending = false;
224 if (!m_compositorState || m_compositorState->pendingAction == None)
227 switch (m_compositorState->pendingAction) {
229 if (!std::isnan(m_compositorState->startTime)) {
230 ASSERT(m_startTime == m_compositorState->startTime);
231 m_compositorState->pendingAction = None;
236 ASSERT(std::isnan(m_startTime));
237 m_compositorState->pendingAction = None;
238 setCurrentTimeInternal((timelineTime - m_compositorState->startTime) * m_playbackRate, TimingUpdateForAnimationFrame);
239 m_currentTimePending = false;
242 ASSERT_NOT_REACHED();
246 void AnimationPlayer::notifyCompositorStartTime(double timelineTime)
248 if (m_compositorState) {
249 ASSERT(m_compositorState->pendingAction == Start);
250 ASSERT(std::isnan(m_compositorState->startTime));
252 double initialCompositorHoldTime = m_compositorState->holdTime;
253 m_compositorState->pendingAction = None;
254 m_compositorState->startTime = timelineTime + currentTimeInternal() / -m_playbackRate;
256 if (paused() || m_compositorState->playbackRate != m_playbackRate || m_compositorState->sourceChanged) {
257 // Paused state, playback rate, or source changed while starting.
258 setCompositorPending();
261 if (m_startTime == timelineTime) {
262 // The start time was set to the incoming compositor start time.
263 // Unlikely, but possible.
264 // FIXME: Depending on what changed above this might still be pending.
266 m_currentTimePending = false;
270 if (!std::isnan(m_startTime) || currentTimeInternal() != initialCompositorHoldTime) {
271 // A new start time or current time was set while starting.
272 setCompositorPending();
278 ASSERT(std::isnan(m_startTime));
281 if (m_playbackRate == 0) {
282 setStartTimeInternal(timelineTime);
284 setStartTimeInternal(timelineTime + currentTimeInternal() / -m_playbackRate);
287 // FIXME: This avoids marking this player as outdated needlessly when a start time
288 // is notified, but we should refactor how outdating works to avoid this.
291 m_currentTimePending = false;
295 double AnimationPlayer::calculateStartTime(double currentTime) const
297 return m_timeline->effectiveTime() - currentTime / m_playbackRate;
300 double AnimationPlayer::calculateCurrentTime() const
303 if (isNull(m_startTime) || !m_timeline)
305 return (m_timeline->effectiveTime() - m_startTime) * m_playbackRate;
308 void AnimationPlayer::setCurrentTime(double newCurrentTime)
310 UseCounter::count(executionContext(), UseCounter::AnimationPlayerSetCurrentTime);
311 if (!std::isfinite(newCurrentTime))
314 setCompositorPending();
315 m_currentTimePending = false;
316 setCurrentTimeInternal(newCurrentTime / 1000, TimingUpdateOnDemand);
319 void AnimationPlayer::setStartTime(double startTime)
321 UseCounter::count(executionContext(), UseCounter::AnimationPlayerSetStartTime);
322 if (m_paused || m_idle)
324 if (!std::isfinite(startTime))
326 if (startTime == m_startTime)
329 setCompositorPending();
330 m_currentTimePending = false;
331 setStartTimeInternal(startTime / 1000);
334 void AnimationPlayer::setStartTimeInternal(double newStartTime)
337 ASSERT(std::isfinite(newStartTime));
338 ASSERT(newStartTime != m_startTime);
340 bool hadStartTime = hasStartTime();
341 double previousCurrentTime = currentTimeInternal();
342 m_startTime = newStartTime;
343 if (m_held && m_playbackRate) {
344 // If held, the start time would still be derrived from the hold time.
345 // Force a new, limited, current time.
347 double currentTime = calculateCurrentTime();
348 if (m_playbackRate > 0 && currentTime > sourceEnd()) {
349 currentTime = sourceEnd();
350 } else if (m_playbackRate < 0 && currentTime < 0) {
353 setCurrentTimeInternal(currentTime, TimingUpdateOnDemand);
355 double newCurrentTime = currentTimeInternal();
357 if (previousCurrentTime != newCurrentTime) {
359 } else if (!hadStartTime && m_timeline) {
360 // Even though this player is not outdated, time to effect change is
361 // infinity until start time is set.
366 void AnimationPlayer::setSource(AnimationNode* newSource)
368 if (m_content == newSource)
371 setCompositorPending(true);
373 double storedCurrentTime = currentTimeInternal();
376 m_content = newSource;
378 // FIXME: This logic needs to be updated once groups are implemented
379 if (newSource->player()) {
380 newSource->player()->cancel();
381 newSource->player()->setSource(0);
383 newSource->attach(this);
386 setCurrentTimeInternal(storedCurrentTime, TimingUpdateOnDemand);
389 String AnimationPlayer::playState()
391 switch (playStateInternal()) {
403 ASSERT_NOT_REACHED();
408 AnimationPlayer::AnimationPlayState AnimationPlayer::playStateInternal()
412 if (m_currentTimePending || (isNull(m_startTime) && !m_paused && m_playbackRate != 0))
421 void AnimationPlayer::pause()
426 setCompositorPending();
427 m_currentTimePending = true;
430 setCurrentTimeInternal(currentTimeInternal(), TimingUpdateOnDemand);
433 void AnimationPlayer::unpause()
437 setCompositorPending();
438 m_currentTimePending = true;
442 void AnimationPlayer::unpauseInternal()
447 setCurrentTimeInternal(currentTimeInternal(), TimingUpdateOnDemand);
450 void AnimationPlayer::play()
453 m_startTime = nullValue();
455 setCompositorPending();
460 double currentTime = this->currentTimeInternal();
461 if (m_playbackRate > 0 && (currentTime < 0 || currentTime >= sourceEnd()))
462 setCurrentTimeInternal(0, TimingUpdateOnDemand);
463 else if (m_playbackRate < 0 && (currentTime <= 0 || currentTime > sourceEnd()))
464 setCurrentTimeInternal(sourceEnd(), TimingUpdateOnDemand);
468 void AnimationPlayer::reverse()
470 if (!m_playbackRate) {
475 setPlaybackRateInternal(-m_playbackRate);
479 void AnimationPlayer::finish(ExceptionState& exceptionState)
481 if (!m_playbackRate || m_idle) {
484 if (m_playbackRate > 0 && sourceEnd() == std::numeric_limits<double>::infinity()) {
485 exceptionState.throwDOMException(InvalidStateError, "AnimationPlayer has source content whose end time is infinity.");
489 setCompositorPending();
494 double newCurrentTime = m_playbackRate < 0 ? 0 : sourceEnd();
495 setCurrentTimeInternal(newCurrentTime, TimingUpdateOnDemand);
497 m_startTime = calculateStartTime(newCurrentTime);
500 m_currentTimePending = false;
504 const AtomicString& AnimationPlayer::interfaceName() const
506 return EventTargetNames::AnimationPlayer;
509 ExecutionContext* AnimationPlayer::executionContext() const
511 return ActiveDOMObject::executionContext();
514 bool AnimationPlayer::hasPendingActivity() const
516 return m_pendingFinishedEvent || (!m_finished && hasEventListeners(EventTypeNames::finish));
519 void AnimationPlayer::stop()
522 m_pendingFinishedEvent = nullptr;
525 bool AnimationPlayer::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
527 if (m_pendingFinishedEvent == event)
528 m_pendingFinishedEvent = nullptr;
529 return EventTargetWithInlineData::dispatchEvent(event);
532 double AnimationPlayer::playbackRate() const
534 UseCounter::count(executionContext(), UseCounter::AnimationPlayerGetPlaybackRate);
535 return m_playbackRate;
538 void AnimationPlayer::setPlaybackRate(double playbackRate)
540 UseCounter::count(executionContext(), UseCounter::AnimationPlayerSetPlaybackRate);
541 if (!std::isfinite(playbackRate))
543 if (playbackRate == m_playbackRate)
546 setPlaybackRateInternal(playbackRate);
549 void AnimationPlayer::setPlaybackRateInternal(double playbackRate)
551 ASSERT(std::isfinite(playbackRate));
552 ASSERT(playbackRate != m_playbackRate);
554 setCompositorPending();
555 if (!finished() && !paused() && hasStartTime())
556 m_currentTimePending = true;
558 double storedCurrentTime = currentTimeInternal();
559 if ((m_playbackRate < 0 && playbackRate >= 0) || (m_playbackRate > 0 && playbackRate <= 0))
562 m_playbackRate = playbackRate;
563 m_startTime = std::numeric_limits<double>::quiet_NaN();
564 setCurrentTimeInternal(storedCurrentTime, TimingUpdateOnDemand);
567 void AnimationPlayer::setOutdated()
571 m_timeline->setOutdatedAnimationPlayer(this);
574 bool AnimationPlayer::canStartAnimationOnCompositor()
576 if (m_playbackRate == 0 || (std::isinf(sourceEnd()) && m_playbackRate < 0))
579 return m_timeline && m_content && m_content->isAnimation() && playing();
582 bool AnimationPlayer::maybeStartAnimationOnCompositor()
584 if (!canStartAnimationOnCompositor())
587 bool reversed = m_playbackRate < 0;
589 double startTime = timeline()->zeroTime() + startTimeInternal();
591 startTime -= sourceEnd() / fabs(m_playbackRate);
594 double timeOffset = 0;
595 if (std::isnan(startTime)) {
596 timeOffset = reversed ? sourceEnd() - currentTimeInternal() : currentTimeInternal();
597 timeOffset = timeOffset / fabs(m_playbackRate);
599 return toAnimation(m_content.get())->maybeStartAnimationOnCompositor(startTime, timeOffset, m_playbackRate);
602 void AnimationPlayer::setCompositorPending(bool sourceChanged)
604 // FIXME: Animation could notify this directly?
605 if (!hasActiveAnimationsOnCompositor()) {
606 m_compositorState.release();
608 if (!m_compositorPending) {
609 m_compositorPending = true;
610 if (sourceChanged && m_compositorState)
611 m_compositorState->sourceChanged = true;
612 timeline()->document()->compositorPendingAnimations().add(this);
616 bool AnimationPlayer::hasActiveAnimationsOnCompositor()
618 if (!m_content || !m_content->isAnimation())
621 return toAnimation(m_content.get())->hasActiveAnimationsOnCompositor();
624 void AnimationPlayer::cancelAnimationOnCompositor()
626 if (hasActiveAnimationsOnCompositor())
627 toAnimation(m_content.get())->cancelAnimationOnCompositor();
630 bool AnimationPlayer::update(TimingUpdateReason reason)
635 updateCurrentTimingState(reason);
639 double inheritedTime = m_idle || isNull(m_timeline->currentTimeInternal()) ? nullValue() : currentTimeInternal();
640 // Special case for end-exclusivity when playing backwards.
641 if (inheritedTime == 0 && m_playbackRate < 0)
643 m_content->updateInheritedTime(inheritedTime, reason);
646 if ((m_idle || finished()) && !m_finished) {
647 if (reason == TimingUpdateForAnimationFrame && (m_idle || hasStartTime())) {
648 const AtomicString& eventType = EventTypeNames::finish;
649 if (executionContext() && hasEventListeners(eventType)) {
650 double eventCurrentTime = currentTimeInternal() * 1000;
651 m_pendingFinishedEvent = AnimationPlayerEvent::create(eventType, eventCurrentTime, timeline()->currentTime());
652 m_pendingFinishedEvent->setTarget(this);
653 m_pendingFinishedEvent->setCurrentTarget(this);
654 m_timeline->document()->enqueueAnimationFrameEvent(m_pendingFinishedEvent);
663 double AnimationPlayer::timeToEffectChange()
666 if (m_held || !hasStartTime())
667 return std::numeric_limits<double>::infinity();
669 return -currentTimeInternal() / m_playbackRate;
670 if (m_playbackRate > 0)
671 return m_content->timeToForwardsEffectChange() / m_playbackRate;
672 return m_content->timeToReverseEffectChange() / -m_playbackRate;
675 void AnimationPlayer::setFinished(bool finished)
677 if (m_finished && !finished) {
679 TRACE_EVENT_ASYNC_BEGIN1("blink", "Animation", this, "Name", TRACE_STR_COPY(m_content->name().utf8().data()));
681 TRACE_EVENT_ASYNC_BEGIN0("blink", "Animation", this);
684 if (!m_finished && finished) {
685 TRACE_EVENT_ASYNC_END0("blink", "Animation", this);
687 m_finished = finished;
690 void AnimationPlayer::cancel()
695 m_holdTime = currentTimeInternal();
698 m_startTime = nullValue();
699 m_currentTimePending = false;
700 setCompositorPending();
703 void AnimationPlayer::uncancel()
716 bool AnimationPlayer::canFree() const
719 return hasOneRef() && m_content->isAnimation() && m_content->hasOneRef();
723 bool AnimationPlayer::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
725 if (eventType == EventTypeNames::finish)
726 UseCounter::count(executionContext(), UseCounter::AnimationPlayerFinishEvent);
727 return EventTargetWithInlineData::addEventListener(eventType, listener, useCapture);
730 void AnimationPlayer::pauseForTesting(double pauseTime)
732 RELEASE_ASSERT(!paused());
733 setCurrentTimeInternal(pauseTime, TimingUpdateOnDemand);
734 if (hasActiveAnimationsOnCompositor())
735 toAnimation(m_content.get())->pauseAnimationForTestingOnCompositor(currentTimeInternal());
736 m_isPausedForTesting = true;
740 void AnimationPlayer::trace(Visitor* visitor)
742 visitor->trace(m_content);
743 visitor->trace(m_timeline);
744 visitor->trace(m_pendingFinishedEvent);
745 EventTargetWithInlineData::trace(visitor);