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='ffff';getComputedStyle(document.body).backgroundColor; is 'rgb(255, 0, 255)'
+PASS document.body.bgColor='ff';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='55201155001155000011';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/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':'ffff', 'expected':[255, 0, 255]},
+ {'test':'ff', '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':'55201155001155000011', '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/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)