Web Animations: Remove timeLag from Player API and model

API changes are guarded by experimental feature flag. No visible changes to CSS
animations and element.animate.

This is a prototype for behavior we plan to incorporate into the Web Animations
specification:
* startTime is effective start time or NaN when paused or starting
* timeLag is removed

Review URL: https://codereview.chromium.org/365163004

git-svn-id: svn://svn.chromium.org/blink/trunk@178619 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent d3692949
...@@ -17,18 +17,18 @@ test(function() { ...@@ -17,18 +17,18 @@ test(function() {
}, 'TimedItem.localTime and TimedItem.currentIteration are null when animation is not associated with a Player'); }, 'TimedItem.localTime and TimedItem.currentIteration are null when animation is not associated with a Player');
test(function() { test(function() {
var animation = element.animate(keyframes, {fill: 'both', duration: 2, iterations: 3}).source; var animation = element.animate(keyframes, {fill: 'both', duration: 2000, iterations: 3}).source;
animation.player.currentTime = -1; animation.player.currentTime = -1000;
assert_equals(animation.localTime, -1); assert_equals(animation.localTime, -1000, 'localTime');
assert_equals(animation.currentIteration, 0); assert_equals(animation.currentIteration, 0);
animation.player.currentTime = 1; animation.player.currentTime = 1000;
assert_equals(animation.localTime, 1); assert_equals(animation.localTime, 1000);
assert_equals(animation.currentIteration, 0); assert_equals(animation.currentIteration, 0);
animation.player.currentTime = 5; animation.player.currentTime = 5000;
assert_equals(animation.localTime, 5); assert_equals(animation.localTime, 5000);
assert_equals(animation.currentIteration, 2); assert_equals(animation.currentIteration, 2);
animation.player.currentTime = 7; animation.player.currentTime = 7000;
assert_equals(animation.localTime, 7); assert_equals(animation.localTime, 7000);
assert_equals(animation.currentIteration, 2); assert_equals(animation.currentIteration, 2);
}, 'TimedItem.localTime and TimedItem.currentIteration return reasonable values when an animation is in effect'); }, 'TimedItem.localTime and TimedItem.currentIteration return reasonable values when an animation is in effect');
......
...@@ -158,7 +158,7 @@ void AnimationNode::updateInheritedTime(double inheritedTime, TimingUpdateReason ...@@ -158,7 +158,7 @@ void AnimationNode::updateInheritedTime(double inheritedTime, TimingUpdateReason
// Test for events even if timing didn't need an update as the player may have gained a start time. // Test for events even if timing didn't need an update as the player may have gained a start time.
// FIXME: Refactor so that we can ASSERT(m_player) here, this is currently required to be nullable for testing. // FIXME: Refactor so that we can ASSERT(m_player) here, this is currently required to be nullable for testing.
if (reason == TimingUpdateForAnimationFrame && (!m_player || m_player->hasStartTime())) { if (reason == TimingUpdateForAnimationFrame && (!m_player || m_player->hasStartTime() || m_player->paused())) {
if (m_eventDelegate) if (m_eventDelegate)
m_eventDelegate->onEventCondition(this); m_eventDelegate->onEventCondition(this);
} }
......
...@@ -61,7 +61,6 @@ AnimationPlayer::AnimationPlayer(ExecutionContext* executionContext, AnimationTi ...@@ -61,7 +61,6 @@ AnimationPlayer::AnimationPlayer(ExecutionContext* executionContext, AnimationTi
, m_playbackRate(1) , m_playbackRate(1)
, m_startTime(nullValue()) , m_startTime(nullValue())
, m_holdTime(nullValue()) , m_holdTime(nullValue())
, m_storedTimeLag(0)
, m_sortInfo(nextSequenceNumber()) , m_sortInfo(nextSequenceNumber())
, m_content(content) , m_content(content)
, m_timeline(&timeline) , m_timeline(&timeline)
...@@ -99,49 +98,46 @@ bool AnimationPlayer::limited(double currentTime) const ...@@ -99,49 +98,46 @@ bool AnimationPlayer::limited(double currentTime) const
return (m_playbackRate < 0 && currentTime <= 0) || (m_playbackRate > 0 && currentTime >= sourceEnd()); return (m_playbackRate < 0 && currentTime <= 0) || (m_playbackRate > 0 && currentTime >= sourceEnd());
} }
double AnimationPlayer::currentTimeWithoutLag() const void AnimationPlayer::setCurrentTimeInternal(double newCurrentTime)
{
if (isNull(m_startTime) || !m_timeline)
return 0;
return (m_timeline->effectiveTime() - m_startTime) * m_playbackRate;
}
double AnimationPlayer::currentTimeWithLag() const
{ {
ASSERT(!m_held); ASSERT(std::isfinite(newCurrentTime));
double time = currentTimeWithoutLag();
return std::isinf(time) ? time : time - m_storedTimeLag;
}
void AnimationPlayer::updateTimingState(double newCurrentTime)
{
ASSERT(!isNull(newCurrentTime));
bool oldHeld = m_held; bool oldHeld = m_held;
bool outdated = false;
m_held = m_paused || !m_playbackRate || limited(newCurrentTime); m_held = m_paused || !m_playbackRate || limited(newCurrentTime);
if (m_held) { if (m_held) {
if (!oldHeld || m_holdTime != newCurrentTime) if (!oldHeld || m_holdTime != newCurrentTime)
setOutdated(); outdated = true;
m_holdTime = newCurrentTime; m_holdTime = newCurrentTime;
m_storedTimeLag = nullValue(); if (m_paused || !m_playbackRate)
m_startTime = nullValue();
} else { } else {
m_holdTime = nullValue(); m_holdTime = nullValue();
m_storedTimeLag = currentTimeWithoutLag() - newCurrentTime; m_startTime = m_timeline->effectiveTime() - newCurrentTime / m_playbackRate;
m_finished = false; m_finished = false;
outdated = true;
}
if (outdated) {
setOutdated(); setOutdated();
cancelAnimationOnCompositor();
if (!m_held)
schedulePendingAnimationOnCompositor();
} }
} }
// Update timing to reflect updated animation clock due to tick
void AnimationPlayer::updateCurrentTimingState() void AnimationPlayer::updateCurrentTimingState()
{ {
if (m_held) { if (m_held) {
updateTimingState(m_holdTime); setCurrentTimeInternal(m_holdTime);
return; return;
} }
if (!limited(currentTimeWithLag())) if (!limited(calculateCurrentTime()))
return; return;
m_held = true; m_held = true;
m_holdTime = m_playbackRate < 0 ? 0 : sourceEnd(); m_holdTime = m_playbackRate < 0 ? 0 : sourceEnd();
m_storedTimeLag = nullValue();
} }
double AnimationPlayer::currentTime() double AnimationPlayer::currentTime()
...@@ -154,37 +150,41 @@ double AnimationPlayer::currentTimeInternal() ...@@ -154,37 +150,41 @@ double AnimationPlayer::currentTimeInternal()
updateCurrentTimingState(); updateCurrentTimingState();
if (m_held) if (m_held)
return m_holdTime; return m_holdTime;
return currentTimeWithLag(); return calculateCurrentTime();
} }
void AnimationPlayer::setCurrentTime(double newCurrentTime) double AnimationPlayer::calculateCurrentTime() const
{ {
setCurrentTimeInternal(newCurrentTime / 1000); ASSERT(!m_held);
if (isNull(m_startTime) || !m_timeline)
return 0;
return (m_timeline->effectiveTime() - m_startTime) * m_playbackRate;
} }
void AnimationPlayer::setCurrentTimeInternal(double newCurrentTime) void AnimationPlayer::setCurrentTime(double newCurrentTime)
{ {
if (!std::isfinite(newCurrentTime)) if (!std::isfinite(newCurrentTime))
return; return;
updateTimingState(newCurrentTime); setCurrentTimeInternal(newCurrentTime / 1000);
cancelAnimationOnCompositor();
schedulePendingAnimationOnCompositor();
} }
void AnimationPlayer::setStartTimeInternal(double newStartTime, bool isUpdateFromCompositor) void AnimationPlayer::setStartTimeInternal(double newStartTime, bool isUpdateFromCompositor)
{ {
ASSERT(!isUpdateFromCompositor || !hasStartTime()); ASSERT(!isUpdateFromCompositor || !hasStartTime());
if (m_paused)
return;
if (!std::isfinite(newStartTime)) if (!std::isfinite(newStartTime))
return; return;
if (newStartTime == m_startTime) if (newStartTime == m_startTime)
return; return;
updateCurrentTimingState(); // Update the value of held
bool hadStartTime = hasStartTime(); bool hadStartTime = hasStartTime();
double previousCurrentTime = currentTimeInternal(); double previousCurrentTime = currentTimeInternal();
m_startTime = newStartTime; m_startTime = newStartTime;
updateCurrentTimingState(); double newCurrentTime = currentTimeInternal();
if (previousCurrentTime != currentTimeInternal()) {
if (previousCurrentTime != newCurrentTime) {
setOutdated(); setOutdated();
} else if (!hadStartTime && m_timeline) { } else if (!hadStartTime && m_timeline) {
// Even though this player is not outdated, time to effect change is // Even though this player is not outdated, time to effect change is
...@@ -212,7 +212,7 @@ void AnimationPlayer::setSource(AnimationNode* newSource) ...@@ -212,7 +212,7 @@ void AnimationPlayer::setSource(AnimationNode* newSource)
newSource->player()->cancel(); newSource->player()->cancel();
newSource->attach(this); newSource->attach(this);
} }
updateTimingState(storedCurrentTime); setCurrentTimeInternal(storedCurrentTime);
schedulePendingAnimationOnCompositor(); schedulePendingAnimationOnCompositor();
} }
...@@ -221,7 +221,7 @@ void AnimationPlayer::pause() ...@@ -221,7 +221,7 @@ void AnimationPlayer::pause()
if (m_paused) if (m_paused)
return; return;
m_paused = true; m_paused = true;
updateTimingState(currentTimeInternal()); setCurrentTimeInternal(currentTimeInternal());
cancelAnimationOnCompositor(); cancelAnimationOnCompositor();
} }
...@@ -230,14 +230,12 @@ void AnimationPlayer::unpause() ...@@ -230,14 +230,12 @@ void AnimationPlayer::unpause()
if (!m_paused) if (!m_paused)
return; return;
m_paused = false; m_paused = false;
updateTimingState(currentTimeInternal()); setCurrentTimeInternal(currentTimeInternal());
schedulePendingAnimationOnCompositor();
} }
void AnimationPlayer::play() void AnimationPlayer::play()
{ {
cancelAnimationOnCompositor(); cancelAnimationOnCompositor();
// Note, unpause schedules pending animation on compositor if necessary.
unpause(); unpause();
if (!m_content) if (!m_content)
return; return;
...@@ -260,8 +258,6 @@ void AnimationPlayer::reverse() ...@@ -260,8 +258,6 @@ void AnimationPlayer::reverse()
setCurrentTimeInternal(0); setCurrentTimeInternal(0);
} }
setPlaybackRate(-m_playbackRate); setPlaybackRate(-m_playbackRate);
cancelAnimationOnCompositor();
// Note, unpause schedules pending animation on compositor if necessary.
unpause(); unpause();
} }
...@@ -279,7 +275,6 @@ void AnimationPlayer::finish(ExceptionState& exceptionState) ...@@ -279,7 +275,6 @@ void AnimationPlayer::finish(ExceptionState& exceptionState)
setCurrentTimeInternal(sourceEnd()); setCurrentTimeInternal(sourceEnd());
} }
ASSERT(finished()); ASSERT(finished());
cancelAnimationOnCompositor();
} }
const AtomicString& AnimationPlayer::interfaceName() const const AtomicString& AnimationPlayer::interfaceName() const
...@@ -318,9 +313,7 @@ void AnimationPlayer::setPlaybackRate(double playbackRate) ...@@ -318,9 +313,7 @@ void AnimationPlayer::setPlaybackRate(double playbackRate)
if ((m_playbackRate < 0 && playbackRate >= 0) || (m_playbackRate > 0 && playbackRate <= 0)) if ((m_playbackRate < 0 && playbackRate >= 0) || (m_playbackRate > 0 && playbackRate <= 0))
m_finished = false; m_finished = false;
m_playbackRate = playbackRate; m_playbackRate = playbackRate;
updateTimingState(storedCurrentTime); setCurrentTimeInternal(storedCurrentTime);
cancelAnimationOnCompositor();
schedulePendingAnimationOnCompositor();
} }
void AnimationPlayer::setOutdated() void AnimationPlayer::setOutdated()
...@@ -344,7 +337,7 @@ bool AnimationPlayer::maybeStartAnimationOnCompositor() ...@@ -344,7 +337,7 @@ bool AnimationPlayer::maybeStartAnimationOnCompositor()
if (!canStartAnimationOnCompositor()) if (!canStartAnimationOnCompositor())
return false; return false;
return toAnimation(m_content.get())->maybeStartAnimationOnCompositor(timeline()->zeroTime() + startTimeInternal() + timeLagInternal()); return toAnimation(m_content.get())->maybeStartAnimationOnCompositor(timeline()->zeroTime() + startTimeInternal());
} }
void AnimationPlayer::schedulePendingAnimationOnCompositor() void AnimationPlayer::schedulePendingAnimationOnCompositor()
...@@ -371,11 +364,12 @@ void AnimationPlayer::cancelAnimationOnCompositor() ...@@ -371,11 +364,12 @@ void AnimationPlayer::cancelAnimationOnCompositor()
bool AnimationPlayer::update(TimingUpdateReason reason) bool AnimationPlayer::update(TimingUpdateReason reason)
{ {
m_outdated = false;
if (!m_timeline) if (!m_timeline)
return false; return false;
updateCurrentTimingState();
m_outdated = false;
if (m_content) { if (m_content) {
double inheritedTime = isNull(m_timeline->currentTimeInternal()) ? nullValue() : currentTimeInternal(); double inheritedTime = isNull(m_timeline->currentTimeInternal()) ? nullValue() : currentTimeInternal();
m_content->updateInheritedTime(inheritedTime, reason); m_content->updateInheritedTime(inheritedTime, reason);
...@@ -432,7 +426,7 @@ bool AnimationPlayer::addEventListener(const AtomicString& eventType, PassRefPtr ...@@ -432,7 +426,7 @@ bool AnimationPlayer::addEventListener(const AtomicString& eventType, PassRefPtr
void AnimationPlayer::pauseForTesting(double pauseTime) void AnimationPlayer::pauseForTesting(double pauseTime)
{ {
RELEASE_ASSERT(!paused()); RELEASE_ASSERT(!paused());
updateTimingState(pauseTime); setCurrentTimeInternal(pauseTime);
if (!m_isPausedForTesting && hasActiveAnimationsOnCompositor()) if (!m_isPausedForTesting && hasActiveAnimationsOnCompositor())
toAnimation(m_content.get())->pauseAnimationForTestingOnCompositor(currentTimeInternal()); toAnimation(m_content.get())->pauseAnimationForTestingOnCompositor(currentTimeInternal());
m_isPausedForTesting = true; m_isPausedForTesting = true;
......
...@@ -65,6 +65,7 @@ public: ...@@ -65,6 +65,7 @@ public:
double currentTime(); double currentTime();
void setCurrentTime(double newCurrentTime); void setCurrentTime(double newCurrentTime);
double calculateCurrentTime() const;
double currentTimeInternal(); double currentTimeInternal();
void setCurrentTimeInternal(double newCurrentTime); void setCurrentTimeInternal(double newCurrentTime);
...@@ -105,9 +106,6 @@ public: ...@@ -105,9 +106,6 @@ public:
AnimationNode* source() { return m_content.get(); } AnimationNode* source() { return m_content.get(); }
void setSource(AnimationNode*); void setSource(AnimationNode*);
double timeLag() { return timeLagInternal() * 1000; }
double timeLagInternal() { return currentTimeWithoutLag() - currentTimeInternal(); }
// Pausing via this method is not reflected in the value returned by // Pausing via this method is not reflected in the value returned by
// paused() and must never overlap with pausing via pause(). // paused() and must never overlap with pausing via pause().
void pauseForTesting(double pauseTime); void pauseForTesting(double pauseTime);
...@@ -159,15 +157,11 @@ private: ...@@ -159,15 +157,11 @@ private:
AnimationPlayer(ExecutionContext*, AnimationTimeline&, AnimationNode*); AnimationPlayer(ExecutionContext*, AnimationTimeline&, AnimationNode*);
double sourceEnd() const; double sourceEnd() const;
bool limited(double currentTime) const; bool limited(double currentTime) const;
double currentTimeWithoutLag() const;
double currentTimeWithLag() const;
void updateTimingState(double newCurrentTime);
void updateCurrentTimingState(); void updateCurrentTimingState();
double m_playbackRate; double m_playbackRate;
double m_startTime; double m_startTime;
double m_holdTime; double m_holdTime;
double m_storedTimeLag;
SortInfo m_sortInfo; SortInfo m_sortInfo;
...@@ -178,8 +172,8 @@ private: ...@@ -178,8 +172,8 @@ private:
bool m_held; bool m_held;
bool m_isPausedForTesting; bool m_isPausedForTesting;
// This indicates timing information relevant to the player has changed by // This indicates timing information relevant to the player's effect
// means other than the ordinary progression of time // has changed by means other than the ordinary progression of time
bool m_outdated; bool m_outdated;
bool m_finished; bool m_finished;
......
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
[RuntimeEnabled=WebAnimationsAPI] attribute AnimationNode? source; [RuntimeEnabled=WebAnimationsAPI] attribute AnimationNode? source;
[RuntimeEnabled=WebAnimationsAPI] attribute double startTime; [RuntimeEnabled=WebAnimationsAPI] attribute double startTime;
[RuntimeEnabled=WebAnimationsAPI] attribute double currentTime; [RuntimeEnabled=WebAnimationsAPI] attribute double currentTime;
[RuntimeEnabled=WebAnimationsAPI] readonly attribute double timeLag;
[RuntimeEnabled=WebAnimationsAPI] attribute double playbackRate; [RuntimeEnabled=WebAnimationsAPI] attribute double playbackRate;
[RuntimeEnabled=WebAnimationsAPI] readonly attribute boolean paused; [RuntimeEnabled=WebAnimationsAPI] readonly attribute boolean paused;
[RuntimeEnabled=WebAnimationsAPI] readonly attribute boolean finished; [RuntimeEnabled=WebAnimationsAPI] readonly attribute boolean finished;
......
...@@ -95,7 +95,6 @@ TEST_F(AnimationAnimationPlayerTest, InitialState) ...@@ -95,7 +95,6 @@ TEST_F(AnimationAnimationPlayerTest, InitialState)
EXPECT_EQ(0, player->currentTimeInternal()); EXPECT_EQ(0, player->currentTimeInternal());
EXPECT_FALSE(player->paused()); EXPECT_FALSE(player->paused());
EXPECT_EQ(1, player->playbackRate()); EXPECT_EQ(1, player->playbackRate());
EXPECT_EQ(0, player->timeLagInternal());
EXPECT_FALSE(player->hasStartTime()); EXPECT_FALSE(player->hasStartTime());
EXPECT_TRUE(isNull(player->startTimeInternal())); EXPECT_TRUE(isNull(player->startTimeInternal()));
...@@ -106,7 +105,6 @@ TEST_F(AnimationAnimationPlayerTest, InitialState) ...@@ -106,7 +105,6 @@ TEST_F(AnimationAnimationPlayerTest, InitialState)
EXPECT_FALSE(player->paused()); EXPECT_FALSE(player->paused());
EXPECT_EQ(1, player->playbackRate()); EXPECT_EQ(1, player->playbackRate());
EXPECT_EQ(0, player->startTimeInternal()); EXPECT_EQ(0, player->startTimeInternal());
EXPECT_EQ(0, player->timeLagInternal());
EXPECT_TRUE(player->hasStartTime()); EXPECT_TRUE(player->hasStartTime());
} }
...@@ -191,27 +189,25 @@ TEST_F(AnimationAnimationPlayerTest, SetCurrentTimeMax) ...@@ -191,27 +189,25 @@ TEST_F(AnimationAnimationPlayerTest, SetCurrentTimeMax)
TEST_F(AnimationAnimationPlayerTest, SetCurrentTimeUnrestrictedDouble) TEST_F(AnimationAnimationPlayerTest, SetCurrentTimeUnrestrictedDouble)
{ {
updateTimeline(10); updateTimeline(10);
player->setCurrentTimeInternal(nullValue()); player->setCurrentTime(nullValue());
EXPECT_EQ(10, player->currentTimeInternal()); EXPECT_EQ(10, player->currentTimeInternal());
player->setCurrentTimeInternal(std::numeric_limits<double>::infinity()); player->setCurrentTime(std::numeric_limits<double>::infinity());
EXPECT_EQ(10, player->currentTimeInternal()); EXPECT_EQ(10, player->currentTimeInternal());
player->setCurrentTimeInternal(-std::numeric_limits<double>::infinity()); player->setCurrentTime(-std::numeric_limits<double>::infinity());
EXPECT_EQ(10, player->currentTimeInternal()); EXPECT_EQ(10, player->currentTimeInternal());
} }
TEST_F(AnimationAnimationPlayerTest, TimeLag)
TEST_F(AnimationAnimationPlayerTest, SetCurrentTimeSetsStartTime)
{ {
player->setCurrentTimeInternal(10); EXPECT_EQ(0, player->startTime());
EXPECT_EQ(-10, player->timeLagInternal()); player->setCurrentTime(1000);
updateTimeline(10); EXPECT_EQ(-1000, player->startTime());
EXPECT_EQ(-10, player->timeLagInternal()); updateTimeline(1);
player->setCurrentTimeInternal(40); EXPECT_EQ(-1000, player->startTime());
EXPECT_EQ(-30, player->timeLagInternal()); EXPECT_EQ(2000, player->currentTime());
updateTimeline(20);
EXPECT_EQ(-20, player->timeLagInternal());
} }
TEST_F(AnimationAnimationPlayerTest, SetStartTime) TEST_F(AnimationAnimationPlayerTest, SetStartTime)
{ {
updateTimeline(20); updateTimeline(20);
...@@ -246,6 +242,29 @@ TEST_F(AnimationAnimationPlayerTest, SetStartTimeOnLimitedAnimationPlayer) ...@@ -246,6 +242,29 @@ TEST_F(AnimationAnimationPlayerTest, SetStartTimeOnLimitedAnimationPlayer)
EXPECT_TRUE(player->finished()); EXPECT_TRUE(player->finished());
} }
TEST_F(AnimationAnimationPlayerTest, StartTimePauseFinish)
{
player->pause();
EXPECT_TRUE(std::isnan(player->startTime()));
player->finish(exceptionState);
EXPECT_TRUE(std::isnan(player->startTime()));
}
TEST_F(AnimationAnimationPlayerTest, StartTimeFinishPause)
{
double startTime = player->startTime();
player->finish(exceptionState);
EXPECT_EQ(startTime, player->startTime());
player->pause();
EXPECT_TRUE(std::isnan(player->startTime()));
}
TEST_F(AnimationAnimationPlayerTest, StartTimeWithZeroPlaybackRate)
{
player->setPlaybackRate(0);
EXPECT_TRUE(std::isnan(player->startTime()));
}
TEST_F(AnimationAnimationPlayerTest, SetStartTimeWhilePaused) TEST_F(AnimationAnimationPlayerTest, SetStartTimeWhilePaused)
{ {
updateTimeline(10); updateTimeline(10);
...@@ -257,7 +276,6 @@ TEST_F(AnimationAnimationPlayerTest, SetStartTimeWhilePaused) ...@@ -257,7 +276,6 @@ TEST_F(AnimationAnimationPlayerTest, SetStartTimeWhilePaused)
EXPECT_EQ(10, player->currentTimeInternal()); EXPECT_EQ(10, player->currentTimeInternal());
} }
TEST_F(AnimationAnimationPlayerTest, PausePlay) TEST_F(AnimationAnimationPlayerTest, PausePlay)
{ {
updateTimeline(10); updateTimeline(10);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment