Title: [90139] trunk
Revision
90139
Author
[email protected]
Date
2011-06-30 11:41:30 -0700 (Thu, 30 Jun 2011)

Log Message

2011-06-30  Tab Atkins  <[email protected]>

        Reviewed by Adam Barth.

        Fix legacy color attribute parsing to match HTML spec
        https://bugs.webkit.org/show_bug.cgi?id=63029

        Tests <body bgcolor> parsing.

        * fast/dom/attribute-legacy-colors-expected.txt: Added.
        * fast/dom/attribute-legacy-colors.html: Added.
        * fast/dom/script-tests/attribute-legacy-colors.js: Added.
2011-06-30  Tab Atkins  <[email protected]>

        Reviewed by Adam Barth.

        Fix legacy color attribute parsing to match HTML spec
        https://bugs.webkit.org/show_bug.cgi?id=63029

        Relevant spec link: http://www.whatwg.org/specs/web-apps/current-work/complete/common-microsyntaxes.html#rules-for-parsing-a-legacy-color-value
        Fix legacy color attribute parsing (<body bgcolor>, <font color>, etc.) to match the HTML spec and more closely match other browsers.

        Test: fast/dom/attribute-legacy-colors.html

        * dom/StyledElement.cpp:
        (WebCore::StyledElement::addCSSColor):

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (90138 => 90139)


--- trunk/LayoutTests/ChangeLog	2011-06-30 18:37:16 UTC (rev 90138)
+++ trunk/LayoutTests/ChangeLog	2011-06-30 18:41:30 UTC (rev 90139)
@@ -1,3 +1,16 @@
+2011-06-30  Tab Atkins  <[email protected]>
+
+        Reviewed by Adam Barth.
+
+        Fix legacy color attribute parsing to match HTML spec
+        https://bugs.webkit.org/show_bug.cgi?id=63029
+
+        Tests <body bgcolor> parsing.
+
+        * fast/dom/attribute-legacy-colors-expected.txt: Added.
+        * fast/dom/attribute-legacy-colors.html: Added.
+        * fast/dom/script-tests/attribute-legacy-colors.js: Added.
+
 2011-06-30  Nate Chapin  <[email protected]>
 
         Unreviewed, remove passing tests from chromium test expectations.

Added: trunk/LayoutTests/fast/dom/attribute-legacy-colors-expected.txt (0 => 90139)


--- trunk/LayoutTests/fast/dom/attribute-legacy-colors-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/dom/attribute-legacy-colors-expected.txt	2011-06-30 18:41:30 UTC (rev 90139)
@@ -0,0 +1,54 @@
+This test ensures that legacy color attributes are parsed properly.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS document.body.bgColor='';getComputedStyle(document.body).backgroundColor; is 'rgba(0, 0, 0, 0)'
+PASS document.body.bgColor='transparent';getComputedStyle(document.body).backgroundColor; is 'rgba(0, 0, 0, 0)'
+PASS document.body.bgColor=' transparent ';getComputedStyle(document.body).backgroundColor; is 'rgba(0, 0, 0, 0)'
+PASS document.body.bgColor='red';getComputedStyle(document.body).backgroundColor; is 'rgb(255, 0, 0)'
+PASS document.body.bgColor=' red ';getComputedStyle(document.body).backgroundColor; is 'rgb(255, 0, 0)'
+PASS document.body.bgColor='#f00';getComputedStyle(document.body).backgroundColor; is 'rgb(255, 0, 0)'
+PASS document.body.bgColor=' #f00 ';getComputedStyle(document.body).backgroundColor; is 'rgb(255, 0, 0)'
+PASS document.body.bgColor='#ff0000';getComputedStyle(document.body).backgroundColor; is 'rgb(255, 0, 0)'
+PASS document.body.bgColor=' #ff0000 ';getComputedStyle(document.body).backgroundColor; is 'rgb(255, 0, 0)'
+PASS document.body.bgColor='#fzz';getComputedStyle(document.body).backgroundColor; is 'rgb(15, 0, 0)'
+PASS document.body.bgColor='#ffzzzz';getComputedStyle(document.body).backgroundColor; is 'rgb(255, 0, 0)'
+PASS document.body.bgColor='f00';getComputedStyle(document.body).backgroundColor; is 'rgb(15, 0, 0)'
+PASS document.body.bgColor='ff0000';getComputedStyle(document.body).backgroundColor; is 'rgb(255, 0, 0)'
+PASS document.body.bgColor='#00000000';getComputedStyle(document.body).backgroundColor; is 'rgb(0, 0, 0)'
+PASS document.body.bgColor='foo';getComputedStyle(document.body).backgroundColor; is 'rgb(15, 0, 0)'
+PASS document.body.bgColor='cheese';getComputedStyle(document.body).backgroundColor; is 'rgb(192, 238, 14)'
+PASS document.body.bgColor='ff򀿿ff';getComputedStyle(document.body).backgroundColor; is 'rgb(255, 0, 255)'
+PASS document.body.bgColor='f򀿿f';getComputedStyle(document.body).backgroundColor; is 'rgb(240, 15, 0)'
+PASS document.body.bgColor='rgb(255, 0, 0)';getComputedStyle(document.body).backgroundColor; is 'rgb(0, 85, 0)'
+PASS document.body.bgColor='550000001155000000115500000011';getComputedStyle(document.body).backgroundColor; is 'rgb(17, 17, 17)'
+PASS document.body.bgColor='550000000155000000015500000001';getComputedStyle(document.body).backgroundColor; is 'rgb(1, 1, 1)'
+PASS document.body.bgColor='550000000055000000005500000000';getComputedStyle(document.body).backgroundColor; is 'rgb(0, 0, 0)'
+PASS document.body.bgColor='550020001155000000115500000011';getComputedStyle(document.body).backgroundColor; is 'rgb(32, 0, 0)'
+PASS document.body.bgColor='55򀿿20򀿿1155򀿿򀿿00115500򀿿0011';getComputedStyle(document.body).backgroundColor; is 'rgb(32, 0, 0)'
+PASS document.body.bgColor='#';getComputedStyle(document.body).backgroundColor; is 'rgb(0, 0, 0)'
+PASS document.body.bgColor='#5';getComputedStyle(document.body).backgroundColor; is 'rgb(5, 0, 0)'
+PASS document.body.bgColor='#55';getComputedStyle(document.body).backgroundColor; is 'rgb(5, 5, 0)'
+PASS document.body.bgColor='#555';getComputedStyle(document.body).backgroundColor; is 'rgb(85, 85, 85)'
+PASS document.body.bgColor='#5555';getComputedStyle(document.body).backgroundColor; is 'rgb(85, 85, 0)'
+PASS document.body.bgColor='#55555';getComputedStyle(document.body).backgroundColor; is 'rgb(85, 85, 80)'
+PASS document.body.bgColor='#555555';getComputedStyle(document.body).backgroundColor; is 'rgb(85, 85, 85)'
+PASS document.body.bgColor='#5555555';getComputedStyle(document.body).backgroundColor; is 'rgb(85, 85, 80)'
+PASS document.body.bgColor='#55555555';getComputedStyle(document.body).backgroundColor; is 'rgb(85, 85, 85)'
+PASS document.body.bgColor='5';getComputedStyle(document.body).backgroundColor; is 'rgb(5, 0, 0)'
+PASS document.body.bgColor='55';getComputedStyle(document.body).backgroundColor; is 'rgb(5, 5, 0)'
+PASS document.body.bgColor='555';getComputedStyle(document.body).backgroundColor; is 'rgb(5, 5, 5)'
+PASS document.body.bgColor='5555';getComputedStyle(document.body).backgroundColor; is 'rgb(85, 85, 0)'
+PASS document.body.bgColor='55555';getComputedStyle(document.body).backgroundColor; is 'rgb(85, 85, 80)'
+PASS document.body.bgColor='555555';getComputedStyle(document.body).backgroundColor; is 'rgb(85, 85, 85)'
+PASS document.body.bgColor='5555555';getComputedStyle(document.body).backgroundColor; is 'rgb(85, 85, 80)'
+PASS document.body.bgColor='55555555';getComputedStyle(document.body).backgroundColor; is 'rgb(85, 85, 85)'
+PASS document.body.bgColor='ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000';getComputedStyle(document.body).backgroundColor; is 'rgb(255, 255, 255)'
+PASS document.body.bgColor='򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿ffffff';getComputedStyle(document.body).backgroundColor; is 'rgb(0, 0, 0)'
+PASS document.body.bgColor=' ';getComputedStyle(document.body).backgroundColor; is 'rgb(0, 0, 0)'
+PASS document.body.bgColor=' ffffff ';getComputedStyle(document.body).backgroundColor; is 'rgb(255, 255, 255)'
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/dom/attribute-legacy-colors.html (0 => 90139)


--- trunk/LayoutTests/fast/dom/attribute-legacy-colors.html	                        (rev 0)
+++ trunk/LayoutTests/fast/dom/attribute-legacy-colors.html	2011-06-30 18:41:30 UTC (rev 90139)
@@ -0,0 +1,8 @@
+<!DOCTYPE HTML>
+<meta charset=utf8>
+<link rel="stylesheet" href=""
+<script src=""
+<p id="description"></p>
+<div id="console"></div>
+<script src=""
+<script src=""
\ No newline at end of file

Added: trunk/LayoutTests/fast/dom/script-tests/attribute-legacy-colors.js (0 => 90139)


--- trunk/LayoutTests/fast/dom/script-tests/attribute-legacy-colors.js	                        (rev 0)
+++ trunk/LayoutTests/fast/dom/script-tests/attribute-legacy-colors.js	2011-06-30 18:41:30 UTC (rev 90139)
@@ -0,0 +1,58 @@
+description("This test ensures that legacy color attributes are parsed properly.");
+
+shouldBe("document.body.bgColor='';getComputedStyle(document.body).backgroundColor;", "'rgba(0, 0, 0, 0)'");
+shouldBe("document.body.bgColor='transparent';getComputedStyle(document.body).backgroundColor;", "'rgba(0, 0, 0, 0)'");
+shouldBe("document.body.bgColor=' transparent ';getComputedStyle(document.body).backgroundColor;", "'rgba(0, 0, 0, 0)'");
+(function(){
+var tests = [
+	{'test':'red', 'expected':[255, 0, 0]},
+	{'test':' red ', 'expected':[255, 0, 0]},
+	{'test':'#f00', 'expected':[255, 0, 0]},
+	{'test':' #f00 ', 'expected':[255, 0, 0]},
+	{'test':'#ff0000', 'expected':[255, 0, 0]},
+	{'test':' #ff0000 ', 'expected':[255, 0, 0]},
+	{'test':'#fzz', 'expected':[15, 0, 0]},
+	{'test':'#ffzzzz', 'expected':[255, 0, 0]},
+	{'test':'f00', 'expected':[15, 0, 0]},
+	{'test':'ff0000', 'expected':[255, 0, 0]},
+	{'test':'#00000000', 'expected':[0, 0, 0]},
+	{'test':'foo', 'expected':[15, 0, 0]},
+	{'test':'cheese', 'expected':[192, 238, 14]},
+	{'test':'ff򀿿ff', 'expected':[255, 0, 255]},
+	{'test':'f򀿿f', 'expected':[240, 15, 0]},
+	{'test':'rgb(255, 0, 0)', 'expected':[0, 85, 0]},
+	{'test':'550000001155000000115500000011', 'expected':[17, 17, 17]},
+	{'test':'550000000155000000015500000001', 'expected':[1, 1, 1]},
+	{'test':'550000000055000000005500000000', 'expected':[0, 0, 0]},
+	{'test':'550020001155000000115500000011', 'expected':[32, 0, 0]},
+	{'test':'55򀿿20򀿿1155򀿿򀿿00115500򀿿0011', 'expected':[32, 0, 0]},
+	{'test':'#', 'expected':[0, 0, 0]},
+	{'test':'#5', 'expected':[5, 0, 0]},
+	{'test':'#55', 'expected':[5, 5, 0]},
+	{'test':'#555', 'expected':[85, 85, 85]},
+	{'test':'#5555', 'expected':[85, 85, 0]},
+	{'test':'#55555', 'expected':[85, 85, 80]},
+	{'test':'#555555', 'expected':[85, 85, 85]},
+	{'test':'#5555555', 'expected':[85, 85, 80]},
+	{'test':'#55555555', 'expected':[85, 85, 85]},
+	{'test':'5', 'expected':[5, 0, 0]},
+	{'test':'55', 'expected':[5, 5, 0]},
+	{'test':'555', 'expected':[5, 5, 5]},
+	{'test':'5555', 'expected':[85, 85, 0]},
+	{'test':'55555', 'expected':[85, 85, 80]},
+	{'test':'555555', 'expected':[85, 85, 85]},
+	{'test':'5555555', 'expected':[85, 85, 80]},
+	{'test':'55555555', 'expected':[85, 85, 85]},
+	{'test':'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000', 'expected':[255, 255, 255]},
+	{'test':'򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿򀿿ffffff', 'expected':[0, 0, 0]},
+	{'test':' ', 'expected':[0, 0, 0]},
+	{'test':' ffffff ', 'expected':[255, 255, 255]}
+];
+
+for(var i = 0; i < tests.length; i++) {
+	var t = tests[i].test;
+	var e = tests[i].expected;
+	shouldBe("document.body.bgColor='" + t + "';getComputedStyle(document.body).backgroundColor;", "'rgb(" + e[0] + ", " + e[1] + ", " + e[2] + ")'");
+}
+})();
+successfullyParsed = true;
\ No newline at end of file

Modified: trunk/Source/WebCore/ChangeLog (90138 => 90139)


--- trunk/Source/WebCore/ChangeLog	2011-06-30 18:37:16 UTC (rev 90138)
+++ trunk/Source/WebCore/ChangeLog	2011-06-30 18:41:30 UTC (rev 90139)
@@ -1,3 +1,18 @@
+2011-06-30  Tab Atkins  <[email protected]>
+
+        Reviewed by Adam Barth.
+
+        Fix legacy color attribute parsing to match HTML spec
+        https://bugs.webkit.org/show_bug.cgi?id=63029
+
+        Relevant spec link: http://www.whatwg.org/specs/web-apps/current-work/complete/common-microsyntaxes.html#rules-for-parsing-a-legacy-color-value
+        Fix legacy color attribute parsing (<body bgcolor>, <font color>, etc.) to match the HTML spec and more closely match other browsers.
+
+        Test: fast/dom/attribute-legacy-colors.html
+
+        * dom/StyledElement.cpp:
+        (WebCore::StyledElement::addCSSColor):
+
 2011-06-28  Hans Wennborg  <[email protected]>
 
         Reviewed by Tony Chang.

Modified: trunk/Source/WebCore/dom/StyledElement.cpp (90138 => 90139)


--- trunk/Source/WebCore/dom/StyledElement.cpp	2011-06-30 18:37:16 UTC (rev 90138)
+++ trunk/Source/WebCore/dom/StyledElement.cpp	2011-06-30 18:41:30 UTC (rev 90139)
@@ -29,6 +29,7 @@
 #include "CSSStyleSelector.h"
 #include "CSSStyleSheet.h"
 #include "CSSValueKeywords.h"
+#include "Color.h"
 #include "ClassList.h"
 #include "ContentSecurityPolicy.h"
 #include "DOMTokenList.h"
@@ -317,77 +318,88 @@
     attr->decl()->setLengthProperty(id, value, false);
 }
 
-/* color parsing that tries to match as close as possible IE 6. */
-void StyledElement::addCSSColor(Attribute* attr, int id, const String& c)
+static String parseColorStringWithCrazyLegacyRules(const String& colorString)
 {
-    // this is the only case no color gets applied in IE.
-    if (!c.length())
-        return;
+    // Per spec, only look at the first 128 digits of the string.
+    const size_t maxColorLength = 128;
+    // We'll pad the buffer with two extra 0s later, so reserve two more than the max.
+    Vector<char, maxColorLength+2> digitBuffer;
+    
+    size_t i = 0;
+    // Skip a leading #.
+    if (colorString[0] == '#')
+        i = 1;
+    
+    // Grab the first 128 characters, replacing non-hex characters with 0.
+    // Non-BMP characters are replaced with "00" due to them appearing as two "characters" in the String.
+    for (; i < colorString.length() && digitBuffer.size() < maxColorLength; i++) {
+        if (!isASCIIHexDigit(colorString[i]))
+            digitBuffer.append('0');
+        else
+            digitBuffer.append(colorString[i]);
+    }
 
-    if (!attr->decl())
-        createMappedDecl(attr);
+    if (!digitBuffer.size())
+        return "#000000";
+
+    // Pad the buffer out to at least the next multiple of three in size.
+    digitBuffer.append('0');
+    digitBuffer.append('0');
+
+    if (digitBuffer.size() < 6)
+        return String::format("#0%c0%c0%c", digitBuffer[0], digitBuffer[1], digitBuffer[2]);
     
-    if (attr->decl()->setProperty(id, c, false))
+    // Split the digits into three components, then search the last 8 digits of each component.
+    ASSERT(digitBuffer.size() >= 6);
+    size_t componentLength = digitBuffer.size() / 3;
+    size_t componentSearchWindowLength = min<size_t>(componentLength, 8);
+    size_t redIndex = componentLength - componentSearchWindowLength;
+    size_t greenIndex = componentLength * 2 - componentSearchWindowLength;
+    size_t blueIndex = componentLength * 3 - componentSearchWindowLength;
+    // Skip digits until one of them is non-zero, or we've only got two digits left in the component.
+    while (digitBuffer[redIndex] == '0' && digitBuffer[greenIndex] == '0' && digitBuffer[blueIndex] == '0' && (componentLength - redIndex) > 2) {
+        redIndex++;
+        greenIndex++;
+        blueIndex++;
+    }
+    ASSERT(redIndex >= 0);
+    ASSERT(redIndex + 1 < componentLength);
+    ASSERT(greenIndex >= componentLength);
+    ASSERT(greenIndex + 1 < componentLength * 2);
+    ASSERT(blueIndex >= componentLength * 2);
+    ASSERT(blueIndex + 1 < digitBuffer.size());
+    return String::format("#%c%c%c%c%c%c", digitBuffer[redIndex], digitBuffer[redIndex + 1], digitBuffer[greenIndex], digitBuffer[greenIndex + 1], digitBuffer[blueIndex], digitBuffer[blueIndex + 1]);   
+}
+
+// Color parsing that matches HTML's "rules for parsing a legacy color value"
+void StyledElement::addCSSColor(Attribute* attribute, int id, const String& attributeValue)
+{
+    // The empty string doesn't apply a color. (Just whitespace does, which is why this check occurs before trimming.)
+    if (!attributeValue.length())
         return;
     
-    String color = c;
-    // not something that fits the specs.
-    
-    // we're emulating IEs color parser here. It maps transparent to black, otherwise it tries to build a rgb value
-    // out of everything you put in. The algorithm is experimentally determined, but seems to work for all test cases I have.
-    
-    // the length of the color value is rounded up to the next
-    // multiple of 3. each part of the rgb triple then gets one third
-    // of the length.
-    //
-    // Each triplet is parsed byte by byte, mapping
-    // each number to a hex value (0-9a-fA-F to their values
-    // everything else to 0).
-    //
-    // The highest non zero digit in all triplets is remembered, and
-    // used as a normalization point to normalize to values between 0
-    // and 255.
-    
-    if (!equalIgnoringCase(color, "transparent")) {
-        if (color[0] == '#')
-            color.remove(0, 1);
-        int basicLength = (color.length() + 2) / 3;
-        if (basicLength > 1) {
-            // IE ignores colors with three digits or less
-            int colors[3] = { 0, 0, 0 };
-            int component = 0;
-            int pos = 0;
-            int maxDigit = basicLength-1;
-            while (component < 3) {
-                // search forward for digits in the string
-                int numDigits = 0;
-                while (pos < (int)color.length() && numDigits < basicLength) {
-                    colors[component] <<= 4;
-                    if (isASCIIHexDigit(color[pos])) {
-                        colors[component] += toASCIIHexValue(color[pos]);
-                        maxDigit = min(maxDigit, numDigits);
-                    }
-                    numDigits++;
-                    pos++;
-                }
-                while (numDigits++ < basicLength)
-                    colors[component] <<= 4;
-                component++;
-            }
-            maxDigit = basicLength - maxDigit;
-            
-            // normalize to 00-ff. The highest filled digit counts, minimum is 2 digits
-            maxDigit -= 2;
-            colors[0] >>= 4 * maxDigit;
-            colors[1] >>= 4 * maxDigit;
-            colors[2] >>= 4 * maxDigit;
-            
-            color = String::format("#%02x%02x%02x", colors[0], colors[1], colors[2]);
-            if (attr->decl()->setProperty(id, color, false))
-                return;
-        }
+    String color = attributeValue.stripWhiteSpace();
+
+    // "transparent" doesn't apply a color either.
+    if (equalIgnoringCase(color, "transparent"))
+        return;
+
+    if (!attribute->decl())
+        createMappedDecl(attribute);
+
+    // If the string is a named CSS color, use that color.
+    Color foundColor;
+    foundColor.setNamedColor(color);
+    if (foundColor.isValid()) {
+        attribute->decl()->setProperty(id, color, false);
+        return;
     }
-    attr->decl()->setProperty(id, CSSValueBlack, false);
+
+    // If the string is a 3 or 6-digit hex color, use that color.
+    if (color[0] == '#' && (color.length() == 4 || color.length() == 7) && attribute->decl()->setProperty(id, color, false))
+        return;
+
+    attribute->decl()->setProperty(id, parseColorStringWithCrazyLegacyRules(color), false);
 }
 
 void StyledElement::createMappedDecl(Attribute* attr)
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to