CSS parser: Add error recovery while parsing @-webkit-keyframes key values.
<http://webkit.org/b/115175>

Source/WebCore:

From Blink r148714 by <apavlov@chromium.org>:

If not a percentage, "from", or "to" value is used in a key list, the rule is erroneous,
and due to the absense of recovery, the parser skips the following, valid CSS rule.

On a related note, keyframes, whose selectors contain invalid keys, should be discarded
altogether, according to <http://www.w3.org/TR/css3-animations/#keyframes>

Tests: animations/keyframes-invalid-keys.html
       fast/css/webkit-keyframes-errors.html

* css/CSSGrammar.y.in:
* css/CSSParser.cpp:
(WebCore::CSSParser::rewriteSpecifiers):

LayoutTests:

From Blink r148714 by <apavlov@chromium.org>.

* animations/keyframes-invalid-keys-expected.txt: Added.
* animations/keyframes-invalid-keys.html: Added.
* fast/css/webkit-keyframes-errors-expected.html: Added.
* fast/css/webkit-keyframes-errors.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@149106 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 7dd6ffd..f90d4b9 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,15 @@
+2013-04-25  Andreas Kling  <akling@apple.com>
+
+        CSS parser: Add error recovery while parsing @-webkit-keyframes key values.
+        <http://webkit.org/b/115175>
+
+        From Blink r148714 by <apavlov@chromium.org>.
+
+        * animations/keyframes-invalid-keys-expected.txt: Added.
+        * animations/keyframes-invalid-keys.html: Added.
+        * fast/css/webkit-keyframes-errors-expected.html: Added.
+        * fast/css/webkit-keyframes-errors.html: Added.
+
 2013-04-25  Ádám Kallai  <kadam@inf.u-szeged.hu>
 
         [Qt] Unreviewed gardening. Skip some failing tests after r148996.
diff --git a/LayoutTests/animations/keyframes-invalid-keys-expected.txt b/LayoutTests/animations/keyframes-invalid-keys-expected.txt
new file mode 100644
index 0000000..91d36c6
--- /dev/null
+++ b/LayoutTests/animations/keyframes-invalid-keys-expected.txt
@@ -0,0 +1,4 @@
+This test performs an animation of the left property. It should always remain 3px, unless there are errors during parsing, resulting in other values in keyframes with bad keys. Four of the keyframes contain invalid keys, and should be discarded altogether ("If a keyframe selector specifies negative percentage values or values higher than 100%, then the keyframe will be ignored", see http://www.w3.org/TR/css3-animations/#keyframes).
+PASS - "left" property for "box" element at 0.2s saw something close to: 3
+PASS - "left" property for "box" element at 0.8s saw something close to: 3
+
diff --git a/LayoutTests/animations/keyframes-invalid-keys.html b/LayoutTests/animations/keyframes-invalid-keys.html
new file mode 100644
index 0000000..d428582
--- /dev/null
+++ b/LayoutTests/animations/keyframes-invalid-keys.html
@@ -0,0 +1,60 @@
+<!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>Keyframes with invalid keys</title>
+  <style type="text/css" media="screen">
+    @-webkit-keyframes "anim" {
+        50% { left: 3px; }
+
+        /* Out-of-range percentage values */
+        -10% { left: 100px; }
+        -10%, from { left: 100px; }
+        from, 110% { left: 100px; }
+        110% { left: 100px; }
+
+        /* Invalid keys (numbers and identifiers) */
+        0, from { left: 100px; }
+        fromto { left: 100px; }
+        60%, unknown { left: 100px; }
+        100 { left: 100px; }
+    }
+    #box {
+        position: absolute;
+        left: 3px;
+        top: 100px;
+        height: 100px;
+        width: 100px;
+        background-color: blue;
+        -webkit-animation-duration: 1s;
+        -webkit-animation-timing-function: linear;
+        -webkit-animation-name: "anim";
+    }
+
+    </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]
+      ["anim", 0.2, "box", "left", 3, 1],
+      ["anim", 0.8, "box", "left", 3, 1],
+    ];
+
+    runAnimationTest(expectedValues);
+
+  </script>
+</head>
+<body>
+This test performs an animation of the left property. It should always remain 3px, unless there are
+errors during parsing, resulting in other values in keyframes with bad keys.
+Four of the keyframes contain invalid keys, and should be discarded altogether
+("If a keyframe selector specifies negative percentage values or values higher than 100%, then the keyframe will be ignored", see <a href="http://www.w3.org/TR/css3-animations/#keyframes">http://www.w3.org/TR/css3-animations/#keyframes</a>).
+<div id="box">
+</div>
+<div id="result">
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/css/webkit-keyframes-errors-expected.html b/LayoutTests/fast/css/webkit-keyframes-errors-expected.html
new file mode 100644
index 0000000..a972e4a
--- /dev/null
+++ b/LayoutTests/fast/css/webkit-keyframes-errors-expected.html
@@ -0,0 +1,26 @@
+<html>
+<body>
+    <p>Test for Blink bug <a href="https://code.google.com/p/chromium/issues/detail?id=228870">228870</a>: CSS parser incorrectly handles invalid @-webkit-keyframes key values</p>
+    <style>
+        #output-1:before {
+            content: "PASSED";
+        }
+
+        #output-2:before {
+            content: "PASSED";
+        }
+
+        #output-3:before {
+            content: "PASSED";
+        }
+
+        #output-4:before {
+            content: "PASSED";
+        }
+    </style>
+    <div id="output-1"> (INTEGER single key)</div>
+    <div id="output-2"> (INTEGER in a key list)</div>
+    <div id="output-3"> (unknown IDENT in a key list)</div>
+    <div id="output-4"> (out-of-range percentage key value in a key list)</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/css/webkit-keyframes-errors.html b/LayoutTests/fast/css/webkit-keyframes-errors.html
new file mode 100644
index 0000000..2b153f38
--- /dev/null
+++ b/LayoutTests/fast/css/webkit-keyframes-errors.html
@@ -0,0 +1,42 @@
+<html>
+<body>
+    <p>Test for Blink bug <a href="https://code.google.com/p/chromium/issues/detail?id=228870">228870</a>: CSS parser incorrectly handles invalid @-webkit-keyframes key values</p>
+    <style>
+        @-webkit-keyframes foo {
+            0 {foo: bar;}
+        }
+
+        #output-1:before {
+            content: "PASSED";
+        }
+
+        @-webkit-keyframes foo {
+            0, 100% {foo: bar;}
+        }
+
+        #output-2:before {
+            content: "PASSED";
+        }
+
+        @-webkit-keyframes foo {
+            10%, none {foo: bar;}
+        }
+
+        #output-3:before {
+            content: "PASSED";
+        }
+
+        @-webkit-keyframes foo {
+            -10%, from {foo: bar;}
+        }
+
+        #output-4:before {
+            content: "PASSED";
+        }
+    </style>
+    <div id="output-1"> (INTEGER single key)</div>
+    <div id="output-2"> (INTEGER in a key list)</div>
+    <div id="output-3"> (unknown IDENT in a key list)</div>
+    <div id="output-4"> (out-of-range percentage key value in a key list)</div>
+</body>
+</html>
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index f0dbb00..bfcb7a8 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,23 @@
+2013-04-25  Andreas Kling  <akling@apple.com>
+
+        CSS parser: Add error recovery while parsing @-webkit-keyframes key values.
+        <http://webkit.org/b/115175>
+
+        From Blink r148714 by <apavlov@chromium.org>:
+
+        If not a percentage, "from", or "to" value is used in a key list, the rule is erroneous,
+        and due to the absense of recovery, the parser skips the following, valid CSS rule.
+
+        On a related note, keyframes, whose selectors contain invalid keys, should be discarded
+        altogether, according to <http://www.w3.org/TR/css3-animations/#keyframes>
+
+        Tests: animations/keyframes-invalid-keys.html
+               fast/css/webkit-keyframes-errors.html
+
+        * css/CSSGrammar.y.in:
+        * css/CSSParser.cpp:
+        (WebCore::CSSParser::rewriteSpecifiers):
+
 2013-04-25  Antti Koivisto  <antti@apple.com>
 
         REGRESSION (r147797): Animations slideshows of images on www.thesuperficial.com are slow
diff --git a/Source/WebCore/css/CSSGrammar.y.in b/Source/WebCore/css/CSSGrammar.y.in
index 539ea68..861f6cc 100644
--- a/Source/WebCore/css/CSSGrammar.y.in
+++ b/Source/WebCore/css/CSSGrammar.y.in
@@ -876,8 +876,13 @@
             $$.fValue = 0;
         else if (str.equalIgnoringCase("to"))
             $$.fValue = 100;
-        else
+        else {
+            $$.unit = 0;
             YYERROR;
+        }
+    }
+    | error {
+        $$.unit = 0;
     }
     ;
 
diff --git a/Source/WebCore/css/CSSParser.cpp b/Source/WebCore/css/CSSParser.cpp
index e5eb085..3d1ab1d 100644
--- a/Source/WebCore/css/CSSParser.cpp
+++ b/Source/WebCore/css/CSSParser.cpp
@@ -11791,7 +11791,23 @@
     // Create a key string from the passed keys
     StringBuilder keyString;
     for (unsigned i = 0; i < keys->size(); ++i) {
+        // Just as per the comment below, we ignore keyframes with
+        // invalid key values (plain numbers or unknown identifiers)
+        // marked as CSSPrimitiveValue::CSS_UNKNOWN during parsing.
+        if (keys->valueAt(i)->unit == CSSPrimitiveValue::CSS_UNKNOWN) {
+            clearProperties();
+            return 0;
+        }
+
+        ASSERT(keys->valueAt(i)->unit == CSSPrimitiveValue::CSS_NUMBER);
         float key = static_cast<float>(keys->valueAt(i)->fValue);
+        if (key < 0 || key > 100) {
+            // As per http://www.w3.org/TR/css3-animations/#keyframes,
+            // "If a keyframe selector specifies negative percentage values
+            // or values higher than 100%, then the keyframe will be ignored."
+            clearProperties();
+            return 0;
+        }
         if (i != 0)
             keyString.append(',');
         keyString.append(String::number(key));