Changeset 90139 in webkit


Ignore:
Timestamp:
Jun 30, 2011 11:41:30 AM (13 years ago)
Author:
commit-queue@webkit.org
Message:

2011-06-30 Tab Atkins <jackalmage@gmail.com>

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 <jackalmage@gmail.com>

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):
Location:
trunk
Files:
3 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r90134 r90139  
     12011-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
    1142011-06-30  Nate Chapin  <japhet@chromium.org>
    215
  • trunk/Source/WebCore/ChangeLog

    r90137 r90139  
     12011-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
    1162011-06-28  Hans Wennborg  <hans@chromium.org>
    217
  • trunk/Source/WebCore/dom/StyledElement.cpp

    r88601 r90139  
    3030#include "CSSStyleSheet.h"
    3131#include "CSSValueKeywords.h"
     32#include "Color.h"
    3233#include "ClassList.h"
    3334#include "ContentSecurityPolicy.h"
     
    318319}
    319320
    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);
     321static 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"
     375void 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);
    391403}
    392404
Note: See TracChangeset for help on using the changeset viewer.