Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / core / animation / Animation.cpp
blob919ff32c8b32ca0ba4992fede809694be58ab4fa
1 /*
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
6 * met:
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
13 * distribution.
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.
31 #include "config.h"
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"
49 namespace blink {
51 namespace {
53 static unsigned nextSequenceNumber()
55 static unsigned next = 0;
56 return ++next;
61 Animation* Animation::create(AnimationEffect* effect, AnimationTimeline* timeline)
63 if (!timeline) {
64 // FIXME: Support creating animations without a timeline.
65 return nullptr;
68 Animation* animation = new Animation(timeline->document()->contextDocument().get(), *timeline, effect);
69 animation->suspendIfNeeded();
71 if (timeline) {
72 timeline->animationAttached(*animation);
73 animation->attachCompositorTimeline();
76 return animation;
79 Animation::Animation(ExecutionContext* executionContext, AnimationTimeline& timeline, AnimationEffect* content)
80 : ActiveDOMObject(executionContext)
81 , m_playState(Idle)
82 , m_playbackRate(1)
83 , m_startTime(nullValue())
84 , m_holdTime(0)
85 , m_startClip(-std::numeric_limits<double>::infinity())
86 , m_endClip(std::numeric_limits<double>::infinity())
87 , m_sequenceNumber(nextSequenceNumber())
88 , m_content(content)
89 , m_timeline(&timeline)
90 , m_paused(false)
91 , m_held(true)
92 , m_isPausedForTesting(false)
93 , m_isCompositedAnimationDisabledForTesting(false)
94 , m_outdated(false)
95 , m_finished(true)
96 , m_compositorState(nullptr)
97 , m_compositorPending(false)
98 , m_compositorGroup(0)
99 , m_currentTimePending(false)
100 , m_stateIsBeingUpdated(false)
102 if (m_content) {
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);
146 if (m_held) {
147 if (!oldHeld || m_holdTime != newCurrentTime)
148 outdated = true;
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);
155 } else {
156 m_holdTime = nullValue();
157 m_startTime = calculateStartTime(newCurrentTime);
158 m_finished = false;
159 outdated = true;
162 if (outdated) {
163 setOutdated();
167 // Update timing to reflect updated animation clock due to tick
168 void Animation::updateCurrentTimingState(TimingUpdateReason reason)
170 if (m_held) {
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
180 // becoming longer.
181 newCurrentTime = clampTo<double>(calculateCurrentTime(), 0, effectEnd());
184 setCurrentTimeInternal(newCurrentTime, reason);
185 } else if (limited(calculateCurrentTime())) {
186 m_held = true;
187 m_holdTime = m_playbackRate < 0 ? 0 : effectEnd();
191 double Animation::startTime(bool& isNull) const
193 double result = startTime();
194 isNull = std::isnan(result);
195 return 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);
207 return 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();
223 #if ENABLE(ASSERT)
224 const_cast<Animation*>(this)->updateCurrentTimingState(TimingUpdateOnDemand);
225 ASSERT(result == (m_held ? m_holdTime : calculateCurrentTime()));
226 #endif
227 return result;
230 double Animation::unlimitedCurrentTimeInternal() const
232 #if ENABLE(ASSERT)
233 currentTimeInternal();
234 #endif
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.
256 return false;
259 if (shouldCancel) {
260 cancelAnimationOnCompositor();
261 m_compositorState = nullptr;
264 ASSERT(!m_compositorState || !std::isnan(m_compositorState->startTime));
266 if (!shouldStart) {
267 m_currentTimePending = false;
270 if (shouldStart) {
271 m_compositorGroup = compositorGroup;
272 if (startOnCompositor) {
273 if (isCandidateForAnimationOnCompositor())
274 createCompositorPlayer();
276 if (maybeStartAnimationOnCompositor())
277 m_compositorState = adoptPtr(new CompositorState(*this));
278 else
279 cancelIncompatibleAnimationsOnCompositor();
283 return true;
286 void Animation::postCommit(double timelineTime)
288 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand, DoNotSetCompositorPending);
290 m_compositorPending = false;
292 if (!m_compositorState || m_compositorState->pendingAction == None)
293 return;
295 switch (m_compositorState->pendingAction) {
296 case Start:
297 if (!std::isnan(m_compositorState->startTime)) {
298 ASSERT(m_startTime == m_compositorState->startTime);
299 m_compositorState->pendingAction = None;
301 break;
302 case Pause:
303 case PauseThenStart:
304 ASSERT(std::isnan(m_startTime));
305 m_compositorState->pendingAction = None;
306 setCurrentTimeInternal((timelineTime - m_compositorState->startTime) * m_playbackRate, TimingUpdateForAnimationFrame);
307 m_currentTimePending = false;
308 break;
309 default:
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.
330 // Maybe...
331 m_currentTimePending = false;
332 return;
335 if (!std::isnan(m_startTime) || currentTimeInternal() != initialCompositorHoldTime) {
336 // A new start time or current time was set while starting.
337 setCompositorPending(true);
338 return;
342 notifyStartTime(timelineTime);
345 void Animation::notifyStartTime(double timelineTime)
347 if (playing()) {
348 ASSERT(std::isnan(m_startTime));
349 ASSERT(m_held);
351 if (m_playbackRate == 0) {
352 setStartTimeInternal(timelineTime);
353 } else {
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.
359 clearOutdated();
360 m_currentTimePending = false;
364 bool Animation::affects(const Element& element, CSSPropertyID property) const
366 if (!m_content || !m_content->isKeyframeEffect())
367 return false;
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)
381 return 0;
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)
390 return;
391 if (startTime == m_startTime)
392 return;
394 m_currentTimePending = false;
395 setStartTimeInternal(startTime / 1000);
398 void Animation::setStartTimeInternal(double newStartTime)
400 ASSERT(!m_paused);
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.
410 m_held = false;
411 double currentTime = calculateCurrentTime();
412 if (m_playbackRate > 0 && currentTime > effectEnd()) {
413 currentTime = effectEnd();
414 } else if (m_playbackRate < 0 && currentTime < 0) {
415 currentTime = 0;
417 setCurrentTimeInternal(currentTime, TimingUpdateOnDemand);
419 updateCurrentTimingState(TimingUpdateOnDemand);
420 double newCurrentTime = currentTimeInternal();
422 if (previousCurrentTime != newCurrentTime) {
423 setOutdated();
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.
427 m_timeline->wake();
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)
440 return;
441 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand, SetCompositorPendingWithEffectChanged);
443 double storedCurrentTime = currentTimeInternal();
444 if (m_content)
445 m_content->detach();
446 m_content = newEffect;
447 if (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);
454 setOutdated();
456 setCurrentTimeInternal(storedCurrentTime, TimingUpdateOnDemand);
459 const char* Animation::playStateString(AnimationPlayState playState)
461 switch (playState) {
462 case Idle:
463 return "idle";
464 case Pending:
465 return "pending";
466 case Running:
467 return "running";
468 case Paused:
469 return "paused";
470 case Finished:
471 return "finished";
472 default:
473 ASSERT_NOT_REACHED();
474 return "";
478 Animation::AnimationPlayState Animation::playStateInternal() const
480 return m_playState;
483 Animation::AnimationPlayState Animation::calculatePlayState()
485 if (m_playState == Idle)
486 return Idle;
487 if (m_currentTimePending || (isNull(m_startTime) && !m_paused && m_playbackRate != 0))
488 return Pending;
489 if (m_paused)
490 return Paused;
491 if (limited())
492 return Finished;
493 return Running;
496 void Animation::pause()
498 if (m_paused)
499 return;
501 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
503 if (playing()) {
504 m_currentTimePending = true;
506 m_paused = true;
507 setCurrentTimeInternal(currentTimeInternal(), TimingUpdateOnDemand);
510 void Animation::unpause()
512 if (!m_paused)
513 return;
515 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
517 m_currentTimePending = true;
518 unpauseInternal();
521 void Animation::unpauseInternal()
523 if (!m_paused)
524 return;
525 m_paused = false;
526 setCurrentTimeInternal(currentTimeInternal(), TimingUpdateOnDemand);
529 void Animation::play()
531 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
533 if (!playing())
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;
541 m_held = true;
542 m_holdTime = 0;
545 m_finished = false;
546 unpauseInternal();
547 if (!m_content)
548 return;
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) {
562 return;
565 setPlaybackRateInternal(-m_playbackRate);
566 play();
569 void Animation::finish(ExceptionState& exceptionState)
571 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
573 if (!m_playbackRate || playStateInternal() == Idle) {
574 return;
576 if (m_playbackRate > 0 && effectEnd() == std::numeric_limits<double>::infinity()) {
577 exceptionState.throwDOMException(InvalidStateError, "Animation has effect whose end time is infinity.");
578 return;
581 double newCurrentTime = m_playbackRate < 0 ? 0 : effectEnd();
582 setCurrentTimeInternal(newCurrentTime, TimingUpdateOnDemand);
583 if (!paused()) {
584 m_startTime = calculateStartTime(newCurrentTime);
587 m_currentTimePending = false;
588 ASSERT(playStateInternal() != Idle);
589 ASSERT(limited());
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);
631 m_finished = true;
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)
650 return;
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))
667 m_finished = false;
669 m_playbackRate = playbackRate;
670 m_startTime = std::numeric_limits<double>::quiet_NaN();
671 setCurrentTimeInternal(storedCurrentTime, TimingUpdateOnDemand);
674 void Animation::clearOutdated()
676 if (!m_outdated)
677 return;
678 m_outdated = false;
679 if (m_timeline)
680 m_timeline->clearOutdatedAnimation(this);
683 void Animation::setOutdated()
685 if (m_outdated)
686 return;
687 m_outdated = true;
688 if (m_timeline)
689 m_timeline->setOutdatedAnimation(this);
692 bool Animation::canStartAnimationOnCompositor() const
694 if (m_isCompositedAnimationDisabledForTesting)
695 return false;
697 // FIXME: Timeline playback rates should be compositable
698 if (m_playbackRate == 0 || (std::isinf(effectEnd()) && m_playbackRate < 0) || (timeline() && timeline()->playbackRate() != 1))
699 return false;
701 return m_timeline && m_content && m_content->isKeyframeEffect() && playing();
704 bool Animation::isCandidateForAnimationOnCompositor() const
706 if (!canStartAnimationOnCompositor())
707 return false;
709 return toKeyframeEffect(m_content.get())->isCandidateForAnimationOnCompositor(m_playbackRate);
712 bool Animation::maybeStartAnimationOnCompositor()
714 if (!canStartAnimationOnCompositor())
715 return false;
717 bool reversed = m_playbackRate < 0;
719 double startTime = timeline()->zeroTime() + startTimeInternal();
720 if (reversed) {
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) {
744 return;
747 if (!m_compositorState || m_compositorState->effectChanged
748 || !playing() || m_compositorState->playbackRate != m_playbackRate
749 || m_compositorState->startTime != m_startTime) {
750 m_compositorPending = true;
751 ASSERT(timeline());
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())
780 return false;
782 return toKeyframeEffect(m_content.get())->hasActiveAnimationsOnCompositor();
785 bool Animation::update(TimingUpdateReason reason)
787 if (!m_timeline)
788 return false;
790 PlayStateUpdateScope updateScope(*this, reason, DoNotSetCompositorPending);
792 clearOutdated();
793 bool idle = playStateInternal() == Idle;
795 if (m_content) {
796 double inheritedTime = idle || isNull(m_timeline->currentTimeInternal())
797 ? nullValue()
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.
803 ? inheritedTime
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)
811 inheritedTime = -1;
812 m_content->updateInheritedTime(inheritedTime, reason);
815 if ((idle || limited()) && !m_finished) {
816 if (reason == TimingUpdateForAnimationFrame && (idle || hasStartTime())) {
817 if (idle) {
818 // TODO(dstockwell): Fire the cancel event.
819 } else {
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);
829 m_finished = true;
832 ASSERT(!m_outdated);
833 return !m_finished || std::isfinite(timeToEffectChange());
836 double Animation::timeToEffectChange()
838 ASSERT(!m_outdated);
839 if (!hasStartTime())
840 return std::numeric_limits<double>::infinity();
842 double currentTime = calculateCurrentTime();
843 if (m_held) {
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();
853 if (!m_content)
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);
872 } else {
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);
878 return result;
881 void Animation::cancel()
883 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
885 if (playStateInternal() == Idle)
886 return;
888 m_holdTime = currentTimeInternal();
889 m_held = true;
890 // TODO
891 m_playState = Idle;
892 m_startTime = nullValue();
893 m_currentTimePending = false;
895 if (timeline())
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;
940 if (timeline)
941 timeline->playerAttached(*this);
945 void Animation::detachCompositorTimeline()
947 if (m_compositorPlayer) {
948 WebCompositorAnimationTimeline* timeline = m_timeline ? m_timeline->compositorTimeline() : nullptr;
949 if (timeline)
950 timeline->playerDestroyed(*this);
954 void Animation::attachCompositedLayers()
956 if (!RuntimeEnabledFeatures::compositorAnimationTimelinesEnabled() || !m_compositorPlayer)
957 return;
959 ASSERT(m_content);
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));
1000 else
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();
1038 #if ENABLE(ASSERT)
1039 // Verify that current time is up to date.
1040 m_animation->currentTimeInternal();
1041 #endif
1043 switch (m_compositorPendingChange) {
1044 case SetCompositorPending:
1045 m_animation->setCompositorPending();
1046 break;
1047 case SetCompositorPendingWithEffectChanged:
1048 m_animation->setCompositorPending(true);
1049 break;
1050 case DoNotSetCompositorPending:
1051 break;
1052 default:
1053 ASSERT_NOT_REACHED();
1054 break;
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;
1076 pause();
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);
1096 } // namespace