Negative animation-delay is treated as 0s
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 25 Apr 2016 20:06:04 +0000 (20:06 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 25 Apr 2016 20:06:04 +0000 (20:06 +0000)
https://bugs.webkit.org/show_bug.cgi?id=141008

Reviewed by Daniel Bates.

Source/WebCore:

Fix keyframe animations which start in the paused state.

Explicitly move such animations from the new to the paused state, and
set m_pauseTime to 0, rather than leaving it at -1. Fix getElapsedTime()
to compute a correct time elapsed time for such animations, which takes
negative delay into account correctly.

Fix assertions which need to account for the new transition of New -> PlayStatePaused.

Test: animations/play-state-start-paused.html

* page/animation/AnimationBase.cpp:
(WebCore::AnimationBase::updateStateMachine):
(WebCore::AnimationBase::getElapsedTime):
* page/animation/KeyframeAnimation.cpp:
(WebCore::KeyframeAnimation::animate):

LayoutTests:

Ref test that has an initially-paused animation on 'left' and with a
3d transform.

* animations/play-state-start-paused-expected.html: Added.
* animations/play-state-start-paused.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@200042 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/animations/play-state-start-paused-expected.html [new file with mode: 0644]
LayoutTests/animations/play-state-start-paused.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/page/animation/AnimationBase.cpp
Source/WebCore/page/animation/KeyframeAnimation.cpp

index 4ef6da0..8f14f53 100644 (file)
@@ -1,3 +1,16 @@
+2016-04-25  Simon Fraser  <simon.fraser@apple.com>
+
+        Negative animation-delay is treated as 0s
+        https://bugs.webkit.org/show_bug.cgi?id=141008
+
+        Reviewed by Daniel Bates.
+        
+        Ref test that has an initially-paused animation on 'left' and with a
+        3d transform.
+
+        * animations/play-state-start-paused-expected.html: Added.
+        * animations/play-state-start-paused.html: Added.
+
 2016-04-25  Brady Eidson  <beidson@apple.com>
 
         Implement latest File object spec (including its constructor).
diff --git a/LayoutTests/animations/play-state-start-paused-expected.html b/LayoutTests/animations/play-state-start-paused-expected.html
new file mode 100644 (file)
index 0000000..f46660f
--- /dev/null
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <style>
+        .container {
+            height: 100px;
+            width: 500px;
+            margin: 4px;
+            border: 1px solid black;
+        }
+        .box {
+            position: relative;
+            width: 100px;
+            height: 100px;
+            background-color: green;
+        }
+        
+        .mover {
+            left: 200px;
+        }
+        
+        .slider {
+            transform: translate3d(200px, 0, 0);
+        }
+    </style>
+</head>
+<body>
+    <div class="container">
+        <div class="mover box"></div>
+    </div>
+    <div class="container">
+        <div class="slider box"></div>
+    </div>
+</body>
+</html>
diff --git a/LayoutTests/animations/play-state-start-paused.html b/LayoutTests/animations/play-state-start-paused.html
new file mode 100644 (file)
index 0000000..a2b3843
--- /dev/null
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <style>
+        .container {
+            height: 100px;
+            width: 500px;
+            margin: 4px;
+            border: 1px solid black;
+        }
+        .box {
+            position: relative;
+            width: 100px;
+            height: 100px;
+            background-color: green;
+            animation-delay: -0.5s;
+            animation-play-state: paused;
+        }
+        
+        /* For manual testing. */
+        .container:hover .box {
+            animation-play-state: running;
+        }
+        
+        .mover {
+            animation: move 1s linear;
+        }
+        
+        .slider {
+            animation: slide 1s linear;
+        }
+        
+        @keyframes move {
+            from { left: 0; }
+            to   { left: 400px; }
+        }
+
+        @keyframes slide {
+            from { transform: translate3d(0, 0, 0); }
+            to   { transform: translate3d(400px, 0, 0); }
+        }
+    </style>
+</head>
+<body>
+    <div class="container">
+        <div class="mover box"></div>
+    </div>
+    <div class="container">
+        <div class="slider box"></div>
+    </div>
+</body>
+</html>
index 8364528..047af58 100644 (file)
@@ -1,3 +1,27 @@
+2016-04-25  Simon Fraser  <simon.fraser@apple.com>
+
+        Negative animation-delay is treated as 0s
+        https://bugs.webkit.org/show_bug.cgi?id=141008
+
+        Reviewed by Daniel Bates.
+        
+        Fix keyframe animations which start in the paused state.
+        
+        Explicitly move such animations from the new to the paused state, and
+        set m_pauseTime to 0, rather than leaving it at -1. Fix getElapsedTime()
+        to compute a correct time elapsed time for such animations, which takes
+        negative delay into account correctly.
+        
+        Fix assertions which need to account for the new transition of New -> PlayStatePaused.
+
+        Test: animations/play-state-start-paused.html
+
+        * page/animation/AnimationBase.cpp:
+        (WebCore::AnimationBase::updateStateMachine):
+        (WebCore::AnimationBase::getElapsedTime):
+        * page/animation/KeyframeAnimation.cpp:
+        (WebCore::KeyframeAnimation::animate):
+
 2016-04-25  Antti Koivisto  <antti@apple.com>
 
         Inline RenderStyle into RenderElement
index 510949b..2448283 100644 (file)
@@ -219,6 +219,7 @@ void AnimationBase::updateStateMachine(AnimationStateInput input, double param)
                 // We are pausing before we even started.
                 LOG(Animations, "%p AnimationState %s -> AnimationState::PausedNew", this, nameForState(m_animationState));
                 m_animationState = AnimationState::PausedNew;
+                m_pauseTime = 0;
             }
 
 #if ENABLE(CSS_ANIMATIONS_LEVEL_2)
@@ -388,7 +389,7 @@ void AnimationBase::updateStateMachine(AnimationStateInput input, double param)
             // AnimationState::PausedWaitResponse, we don't yet have a valid startTime, so we send 0 to startAnimation.
             // When the AnimationStateInput::StartTimeSet comes in and we were in AnimationState::PausedRun, we will notice
             // that we have already set the startTime and will ignore it.
-            ASSERT(input == AnimationStateInput::PlayStateRunning || input == AnimationStateInput::StartTimeSet || input == AnimationStateInput::StyleAvailable || input == AnimationStateInput::StartAnimation);
+            ASSERT(input == AnimationStateInput::PlayStatePaused || input == AnimationStateInput::PlayStateRunning || input == AnimationStateInput::StartTimeSet || input == AnimationStateInput::StyleAvailable || input == AnimationStateInput::StartAnimation);
             ASSERT(paused());
 
             if (input == AnimationStateInput::PlayStateRunning) {
@@ -397,6 +398,7 @@ void AnimationBase::updateStateMachine(AnimationStateInput input, double param)
                     // to start, so jump back to the New state and reset.
                     LOG(Animations, "%p AnimationState %s -> AnimationState::New", this, nameForState(m_animationState));
                     m_animationState = AnimationState::New;
+                    m_pauseTime = -1;
                     updateStateMachine(input, param);
                     break;
                 }
@@ -406,6 +408,7 @@ void AnimationBase::updateStateMachine(AnimationStateInput input, double param)
                     m_startTime += beginAnimationUpdateTime() - m_pauseTime;
                 else
                     m_startTime = 0;
+
                 m_pauseTime = -1;
 
                 if (m_animationState == AnimationState::PausedWaitStyleAvailable) {
@@ -446,7 +449,7 @@ void AnimationBase::updateStateMachine(AnimationStateInput input, double param)
                 break;
             }
 
-            ASSERT(m_animationState == AnimationState::PausedWaitStyleAvailable);
+            ASSERT(m_animationState == AnimationState::PausedNew || m_animationState == AnimationState::PausedWaitStyleAvailable);
             // We are paused but we got the callback that notifies us that style has been updated.
             // We move to the AnimationState::PausedWaitResponse state
             LOG(Animations, "%p AnimationState %s -> PausedWaitResponse", this, nameForState(m_animationState));
@@ -741,10 +744,14 @@ double AnimationBase::getElapsedTime() const
     }
 #endif
 
-    if (paused())
-        return m_pauseTime - m_startTime;
+    if (paused()) {
+        double delayOffset = (!m_startTime && m_animation->delay() < 0) ? m_animation->delay() : 0;
+        return m_pauseTime - m_startTime - delayOffset;
+    }
+
     if (m_startTime <= 0)
         return 0;
+
     if (postActive() || fillingForwards())
         return m_totalDuration;
 
index 5333221..506dd1f 100644 (file)
@@ -131,8 +131,12 @@ bool KeyframeAnimation::animate(CompositeAnimation* compositeAnimation, RenderEl
     fireAnimationEventsIfNeeded();
     
     // If we have not yet started, we will not have a valid start time, so just start the animation if needed.
-    if (isNew() && m_animation->playState() == AnimPlayStatePlaying && !compositeAnimation->isSuspended())
-        updateStateMachine(AnimationStateInput::StartAnimation, -1);
+    if (isNew()) {
+        if (m_animation->playState() == AnimPlayStatePlaying && !compositeAnimation->isSuspended())
+            updateStateMachine(AnimationStateInput::StartAnimation, -1);
+        else if (m_animation->playState() == AnimPlayStatePaused)
+            updateStateMachine(AnimationStateInput::PlayStatePaused, -1);
+    }
 
     // If we get this far and the animation is done, it means we are cleaning up a just finished animation.
     // If so, we need to send back the targetStyle.