Source/WebCore: Implement reverse animation direction
authorigor.o@sisa.samsung.com <igor.o@sisa.samsung.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Feb 2012 02:07:11 +0000 (02:07 +0000)
committerigor.o@sisa.samsung.com <igor.o@sisa.samsung.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Feb 2012 02:07:11 +0000 (02:07 +0000)
Implement reverse animation direction
https://bugs.webkit.org/show_bug.cgi?id=60525

Implement reverse and alternate-reverse direction.

Reviewed by Dean Jackson.

Tests: animations/animation-direction-alternate-reverse.html
       animations/animation-direction-reverse.html
       animations/fill-mode-reverse.html

* css/CSSParser.cpp:
(WebCore::CSSParser::parseAnimationDirection):
* css/CSSStyleSelector.cpp:
(WebCore::CSSStyleSelector::mapAnimationDirection):
* css/CSSValueKeywords.in:
* page/WebKitAnimation.cpp:
(WebCore::WebKitAnimation::direction):
* page/WebKitAnimation.h:
* page/animation/AnimationBase.cpp:
(WebCore::AnimationBase::fractionalTime):
* platform/animation/Animation.h:
(Animation):
* platform/graphics/texmap/TextureMapperAnimation.cpp:
(WebCore):
(WebCore::shouldReverseAnimationValue):
(WebCore::normalizedAnimationValue):

LayoutTests: Implement reverse animation direction
https://bugs.webkit.org/show_bug.cgi?id=60525

Add test for the new animation-direction values.

Reviewed by Dean Jackson.

* animations/animation-direction-alternate-reverse-expected.txt: Added.
* animations/animation-direction-alternate-reverse.html: Added.
* animations/animation-direction-reverse-expected.txt: Added.
* animations/animation-direction-reverse.html: Added.
* animations/fill-mode-reverse-expected.txt: Added.
* animations/fill-mode-reverse.html: Added.

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

16 files changed:
LayoutTests/ChangeLog
LayoutTests/animations/animation-direction-alternate-reverse-expected.txt [new file with mode: 0644]
LayoutTests/animations/animation-direction-alternate-reverse.html [new file with mode: 0644]
LayoutTests/animations/animation-direction-reverse-expected.txt [new file with mode: 0644]
LayoutTests/animations/animation-direction-reverse.html [new file with mode: 0644]
LayoutTests/animations/fill-mode-reverse-expected.txt [new file with mode: 0644]
LayoutTests/animations/fill-mode-reverse.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/css/CSSParser.cpp
Source/WebCore/css/CSSStyleSelector.cpp
Source/WebCore/css/CSSValueKeywords.in
Source/WebCore/page/WebKitAnimation.cpp
Source/WebCore/page/WebKitAnimation.h
Source/WebCore/page/animation/AnimationBase.cpp
Source/WebCore/platform/animation/Animation.h
Source/WebCore/platform/graphics/texmap/TextureMapperAnimation.cpp

index a096867..830bcb4 100644 (file)
@@ -1,3 +1,19 @@
+2012-02-08  Igor Oliveira  <igor.o@sisa.samsung.com>
+
+        Implement reverse animation direction
+        https://bugs.webkit.org/show_bug.cgi?id=60525
+
+        Add test for the new animation-direction values.
+
+        Reviewed by Dean Jackson.
+
+        * animations/animation-direction-alternate-reverse-expected.txt: Added.
+        * animations/animation-direction-alternate-reverse.html: Added.
+        * animations/animation-direction-reverse-expected.txt: Added.
+        * animations/animation-direction-reverse.html: Added.
+        * animations/fill-mode-reverse-expected.txt: Added.
+        * animations/fill-mode-reverse.html: Added.
+
 2012-02-08  David Hyatt  <hyatt@apple.com>
 
         https://bugs.webkit.org/show_bug.cgi?id=78157
diff --git a/LayoutTests/animations/animation-direction-alternate-reverse-expected.txt b/LayoutTests/animations/animation-direction-alternate-reverse-expected.txt
new file mode 100644 (file)
index 0000000..282fa27
--- /dev/null
@@ -0,0 +1,5 @@
+PASS - "left" property for "box" element at 1s saw something close to: 200
+PASS - "left" property for "box" element at 2s saw something close to: 0
+PASS - "left" property for "box" element at 3s saw something close to: 200
+PASS - "left" property for "box" element at 4s saw something close to: 400
+
diff --git a/LayoutTests/animations/animation-direction-alternate-reverse.html b/LayoutTests/animations/animation-direction-alternate-reverse.html
new file mode 100644 (file)
index 0000000..66a1613
--- /dev/null
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+  <style type="text/css" media="screen">
+  
+    #container {
+      position: relative;
+      border: 1px solid black;
+      height: 100px;
+      width: 500px;
+    }
+    
+    #box {
+      position: absolute;
+      height: 100px;
+      width: 100px;
+      background-color: blue;
+      -webkit-animation-name: move;
+      -webkit-animation-duration: 2s;
+      -webkit-animation-direction: alternate-reverse;
+      -webkit-animation-iteration-count: 2;
+      -webkit-animation-timing-function: linear;
+    }
+
+    @-webkit-keyframes move {
+      0%   {
+        left: 0;
+      }
+      100% {
+        left: 400px;
+      }
+    }
+    
+  </style>
+  <script src="resources/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]
+      ["move", 1.0, "box", "left", 200, 20],
+      ["move", 2.0, "box", "left", 0, 20],
+
+      ["move", 3.0, "box", "left", 200, 20],
+      ["move", 4.0, "box", "left", 400, 20],
+    ];
+    
+    runAnimationTest(expectedValues);
+  </script>
+</head>
+<body>
+
+<!-- Test animation-direction: alternate-reverse -->
+<div id="container">
+  <div id="box"></div>
+</div>
+
+<div id="result"></div>
+
+</body>
+</html>
diff --git a/LayoutTests/animations/animation-direction-reverse-expected.txt b/LayoutTests/animations/animation-direction-reverse-expected.txt
new file mode 100644 (file)
index 0000000..83681d0
--- /dev/null
@@ -0,0 +1,4 @@
+PASS - "webkitTransform" property for "box" element at 0.5s saw something close to: 1,0,0,1,150,0
+PASS - "webkitTransform" property for "box" element at 1s saw something close to: 1,0,0,1,100,0
+PASS - "webkitTransform" property for "box" element at 2.5s saw something close to: 1,0,0,1,200,0
+
diff --git a/LayoutTests/animations/animation-direction-reverse.html b/LayoutTests/animations/animation-direction-reverse.html
new file mode 100644 (file)
index 0000000..e755d81
--- /dev/null
@@ -0,0 +1,59 @@
+<html lang="en">
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <title>Test of -webkit-animation-play-state</title>
+  <style type="text/css" media="screen">
+    body {
+      margin: 0;
+    }
+
+    #box {
+      position: absolute;
+      left: 0px;
+      top: 100px;
+      height: 100px;
+      width: 100px;
+      background-color: red;
+      margin: 0;
+      -webkit-animation-duration: 2s;
+      -webkit-animation-direction: reverse;
+      -webkit-animation-timing-function: linear;
+      -webkit-animation-name: "move1";
+    }
+    @-webkit-keyframes "move1" {
+      from { -webkit-transform: translateX(0px); }
+      to   { -webkit-transform: translateX(200px); }
+    }
+    #result {
+      color: white; /* hide from pixel results */
+    }
+  </style>
+  <script src="resources/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]
+      ["move1", 0.5, "box", "webkitTransform", [1,0,0,1, 150,0], 20],
+      ["move1", 1.0, "box", "webkitTransform", [1,0,0,1,100,0], 20],
+      ["move1", 2.5, "box", "webkitTransform", [1,0,0,1, 200,0], 20],
+    ];
+
+    function pauseAnimation()
+    {
+        document.getElementById("box").style.webkitAnimationPlayState = "paused";
+    }
+
+    function setTimers()
+    {
+        setTimeout(pauseAnimation, 2500);
+    }
+
+    runAnimationTest(expectedValues, setTimers, null, true);
+
+  </script>
+</head>
+<body>
+<div id="box"></div>
+<div id="result"></div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/animations/fill-mode-reverse-expected.txt b/LayoutTests/animations/fill-mode-reverse-expected.txt
new file mode 100644 (file)
index 0000000..42e3c4f
--- /dev/null
@@ -0,0 +1,17 @@
+This test performs an animation of the left property with four different fill modes. It animates over 0.1 second with a 0.1 second delay. It takes snapshots at document load and the end of the animation.
+None
+Backwards
+Forwards
+Both
+Both iterating
+PASS - start of animation - id: a expected: 100 actual: 100
+PASS - start of animation - id: b expected: 300 actual: 300
+PASS - start of animation - id: c expected: 100 actual: 100
+PASS - start of animation - id: d expected: 300 actual: 300
+PASS - start of animation - id: e expected: 200 actual: 200
+PASS - end of animation - id: a expected: 100 actual: 100
+PASS - end of animation - id: b expected: 100 actual: 100
+PASS - end of animation - id: c expected: 300 actual: 300
+PASS - end of animation - id: d expected: 300 actual: 300
+PASS - end of animation - id: e expected: 200 actual: 200
+
diff --git a/LayoutTests/animations/fill-mode-reverse.html b/LayoutTests/animations/fill-mode-reverse.html
new file mode 100644 (file)
index 0000000..6d8f469
--- /dev/null
@@ -0,0 +1,131 @@
+<!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 simple animation with fill modes</title>
+  <style type="text/css" media="screen">
+    .box {
+      position: relative;
+      left: 100px;
+      top: 10px;
+      height: 100px;
+      width: 100px;
+      -webkit-animation-delay: 0.1s;
+      -webkit-animation-duration: 2s;
+      -webkit-animation-timing-function: linear;
+      -webkit-animation-name: anim;
+      -webkit-animation-direction: reverse
+    }
+    @-webkit-keyframes anim {
+        from { left: 200px; }
+        to   { left: 300px; }
+    }
+    #a {
+      background-color: blue;
+      -webkit-animation-fill-mode: none;
+    }
+    #b {
+      background-color: red;
+      -webkit-animation-fill-mode: backwards;
+    }
+    #c {
+      background-color: green;
+      -webkit-animation-fill-mode: forwards;
+    }
+    #d {
+      background-color: yellow;
+      -webkit-animation-fill-mode: both;
+    }
+    #e {
+      background-color: #999;
+      -webkit-animation-fill-mode: both;
+      -webkit-animation-iteration-count: 2;
+      -webkit-animation-direction: alternate;
+    }
+  </style>
+  <script type="text/javascript" charset="utf-8">
+    const numAnims = 5;
+    var animsFinished = 0;
+    const allowance = 5;
+    const expectedValues = [
+      {id: "a", start: 100, end: 100},
+      {id: "b", start: 300, end: 100},
+      {id: "c", start: 100, end: 300},
+      {id: "d", start: 300, end: 300},
+      {id: "e", start: 200, end: 200}
+    ];
+    var result = "";
+
+    if (window.layoutTestController) {
+        layoutTestController.dumpAsText();
+        layoutTestController.waitUntilDone();
+    }
+
+    function animationEnded(event) {
+        if (++animsFinished == numAnims) {
+            setTimeout(endTest, 0); // this set timeout should be ok in the test environment
+                                    // since we're just giving style a chance to resolve
+        }
+    };
+
+    function endTest() {
+
+        for (var i=0; i < expectedValues.length; i++) {
+            var el = document.getElementById(expectedValues[i].id);
+            var expectedValue = expectedValues[i].end;
+            var realValue = window.getComputedStyle(el).getPropertyCSSValue("left").getFloatValue(CSSPrimitiveValue.CSS_NUMBER);
+            if (Math.abs(expectedValue - realValue) < allowance) {
+              result += "PASS";
+            } else {
+              result += "FAIL";
+            }
+            result += " - end of animation - id: " + expectedValues[i].id + " expected: " + expectedValue + " actual: " + realValue + "<br>";
+        }
+        document.getElementById('result').innerHTML = result;
+
+        if (window.layoutTestController)
+            layoutTestController.notifyDone();
+    }
+
+    window.onload = function () {
+        for (var i=0; i < expectedValues.length; i++) {
+            var el = document.getElementById(expectedValues[i].id);
+            var expectedValue = expectedValues[i].start;
+            var realValue = window.getComputedStyle(el).getPropertyCSSValue("left").getFloatValue(CSSPrimitiveValue.CSS_NUMBER);
+            if (Math.abs(expectedValue - realValue) < allowance) {
+              result += "PASS";
+            } else {
+              result += "FAIL";
+            }
+            result += " - start of animation - id: " + expectedValues[i].id + " expected: " + expectedValue + " actual: " + realValue + "<br>";
+        }
+        document.addEventListener("webkitAnimationEnd", animationEnded, false);
+    };
+
+  </script>
+</head>
+<body>
+This test performs an animation of the left property with four different
+fill modes. It animates over 0.1 second with a 0.1 second delay.
+It takes snapshots at document load and the end of the animation.
+<div id="a" class="box">
+  None
+</div>
+<div id="b" class="box">
+  Backwards
+</div>
+<div id="c" class="box">
+  Forwards
+</div>
+<div id="d" class="box">
+  Both
+</div>
+<div id="e" class="box">
+  Both iterating
+</div>
+<div id="result">
+</div>
+</body>
+</html>
index d8bfb02..04d16f0 100644 (file)
@@ -1,3 +1,35 @@
+2012-02-08  Igor Oliveira  <igor.o@sisa.samsung.com>
+
+        Implement reverse animation direction
+
+        Implement reverse animation direction
+        https://bugs.webkit.org/show_bug.cgi?id=60525
+
+        Implement reverse and alternate-reverse direction.
+
+        Reviewed by Dean Jackson.
+
+        Tests: animations/animation-direction-alternate-reverse.html
+               animations/animation-direction-reverse.html
+               animations/fill-mode-reverse.html
+
+        * css/CSSParser.cpp:
+        (WebCore::CSSParser::parseAnimationDirection):
+        * css/CSSStyleSelector.cpp:
+        (WebCore::CSSStyleSelector::mapAnimationDirection):
+        * css/CSSValueKeywords.in:
+        * page/WebKitAnimation.cpp:
+        (WebCore::WebKitAnimation::direction):
+        * page/WebKitAnimation.h:
+        * page/animation/AnimationBase.cpp:
+        (WebCore::AnimationBase::fractionalTime):
+        * platform/animation/Animation.h:
+        (Animation):
+        * platform/graphics/texmap/TextureMapperAnimation.cpp:
+        (WebCore):
+        (WebCore::shouldReverseAnimationValue):
+        (WebCore::normalizedAnimationValue):
+
 2012-02-08  James Robinson  <jamesr@chromium.org>
 
         [chromium] Avoid creating a temporary GraphicsContext3D if someone requests the WebView's GraphicsContext3D before initialization is complete
index 44d7ff7..8a10751 100644 (file)
@@ -3376,7 +3376,7 @@ PassRefPtr<CSSValue> CSSParser::parseAnimationDelay()
 PassRefPtr<CSSValue> CSSParser::parseAnimationDirection()
 {
     CSSParserValue* value = m_valueList->current();
-    if (value->id == CSSValueNormal || value->id == CSSValueAlternate)
+    if (value->id == CSSValueNormal || value->id == CSSValueAlternate || value->id == CSSValueReverse || value->id == CSSValueAlternateReverse)
         return cssValuePool()->createIdentifierValue(value->id);
     return 0;
 }
index ffd7c4f..54cdd93 100644 (file)
@@ -4318,7 +4318,20 @@ void CSSStyleSelector::mapAnimationDirection(Animation* layer, CSSValue* value)
         return;
 
     CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
-    layer->setDirection(primitiveValue->getIdent() == CSSValueAlternate ? Animation::AnimationDirectionAlternate : Animation::AnimationDirectionNormal);
+    switch (primitiveValue->getIdent()) {
+    case CSSValueNormal:
+        layer->setDirection(Animation::AnimationDirectionNormal);
+        break;
+    case CSSValueAlternate:
+        layer->setDirection(Animation::AnimationDirectionAlternate);
+        break;
+    case CSSValueReverse:
+        layer->setDirection(Animation::AnimationDirectionReverse);
+        break;
+    case CSSValueAlternateReverse:
+        layer->setDirection(Animation::AnimationDirectionAlternateReverse);
+        break;
+    }
 }
 
 void CSSStyleSelector::mapAnimationDuration(Animation* animation, CSSValue* value)
index 713038a..dd5c27c 100644 (file)
@@ -700,6 +700,8 @@ lines
 //
 // alternate
 
+alternate-reverse
+
 //
 // CSS_PROP__WEBKIT_ANIMATION_FILL_MODE
 //
index b757d23..98e7736 100644 (file)
@@ -84,9 +84,18 @@ bool WebKitAnimation::ended() const
 
 WebKitAnimation::Direction WebKitAnimation::direction() const
 {
-    if (m_keyframeAnimation->animation()->direction() == Animation::AnimationDirectionNormal)
+    switch (m_keyframeAnimation->animation()->direction()) {
+    case Animation::AnimationDirectionNormal:
         return DIRECTION_NORMAL;
-    return DIRECTION_ALTERNATE;
+    case Animation::AnimationDirectionAlternate:
+        return DIRECTION_ALTERNATE;
+    case Animation::AnimationDirectionReverse:
+        return DIRECTION_REVERSE;
+    case Animation::AnimationDirectionAlternateReverse:
+        return DIRECTION_ALTERNATE_REVERSE;
+    }
+    ASSERT_NOT_REACHED();
+    return DIRECTION_NORMAL;
 }
 
 WebKitAnimation::FillMode WebKitAnimation::fillMode() const
index 6bea1e5..bef7438 100644 (file)
@@ -59,7 +59,7 @@ public:
     bool ended() const;
 
     // direction
-    enum Direction { DIRECTION_NORMAL, DIRECTION_ALTERNATE };
+    enum Direction { DIRECTION_NORMAL, DIRECTION_ALTERNATE, DIRECTION_REVERSE, DIRECTION_ALTERNATE_REVERSE };
     Direction direction() const;
 
     // fill mode
index e3ad92f..4fd0409 100644 (file)
@@ -1673,7 +1673,9 @@ double AnimationBase::fractionalTime(double scale, double elapsedTime, double of
         integralTime = min(integralTime, m_animation->iterationCount() - 1);
     fractionalTime -= integralTime;
 
-    if ((m_animation->direction() == Animation::AnimationDirectionAlternate) && (integralTime & 1))
+    if (((m_animation->direction() == Animation::AnimationDirectionAlternate) && (integralTime & 1))
+        || ((m_animation->direction() == Animation::AnimationDirectionAlternateReverse) && !(integralTime & 1))
+        || m_animation->direction() == Animation::AnimationDirectionReverse)
         fractionalTime = 1 - fractionalTime;
 
     if (scale != 1 || offset)
index 0a5f4d2..175d95a 100644 (file)
@@ -42,7 +42,7 @@ public:
 
     static PassRefPtr<Animation> create() { return adoptRef(new Animation); }
     static PassRefPtr<Animation> create(const Animation* o) { return adoptRef(new Animation(*o)); }
-    
+
     bool isDelaySet() const { return m_delaySet; }
     bool isDirectionSet() const { return m_directionSet; }
     bool isDurationSet() const { return m_durationSet; }
@@ -96,7 +96,12 @@ public:
 
     double delay() const { return m_delay; }
 
-    enum AnimationDirection { AnimationDirectionNormal, AnimationDirectionAlternate };
+    enum AnimationDirection {
+        AnimationDirectionNormal,
+        AnimationDirectionAlternate,
+        AnimationDirectionReverse,
+        AnimationDirectionAlternateReverse
+    };
     AnimationDirection direction() const { return static_cast<AnimationDirection>(m_direction); }
 
     unsigned fillMode() const { return m_fillMode; }
@@ -144,7 +149,7 @@ private:
     double m_delay;
     double m_duration;
     RefPtr<TimingFunction> m_timingFunction;
-    unsigned m_direction : 1; // AnimationDirection
+    unsigned m_direction : 2; // AnimationDirection
     unsigned m_fillMode : 2;
 
     unsigned m_playState     : 2;
index 09714d9..6be518a 100644 (file)
 #if USE(TEXTURE_MAPPER)
 namespace WebCore {
 
-static double normalizedAnimationValue(double runningTime, double duration, bool alternate)
+
+static bool shouldReverseAnimationValue(Animation::AnimationDirection direction, int loopCount)
+{
+    if (((direction == Animation::AnimationDirectionAlternate) && (loopCount & 1))
+        || ((direction == Animation::AnimationDirectionAlternateReverse) && !(loopCount & 1))
+        || direction == Animation::AnimationDirectionReverse)
+        return true;
+    return false;
+}
+
+static double normalizedAnimationValue(double runningTime, double duration, Animation::AnimationDirection direction)
 {
     if (!duration)
         return 0;
@@ -35,7 +45,8 @@ static double normalizedAnimationValue(double runningTime, double duration, bool
     const double lastFullLoop = duration * double(loopCount);
     const double remainder = runningTime - lastFullLoop;
     const double normalized = remainder / duration;
-    return (loopCount % 2 && alternate) ? (1 - normalized) : normalized;
+
+    return shouldReverseAnimationValue(direction, loopCount) ? 1 - normalized : normalized;
 }
 
 static float applyOpacityAnimation(float fromOpacity, float toOpacity, double progress)