Index: Source/core/animation/AnimationPlayer.cpp |
diff --git a/Source/core/animation/AnimationPlayer.cpp b/Source/core/animation/AnimationPlayer.cpp |
index f10b029035b05a69060a171f67c2d32ce734e7b6..b1760edf33644f03314a2a5db57e79a09200522d 100644 |
--- a/Source/core/animation/AnimationPlayer.cpp |
+++ b/Source/core/animation/AnimationPlayer.cpp |
@@ -61,6 +61,7 @@ PassRefPtrWillBeRawPtr<AnimationPlayer> AnimationPlayer::create(ExecutionContext |
AnimationPlayer::AnimationPlayer(ExecutionContext* executionContext, AnimationTimeline& timeline, AnimationNode* content) |
: ActiveDOMObject(executionContext) |
+ , m_playState(Idle) |
, m_playbackRate(1) |
, m_startTime(nullValue()) |
, m_holdTime(0) |
@@ -75,7 +76,6 @@ AnimationPlayer::AnimationPlayer(ExecutionContext* executionContext, AnimationTi |
, m_compositorState(nullptr) |
, m_compositorPending(true) |
, m_currentTimePending(false) |
- , m_idle(true) |
{ |
if (m_content) { |
if (m_content->player()) { |
@@ -106,6 +106,18 @@ bool AnimationPlayer::limited(double currentTime) const |
return (m_playbackRate < 0 && currentTime <= 0) || (m_playbackRate > 0 && currentTime >= sourceEnd()); |
} |
+void AnimationPlayer::setCurrentTime(double newCurrentTime) |
+{ |
+ UseCounter::count(executionContext(), UseCounter::AnimationPlayerSetCurrentTime); |
+ if (!std::isfinite(newCurrentTime)) |
+ return; |
+ |
+ PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); |
+ |
+ m_currentTimePending = false; |
+ setCurrentTimeInternal(newCurrentTime / 1000, TimingUpdateOnDemand); |
+} |
+ |
void AnimationPlayer::setCurrentTimeInternal(double newCurrentTime, TimingUpdateReason reason) |
{ |
ASSERT(std::isfinite(newCurrentTime)); |
@@ -126,7 +138,7 @@ void AnimationPlayer::setCurrentTimeInternal(double newCurrentTime, TimingUpdate |
} else { |
m_holdTime = nullValue(); |
m_startTime = calculateStartTime(newCurrentTime); |
- setFinished(false); |
+ m_finished = false; |
outdated = true; |
} |
@@ -170,18 +182,23 @@ double AnimationPlayer::currentTime(bool& isNull) |
double AnimationPlayer::currentTime() |
{ |
+ PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); |
+ |
UseCounter::count(executionContext(), UseCounter::AnimationPlayerGetCurrentTime); |
- if (m_currentTimePending || m_idle) |
+ if (m_currentTimePending || playStateInternal() == Idle) |
return std::numeric_limits<double>::quiet_NaN(); |
+ |
return currentTimeInternal() * 1000; |
} |
-double AnimationPlayer::currentTimeInternal() |
+double AnimationPlayer::currentTimeInternal() const |
{ |
- updateCurrentTimingState(TimingUpdateOnDemand); |
- if (m_held) |
- return m_holdTime; |
- return calculateCurrentTime(); |
+ 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; |
} |
void AnimationPlayer::preCommit(bool startOnCompositor) |
@@ -191,6 +208,8 @@ void AnimationPlayer::preCommit(bool startOnCompositor) |
return; |
} |
+ 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 && !std::isnan(m_compositorState->startTime) && !std::isnan(m_startTime))); |
@@ -204,7 +223,6 @@ void AnimationPlayer::preCommit(bool startOnCompositor) |
if (shouldCancel) { |
cancelAnimationOnCompositor(); |
m_compositorState = nullptr; |
- |
} |
if (!shouldStart) { |
@@ -218,6 +236,8 @@ void AnimationPlayer::preCommit(bool startOnCompositor) |
void AnimationPlayer::postCommit(double timelineTime) |
{ |
+ PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand, DoNotSetCompositorPending); |
+ |
m_compositorPending = false; |
if (!m_compositorState || m_compositorState->pendingAction == None) |
@@ -244,6 +264,8 @@ void AnimationPlayer::postCommit(double timelineTime) |
void AnimationPlayer::notifyCompositorStartTime(double timelineTime) |
{ |
+ PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); |
+ |
if (m_compositorState) { |
ASSERT(m_compositorState->pendingAction == Start); |
ASSERT(std::isnan(m_compositorState->startTime)); |
@@ -252,11 +274,6 @@ void AnimationPlayer::notifyCompositorStartTime(double timelineTime) |
m_compositorState->pendingAction = None; |
m_compositorState->startTime = timelineTime; |
- if (paused() || m_compositorState->playbackRate != m_playbackRate || m_compositorState->sourceChanged) { |
- // Paused state, playback rate, or source changed while starting. |
- setCompositorPending(); |
- } |
- |
if (m_startTime == timelineTime) { |
// The start time was set to the incoming compositor start time. |
// Unlikely, but possible. |
@@ -268,11 +285,16 @@ void AnimationPlayer::notifyCompositorStartTime(double timelineTime) |
if (!std::isnan(m_startTime) || currentTimeInternal() != initialCompositorHoldTime) { |
// A new start time or current time was set while starting. |
- setCompositorPending(); |
+ setCompositorPending(true); |
return; |
} |
} |
+ notifyStartTime(timelineTime); |
+} |
+ |
+void AnimationPlayer::notifyStartTime(double timelineTime) |
+{ |
if (playing()) { |
ASSERT(std::isnan(m_startTime)); |
ASSERT(m_held); |
@@ -304,28 +326,18 @@ double AnimationPlayer::calculateCurrentTime() const |
return (m_timeline->effectiveTime() - m_startTime) * m_playbackRate; |
} |
-void AnimationPlayer::setCurrentTime(double newCurrentTime) |
-{ |
- UseCounter::count(executionContext(), UseCounter::AnimationPlayerSetCurrentTime); |
- if (!std::isfinite(newCurrentTime)) |
- return; |
- |
- setCompositorPending(); |
- m_currentTimePending = false; |
- setCurrentTimeInternal(newCurrentTime / 1000, TimingUpdateOnDemand); |
-} |
- |
void AnimationPlayer::setStartTime(double startTime) |
{ |
+ PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); |
+ |
UseCounter::count(executionContext(), UseCounter::AnimationPlayerSetStartTime); |
- if (m_paused || m_idle) |
+ if (m_paused || playStateInternal() == Idle) |
return; |
if (!std::isfinite(startTime)) |
return; |
if (startTime == m_startTime) |
return; |
- setCompositorPending(); |
m_currentTimePending = false; |
setStartTimeInternal(startTime / 1000); |
} |
@@ -351,6 +363,7 @@ void AnimationPlayer::setStartTimeInternal(double newStartTime) |
} |
setCurrentTimeInternal(currentTime, TimingUpdateOnDemand); |
} |
+ updateCurrentTimingState(TimingUpdateOnDemand); |
double newCurrentTime = currentTimeInternal(); |
if (previousCurrentTime != newCurrentTime) { |
@@ -367,7 +380,7 @@ void AnimationPlayer::setSource(AnimationNode* newSource) |
if (m_content == newSource) |
return; |
- setCompositorPending(true); |
+ PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand, SetCompositorPendingWithSourceChanged); |
double storedCurrentTime = currentTimeInternal(); |
if (m_content) |
@@ -385,9 +398,9 @@ void AnimationPlayer::setSource(AnimationNode* newSource) |
setCurrentTimeInternal(storedCurrentTime, TimingUpdateOnDemand); |
} |
-String AnimationPlayer::playState() |
+const char* AnimationPlayer::playStateString(AnimationPlayState playState) |
{ |
- switch (playStateInternal()) { |
+ switch (playState) { |
case Idle: |
return "idle"; |
case Pending: |
@@ -404,9 +417,14 @@ String AnimationPlayer::playState() |
} |
} |
-AnimationPlayer::AnimationPlayState AnimationPlayer::playStateInternal() |
+AnimationPlayer::AnimationPlayState AnimationPlayer::playStateInternal() const |
+{ |
+ return m_playState; |
+} |
+ |
+AnimationPlayer::AnimationPlayState AnimationPlayer::calculatePlayState() |
{ |
- if (m_idle) |
+ if (m_playState == Idle) |
return Idle; |
if (m_currentTimePending || (isNull(m_startTime) && !m_paused && m_playbackRate != 0)) |
return Pending; |
@@ -421,8 +439,10 @@ void AnimationPlayer::pause() |
{ |
if (m_paused) |
return; |
+ |
+ PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); |
+ |
if (playing()) { |
- setCompositorPending(); |
m_currentTimePending = true; |
} |
m_paused = true; |
@@ -433,7 +453,9 @@ void AnimationPlayer::unpause() |
{ |
if (!m_paused) |
return; |
- setCompositorPending(); |
+ |
+ PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); |
+ |
m_currentTimePending = true; |
unpauseInternal(); |
} |
@@ -448,10 +470,11 @@ void AnimationPlayer::unpauseInternal() |
void AnimationPlayer::play() |
{ |
+ PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); |
+ |
if (!playing()) |
m_startTime = nullValue(); |
- setCompositorPending(); |
uncancel(); |
unpauseInternal(); |
if (!m_content) |
@@ -461,7 +484,7 @@ void AnimationPlayer::play() |
setCurrentTimeInternal(0, TimingUpdateOnDemand); |
else if (m_playbackRate < 0 && (currentTime <= 0 || currentTime > sourceEnd())) |
setCurrentTimeInternal(sourceEnd(), TimingUpdateOnDemand); |
- setFinished(false); |
+ m_finished = false; |
} |
void AnimationPlayer::reverse() |
@@ -477,16 +500,15 @@ void AnimationPlayer::reverse() |
void AnimationPlayer::finish(ExceptionState& exceptionState) |
{ |
- if (!m_playbackRate || m_idle) { |
+ 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; |
} |
- if (playing()) { |
- setCompositorPending(); |
- } |
uncancel(); |
@@ -517,7 +539,9 @@ bool AnimationPlayer::hasPendingActivity() const |
void AnimationPlayer::stop() |
{ |
- setFinished(true); |
+ PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); |
+ |
+ m_finished = true; |
m_pendingFinishedEvent = nullptr; |
} |
@@ -542,6 +566,8 @@ void AnimationPlayer::setPlaybackRate(double playbackRate) |
if (playbackRate == m_playbackRate) |
return; |
+ PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); |
+ |
setPlaybackRateInternal(playbackRate); |
} |
@@ -550,13 +576,12 @@ void AnimationPlayer::setPlaybackRateInternal(double playbackRate) |
ASSERT(std::isfinite(playbackRate)); |
ASSERT(playbackRate != m_playbackRate); |
- setCompositorPending(); |
if (!finished() && !paused() && hasStartTime()) |
m_currentTimePending = true; |
double storedCurrentTime = currentTimeInternal(); |
if ((m_playbackRate < 0 && playbackRate >= 0) || (m_playbackRate > 0 && playbackRate <= 0)) |
- setFinished(false); |
+ m_finished = false; |
m_playbackRate = playbackRate; |
m_startTime = std::numeric_limits<double>::quiet_NaN(); |
@@ -597,10 +622,17 @@ void AnimationPlayer::setCompositorPending(bool sourceChanged) |
if (!hasActiveAnimationsOnCompositor()) { |
m_compositorState.release(); |
} |
- if (!m_compositorPending) { |
+ 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; |
- if (sourceChanged && m_compositorState) |
- m_compositorState->sourceChanged = true; |
timeline()->document()->compositorPendingAnimations().add(this); |
} |
} |
@@ -624,19 +656,21 @@ bool AnimationPlayer::update(TimingUpdateReason reason) |
if (!m_timeline) |
return false; |
- updateCurrentTimingState(reason); |
+ PlayStateUpdateScope updateScope(*this, reason, DoNotSetCompositorPending); |
+ |
m_outdated = false; |
+ bool idle = playStateInternal() == Idle; |
if (m_content) { |
- double inheritedTime = m_idle || isNull(m_timeline->currentTimeInternal()) ? nullValue() : currentTimeInternal(); |
+ 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 ((m_idle || finished()) && !m_finished) { |
- if (reason == TimingUpdateForAnimationFrame && (m_idle || hasStartTime())) { |
+ if ((idle || finished()) && !m_finished) { |
+ if (reason == TimingUpdateForAnimationFrame && (idle || hasStartTime())) { |
const AtomicString& eventType = EventTypeNames::finish; |
if (executionContext() && hasEventListeners(eventType)) { |
double eventCurrentTime = currentTimeInternal() * 1000; |
@@ -645,7 +679,7 @@ bool AnimationPlayer::update(TimingUpdateReason reason) |
m_pendingFinishedEvent->setCurrentTarget(this); |
m_timeline->document()->enqueueAnimationFrameEvent(m_pendingFinishedEvent); |
} |
- setFinished(true); |
+ m_finished = true; |
} |
} |
ASSERT(!m_outdated); |
@@ -664,43 +698,88 @@ double AnimationPlayer::timeToEffectChange() |
return m_content->timeToReverseEffectChange() / -m_playbackRate; |
} |
-void AnimationPlayer::setFinished(bool finished) |
-{ |
- if (m_finished && !finished) { |
- if (m_content) { |
- TRACE_EVENT_ASYNC_BEGIN1("blink", "Animation", this, "Name", TRACE_STR_COPY(m_content->name().utf8().data())); |
- } else { |
- TRACE_EVENT_ASYNC_BEGIN0("blink", "Animation", this); |
- } |
- } |
- if (!m_finished && finished) { |
- TRACE_EVENT_ASYNC_END0("blink", "Animation", this); |
- } |
- m_finished = finished; |
-} |
- |
void AnimationPlayer::cancel() |
{ |
- if (m_idle) |
+ PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); |
+ |
+ if (playStateInternal() == Idle) |
return; |
m_holdTime = currentTimeInternal(); |
m_held = true; |
- m_idle = true; |
+ // TODO |
+ m_playState = Idle; |
m_startTime = nullValue(); |
m_currentTimePending = false; |
- setCompositorPending(); |
} |
void AnimationPlayer::uncancel() |
{ |
- if (!m_idle) |
+ PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); |
+ |
+ if (playStateInternal() != Idle) |
return; |
- m_idle = false; |
+ // 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; |
- setFinished(false); |
+ m_finished = false; |
+} |
+ |
+AnimationPlayer::PlayStateUpdateScope::PlayStateUpdateScope(AnimationPlayer& player, TimingUpdateReason reason, CompositorPendingChange compositorPendingChange) |
+ : m_player(player) |
+ , m_initial(player.playStateInternal()) |
+ , m_compositorPendingChange(compositorPendingChange) |
+{ |
+ m_player.updateCurrentTimingState(reason); |
+} |
+ |
+AnimationPlayer::PlayStateUpdateScope::~PlayStateUpdateScope() |
+{ |
+ AnimationPlayState oldPlayState = m_initial; |
+ AnimationPlayState newPlayState = m_player.calculatePlayState(); |
+ if (oldPlayState != newPlayState) { |
+ bool wasActive = oldPlayState == Pending || oldPlayState == Running; |
+ bool isActive = newPlayState == Pending || newPlayState == Running; |
+ if (!wasActive && isActive) { |
+ if (m_player.m_content) { |
+ TRACE_EVENT_ASYNC_BEGIN1("blink", "Animation", &m_player, "Name", TRACE_STR_COPY(m_player.m_content->name().utf8().data())); |
+ } else { |
+ TRACE_EVENT_ASYNC_BEGIN0("blink", "Animation", &m_player); |
+ } |
+ } else if (wasActive && !isActive) { |
+ if (oldPlayState != Idle && oldPlayState != Finished) { |
+ TRACE_EVENT_ASYNC_END0("blink", "Animation", &m_player); |
+ } |
+ } |
+ if (isActive) { |
+ TRACE_EVENT_ASYNC_STEP_INTO0("blink", "Animation", &m_player, playStateString(newPlayState)); |
+ } |
+ } |
+ |
+ m_player.m_playState = newPlayState; |
+ |
+#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; |
+ } |
} |