Index: Source/core/animation/AnimationPlayer.cpp |
diff --git a/Source/core/animation/AnimationPlayer.cpp b/Source/core/animation/AnimationPlayer.cpp |
deleted file mode 100644 |
index 99a947be0be39fd2838bd2cb755a7331076d2671..0000000000000000000000000000000000000000 |
--- a/Source/core/animation/AnimationPlayer.cpp |
+++ /dev/null |
@@ -1,1032 +0,0 @@ |
-/* |
- * Copyright (C) 2013 Google Inc. All rights reserved. |
- * |
- * Redistribution and use in source and binary forms, with or without |
- * modification, are permitted provided that the following conditions are |
- * met: |
- * |
- * * Redistributions of source code must retain the above copyright |
- * notice, this list of conditions and the following disclaimer. |
- * * Redistributions in binary form must reproduce the above |
- * copyright notice, this list of conditions and the following disclaimer |
- * in the documentation and/or other materials provided with the |
- * distribution. |
- * * Neither the name of Google Inc. nor the names of its |
- * contributors may be used to endorse or promote products derived from |
- * this software without specific prior written permission. |
- * |
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
- */ |
- |
-#include "config.h" |
-#include "core/animation/AnimationPlayer.h" |
- |
-#include "core/animation/Animation.h" |
-#include "core/animation/AnimationTimeline.h" |
-#include "core/dom/Document.h" |
-#include "core/dom/ExceptionCode.h" |
-#include "core/events/AnimationPlayerEvent.h" |
-#include "core/frame/UseCounter.h" |
-#include "core/inspector/InspectorInstrumentation.h" |
-#include "core/inspector/InspectorTraceEvents.h" |
-#include "platform/RuntimeEnabledFeatures.h" |
-#include "platform/TraceEvent.h" |
-#include "public/platform/Platform.h" |
-#include "public/platform/WebCompositorAnimationPlayer.h" |
-#include "public/platform/WebCompositorSupport.h" |
-#include "wtf/MathExtras.h" |
- |
-namespace blink { |
- |
-namespace { |
- |
-static unsigned nextSequenceNumber() |
-{ |
- static unsigned next = 0; |
- return ++next; |
-} |
- |
-} |
- |
-PassRefPtrWillBeRawPtr<AnimationPlayer> AnimationPlayer::create(AnimationNode* source, AnimationTimeline* timeline) |
-{ |
- if (!timeline) { |
- // FIXME: Support creating players without a timeline. |
- return nullptr; |
- } |
- |
- RefPtrWillBeRawPtr<AnimationPlayer> player = adoptRefWillBeNoop(new AnimationPlayer(timeline->document()->contextDocument().get(), *timeline, source)); |
- player->suspendIfNeeded(); |
- |
- if (timeline) { |
- timeline->playerAttached(*player); |
- player->attachCompositorTimeline(); |
- } |
- |
- return player.release(); |
-} |
- |
-AnimationPlayer::AnimationPlayer(ExecutionContext* executionContext, AnimationTimeline& timeline, AnimationNode* content) |
- : ActiveDOMObject(executionContext) |
- , m_playState(Idle) |
- , m_playbackRate(1) |
- , m_startTime(nullValue()) |
- , m_holdTime(0) |
- , m_sequenceNumber(nextSequenceNumber()) |
- , m_content(content) |
- , m_timeline(&timeline) |
- , m_paused(false) |
- , m_held(true) |
- , m_isPausedForTesting(false) |
- , m_outdated(false) |
- , m_finished(true) |
- , m_compositorState(nullptr) |
- , m_compositorPending(false) |
- , m_compositorGroup(0) |
- , m_currentTimePending(false) |
- , m_stateIsBeingUpdated(false) |
-{ |
- if (m_content) { |
- if (m_content->player()) { |
- m_content->player()->cancel(); |
- m_content->player()->setSource(0); |
- } |
- m_content->attach(this); |
- } |
-} |
- |
-AnimationPlayer::~AnimationPlayer() |
-{ |
-#if !ENABLE(OILPAN) |
- if (m_content) |
- m_content->detach(); |
- if (m_timeline) |
- m_timeline->playerDestroyed(this); |
-#endif |
- |
- destroyCompositorPlayer(); |
-} |
- |
-#if !ENABLE(OILPAN) |
-void AnimationPlayer::detachFromTimeline() |
-{ |
- dispose(); |
- m_timeline = nullptr; |
-} |
-#endif |
- |
-double AnimationPlayer::sourceEnd() const |
-{ |
- return m_content ? m_content->endTimeInternal() : 0; |
-} |
- |
-bool AnimationPlayer::limited(double currentTime) const |
-{ |
- return (m_playbackRate < 0 && currentTime <= 0) || (m_playbackRate > 0 && currentTime >= sourceEnd()); |
-} |
- |
-void AnimationPlayer::setCurrentTime(double newCurrentTime) |
-{ |
- PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); |
- |
- m_currentTimePending = false; |
- setCurrentTimeInternal(newCurrentTime / 1000, TimingUpdateOnDemand); |
- |
- if (calculatePlayState() == Finished) |
- m_startTime = calculateStartTime(newCurrentTime); |
-} |
- |
-void AnimationPlayer::setCurrentTimeInternal(double newCurrentTime, TimingUpdateReason reason) |
-{ |
- ASSERT(std::isfinite(newCurrentTime)); |
- |
- bool oldHeld = m_held; |
- bool outdated = false; |
- bool isLimited = limited(newCurrentTime); |
- m_held = m_paused || !m_playbackRate || isLimited || std::isnan(m_startTime); |
- if (m_held) { |
- if (!oldHeld || m_holdTime != newCurrentTime) |
- outdated = true; |
- m_holdTime = newCurrentTime; |
- if (m_paused || !m_playbackRate) { |
- m_startTime = nullValue(); |
- } else if (isLimited && std::isnan(m_startTime) && reason == TimingUpdateForAnimationFrame) { |
- m_startTime = calculateStartTime(newCurrentTime); |
- } |
- } else { |
- m_holdTime = nullValue(); |
- m_startTime = calculateStartTime(newCurrentTime); |
- m_finished = false; |
- outdated = true; |
- } |
- |
- if (outdated) { |
- setOutdated(); |
- } |
-} |
- |
-// Update timing to reflect updated animation clock due to tick |
-void AnimationPlayer::updateCurrentTimingState(TimingUpdateReason reason) |
-{ |
- if (m_held) { |
- double newCurrentTime = m_holdTime; |
- if (playStateInternal() == Finished && !isNull(m_startTime) && m_timeline) { |
- // Add hystersis due to floating point error accumulation |
- if (!limited(calculateCurrentTime() + 0.001 * m_playbackRate)) { |
- // The current time became unlimited, eg. due to a backwards |
- // seek of the timeline. |
- newCurrentTime = calculateCurrentTime(); |
- } else if (!limited(m_holdTime)) { |
- // The hold time became unlimited, eg. due to the source content |
- // becoming longer. |
- newCurrentTime = clampTo<double>(calculateCurrentTime(), 0, sourceEnd()); |
- } |
- } |
- setCurrentTimeInternal(newCurrentTime, reason); |
- } else if (limited(calculateCurrentTime())) { |
- m_held = true; |
- m_holdTime = m_playbackRate < 0 ? 0 : sourceEnd(); |
- } |
-} |
- |
-double AnimationPlayer::startTime(bool& isNull) const |
-{ |
- double result = startTime(); |
- isNull = std::isnan(result); |
- return result; |
-} |
- |
-double AnimationPlayer::startTime() const |
-{ |
- return m_startTime * 1000; |
-} |
- |
-double AnimationPlayer::currentTime(bool& isNull) |
-{ |
- double result = currentTime(); |
- isNull = std::isnan(result); |
- return result; |
-} |
- |
-double AnimationPlayer::currentTime() |
-{ |
- PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); |
- |
- if (m_currentTimePending || playStateInternal() == Idle) |
- return std::numeric_limits<double>::quiet_NaN(); |
- |
- return currentTimeInternal() * 1000; |
-} |
- |
-double AnimationPlayer::currentTimeInternal() const |
-{ |
- double result = m_held ? m_holdTime : calculateCurrentTime(); |
-#if ENABLE(ASSERT) |
- const_cast<AnimationPlayer*>(this)->updateCurrentTimingState(TimingUpdateOnDemand); |
- ASSERT(result == (m_held ? m_holdTime : calculateCurrentTime())); |
-#endif |
- return result; |
-} |
- |
-double AnimationPlayer::unlimitedCurrentTimeInternal() const |
-{ |
-#if ENABLE(ASSERT) |
- currentTimeInternal(); |
-#endif |
- return playStateInternal() == Paused || isNull(m_startTime) |
- ? currentTimeInternal() |
- : calculateCurrentTime(); |
-} |
- |
-void AnimationPlayer::preCommit(int compositorGroup, bool startOnCompositor) |
-{ |
- PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand, DoNotSetCompositorPending); |
- |
- bool softChange = m_compositorState && (paused() || m_compositorState->playbackRate != m_playbackRate); |
- bool hardChange = m_compositorState && (m_compositorState->sourceChanged || m_compositorState->startTime != m_startTime); |
- |
- // FIXME: softChange && !hardChange should generate a Pause/ThenStart, |
- // not a Cancel, but we can't communicate these to the compositor yet. |
- |
- bool changed = softChange || hardChange; |
- bool shouldCancel = (!playing() && m_compositorState) || changed; |
- bool shouldStart = playing() && (!m_compositorState || changed); |
- |
- if (shouldCancel) { |
- cancelAnimationOnCompositor(); |
- m_compositorState = nullptr; |
- } |
- |
- if (m_compositorState && m_compositorState->pendingAction == Start) { |
- // Still waiting for a start time. |
- return; |
- } |
- |
- ASSERT(!m_compositorState || !std::isnan(m_compositorState->startTime)); |
- |
- if (!shouldStart) { |
- m_currentTimePending = false; |
- } |
- |
- if (shouldStart) { |
- m_compositorGroup = compositorGroup; |
- if (startOnCompositor) { |
- if (isCandidateForAnimationOnCompositor()) |
- createCompositorPlayer(); |
- |
- if (maybeStartAnimationOnCompositor()) |
- m_compositorState = adoptPtr(new CompositorState(*this)); |
- else |
- cancelIncompatibleAnimationsOnCompositor(); |
- } |
- } |
-} |
- |
-void AnimationPlayer::postCommit(double timelineTime) |
-{ |
- PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand, DoNotSetCompositorPending); |
- |
- m_compositorPending = false; |
- |
- if (!m_compositorState || m_compositorState->pendingAction == None) |
- return; |
- |
- switch (m_compositorState->pendingAction) { |
- case Start: |
- if (!std::isnan(m_compositorState->startTime)) { |
- ASSERT(m_startTime == m_compositorState->startTime); |
- m_compositorState->pendingAction = None; |
- } |
- break; |
- case Pause: |
- case PauseThenStart: |
- ASSERT(std::isnan(m_startTime)); |
- m_compositorState->pendingAction = None; |
- setCurrentTimeInternal((timelineTime - m_compositorState->startTime) * m_playbackRate, TimingUpdateForAnimationFrame); |
- m_currentTimePending = false; |
- break; |
- default: |
- ASSERT_NOT_REACHED(); |
- } |
-} |
- |
-void AnimationPlayer::notifyCompositorStartTime(double timelineTime) |
-{ |
- PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand, DoNotSetCompositorPending); |
- |
- if (m_compositorState) { |
- ASSERT(m_compositorState->pendingAction == Start); |
- ASSERT(std::isnan(m_compositorState->startTime)); |
- |
- double initialCompositorHoldTime = m_compositorState->holdTime; |
- m_compositorState->pendingAction = None; |
- m_compositorState->startTime = timelineTime + currentTimeInternal() / -m_playbackRate; |
- |
- if (m_startTime == timelineTime) { |
- // The start time was set to the incoming compositor start time. |
- // Unlikely, but possible. |
- // FIXME: Depending on what changed above this might still be pending. |
- // Maybe... |
- m_currentTimePending = false; |
- return; |
- } |
- |
- if (!std::isnan(m_startTime) || currentTimeInternal() != initialCompositorHoldTime) { |
- // A new start time or current time was set while starting. |
- setCompositorPending(true); |
- return; |
- } |
- } |
- |
- notifyStartTime(timelineTime); |
-} |
- |
-void AnimationPlayer::notifyStartTime(double timelineTime) |
-{ |
- if (playing()) { |
- ASSERT(std::isnan(m_startTime)); |
- ASSERT(m_held); |
- |
- if (m_playbackRate == 0) { |
- setStartTimeInternal(timelineTime); |
- } else { |
- setStartTimeInternal(timelineTime + currentTimeInternal() / -m_playbackRate); |
- } |
- |
- // FIXME: This avoids marking this player as outdated needlessly when a start time |
- // is notified, but we should refactor how outdating works to avoid this. |
- m_outdated = false; |
- |
- m_currentTimePending = false; |
- } |
-} |
- |
-bool AnimationPlayer::affects(const Element& element, CSSPropertyID property) const |
-{ |
- if (!m_content || !m_content->isAnimation()) |
- return false; |
- |
- const Animation* animation = toAnimation(m_content.get()); |
- return (animation->target() == &element) && animation->affects(PropertyHandle(property)); |
-} |
- |
-double AnimationPlayer::calculateStartTime(double currentTime) const |
-{ |
- return m_timeline->effectiveTime() - currentTime / m_playbackRate; |
-} |
- |
-double AnimationPlayer::calculateCurrentTime() const |
-{ |
- if (isNull(m_startTime) || !m_timeline) |
- return 0; |
- return (m_timeline->effectiveTime() - m_startTime) * m_playbackRate; |
-} |
- |
-void AnimationPlayer::setStartTime(double startTime) |
-{ |
- PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); |
- |
- if (m_paused || playStateInternal() == Idle) |
- return; |
- if (startTime == m_startTime) |
- return; |
- |
- m_currentTimePending = false; |
- setStartTimeInternal(startTime / 1000); |
-} |
- |
-void AnimationPlayer::setStartTimeInternal(double newStartTime) |
-{ |
- ASSERT(!m_paused); |
- ASSERT(std::isfinite(newStartTime)); |
- ASSERT(newStartTime != m_startTime); |
- |
- bool hadStartTime = hasStartTime(); |
- double previousCurrentTime = currentTimeInternal(); |
- m_startTime = newStartTime; |
- if (m_held && m_playbackRate) { |
- // If held, the start time would still be derrived from the hold time. |
- // Force a new, limited, current time. |
- m_held = false; |
- double currentTime = calculateCurrentTime(); |
- if (m_playbackRate > 0 && currentTime > sourceEnd()) { |
- currentTime = sourceEnd(); |
- } else if (m_playbackRate < 0 && currentTime < 0) { |
- currentTime = 0; |
- } |
- setCurrentTimeInternal(currentTime, TimingUpdateOnDemand); |
- } |
- updateCurrentTimingState(TimingUpdateOnDemand); |
- double newCurrentTime = currentTimeInternal(); |
- |
- if (previousCurrentTime != newCurrentTime) { |
- setOutdated(); |
- } else if (!hadStartTime && m_timeline) { |
- // Even though this player is not outdated, time to effect change is |
- // infinity until start time is set. |
- m_timeline->wake(); |
- } |
-} |
- |
-void AnimationPlayer::setSource(AnimationNode* newSource) |
-{ |
- if (m_content == newSource) |
- return; |
- PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand, SetCompositorPendingWithSourceChanged); |
- |
- double storedCurrentTime = currentTimeInternal(); |
- if (m_content) |
- m_content->detach(); |
- m_content = newSource; |
- if (newSource) { |
- // FIXME: This logic needs to be updated once groups are implemented |
- if (newSource->player()) { |
- newSource->player()->cancel(); |
- newSource->player()->setSource(0); |
- } |
- newSource->attach(this); |
- setOutdated(); |
- } |
- setCurrentTimeInternal(storedCurrentTime, TimingUpdateOnDemand); |
-} |
- |
-const char* AnimationPlayer::playStateString(AnimationPlayState playState) |
-{ |
- switch (playState) { |
- case Idle: |
- return "idle"; |
- case Pending: |
- return "pending"; |
- case Running: |
- return "running"; |
- case Paused: |
- return "paused"; |
- case Finished: |
- return "finished"; |
- default: |
- ASSERT_NOT_REACHED(); |
- return ""; |
- } |
-} |
- |
-AnimationPlayer::AnimationPlayState AnimationPlayer::playStateInternal() const |
-{ |
- return m_playState; |
-} |
- |
-AnimationPlayer::AnimationPlayState AnimationPlayer::calculatePlayState() |
-{ |
- if (m_playState == Idle) |
- return Idle; |
- if (m_currentTimePending || (isNull(m_startTime) && !m_paused && m_playbackRate != 0)) |
- return Pending; |
- if (m_paused) |
- return Paused; |
- if (limited()) |
- return Finished; |
- return Running; |
-} |
- |
-void AnimationPlayer::pause() |
-{ |
- if (m_paused) |
- return; |
- |
- PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); |
- |
- if (playing()) { |
- m_currentTimePending = true; |
- } |
- m_paused = true; |
- setCurrentTimeInternal(currentTimeInternal(), TimingUpdateOnDemand); |
-} |
- |
-void AnimationPlayer::unpause() |
-{ |
- if (!m_paused) |
- return; |
- |
- PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); |
- |
- m_currentTimePending = true; |
- unpauseInternal(); |
-} |
- |
-void AnimationPlayer::unpauseInternal() |
-{ |
- if (!m_paused) |
- return; |
- m_paused = false; |
- setCurrentTimeInternal(currentTimeInternal(), TimingUpdateOnDemand); |
-} |
- |
-void AnimationPlayer::play() |
-{ |
- PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); |
- |
- if (!playing()) |
- m_startTime = nullValue(); |
- |
- if (playStateInternal() == Idle) { |
- // We may not go into the pending state, but setting it to something other |
- // than Idle here will force an update. |
- ASSERT(isNull(m_startTime)); |
- m_playState = Pending; |
- m_held = true; |
- m_holdTime = 0; |
- } |
- |
- m_finished = false; |
- unpauseInternal(); |
- if (!m_content) |
- return; |
- double currentTime = this->currentTimeInternal(); |
- if (m_playbackRate > 0 && (currentTime < 0 || currentTime >= sourceEnd())) { |
- m_startTime = nullValue(); |
- setCurrentTimeInternal(0, TimingUpdateOnDemand); |
- } else if (m_playbackRate < 0 && (currentTime <= 0 || currentTime > sourceEnd())) { |
- m_startTime = nullValue(); |
- setCurrentTimeInternal(sourceEnd(), TimingUpdateOnDemand); |
- } |
-} |
- |
-void AnimationPlayer::reverse() |
-{ |
- if (!m_playbackRate) { |
- return; |
- } |
- |
- setPlaybackRateInternal(-m_playbackRate); |
- play(); |
-} |
- |
-void AnimationPlayer::finish(ExceptionState& exceptionState) |
-{ |
- PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); |
- |
- if (!m_playbackRate || playStateInternal() == Idle) { |
- return; |
- } |
- if (m_playbackRate > 0 && sourceEnd() == std::numeric_limits<double>::infinity()) { |
- exceptionState.throwDOMException(InvalidStateError, "AnimationPlayer has source content whose end time is infinity."); |
- return; |
- } |
- |
- double newCurrentTime = m_playbackRate < 0 ? 0 : sourceEnd(); |
- setCurrentTimeInternal(newCurrentTime, TimingUpdateOnDemand); |
- if (!paused()) { |
- m_startTime = calculateStartTime(newCurrentTime); |
- } |
- |
- m_currentTimePending = false; |
- ASSERT(playStateInternal() != Idle); |
- ASSERT(limited()); |
-} |
- |
-ScriptPromise AnimationPlayer::finished(ScriptState* scriptState) |
-{ |
- if (!m_finishedPromise) { |
- m_finishedPromise = new AnimationPlayerPromise(scriptState->executionContext(), this, AnimationPlayerPromise::Finished); |
- if (playStateInternal() == Finished) |
- m_finishedPromise->resolve(this); |
- } |
- return m_finishedPromise->promise(scriptState->world()); |
-} |
- |
-ScriptPromise AnimationPlayer::ready(ScriptState* scriptState) |
-{ |
- if (!m_readyPromise) { |
- m_readyPromise = new AnimationPlayerPromise(scriptState->executionContext(), this, AnimationPlayerPromise::Ready); |
- if (playStateInternal() != Pending) |
- m_readyPromise->resolve(this); |
- } |
- return m_readyPromise->promise(scriptState->world()); |
-} |
- |
-const AtomicString& AnimationPlayer::interfaceName() const |
-{ |
- return EventTargetNames::AnimationPlayer; |
-} |
- |
-ExecutionContext* AnimationPlayer::executionContext() const |
-{ |
- return ActiveDOMObject::executionContext(); |
-} |
- |
-bool AnimationPlayer::hasPendingActivity() const |
-{ |
- return m_pendingFinishedEvent || (!m_finished && hasEventListeners(EventTypeNames::finish)); |
-} |
- |
-void AnimationPlayer::stop() |
-{ |
- PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); |
- |
- m_finished = true; |
- m_pendingFinishedEvent = nullptr; |
-} |
- |
-bool AnimationPlayer::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event) |
-{ |
- if (m_pendingFinishedEvent == event) |
- m_pendingFinishedEvent = nullptr; |
- return EventTargetWithInlineData::dispatchEvent(event); |
-} |
- |
-double AnimationPlayer::playbackRate() const |
-{ |
- return m_playbackRate; |
-} |
- |
-void AnimationPlayer::setPlaybackRate(double playbackRate) |
-{ |
- if (playbackRate == m_playbackRate) |
- return; |
- |
- PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); |
- |
- setPlaybackRateInternal(playbackRate); |
-} |
- |
-void AnimationPlayer::setPlaybackRateInternal(double playbackRate) |
-{ |
- ASSERT(std::isfinite(playbackRate)); |
- ASSERT(playbackRate != m_playbackRate); |
- |
- if (!limited() && !paused() && hasStartTime()) |
- m_currentTimePending = true; |
- |
- double storedCurrentTime = currentTimeInternal(); |
- if ((m_playbackRate < 0 && playbackRate >= 0) || (m_playbackRate > 0 && playbackRate <= 0)) |
- m_finished = false; |
- |
- m_playbackRate = playbackRate; |
- m_startTime = std::numeric_limits<double>::quiet_NaN(); |
- setCurrentTimeInternal(storedCurrentTime, TimingUpdateOnDemand); |
-} |
- |
-void AnimationPlayer::setOutdated() |
-{ |
- m_outdated = true; |
- if (m_timeline) |
- m_timeline->setOutdatedAnimationPlayer(this); |
-} |
- |
-bool AnimationPlayer::canStartAnimationOnCompositor() const |
-{ |
- // FIXME: Timeline playback rates should be compositable |
- if (m_playbackRate == 0 || (std::isinf(sourceEnd()) && m_playbackRate < 0) || (timeline() && timeline()->playbackRate() != 1)) |
- return false; |
- |
- return m_timeline && m_content && m_content->isAnimation() && playing(); |
-} |
- |
-bool AnimationPlayer::isCandidateForAnimationOnCompositor() const |
-{ |
- if (!canStartAnimationOnCompositor()) |
- return false; |
- |
- return toAnimation(m_content.get())->isCandidateForAnimationOnCompositor(m_playbackRate); |
-} |
- |
-bool AnimationPlayer::maybeStartAnimationOnCompositor() |
-{ |
- if (!canStartAnimationOnCompositor()) |
- return false; |
- |
- bool reversed = m_playbackRate < 0; |
- |
- double startTime = timeline()->zeroTime() + startTimeInternal(); |
- if (reversed) { |
- startTime -= sourceEnd() / fabs(m_playbackRate); |
- } |
- |
- double timeOffset = 0; |
- if (std::isnan(startTime)) { |
- timeOffset = reversed ? sourceEnd() - currentTimeInternal() : currentTimeInternal(); |
- timeOffset = timeOffset / fabs(m_playbackRate); |
- } |
- ASSERT(m_compositorGroup != 0); |
- return toAnimation(m_content.get())->maybeStartAnimationOnCompositor(m_compositorGroup, startTime, timeOffset, m_playbackRate); |
-} |
- |
-void AnimationPlayer::setCompositorPending(bool sourceChanged) |
-{ |
- // FIXME: Animation could notify this directly? |
- if (!hasActiveAnimationsOnCompositor()) { |
- destroyCompositorPlayer(); |
- m_compositorState.release(); |
- } |
- if (sourceChanged && m_compositorState) { |
- m_compositorState->sourceChanged = true; |
- } |
- if (m_compositorPending || m_isPausedForTesting) { |
- return; |
- } |
- |
- if (sourceChanged || !m_compositorState |
- || !playing() || m_compositorState->playbackRate != m_playbackRate |
- || m_compositorState->startTime != m_startTime) { |
- m_compositorPending = true; |
- ASSERT(timeline()); |
- ASSERT(timeline()->document()); |
- timeline()->document()->compositorPendingAnimations().add(this); |
- } |
-} |
- |
-void AnimationPlayer::cancelAnimationOnCompositor() |
-{ |
- if (hasActiveAnimationsOnCompositor()) |
- toAnimation(m_content.get())->cancelAnimationOnCompositor(); |
- |
- destroyCompositorPlayer(); |
-} |
- |
-void AnimationPlayer::restartAnimationOnCompositor() |
-{ |
- if (hasActiveAnimationsOnCompositor()) |
- toAnimation(m_content.get())->restartAnimationOnCompositor(); |
-} |
- |
-void AnimationPlayer::cancelIncompatibleAnimationsOnCompositor() |
-{ |
- if (m_content && m_content->isAnimation()) |
- toAnimation(m_content.get())->cancelIncompatibleAnimationsOnCompositor(); |
-} |
- |
-bool AnimationPlayer::hasActiveAnimationsOnCompositor() |
-{ |
- if (!m_content || !m_content->isAnimation()) |
- return false; |
- |
- return toAnimation(m_content.get())->hasActiveAnimationsOnCompositor(); |
-} |
- |
-bool AnimationPlayer::update(TimingUpdateReason reason) |
-{ |
- if (!m_timeline) |
- return false; |
- |
- PlayStateUpdateScope updateScope(*this, reason, DoNotSetCompositorPending); |
- |
- m_outdated = false; |
- bool idle = playStateInternal() == Idle; |
- |
- if (m_content) { |
- double inheritedTime = idle || isNull(m_timeline->currentTimeInternal()) ? nullValue() : currentTimeInternal(); |
- // Special case for end-exclusivity when playing backwards. |
- if (inheritedTime == 0 && m_playbackRate < 0) |
- inheritedTime = -1; |
- m_content->updateInheritedTime(inheritedTime, reason); |
- } |
- |
- if ((idle || limited()) && !m_finished) { |
- if (reason == TimingUpdateForAnimationFrame && (idle || hasStartTime())) { |
- const AtomicString& eventType = EventTypeNames::finish; |
- if (executionContext() && hasEventListeners(eventType)) { |
- double eventCurrentTime = currentTimeInternal() * 1000; |
- m_pendingFinishedEvent = AnimationPlayerEvent::create(eventType, eventCurrentTime, timeline()->currentTime()); |
- m_pendingFinishedEvent->setTarget(this); |
- m_pendingFinishedEvent->setCurrentTarget(this); |
- m_timeline->document()->enqueueAnimationFrameEvent(m_pendingFinishedEvent); |
- } |
- m_finished = true; |
- } |
- } |
- ASSERT(!m_outdated); |
- return !m_finished; |
-} |
- |
-double AnimationPlayer::timeToEffectChange() |
-{ |
- ASSERT(!m_outdated); |
- if (m_held || !hasStartTime()) |
- return std::numeric_limits<double>::infinity(); |
- if (!m_content) |
- return -currentTimeInternal() / m_playbackRate; |
- double result = m_playbackRate > 0 |
- ? m_content->timeToForwardsEffectChange() / m_playbackRate |
- : m_content->timeToReverseEffectChange() / -m_playbackRate; |
- return !hasActiveAnimationsOnCompositor() && m_content->phase() == AnimationNode::PhaseActive |
- ? 0 |
- : result; |
-} |
- |
-void AnimationPlayer::cancel() |
-{ |
- PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); |
- |
- if (playStateInternal() == Idle) |
- return; |
- |
- m_holdTime = currentTimeInternal(); |
- m_held = true; |
- // TODO |
- m_playState = Idle; |
- m_startTime = nullValue(); |
- m_currentTimePending = false; |
- |
- InspectorInstrumentation::didCancelAnimationPlayer(timeline()->document(), this); |
-} |
- |
-void AnimationPlayer::beginUpdatingState() |
-{ |
- // Nested calls are not allowed! |
- ASSERT(!m_stateIsBeingUpdated); |
- m_stateIsBeingUpdated = true; |
-} |
- |
-void AnimationPlayer::endUpdatingState() |
-{ |
- ASSERT(m_stateIsBeingUpdated); |
- m_stateIsBeingUpdated = false; |
-} |
- |
-void AnimationPlayer::createCompositorPlayer() |
-{ |
- if (RuntimeEnabledFeatures::compositorAnimationTimelinesEnabled() && !m_compositorPlayer && Platform::current()->compositorSupport()) { |
- m_compositorPlayer = adoptPtr(Platform::current()->compositorSupport()->createAnimationPlayer()); |
- ASSERT(m_compositorPlayer); |
- m_compositorPlayer->setAnimationDelegate(this); |
- attachCompositorTimeline(); |
- } |
- |
- attachCompositedLayers(); |
-} |
- |
-void AnimationPlayer::destroyCompositorPlayer() |
-{ |
- detachCompositedLayers(); |
- |
- if (m_compositorPlayer) { |
- detachCompositorTimeline(); |
- m_compositorPlayer->setAnimationDelegate(nullptr); |
- } |
- m_compositorPlayer.clear(); |
-} |
- |
-void AnimationPlayer::attachCompositorTimeline() |
-{ |
- if (m_compositorPlayer) { |
- WebCompositorAnimationTimeline* timeline = m_timeline ? m_timeline->compositorTimeline() : nullptr; |
- if (timeline) |
- timeline->playerAttached(*this); |
- } |
-} |
- |
-void AnimationPlayer::detachCompositorTimeline() |
-{ |
- if (m_compositorPlayer) { |
- WebCompositorAnimationTimeline* timeline = m_timeline ? m_timeline->compositorTimeline() : nullptr; |
- if (timeline) |
- timeline->playerDestroyed(*this); |
- } |
-} |
- |
-void AnimationPlayer::attachCompositedLayers() |
-{ |
- if (!RuntimeEnabledFeatures::compositorAnimationTimelinesEnabled() || !m_compositorPlayer) |
- return; |
- |
- ASSERT(m_content); |
- ASSERT(m_content->isAnimation()); |
- |
- if (toAnimation(m_content.get())->canAttachCompositedLayers()) |
- toAnimation(m_content.get())->attachCompositedLayers(); |
-} |
- |
-void AnimationPlayer::detachCompositedLayers() |
-{ |
- if (m_compositorPlayer && m_compositorPlayer->isLayerAttached()) |
- m_compositorPlayer->detachLayer(); |
-} |
- |
-void AnimationPlayer::notifyAnimationStarted(double monotonicTime, int group) |
-{ |
- ASSERT(RuntimeEnabledFeatures::compositorAnimationTimelinesEnabled()); |
- timeline()->document()->compositorPendingAnimations().notifyCompositorAnimationStarted(monotonicTime, group); |
-} |
- |
-AnimationPlayer::PlayStateUpdateScope::PlayStateUpdateScope(AnimationPlayer& player, TimingUpdateReason reason, CompositorPendingChange compositorPendingChange) |
- : m_player(player) |
- , m_initialPlayState(m_player->playStateInternal()) |
- , m_compositorPendingChange(compositorPendingChange) |
-{ |
- m_player->beginUpdatingState(); |
- m_player->updateCurrentTimingState(reason); |
-} |
- |
-AnimationPlayer::PlayStateUpdateScope::~PlayStateUpdateScope() |
-{ |
- AnimationPlayState oldPlayState = m_initialPlayState; |
- AnimationPlayState newPlayState = m_player->calculatePlayState(); |
- |
- m_player->m_playState = newPlayState; |
- if (oldPlayState != newPlayState) { |
- bool wasActive = oldPlayState == Pending || oldPlayState == Running; |
- bool isActive = newPlayState == Pending || newPlayState == Running; |
- if (!wasActive && isActive) |
- TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("blink.animations," TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Animation", m_player, "data", InspectorAnimationEvent::data(*m_player)); |
- else if (wasActive && !isActive) |
- TRACE_EVENT_NESTABLE_ASYNC_END1("blink.animations," TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Animation", m_player, "endData", InspectorAnimationStateEvent::data(*m_player)); |
- else |
- TRACE_EVENT_NESTABLE_ASYNC_INSTANT1("blink.animations," TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Animation", m_player, "data", InspectorAnimationStateEvent::data(*m_player)); |
- } |
- |
- // Ordering is important, the ready promise should resolve/reject before |
- // the finished promise. |
- if (m_player->m_readyPromise && newPlayState != oldPlayState) { |
- if (newPlayState == Idle) { |
- if (m_player->m_readyPromise->state() == AnimationPlayerPromise::Pending) { |
- m_player->m_readyPromise->reject(DOMException::create(AbortError)); |
- } |
- m_player->m_readyPromise->reset(); |
- m_player->m_readyPromise->resolve(m_player); |
- } else if (oldPlayState == Pending) { |
- m_player->m_readyPromise->resolve(m_player); |
- } else if (newPlayState == Pending) { |
- ASSERT(m_player->m_readyPromise->state() != AnimationPlayerPromise::Pending); |
- m_player->m_readyPromise->reset(); |
- } |
- } |
- |
- if (m_player->m_finishedPromise && newPlayState != oldPlayState) { |
- if (newPlayState == Idle) { |
- if (m_player->m_finishedPromise->state() == AnimationPlayerPromise::Pending) { |
- m_player->m_finishedPromise->reject(DOMException::create(AbortError)); |
- } |
- m_player->m_finishedPromise->reset(); |
- } else if (newPlayState == Finished) { |
- m_player->m_finishedPromise->resolve(m_player); |
- } else if (oldPlayState == Finished) { |
- m_player->m_finishedPromise->reset(); |
- } |
- } |
- |
- if (oldPlayState != newPlayState && (oldPlayState == Idle || newPlayState == Idle)) { |
- m_player->setOutdated(); |
- } |
- |
-#if ENABLE(ASSERT) |
- // Verify that current time is up to date. |
- m_player->currentTimeInternal(); |
-#endif |
- |
- switch (m_compositorPendingChange) { |
- case SetCompositorPending: |
- m_player->setCompositorPending(); |
- break; |
- case SetCompositorPendingWithSourceChanged: |
- m_player->setCompositorPending(true); |
- break; |
- case DoNotSetCompositorPending: |
- break; |
- default: |
- ASSERT_NOT_REACHED(); |
- break; |
- } |
- m_player->endUpdatingState(); |
- |
- if (oldPlayState != newPlayState && newPlayState == Running) |
- InspectorInstrumentation::didCreateAnimationPlayer(m_player->timeline()->document(), m_player); |
-} |
- |
-bool AnimationPlayer::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture) |
-{ |
- if (eventType == EventTypeNames::finish) |
- UseCounter::count(executionContext(), UseCounter::AnimationPlayerFinishEvent); |
- return EventTargetWithInlineData::addEventListener(eventType, listener, useCapture); |
-} |
- |
-void AnimationPlayer::pauseForTesting(double pauseTime) |
-{ |
- RELEASE_ASSERT(!paused()); |
- setCurrentTimeInternal(pauseTime, TimingUpdateOnDemand); |
- if (hasActiveAnimationsOnCompositor()) |
- toAnimation(m_content.get())->pauseAnimationForTestingOnCompositor(currentTimeInternal()); |
- m_isPausedForTesting = true; |
- pause(); |
-} |
- |
-DEFINE_TRACE(AnimationPlayer) |
-{ |
- visitor->trace(m_content); |
- visitor->trace(m_timeline); |
- visitor->trace(m_pendingFinishedEvent); |
- visitor->trace(m_finishedPromise); |
- visitor->trace(m_readyPromise); |
- EventTargetWithInlineData::trace(visitor); |
- ActiveDOMObject::trace(visitor); |
-} |
- |
-} // namespace |