关于html:如何计算bgcolor属性?

How is the bgcolor property being calculated?

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
Why does HTML think"chucknorris" is a color?

如何计算bgcolor属性?

当我使用以下HTML代码时…

1
<body bgcolor="#Deine Mutter hat eine Farbe und die ist grün."></body>

…我得到的是以下颜色。

#Deine Mutter hat eine Farbe und die ist grün.

顺便说一下:当我尝试在CSS中使用它时,它将不起作用,将应用标准颜色:

1
2
3
body{
    color: #IchwillGOLD;
}

为什么?


我的第一次尝试是一个关于错误的小尝试,虽然我发现了一些有趣的系统属性,但还不足以形成一个答案。接下来,我把注意力转向了标准。我之所以相信这个标准是因为我在三个不同的浏览器上测试了它,实际上它们都做了相同的事情。根据标准,我发现会发生什么:

  • 所有不是十六进制的字符都被零替换(因此只剩下零、1-9和a-e)
  • 字符串的末尾零填充为三的倍数
  • 然后将字符串分成三个相等的部分,每个部分代表一种颜色
  • 如果结果字符串超过8个字符,则取每个字符串的最后8个字符
  • 只要每个字符串都以零开头,就从每个字符串中删除第一个字符(由于该特定字符串以De开头,所以不会发生在该字符串中)。
  • 前两个字符取自这些字符串中的每一个,并转换为数字,用作颜色的一个组件。
  • 这样,你会看到你得到了00FA00Deine Mutter hat eine Farbe und die ist grün.

    HTML5标准更准确地描述了这个过程,并在这里实际描述了更多的几个案例:http://www.w3.org/tr/html5/common microsyntaxes.html colors under the"Rules for Parsing a Legacy Color Value"


    正如我在注释中所说,htmlparser将它作为一个css属性添加,正如Jasper已经回答过的那样,它是按规格划分的。

    实施

    webkit解析html parser.cpp中的HTML,如果解析器是inbody,则在htmlbodyelement.cpp中将bgcolor属性添加为csscolor。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // Color parsing that matches HTML's"rules for parsing a legacy color value"
    void HTMLElement::addHTMLColorToStyle(StylePropertySet* style, CSSPropertyID propertyID, const String& attributeValue)
    {
        // An empty string doesn't apply a color. (One containing only whitespace does, which is why this check occurs before stripping.)
        if (attributeValue.isEmpty())
            return;

        String colorString = attributeValue.stripWhiteSpace();

        //"transparent" doesn't apply a color either.
        if (equalIgnoringCase(colorString,"transparent"))
            return;

        // If the string is a named CSS color or a 3/6-digit hex color, use that.
        Color parsedColor(colorString);
        if (!parsedColor.isValid())
            parsedColor.setRGB(parseColorStringWithCrazyLegacyRules(colorString));

        style->setProperty(propertyID, cssValuePool().createColorValue(parsedColor.rgb()));
    }

    你很有可能以这种方法结束:

    1
    static RGBA32 parseColorStringWithCrazyLegacyRules(const String& colorString)

    我认为它支持这样的传统颜色:body bgcolor=ff0000(mozilla gecko测试)。

  • 跳过前导#
  • 抓取前128个字符,将非十六进制字符替换为0。一千一百二十
  • 非BMP字符替换为"00",因为它们在字符串中显示为两个"字符"。
  • 如果没有数字,返回黑色
  • 将数字分成三个部分,然后搜索每个部分的最后8位。
  • webkit/htmlelement.cpp的代码:parseColorStringWithCrazylegacyRules:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    static RGBA32 parseColorStringWithCrazyLegacyRules(const String& colorString)
    {
        // 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 (!digitBuffer.size())
            return Color::black;

        // 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 makeRGB(toASCIIHexValue(digitBuffer[0]), toASCIIHexValue(digitBuffer[1]), toASCIIHexValue(digitBuffer[2]));

        // 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 + 1 < componentLength);
        ASSERT(greenIndex >= componentLength);
        ASSERT(greenIndex + 1 < componentLength * 2);
        ASSERT(blueIndex >= componentLength * 2);
        ASSERT(blueIndex + 1 < digitBuffer.size());

        int redValue = toASCIIHexValue(digitBuffer[redIndex], digitBuffer[redIndex + 1]);
        int greenValue = toASCIIHexValue(digitBuffer[greenIndex], digitBuffer[greenIndex + 1]);
        int blueValue = toASCIIHexValue(digitBuffer[blueIndex], digitBuffer[blueIndex + 1]);
        return makeRGB(redValue, greenValue, blueValue);
    }