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() {
}, 'TimedItem.localTime and TimedItem.currentIteration are null when animation is not associated with a Player');
test(function() {
var animation = element.animate(keyframes, {fill: 'both', duration: 2, iterations: 3}).source;
animation.player.currentTime = -1;
assert_equals(animation.localTime, -1);
var animation = element.animate(keyframes, {fill: 'both', duration: 2000, iterations: 3}).source;
animation.player.currentTime = -1000;
assert_equals(animation.localTime, -1000, 'localTime');
assert_equals(animation.currentIteration, 0);
animation.player.currentTime = 1;
assert_equals(animation.localTime, 1);
animation.player.currentTime = 1000;
assert_equals(animation.localTime, 1000);
assert_equals(animation.currentIteration, 0);
animation.player.currentTime = 5;
assert_equals(animation.localTime, 5);
animation.player.currentTime = 5000;
assert_equals(animation.localTime, 5000);
assert_equals(animation.currentIteration, 2);
animation.player.currentTime = 7;
assert_equals(animation.localTime, 7);
animation.player.currentTime = 7000;
assert_equals(animation.localTime, 7000);
assert_equals(animation.currentIteration, 2);
}, 'TimedItem.localTime and TimedItem.currentIteration return reasonable values when an animation is in effect');
......
......@@ -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.
// 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)
m_eventDelegate->onEventCondition(this);
}
......
......@@ -61,7 +61,6 @@ AnimationPlayer::AnimationPlayer(ExecutionContext* executionContext, AnimationTi
, m_playbackRate(1)
, m_startTime(nullValue())
, m_holdTime(nullValue())
, m_storedTimeLag(0)
, m_sortInfo(nextSequenceNumber())
, m_content(content)
, m_timeline(&timeline)
......@@ -99,49 +98,46 @@ bool AnimationPlayer::limited(double currentTime) const
return (m_playbackRate < 0 && currentTime <= 0) || (m_playbackRate > 0 && currentTime >= sourceEnd());
}
double AnimationPlayer::currentTimeWithoutLag() const
{
if (isNull(m_startTime) || !m_timeline)
return 0;
return (m_timeline->effectiveTime() - m_startTime) * m_playbackRate;
}
double AnimationPlayer::currentTimeWithLag() const
void AnimationPlayer::setCurrentTimeInternal(double newCurrentTime)
{
ASSERT(!m_held);
double time = currentTimeWithoutLag();
return std::isinf(time) ? time : time - m_storedTimeLag;
}
ASSERT(std::isfinite(newCurrentTime));
void AnimationPlayer::updateTimingState(double newCurrentTime)
{
ASSERT(!isNull(newCurrentTime));
bool oldHeld = m_held;
bool outdated = false;
m_held = m_paused || !m_playbackRate || limited(newCurrentTime);
if (m_held) {
if (!oldHeld || m_holdTime != newCurrentTime)
setOutdated();
outdated = true;
m_holdTime = newCurrentTime;
m_storedTimeLag = nullValue();
if (m_paused || !m_playbackRate)
m_startTime = nullValue();
} else {
m_holdTime = nullValue();
m_storedTimeLag = currentTimeWithoutLag() - newCurrentTime;
m_startTime = m_timeline->effectiveTime() - newCurrentTime / m_playbackRate;
m_finished = false;
outdated = true;
}
if (outdated) {
setOutdated();
cancelAnimationOnCompositor();
if (!m_held)
schedulePendingAnimationOnCompositor();
}
}
// Update timing to reflect updated animation clock due to tick
void AnimationPlayer::updateCurrentTimingState()
{
if (m_held) {
updateTimingState(m_holdTime);
setCurrentTimeInternal(m_holdTime);
return;
}
if (!limited(currentTimeWithLag()))
if (!limited(calculateCurrentTime()))
return;
m_held = true;
m_holdTime = m_playbackRate < 0 ? 0 : sourceEnd();
m_storedTimeLag = nullValue();
}
double AnimationPlayer::currentTime()
......@@ -154,37 +150,41 @@ double AnimationPlayer::currentTimeInternal()
updateCurrentTimingState();
if (m_held)
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))
return;
updateTimingState(newCurrentTime);
cancelAnimationOnCompositor();
schedulePendingAnimationOnCompositor();
setCurrentTimeInternal(newCurrentTime / 1000);
}
void AnimationPlayer::setStartTimeInternal(double newStartTime, bool isUpdateFromCompositor)
{
ASSERT(!isUpdateFromCompositor || !hasStartTime());
if (m_paused)
return;
if (!std::isfinite(newStartTime))
return;
if (newStartTime == m_startTime)
return;
updateCurrentTimingState(); // Update the value of held
bool hadStartTime = hasStartTime();
double previousCurrentTime = currentTimeInternal();
m_startTime = newStartTime;
updateCurrentTimingState();
if (previousCurrentTime != currentTimeInternal()) {
double newCurrentTime = currentTimeInternal();
if (previousCurrentTime != newCurrentTime) {
setOutdated();
} else if (!hadStartTime && m_timeline) {
// Even though this player is not outdated, time to effect change is
......@@ -212,7 +212,7 @@ void AnimationPlayer::setSource(AnimationNode* newSource)
newSource->player()->cancel();
newSource->attach(this);
}
updateTimingState(storedCurrentTime);
setCurrentTimeInternal(storedCurrentTime);
schedulePendingAnimationOnCompositor();
}
......@@ -221,7 +221,7 @@ void AnimationPlayer::pause()
if (m_paused)
return;
m_paused = true;
updateTimingState(currentTimeInternal());
setCurrentTimeInternal(currentTimeInternal());
cancelAnimationOnCompositor();
}
......@@ -230,14 +230,12 @@ void AnimationPlayer::unpause()
if (!m_paused)
return;
m_paused = false;
updateTimingState(currentTimeInternal());
schedulePendingAnimationOnCompositor();
setCurrentTimeInternal(currentTimeInternal());
}
void AnimationPlayer::play()
{
cancelAnimationOnCompositor();
// Note, unpause schedules pending animation on compositor if necessary.
unpause();
if (!m_content)
return;
......@@ -260,8 +258,6 @@ void AnimationPlayer::reverse()
setCurrentTimeInternal(0);
}
setPlaybackRate(-m_playbackRate);
cancelAnimationOnCompositor();
// Note, unpause schedules pending animation on compositor if necessary.
unpause();
}
......@@ -279,7 +275,6 @@ void AnimationPlayer::finish(ExceptionState& exceptionState)
setCurrentTimeInternal(sourceEnd());
}
ASSERT(finished());
cancelAnimationOnCompositor();
}
const AtomicString& AnimationPlayer::interfaceName() const
......@@ -318,9 +313,7 @@ void AnimationPlayer::setPlaybackRate(double playbackRate)
if ((m_playbackRate < 0 && playbackRate >= 0) || (m_playbackRate > 0 && playbackRate <= 0))
m_finished = false;
m_playbackRate = playbackRate;
updateTimingState(storedCurrentTime);
cancelAnimationOnCompositor();
schedulePendingAnimationOnCompositor();
setCurrentTimeInternal(storedCurrentTime);
}
void AnimationPlayer::setOutdated()
......@@ -344,7 +337,7 @@ bool AnimationPlayer::maybeStartAnimationOnCompositor()
if (!canStartAnimationOnCompositor())
return false;
return toAnimation(m_content.get())->maybeStartAnimationOnCompositor(timeline()->zeroTime() + startTimeInternal() + timeLagInternal());
return toAnimation(m_content.get())->maybeStartAnimationOnCompositor(timeline()->zeroTime() + startTimeInternal());
}
void AnimationPlayer::schedulePendingAnimationOnCompositor()
......@@ -371,11 +364,12 @@ void AnimationPlayer::cancelAnimationOnCompositor()
bool AnimationPlayer::update(TimingUpdateReason reason)
{
m_outdated = false;
if (!m_timeline)
return false;
updateCurrentTimingState();
m_outdated = false;
if (m_content) {
double inheritedTime = isNull(m_timeline->currentTimeInternal()) ? nullValue() : currentTimeInternal();
m_content->updateInheritedTime(inheritedTime, reason);
......@@ -432,7 +426,7 @@ bool AnimationPlayer::addEventListener(const AtomicString& eventType, PassRefPtr
void AnimationPlayer::pauseForTesting(double pauseTime)
{
RELEASE_ASSERT(!paused());
updateTimingState(pauseTime);
setCurrentTimeInternal(pauseTime);
if (!m_isPausedForTesting && hasActiveAnimationsOnCompositor())
toAnimation(m_content.get())->pauseAnimationForTestingOnCompositor(currentTimeInternal());
m_isPausedForTesting = true;
......
......@@ -65,6 +65,7 @@ public:
double currentTime();
void setCurrentTime(double newCurrentTime);
double calculateCurrentTime() const;
double currentTimeInternal();
void setCurrentTimeInternal(double newCurrentTime);
......@@ -105,9 +106,6 @@ public:
AnimationNode* source() { return m_content.get(); }
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
// paused() and must never overlap with pausing via pause().
void pauseForTesting(double pauseTime);
......@@ -159,15 +157,11 @@ private:
AnimationPlayer(ExecutionContext*, AnimationTimeline&, AnimationNode*);
double sourceEnd() const;
bool limited(double currentTime) const;
double currentTimeWithoutLag() const;
double currentTimeWithLag() const;
void updateTimingState(double newCurrentTime);
void updateCurrentTimingState();
double m_playbackRate;
double m_startTime;
double m_holdTime;
double m_storedTimeLag;
SortInfo m_sortInfo;
......@@ -178,8 +172,8 @@ private:
bool m_held;
bool m_isPausedForTesting;
// This indicates timing information relevant to the player has changed by
// means other than the ordinary progression of time
// This indicates timing information relevant to the player's effect
// has changed by means other than the ordinary progression of time
bool m_outdated;
bool m_finished;
......
......@@ -37,7 +37,6 @@
[RuntimeEnabled=WebAnimationsAPI] attribute AnimationNode? source;
[RuntimeEnabled=WebAnimationsAPI] attribute double startTime;
[RuntimeEnabled=WebAnimationsAPI] attribute double currentTime;
[RuntimeEnabled=WebAnimationsAPI] readonly attribute double timeLag;
[RuntimeEnabled=WebAnimationsAPI] attribute double playbackRate;
[RuntimeEnabled=WebAnimationsAPI] readonly attribute boolean paused;
[RuntimeEnabled=WebAnimationsAPI] readonly attribute boolean finished;
......
......@@ -95,7 +95,6 @@ TEST_F(AnimationAnimationPlayerTest, InitialState)
EXPECT_EQ(0, player->currentTimeInternal());
EXPECT_FALSE(player->paused());
EXPECT_EQ(1, player->playbackRate());
EXPECT_EQ(0, player->timeLagInternal());
EXPECT_FALSE(player->hasStartTime());
EXPECT_TRUE(isNull(player->startTimeInternal()));
......@@ -106,7 +105,6 @@ TEST_F(AnimationAnimationPlayerTest, InitialState)
EXPECT_FALSE(player->paused());
EXPECT_EQ(1, player->playbackRate());
EXPECT_EQ(0, player->startTimeInternal());
EXPECT_EQ(0, player->timeLagInternal());
EXPECT_TRUE(player->hasStartTime());
}
......@@ -191,27 +189,25 @@ TEST_F(AnimationAnimationPlayerTest, SetCurrentTimeMax)
TEST_F(AnimationAnimationPlayerTest, SetCurrentTimeUnrestrictedDouble)
{
updateTimeline(10);
player->setCurrentTimeInternal(nullValue());
player->setCurrentTime(nullValue());
EXPECT_EQ(10, player->currentTimeInternal());
player->setCurrentTimeInternal(std::numeric_limits<double>::infinity());
player->setCurrentTime(std::numeric_limits<double>::infinity());
EXPECT_EQ(10, player->currentTimeInternal());
player->setCurrentTimeInternal(-std::numeric_limits<double>::infinity());
player->setCurrentTime(-std::numeric_limits<double>::infinity());
EXPECT_EQ(10, player->currentTimeInternal());
}
TEST_F(AnimationAnimationPlayerTest, TimeLag)
TEST_F(AnimationAnimationPlayerTest, SetCurrentTimeSetsStartTime)
{
player->setCurrentTimeInternal(10);
EXPECT_EQ(-10, player->timeLagInternal());
updateTimeline(10);
EXPECT_EQ(-10, player->timeLagInternal());
player->setCurrentTimeInternal(40);
EXPECT_EQ(-30, player->timeLagInternal());
updateTimeline(20);
EXPECT_EQ(-20, player->timeLagInternal());
EXPECT_EQ(0, player->startTime());
player->setCurrentTime(1000);
EXPECT_EQ(-1000, player->startTime());
updateTimeline(1);
EXPECT_EQ(-1000, player->startTime());
EXPECT_EQ(2000, player->currentTime());
}
TEST_F(AnimationAnimationPlayerTest, SetStartTime)
{
updateTimeline(20);
......@@ -246,6 +242,29 @@ TEST_F(AnimationAnimationPlayerTest, SetStartTimeOnLimitedAnimationPlayer)
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)
{
updateTimeline(10);
......@@ -257,7 +276,6 @@ TEST_F(AnimationAnimationPlayerTest, SetStartTimeWhilePaused)
EXPECT_EQ(10, player->currentTimeInternal());
}
TEST_F(AnimationAnimationPlayerTest, PausePlay)
{
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