Changeset 90139 in webkit
- Timestamp:
- Jun 30, 2011, 11:41:30 AM (14 years ago)
- Location:
- trunk
- Files:
-
- 3 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r90134 r90139 1 2011-06-30 Tab Atkins <jackalmage@gmail.com> 2 3 Reviewed by Adam Barth. 4 5 Fix legacy color attribute parsing to match HTML spec 6 https://bugs.webkit.org/show_bug.cgi?id=63029 7 8 Tests <body bgcolor> parsing. 9 10 * fast/dom/attribute-legacy-colors-expected.txt: Added. 11 * fast/dom/attribute-legacy-colors.html: Added. 12 * fast/dom/script-tests/attribute-legacy-colors.js: Added. 13 1 14 2011-06-30 Nate Chapin <japhet@chromium.org> 2 15 -
trunk/Source/WebCore/ChangeLog
r90137 r90139 1 2011-06-30 Tab Atkins <jackalmage@gmail.com> 2 3 Reviewed by Adam Barth. 4 5 Fix legacy color attribute parsing to match HTML spec 6 https://bugs.webkit.org/show_bug.cgi?id=63029 7 8 Relevant spec link: http://www.whatwg.org/specs/web-apps/current-work/complete/common-microsyntaxes.html#rules-for-parsing-a-legacy-color-value 9 Fix legacy color attribute parsing (<body bgcolor>, <font color>, etc.) to match the HTML spec and more closely match other browsers. 10 11 Test: fast/dom/attribute-legacy-colors.html 12 13 * dom/StyledElement.cpp: 14 (WebCore::StyledElement::addCSSColor): 15 1 16 2011-06-28 Hans Wennborg <hans@chromium.org> 2 17 -
trunk/Source/WebCore/dom/StyledElement.cpp
r88601 r90139 30 30 #include "CSSStyleSheet.h" 31 31 #include "CSSValueKeywords.h" 32 #include "Color.h" 32 33 #include "ClassList.h" 33 34 #include "ContentSecurityPolicy.h" … … 318 319 } 319 320 320 /* color parsing that tries to match as close as possible IE 6. */ 321 void StyledElement::addCSSColor(Attribute* attr, int id, const String& c) 322 { 323 // this is the only case no color gets applied in IE. 324 if (!c.length()) 325 return; 326 327 if (!attr->decl()) 328 createMappedDecl(attr); 329 330 if (attr->decl()->setProperty(id, c, false)) 331 return; 332 333 String color = c; 334 // not something that fits the specs. 335 336 // we're emulating IEs color parser here. It maps transparent to black, otherwise it tries to build a rgb value 337 // out of everything you put in. The algorithm is experimentally determined, but seems to work for all test cases I have. 338 339 // the length of the color value is rounded up to the next 340 // multiple of 3. each part of the rgb triple then gets one third 341 // of the length. 342 // 343 // Each triplet is parsed byte by byte, mapping 344 // each number to a hex value (0-9a-fA-F to their values 345 // everything else to 0). 346 // 347 // The highest non zero digit in all triplets is remembered, and 348 // used as a normalization point to normalize to values between 0 349 // and 255. 350 351 if (!equalIgnoringCase(color, "transparent")) { 352 if (color[0] == '#') 353 color.remove(0, 1); 354 int basicLength = (color.length() + 2) / 3; 355 if (basicLength > 1) { 356 // IE ignores colors with three digits or less 357 int colors[3] = { 0, 0, 0 }; 358 int component = 0; 359 int pos = 0; 360 int maxDigit = basicLength-1; 361 while (component < 3) { 362 // search forward for digits in the string 363 int numDigits = 0; 364 while (pos < (int)color.length() && numDigits < basicLength) { 365 colors[component] <<= 4; 366 if (isASCIIHexDigit(color[pos])) { 367 colors[component] += toASCIIHexValue(color[pos]); 368 maxDigit = min(maxDigit, numDigits); 369 } 370 numDigits++; 371 pos++; 372 } 373 while (numDigits++ < basicLength) 374 colors[component] <<= 4; 375 component++; 376 } 377 maxDigit = basicLength - maxDigit; 378 379 // normalize to 00-ff. The highest filled digit counts, minimum is 2 digits 380 maxDigit -= 2; 381 colors[0] >>= 4 * maxDigit; 382 colors[1] >>= 4 * maxDigit; 383 colors[2] >>= 4 * maxDigit; 384 385 color = String::format("#%02x%02x%02x", colors[0], colors[1], colors[2]); 386 if (attr->decl()->setProperty(id, color, false)) 387 return; 388 } 389 } 390 attr->decl()->setProperty(id, CSSValueBlack, false); 321 static String parseColorStringWithCrazyLegacyRules(const String& colorString) 322 { 323 // Per spec, only look at the first 128 digits of the string. 324 const size_t maxColorLength = 128; 325 // We'll pad the buffer with two extra 0s later, so reserve two more than the max. 326 Vector<char, maxColorLength+2> digitBuffer; 327 328 size_t i = 0; 329 // Skip a leading #. 330 if (colorString[0] == '#') 331 i = 1; 332 333 // Grab the first 128 characters, replacing non-hex characters with 0. 334 // Non-BMP characters are replaced with "00" due to them appearing as two "characters" in the String. 335 for (; i < colorString.length() && digitBuffer.size() < maxColorLength; i++) { 336 if (!isASCIIHexDigit(colorString[i])) 337 digitBuffer.append('0'); 338 else 339 digitBuffer.append(colorString[i]); 340 } 341 342 if (!digitBuffer.size()) 343 return "#000000"; 344 345 // Pad the buffer out to at least the next multiple of three in size. 346 digitBuffer.append('0'); 347 digitBuffer.append('0'); 348 349 if (digitBuffer.size() < 6) 350 return String::format("#0%c0%c0%c", digitBuffer[0], digitBuffer[1], digitBuffer[2]); 351 352 // Split the digits into three components, then search the last 8 digits of each component. 353 ASSERT(digitBuffer.size() >= 6); 354 size_t componentLength = digitBuffer.size() / 3; 355 size_t componentSearchWindowLength = min<size_t>(componentLength, 8); 356 size_t redIndex = componentLength - componentSearchWindowLength; 357 size_t greenIndex = componentLength * 2 - componentSearchWindowLength; 358 size_t blueIndex = componentLength * 3 - componentSearchWindowLength; 359 // Skip digits until one of them is non-zero, or we've only got two digits left in the component. 360 while (digitBuffer[redIndex] == '0' && digitBuffer[greenIndex] == '0' && digitBuffer[blueIndex] == '0' && (componentLength - redIndex) > 2) { 361 redIndex++; 362 greenIndex++; 363 blueIndex++; 364 } 365 ASSERT(redIndex >= 0); 366 ASSERT(redIndex + 1 < componentLength); 367 ASSERT(greenIndex >= componentLength); 368 ASSERT(greenIndex + 1 < componentLength * 2); 369 ASSERT(blueIndex >= componentLength * 2); 370 ASSERT(blueIndex + 1 < digitBuffer.size()); 371 return String::format("#%c%c%c%c%c%c", digitBuffer[redIndex], digitBuffer[redIndex + 1], digitBuffer[greenIndex], digitBuffer[greenIndex + 1], digitBuffer[blueIndex], digitBuffer[blueIndex + 1]); 372 } 373 374 // Color parsing that matches HTML's "rules for parsing a legacy color value" 375 void StyledElement::addCSSColor(Attribute* attribute, int id, const String& attributeValue) 376 { 377 // The empty string doesn't apply a color. (Just whitespace does, which is why this check occurs before trimming.) 378 if (!attributeValue.length()) 379 return; 380 381 String color = attributeValue.stripWhiteSpace(); 382 383 // "transparent" doesn't apply a color either. 384 if (equalIgnoringCase(color, "transparent")) 385 return; 386 387 if (!attribute->decl()) 388 createMappedDecl(attribute); 389 390 // If the string is a named CSS color, use that color. 391 Color foundColor; 392 foundColor.setNamedColor(color); 393 if (foundColor.isValid()) { 394 attribute->decl()->setProperty(id, color, false); 395 return; 396 } 397 398 // If the string is a 3 or 6-digit hex color, use that color. 399 if (color[0] == '#' && (color.length() == 4 || color.length() == 7) && attribute->decl()->setProperty(id, color, false)) 400 return; 401 402 attribute->decl()->setProperty(id, parseColorStringWithCrazyLegacyRules(color), false); 391 403 } 392 404
Note:
See TracChangeset
for help on using the changeset viewer.