Fixed https://bugs.webkit.org/show_bug.cgi?id=22870
authorcmarrin@apple.com <cmarrin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 7 Jan 2009 00:35:51 +0000 (00:35 +0000)
committercmarrin@apple.com <cmarrin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 7 Jan 2009 00:35:51 +0000 (00:35 +0000)
        I added calls beginAnimationUpdate() and endAnimationUpdate() calls
        to AnimationController. These are called by Document at the start
        and end of the recalcStyle cycle. Right now, I'm just using the
        beginAnimationUpdate() method to reset an animation time value.
        The first time the animation time is accessed after this reset I set
        it to the currentTime. So all animations in that cycle get the same
        start time.

        The test cases checked in test this, but in the case of the 'left'
        test it actually doesn't make any difference in most cases. This is
        because values are clamped to whole pixels, so the start times would
        have to be pretty far off for the test to fail using the old
        currentTime() model. Still, under really heavy load, it's possible for
        the test to fail without these changes.

        The 'transform' test is another story. It animates to the full resolution
        of a floating point number, so the test fails miserably without this
        fix.

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

13 files changed:
LayoutTests/ChangeLog
LayoutTests/animations/animation-test-helpers.js
LayoutTests/animations/simultaneous-start-left-expected.txt [new file with mode: 0644]
LayoutTests/animations/simultaneous-start-left.html [new file with mode: 0644]
LayoutTests/animations/simultaneous-start-transform-expected.txt [new file with mode: 0644]
LayoutTests/animations/simultaneous-start-transform.html [new file with mode: 0644]
WebCore/ChangeLog
WebCore/dom/Document.cpp
WebCore/page/animation/AnimationBase.cpp
WebCore/page/animation/AnimationBase.h
WebCore/page/animation/AnimationController.cpp
WebCore/page/animation/AnimationController.h
WebCore/page/animation/KeyframeAnimation.cpp

index eacf8ab..244210c 100644 (file)
@@ -1,3 +1,15 @@
+2009-01-06  Chris Marrin  <cmarrin@apple.com>
+
+        Reviewed by David Hyatt.
+
+        * animations/animation-test-helpers.js:
+        (runAnimationTest.matrixStringToArray):
+        (runAnimationTest.checkExpectedValue):
+        * animations/simultaneous-start-left-expected.txt: Added.
+        * animations/simultaneous-start-left.html: Added.
+        * animations/simultaneous-start-transform-expected.txt: Added.
+        * animations/simultaneous-start-transform.html: Added.
+
 2009-01-06  Dean Jackson  <dino@apple.com>
 
         Reviewed by Dave Hyatt.
index 464fd97..a331286 100644 (file)
@@ -12,15 +12,19 @@ Function parameters:
     Each sub-array must contain these items in this order:
     - the name of the CSS animation (may be null) [1]
     - the time in seconds at which to snapshot the CSS property
-    - the id of the element on which to get the CSS property value
-    - the name of the CSS property to get [2]
+    - the id of the element on which to get the CSS property value [2]
+    - the name of the CSS property to get [3]
     - the expected value for the CSS property
     - the tolerance to use when comparing the effective CSS property value with its expected value
 
     [1] If null is passed, a regular setTimeout() will be used instead to snapshot the animated property in the future,
-    instead of fast forwarding using the pauseAnimationAtTimeOnElementWithId() JS API from DRT 
+    instead of fast forwarding using the pauseAnimationAtTimeOnElementWithId() JS API from DRT
+    
+    [2] If a single string is passed, it is the id of the element to test. If an array with 2 elements is passed they
+    are the ids of 2 elements, whose values are compared for equality. In this case the expected value is ignored
+    but the tolerance is used in the comparison.
 
-    [2] If the CSS property name is "webkitTransform", expected value must be an array of 1 or more numbers corresponding to the matrix elements,
+    [3] If the CSS property name is "webkitTransform", expected value must be an array of 1 or more numbers corresponding to the matrix elements,
     or a string which will be compared directly (useful if the expected value is "none")
     If the CSS property name is "webkitTransform.N", expected value must be a number corresponding to the Nth element of the matrix
 
@@ -35,7 +39,14 @@ function runAnimationTest(expected, callback, event)
         var diff = Math.abs(actual - desired);
         return diff <= tolerance;
     }
-
+    
+    function matrixStringToArray(s)
+    {
+        var m = s.split("(");
+        m = m[1].split(")");
+        return m[0].split(",");
+    }
+    
     function checkExpectedValue(expected, index)
     {
         var animationName = expected[index][0];
@@ -45,44 +56,90 @@ function runAnimationTest(expected, callback, event)
         var expectedValue = expected[index][4];
         var tolerance = expected[index][5];
 
+        // Check for a pair of element Ids
+        var compareElements = false;
+        var elementId2;
+        if (typeof elementId != "string") {
+            if (elementId.length != 2)
+                return;
+                
+            elementId2 = elementId[1];
+            elementId = elementId[0];
+            compareElements = true;
+        }
+
         if (animationName && hasPauseAnimationAPI && !layoutTestController.pauseAnimationAtTimeOnElementWithId(animationName, time, elementId)) {
             result += "FAIL - animation \"" + animationName + "\" is not running" + "<br>";
             return;
         }
-
-        var computedValue;
-        var pass;
+        
+        if (compareElements && animationName && hasPauseAnimationAPI && !layoutTestController.pauseAnimationAtTimeOnElementWithId(animationName, time, elementId2)) {
+            result += "FAIL - animation \"" + animationName + "\" is not running" + "<br>";
+            return;
+        }
+        
+        var computedValue, computedValue2;
+        var pass = true;
         if (!property.indexOf("webkitTransform")) {
             computedValue = window.getComputedStyle(document.getElementById(elementId)).webkitTransform;
-
-            if (typeof expectedValue == "string")
-                pass = (computedValue == expectedValue);
-            else if (typeof expectedValue == "number") {
-                var m = computedValue.split("(");
-                var m = m[1].split(",");
-                pass = isCloseEnough(parseFloat(m[parseInt(property.substring(16))]), expectedValue, tolerance);
-            } else {
-                var m = computedValue.split("(");
-                var m = m[1].split(",");
-                for (i = 0; i < expectedValue.length; ++i) {
-                    pass = isCloseEnough(parseFloat(m[i]), expectedValue[i], tolerance);
+            if (compareElements) {
+                computedValue2 = window.getComputedStyle(document.getElementById(elementId2)).webkitTransform;
+                var m1 = matrixStringToArray(computedValue);
+                var m2 = matrixStringToArray(computedValue2);
+                
+                // for now we assume that both matrices are either both 2D or both 3D
+                var count = (computedValue.substring(0, 7) == "matrix3d") ? 16 : 6;
+                for (var i = 0; i < count; ++i) {
+                    pass = isCloseEnough(parseFloat(m1[i]), m2[i], tolerance);
                     if (!pass)
                         break;
+                }                
+            } else {
+                if (typeof expectedValue == "string")
+                    pass = (computedValue == expectedValue);
+                else if (typeof expectedValue == "number") {
+                    var m = matrixStringToArray(computedValue);
+                    pass = isCloseEnough(parseFloat(m[parseInt(property.substring(16))]), expectedValue, tolerance);
+                } else {
+                    var m = matrixStringToArray(computedValue);
+                    for (i = 0; i < expectedValue.length; ++i) {
+                        pass = isCloseEnough(parseFloat(m[i]), expectedValue[i], tolerance);
+                        if (!pass)
+                            break;
+                    }
                 }
             }
         } else if (property == "lineHeight") {
             computedValue = parseInt(window.getComputedStyle(document.getElementById(elementId)).lineHeight);
-            pass = isCloseEnough(computedValue, expectedValue, tolerance);
-        } else {    
+            if (compareElements) {
+                computedValue2 = parseInt(window.getComputedStyle(document.getElementById(elementId2)).lineHeight);
+                pass = isCloseEnough(computedValue, computedValue2, tolerance);
+            }
+            else
+                pass = isCloseEnough(computedValue, expectedValue, tolerance);
+        } else {
             var computedStyle = window.getComputedStyle(document.getElementById(elementId)).getPropertyCSSValue(property);
             computedValue = computedStyle.getFloatValue(CSSPrimitiveValue.CSS_NUMBER);
-            pass = isCloseEnough(computedValue, expectedValue, tolerance);
+            if (compareElements) {
+                var computedStyle2 = window.getComputedStyle(document.getElementById(elementId2)).getPropertyCSSValue(property);
+                computedValue2 = computedStyle2.getFloatValue(CSSPrimitiveValue.CSS_NUMBER);
+                pass = isCloseEnough(computedValue, computedValue2, tolerance);
+            }
+            else
+                pass = isCloseEnough(computedValue, expectedValue, tolerance);
         }
 
-        if (pass)
-            result += "PASS - \"" + property + "\" property for \"" + elementId + "\" element at " + time + "s saw something close to: " + expectedValue + "<br>";
-        else
-            result += "FAIL - \"" + property + "\" property for \"" + elementId + "\" element at " + time + "s expected: " + expectedValue + " but saw: " + computedValue + "<br>";
+        if (compareElements) {
+            if (pass)
+                result += "PASS - \"" + property + "\" property for \"" + elementId + "\" and \"" + elementId2 + "\" elements at " + time + "s are close enough to each other" + "<br>";
+            else
+                result += "FAIL - \"" + property + "\" property for \"" + elementId + "\" and \"" + elementId2 + "\" elements at " + time + "s saw: \"" + computedValue + "\" and \"" + computedValue2 + "\" which are not close enough to each other" + "<br>";
+        } else {
+            if (pass)
+                result += "PASS - \"" + property + "\" property for \"" + elementId + "\" element at " + time + "s saw something close to: " + expectedValue + "<br>";
+            else
+                result += "FAIL - \"" + property + "\" property for \"" + elementId + "\" element at " + time + "s expected: " + expectedValue + " but saw: " + computedValue + "<br>";
+        }
     }
 
     function endTest()
diff --git a/LayoutTests/animations/simultaneous-start-left-expected.txt b/LayoutTests/animations/simultaneous-start-left-expected.txt
new file mode 100644 (file)
index 0000000..0fa9d09
--- /dev/null
@@ -0,0 +1,11 @@
+This test performs an animation of the left property. It animates over 10 seconds. It takes 3 snapshots and expects each result to be within a specified range.
+PASS - "left" property for "box1" element at 2s saw something close to: 170
+PASS - "left" property for "box2" element at 2s saw something close to: 170
+PASS - "left" property for "box1" and "box2" elements at 2s are close enough to each other
+PASS - "left" property for "box1" element at 5s saw something close to: 410
+PASS - "left" property for "box2" element at 5s saw something close to: 410
+PASS - "left" property for "box1" and "box2" elements at 5s are close enough to each other
+PASS - "left" property for "box1" element at 8s saw something close to: 650
+PASS - "left" property for "box2" element at 8s saw something close to: 650
+PASS - "left" property for "box1" and "box2" elements at 8s are close enough to each other
+
diff --git a/LayoutTests/animations/simultaneous-start-left.html b/LayoutTests/animations/simultaneous-start-left.html
new file mode 100644 (file)
index 0000000..20b7368
--- /dev/null
@@ -0,0 +1,62 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+   "http://www.w3.org/TR/html4/loose.dtd">
+
+<html lang="en">
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <title>Test simultaneous starting of two animations</title>
+  <style type="text/css" media="screen">
+    .box {
+      position: relative;
+      left: 100px;
+      height: 100px;
+      width: 100px;
+      background-color: blue;
+      -webkit-animation-duration: 10s;
+      -webkit-animation-timing-function: linear;
+      -webkit-animation-name: "anim";
+    }
+    @-webkit-keyframes "anim" {
+        from { left: 10px; }
+        to   { left: 810px; }
+    }
+    #box1 {
+        top: 10px;
+        background-color: blue;
+    }
+    #box2 {
+        top: 10px;
+        background-color: red;
+    }
+  </style>
+  <script src="animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
+  <script type="text/javascript" charset="utf-8">
+
+    const expectedValues = [
+      // [animation-name, time, element-id, property, expected-value, tolerance]
+      ["anim", 2, "box1", "left", 170, 5],
+      ["anim", 2, "box2", "left", 170, 5],
+      ["anim", 2, ["box1", "box2"], "left", "", 0],
+      ["anim", 5, "box1", "left", 410, 5],
+      ["anim", 5, "box2", "left", 410, 5],
+      ["anim", 5, ["box1", "box2"], "left", "", 0],
+      ["anim", 8, "box1", "left", 650, 5],
+      ["anim", 8, "box2", "left", 650, 5],
+      ["anim", 8, ["box1", "box2"], "left", "", 0],
+    ];
+    
+    runAnimationTest(expectedValues);
+    
+  </script>
+</head>
+<body>
+This test performs an animation of the left property. It animates over 10 seconds.
+It takes 3 snapshots and expects each result to be within a specified range.
+<div id="box1" class="box">
+</div>
+<div id="box2" class="box">
+</div>
+<div id="result">
+</div>
+</body>
+</html>
diff --git a/LayoutTests/animations/simultaneous-start-transform-expected.txt b/LayoutTests/animations/simultaneous-start-transform-expected.txt
new file mode 100644 (file)
index 0000000..d9e8722
--- /dev/null
@@ -0,0 +1,10 @@
+This test performs an animation of the transform property. It animates over 10 seconds. It takes 3 snapshots and expects each result to be within a specified range. PASS - "webkitTransform" property for "box1" element at 2s saw something close to: 0.309017,0.951057
+PASS - "webkitTransform" property for "box2" element at 2s saw something close to: 0.309017,0.951057
+PASS - "webkitTransform" property for "box1" and "box2" elements at 2s are close enough to each other
+PASS - "webkitTransform" property for "box1" element at 5s saw something close to: -1,0
+PASS - "webkitTransform" property for "box2" element at 5s saw something close to: -1,0
+PASS - "webkitTransform" property for "box1" and "box2" elements at 5s are close enough to each other
+PASS - "webkitTransform" property for "box1" element at 8s saw something close to: 0.309017,-0.951057
+PASS - "webkitTransform" property for "box2" element at 8s saw something close to: 0.309017,-0.951057
+PASS - "webkitTransform" property for "box1" and "box2" elements at 8s are close enough to each other
+
diff --git a/LayoutTests/animations/simultaneous-start-transform.html b/LayoutTests/animations/simultaneous-start-transform.html
new file mode 100644 (file)
index 0000000..adf4197
--- /dev/null
@@ -0,0 +1,62 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+   "http://www.w3.org/TR/html4/loose.dtd">
+
+<html lang="en">
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <title>Test simultaneous starting of two animations</title>
+  <style type="text/css" media="screen">
+    .box {
+      position: absolute;
+      top: 40px;
+      height: 100px;
+      width: 100px;
+      background-color: blue;
+      -webkit-animation-duration: 10s;
+      -webkit-animation-timing-function: linear;
+      -webkit-animation-name: "anim";
+    }
+    @-webkit-keyframes "anim" {
+        from { -webkit-transform: rotate(0deg); }
+        to   { -webkit-transform: rotate(360deg); }
+    }
+    #box1 {
+        left: 40px;
+        background-color: blue;
+    }
+    #box2 {
+        left: 160px;
+        background-color: red;
+    }
+  </style>
+  <script src="animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
+  <script type="text/javascript" charset="utf-8">
+
+    const expectedValues = [
+      // [animation-name, time, element-id, property, expected-value, tolerance]
+      ["anim", 2, "box1", "webkitTransform", [ 0.309017, 0.951057 ], 0.05],
+      ["anim", 2, "box2", "webkitTransform", [ 0.309017, 0.951057 ], 0.05],
+      ["anim", 2, ["box1", "box2"], "webkitTransform", "", 0],
+      ["anim", 5, "box1", "webkitTransform", [ -1, 0 ], 0.05],
+      ["anim", 5, "box2", "webkitTransform", [ -1, 0 ], 0.05],
+      ["anim", 5, ["box1", "box2"], "webkitTransform", "", 0],
+      ["anim", 8, "box1", "webkitTransform", [ 0.309017, -0.951057 ], 0.05],
+      ["anim", 8, "box2", "webkitTransform", [ 0.309017, -0.951057 ], 0.05],
+      ["anim", 8, ["box1", "box2"], "webkitTransform", "", 0],
+    ];
+    
+    runAnimationTest(expectedValues);
+    
+  </script>
+</head>
+<body>
+This test performs an animation of the transform property. It animates over 10 seconds.
+It takes 3 snapshots and expects each result to be within a specified range.
+<div id="box1" class="box">
+</div>
+<div id="box2" class="box">
+</div>
+<div id="result" style="position:absolute; top:150px">
+</div>
+</body>
+</html>
index bd2ecfc..d0626aa 100644 (file)
@@ -1,3 +1,53 @@
+2009-01-06  Chris Marrin  <cmarrin@apple.com>
+
+        Reviewed by David Hyatt.
+
+        Tests: animations/simultaneous-start-left.html
+               animations/simultaneous-start-transform.html
+
+        Fixed https://bugs.webkit.org/show_bug.cgi?id=22870
+        I added calls beginAnimationUpdate() and endAnimationUpdate() calls
+        to AnimationController. These are called by Document at the start
+        and end of the recalcStyle cycle. Right now, I'm just using the 
+        beginAnimationUpdate() method to reset an animation time value.
+        The first time the animation time is accessed after this reset I set
+        it to the currentTime. So all animations in that cycle get the same
+        start time. 
+
+        The test cases checked in test this, but in the case of the 'left'
+        test it actually doesn't make any difference in most cases. This is
+        because values are clamped to whole pixels, so the start times would 
+        have to be pretty far off for the test to fail using the old
+        currentTime() model. Still, under really heavy load, it's possible for
+        the test to fail without these changes.
+
+        The 'transform' test is another story. It animates to the full resolution
+        of a floating point number, so the test fails miserably without this
+        fix.
+
+        * dom/Document.cpp:
+        (WebCore::Document::recalcStyle):
+        * page/animation/AnimationBase.cpp:
+        (WebCore::AnimationBase::updateStateMachine):
+        (WebCore::AnimationBase::fireAnimationEventsIfNeeded):
+        (WebCore::AnimationBase::willNeedService):
+        (WebCore::AnimationBase::progress):
+        (WebCore::AnimationBase::goIntoEndingOrLoopingState):
+        (WebCore::AnimationBase::beginAnimationUpdateTime):
+        * page/animation/AnimationBase.h:
+        * page/animation/AnimationController.cpp:
+        (WebCore::AnimationControllerPrivate::beginAnimationUpdateTime):
+        (WebCore::AnimationControllerPrivate::setBeginAnimationUpdateTime):
+        (WebCore::AnimationControllerPrivate::AnimationControllerPrivate):
+        (WebCore::AnimationController::updateAnimations):
+        (WebCore::AnimationController::beginAnimationUpdateTime):
+        (WebCore::AnimationController::beginAnimationUpdate):
+        (WebCore::AnimationController::endAnimationUpdate):
+        * page/animation/AnimationController.h:
+        * page/animation/KeyframeAnimation.cpp:
+        (WebCore::KeyframeAnimation::animate):
+
 2009-01-06  Julien Chaffraix  <jchaffraix@webkit.org>
 
         Reviewed by Nikolas Zimmermann.
index 481d0f9..4b43c42 100644 (file)
@@ -1104,7 +1104,9 @@ void Document::recalcStyle(StyleChange change)
     
     if (m_inStyleRecalc)
         return; // Guard against re-entrancy. -dwh
-        
+    
+    m_frame->animation()->beginAnimationUpdate();
+
     m_inStyleRecalc = true;
     suspendPostAttachCallbacks();
     
@@ -1169,6 +1171,8 @@ bail_out:
         m_closeAfterStyleRecalc = false;
         implicitClose();
     }
+    
+    m_frame->animation()->endAnimationUpdate();
 }
 
 void Document::updateRendering()
index 471ffe6..c8b468d 100644 (file)
@@ -533,7 +533,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param)
             // If we are in AnimationStateStartWaitResponse, the animation will get canceled before 
             // we get a response, so move to the next state.
             endAnimation(false);
-            updateStateMachine(AnimationStateInputStartTimeSet, currentTime());
+            updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime());
         }
         return;
     }
@@ -552,7 +552,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param)
             ASSERT(input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunnning || input == AnimationStateInputPlayStatePaused);
             if (input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunnning) {
                 m_waitedForResponse = false;
-                m_requestedStartTime = currentTime();
+                m_requestedStartTime = beginAnimationUpdateTime();
                 m_animState = AnimationStateStartWaitTimer;
             }
             break;
@@ -571,7 +571,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param)
             } else {
                 ASSERT(!paused());
                 // We're waiting for the start timer to fire and we got a pause. Cancel the timer, pause and wait
-                m_pauseTime = currentTime();
+                m_pauseTime = beginAnimationUpdateTime();
                 m_animState = AnimationStatePausedWaitTimer;
             }
             break;
@@ -592,7 +592,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param)
             if (overridden() || !startAnimation(0)) {
                 // We're not going to get a startTime callback, so fire the start time here
                 m_animState = AnimationStateStartWaitResponse;
-                updateStateMachine(AnimationStateInputStartTimeSet, currentTime());
+                updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime());
             } else
                 m_waitedForResponse = true;
             break;
@@ -633,7 +633,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param)
                 goIntoEndingOrLoopingState();
             } else {
                 // We are pausing while running. Cancel the animation and wait
-                m_pauseTime = currentTime();
+                m_pauseTime = beginAnimationUpdateTime();
                 endAnimation(false);
                 m_animState = AnimationStatePausedRun;
             }
@@ -657,7 +657,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param)
                 }
             } else {
                 // We are pausing while running. Cancel the animation and wait
-                m_pauseTime = currentTime();
+                m_pauseTime = beginAnimationUpdateTime();
                 endAnimation(false);
                 m_animState = AnimationStatePausedRun;
             }
@@ -667,7 +667,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param)
             ASSERT(input == AnimationStateInputPlayStateRunnning);
             ASSERT(paused());
             // Update the times
-            m_startTime += currentTime() - m_pauseTime;
+            m_startTime += beginAnimationUpdateTime() - m_pauseTime;
             m_pauseTime = -1;
 
             // we were waiting for the start timer to fire, go back and wait again
@@ -684,7 +684,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param)
             ASSERT(paused());
             // Update the times
             if (m_animState == AnimationStatePausedRun)
-                m_startTime += currentTime() - m_pauseTime;
+                m_startTime += beginAnimationUpdateTime() - m_pauseTime;
             else
                 m_startTime = 0;
             m_pauseTime = -1;
@@ -695,7 +695,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param)
             // Start the animation
             if (overridden() || !startAnimation(m_startTime)) {
                 // We're not going to get a startTime callback, so fire the start time here
-                updateStateMachine(AnimationStateInputStartTimeSet, currentTime());
+                updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime());
             } else
                 m_waitedForResponse = true;
             break;
@@ -720,12 +720,12 @@ void AnimationBase::fireAnimationEventsIfNeeded()
     
     // Check for start timeout
     if (m_animState == AnimationStateStartWaitTimer) {
-        if (currentTime() - m_requestedStartTime >= m_animation->delay())
+        if (beginAnimationUpdateTime() - m_requestedStartTime >= m_animation->delay())
             updateStateMachine(AnimationStateInputStartTimerFired, 0);
         return;
     }
     
-    double elapsedDuration = currentTime() - m_startTime;
+    double elapsedDuration = beginAnimationUpdateTime() - m_startTime;
     ASSERT(elapsedDuration >= 0);
     
     // Check for end timeout
@@ -767,7 +767,7 @@ double AnimationBase::willNeedService() const
         return -1;
         
     if (m_animState == AnimationStateStartWaitTimer) {
-        double timeFromNow = m_animation->delay() - (currentTime() - m_requestedStartTime);
+        double timeFromNow = m_animation->delay() - (beginAnimationUpdateTime() - m_requestedStartTime);
         return (float) ((timeFromNow > 0) ? timeFromNow : 0);
     }
     
@@ -780,7 +780,7 @@ double AnimationBase::progress(double scale, double offset, const TimingFunction
     if (preActive())
         return 0;
 
-    double elapsedTime = running() && !paused() ? (currentTime() - m_startTime) : (m_pauseTime - m_startTime);
+    double elapsedTime = running() && !paused() ? (beginAnimationUpdateTime() - m_startTime) : (m_pauseTime - m_startTime);
     if (running() && elapsedTime < 0)
         return 0;
 
@@ -826,7 +826,7 @@ void AnimationBase::goIntoEndingOrLoopingState()
     if (m_animation->iterationCount() > 0)
         totalDuration = m_animation->duration() * m_animation->iterationCount();
 
-    const double elapsedDuration = currentTime() - m_startTime;
+    const double elapsedDuration = beginAnimationUpdateTime() - m_startTime;
     ASSERT(elapsedDuration >= 0);
     double durationLeft = 0;
     double nextIterationTime = totalDuration;
@@ -852,4 +852,9 @@ void AnimationBase::pauseAtTime(double t)
     m_pauseTime = m_startTime + t - m_animation->delay();
 }
 
+double AnimationBase::beginAnimationUpdateTime() const
+{
+    return m_compAnim->animationController()->beginAnimationUpdateTime();
+}
+
 } // namespace WebCore
index 23502d7..3a5cb85 100644 (file)
@@ -153,6 +153,8 @@ public:
     
     void pauseAtTime(double t);
     
+    double beginAnimationUpdateTime() const;
+    
 protected:
     virtual void overrideAnimations() { }
     virtual void resumeOverriddenAnimations() { }
index d05d482..7e4a894 100644 (file)
 #include "CSSParser.h"
 #include "EventNames.h"
 #include "Frame.h"
+#include "SystemTime.h"
 #include "Timer.h"
 
 namespace WebCore {
 
 static const double cAnimationTimerDelay = 0.025;
+static const double cBeginAnimationUpdateTimeNotSet = -1;
 
 class AnimationControllerPrivate {
 public:
@@ -65,6 +67,15 @@ public:
     bool pauseAnimationAtTime(RenderObject*, const String& name, double t);
     bool pauseTransitionAtTime(RenderObject*, const String& property, double t);
 
+    double beginAnimationUpdateTime()
+    {
+        if (m_beginAnimationUpdateTime == cBeginAnimationUpdateTimeNotSet)
+            m_beginAnimationUpdateTime = currentTime();
+        return m_beginAnimationUpdateTime;
+    }
+    
+    void setBeginAnimationUpdateTime(double t) { m_beginAnimationUpdateTime = t; }
+    
 private:
     typedef HashMap<RenderObject*, RefPtr<CompositeAnimation> > RenderObjectAnimationMap;
 
@@ -82,12 +93,15 @@ private:
     };
     
     Vector<EventToDispatch> m_eventsToDispatch;
+    
+    double m_beginAnimationUpdateTime;
 };
 
 AnimationControllerPrivate::AnimationControllerPrivate(Frame* frame)
     : m_animationTimer(this, &AnimationControllerPrivate::animationTimerFired)
     , m_updateRenderingDispatcher(this, &AnimationControllerPrivate::updateRenderingDispatcherFired)
     , m_frame(frame)
+    , m_beginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet)
 {
 }
 
@@ -316,7 +330,7 @@ void AnimationController::cancelAnimations(RenderObject* renderer)
 }
 
 PassRefPtr<RenderStyle> AnimationController::updateAnimations(RenderObject* renderer, RenderStyle* newStyle)
-{    
+{
     // Don't do anything if we're in the cache
     if (!renderer->document() || renderer->document()->inPageCache())
         return newStyle;
@@ -402,4 +416,18 @@ void AnimationController::styleAvailable()
     m_data->styleAvailable();
 }
 
+double AnimationController::beginAnimationUpdateTime()
+{
+    return m_data->beginAnimationUpdateTime();
+}
+
+void AnimationController::beginAnimationUpdate()
+{
+    m_data->setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
+}
+
+void AnimationController::endAnimationUpdate()
+{
+}
+
 } // namespace WebCore
index b1c4bb5..23445fe 100644 (file)
@@ -74,6 +74,11 @@ public:
         else
             m_numStyleAvailableWaiters--;
     }
+    
+    double beginAnimationUpdateTime();
+    
+    void beginAnimationUpdate();
+    void endAnimationUpdate();
 
 private:
     AnimationControllerPrivate* m_data;
index 07fe984..aae37a7 100644 (file)
@@ -87,7 +87,7 @@ void KeyframeAnimation::animate(CompositeAnimation*, RenderObject*, const Render
     // We should cache the last pair or something.
 
     // Find the first key
-    double elapsedTime = (m_startTime > 0 || m_pauseTime > 0) ? ((!paused() ? currentTime() : m_pauseTime) - m_startTime) : 0;
+    double elapsedTime = (m_startTime > 0 || m_pauseTime > 0) ? ((!paused() ? beginAnimationUpdateTime() : m_pauseTime) - m_startTime) : 0;
     if (elapsedTime < 0)
         elapsedTime = 0;