Home | History | Annotate | Download | only in graphics
      1 /*
      2  * Copyright (C) 2003, 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "platform/graphics/Color.h"
     28 
     29 #include "platform/Decimal.h"
     30 #include "wtf/Assertions.h"
     31 #include "wtf/HexNumber.h"
     32 #include "wtf/MathExtras.h"
     33 #include "wtf/dtoa.h"
     34 #include "wtf/text/StringBuilder.h"
     35 
     36 using namespace std;
     37 
     38 namespace WebCore {
     39 
     40 #if !COMPILER(MSVC) || COMPILER(CLANG)
     41 // FIXME: Use C++11 strong enums to avoid static data member with initializer definition problems.
     42 const RGBA32 Color::black;
     43 const RGBA32 Color::white;
     44 const RGBA32 Color::darkGray;
     45 const RGBA32 Color::gray;
     46 const RGBA32 Color::lightGray;
     47 const RGBA32 Color::transparent;
     48 #endif
     49 
     50 static const RGBA32 lightenedBlack = 0xFF545454;
     51 static const RGBA32 darkenedWhite = 0xFFABABAB;
     52 
     53 RGBA32 makeRGB(int r, int g, int b)
     54 {
     55     return 0xFF000000 | max(0, min(r, 255)) << 16 | max(0, min(g, 255)) << 8 | max(0, min(b, 255));
     56 }
     57 
     58 RGBA32 makeRGBA(int r, int g, int b, int a)
     59 {
     60     return max(0, min(a, 255)) << 24 | max(0, min(r, 255)) << 16 | max(0, min(g, 255)) << 8 | max(0, min(b, 255));
     61 }
     62 
     63 static int colorFloatToRGBAByte(float f)
     64 {
     65     // We use lroundf and 255 instead of nextafterf(256, 0) to match CG's rounding
     66     return max(0, min(static_cast<int>(lroundf(255.0f * f)), 255));
     67 }
     68 
     69 RGBA32 makeRGBA32FromFloats(float r, float g, float b, float a)
     70 {
     71     return colorFloatToRGBAByte(a) << 24 | colorFloatToRGBAByte(r) << 16 | colorFloatToRGBAByte(g) << 8 | colorFloatToRGBAByte(b);
     72 }
     73 
     74 RGBA32 colorWithOverrideAlpha(RGBA32 color, float overrideAlpha)
     75 {
     76     RGBA32 rgbOnly = color & 0x00FFFFFF;
     77     RGBA32 rgba = rgbOnly | colorFloatToRGBAByte(overrideAlpha) << 24;
     78     return rgba;
     79 }
     80 
     81 static double calcHue(double temp1, double temp2, double hueVal)
     82 {
     83     if (hueVal < 0.0)
     84         hueVal++;
     85     else if (hueVal > 1.0)
     86         hueVal--;
     87     if (hueVal * 6.0 < 1.0)
     88         return temp1 + (temp2 - temp1) * hueVal * 6.0;
     89     if (hueVal * 2.0 < 1.0)
     90         return temp2;
     91     if (hueVal * 3.0 < 2.0)
     92         return temp1 + (temp2 - temp1) * (2.0 / 3.0 - hueVal) * 6.0;
     93     return temp1;
     94 }
     95 
     96 // Explanation of this algorithm can be found in the CSS3 Color Module
     97 // specification at http://www.w3.org/TR/css3-color/#hsl-color with further
     98 // explanation available at http://en.wikipedia.org/wiki/HSL_color_space
     99 
    100 // all values are in the range of 0 to 1.0
    101 RGBA32 makeRGBAFromHSLA(double hue, double saturation, double lightness, double alpha)
    102 {
    103     const double scaleFactor = nextafter(256.0, 0.0);
    104 
    105     if (!saturation) {
    106         int greyValue = static_cast<int>(lightness * scaleFactor);
    107         return makeRGBA(greyValue, greyValue, greyValue, static_cast<int>(alpha * scaleFactor));
    108     }
    109 
    110     double temp2 = lightness < 0.5 ? lightness * (1.0 + saturation) : lightness + saturation - lightness * saturation;
    111     double temp1 = 2.0 * lightness - temp2;
    112 
    113     return makeRGBA(static_cast<int>(calcHue(temp1, temp2, hue + 1.0 / 3.0) * scaleFactor),
    114                     static_cast<int>(calcHue(temp1, temp2, hue) * scaleFactor),
    115                     static_cast<int>(calcHue(temp1, temp2, hue - 1.0 / 3.0) * scaleFactor),
    116                     static_cast<int>(alpha * scaleFactor));
    117 }
    118 
    119 RGBA32 makeRGBAFromCMYKA(float c, float m, float y, float k, float a)
    120 {
    121     double colors = 1 - k;
    122     int r = static_cast<int>(nextafter(256, 0) * (colors * (1 - c)));
    123     int g = static_cast<int>(nextafter(256, 0) * (colors * (1 - m)));
    124     int b = static_cast<int>(nextafter(256, 0) * (colors * (1 - y)));
    125     return makeRGBA(r, g, b, static_cast<float>(nextafter(256, 0) * a));
    126 }
    127 
    128 // originally moved here from the CSS parser
    129 template <typename CharacterType>
    130 static inline bool parseHexColorInternal(const CharacterType* name, unsigned length, RGBA32& rgb)
    131 {
    132     if (length != 3 && length != 6)
    133         return false;
    134     unsigned value = 0;
    135     for (unsigned i = 0; i < length; ++i) {
    136         if (!isASCIIHexDigit(name[i]))
    137             return false;
    138         value <<= 4;
    139         value |= toASCIIHexValue(name[i]);
    140     }
    141     if (length == 6) {
    142         rgb = 0xFF000000 | value;
    143         return true;
    144     }
    145     // #abc converts to #aabbcc
    146     rgb = 0xFF000000
    147         | (value & 0xF00) << 12 | (value & 0xF00) << 8
    148         | (value & 0xF0) << 8 | (value & 0xF0) << 4
    149         | (value & 0xF) << 4 | (value & 0xF);
    150     return true;
    151 }
    152 
    153 bool Color::parseHexColor(const LChar* name, unsigned length, RGBA32& rgb)
    154 {
    155     return parseHexColorInternal(name, length, rgb);
    156 }
    157 
    158 bool Color::parseHexColor(const UChar* name, unsigned length, RGBA32& rgb)
    159 {
    160     return parseHexColorInternal(name, length, rgb);
    161 }
    162 
    163 bool Color::parseHexColor(const String& name, RGBA32& rgb)
    164 {
    165     unsigned length = name.length();
    166 
    167     if (!length)
    168         return false;
    169     if (name.is8Bit())
    170         return parseHexColor(name.characters8(), name.length(), rgb);
    171     return parseHexColor(name.characters16(), name.length(), rgb);
    172 }
    173 
    174 int differenceSquared(const Color& c1, const Color& c2)
    175 {
    176     int dR = c1.red() - c2.red();
    177     int dG = c1.green() - c2.green();
    178     int dB = c1.blue() - c2.blue();
    179     return dR * dR + dG * dG + dB * dB;
    180 }
    181 
    182 bool Color::setFromString(const String& name)
    183 {
    184     if (name[0] != '#')
    185         return setNamedColor(name);
    186     if (name.is8Bit())
    187         return parseHexColor(name.characters8() + 1, name.length() - 1, m_color);
    188     return parseHexColor(name.characters16() + 1, name.length() - 1, m_color);
    189 }
    190 
    191 String Color::serializedAsCSSComponentValue() const
    192 {
    193     StringBuilder result;
    194     result.reserveCapacity(32);
    195     bool colorHasAlpha = hasAlpha();
    196     if (colorHasAlpha)
    197         result.append("rgba(", 5);
    198     else
    199         result.append("rgb(", 4);
    200 
    201     result.appendNumber(static_cast<unsigned char>(red()));
    202     result.append(", ", 2);
    203 
    204     result.appendNumber(static_cast<unsigned char>(green()));
    205     result.append(", ", 2);
    206 
    207     result.appendNumber(static_cast<unsigned char>(blue()));
    208     if (colorHasAlpha) {
    209         result.append(", ", 2);
    210 
    211         NumberToStringBuffer buffer;
    212         const char* alphaString = numberToFixedPrecisionString(alpha() / 255.0f, 6, buffer, true);
    213         result.append(alphaString, strlen(alphaString));
    214     }
    215 
    216     result.append(')');
    217     return result.toString();
    218 }
    219 
    220 String Color::serialized() const
    221 {
    222     if (!hasAlpha()) {
    223         StringBuilder builder;
    224         builder.reserveCapacity(7);
    225         builder.append('#');
    226         appendByteAsHex(red(), builder, Lowercase);
    227         appendByteAsHex(green(), builder, Lowercase);
    228         appendByteAsHex(blue(), builder, Lowercase);
    229         return builder.toString();
    230     }
    231 
    232     StringBuilder result;
    233     result.reserveCapacity(28);
    234     const char commaSpace[] = ", ";
    235     const char rgbaParen[] = "rgba(";
    236 
    237     result.append(rgbaParen, 5);
    238     result.appendNumber(red());
    239     result.append(commaSpace, 2);
    240     result.appendNumber(green());
    241     result.append(commaSpace, 2);
    242     result.appendNumber(blue());
    243     result.append(commaSpace, 2);
    244 
    245     if (!alpha())
    246         result.append('0');
    247     else {
    248         result.append(Decimal::fromDouble(alpha() / 255.0).toString());
    249     }
    250 
    251     result.append(')');
    252     return result.toString();
    253 }
    254 
    255 String Color::nameForRenderTreeAsText() const
    256 {
    257     if (alpha() < 0xFF)
    258         return String::format("#%02X%02X%02X%02X", red(), green(), blue(), alpha());
    259     return String::format("#%02X%02X%02X", red(), green(), blue());
    260 }
    261 
    262 static inline const NamedColor* findNamedColor(const String& name)
    263 {
    264     char buffer[64]; // easily big enough for the longest color name
    265     unsigned length = name.length();
    266     if (length > sizeof(buffer) - 1)
    267         return 0;
    268     for (unsigned i = 0; i < length; ++i) {
    269         UChar c = name[i];
    270         if (!c || c > 0x7F)
    271             return 0;
    272         buffer[i] = toASCIILower(static_cast<char>(c));
    273     }
    274     buffer[length] = '\0';
    275     return findColor(buffer, length);
    276 }
    277 
    278 bool Color::setNamedColor(const String& name)
    279 {
    280     const NamedColor* foundColor = findNamedColor(name);
    281     m_color = foundColor ? foundColor->ARGBValue : 0;
    282     return foundColor;
    283 }
    284 
    285 Color Color::light() const
    286 {
    287     // Hardcode this common case for speed.
    288     if (m_color == black)
    289         return lightenedBlack;
    290 
    291     const float scaleFactor = nextafterf(256.0f, 0.0f);
    292 
    293     float r, g, b, a;
    294     getRGBA(r, g, b, a);
    295 
    296     float v = max(r, max(g, b));
    297 
    298     if (v == 0.0f)
    299         // Lightened black with alpha.
    300         return Color(0x54, 0x54, 0x54, alpha());
    301 
    302     float multiplier = min(1.0f, v + 0.33f) / v;
    303 
    304     return Color(static_cast<int>(multiplier * r * scaleFactor),
    305                  static_cast<int>(multiplier * g * scaleFactor),
    306                  static_cast<int>(multiplier * b * scaleFactor),
    307                  alpha());
    308 }
    309 
    310 Color Color::dark() const
    311 {
    312     // Hardcode this common case for speed.
    313     if (m_color == white)
    314         return darkenedWhite;
    315 
    316     const float scaleFactor = nextafterf(256.0f, 0.0f);
    317 
    318     float r, g, b, a;
    319     getRGBA(r, g, b, a);
    320 
    321     float v = max(r, max(g, b));
    322     float multiplier = max(0.0f, (v - 0.33f) / v);
    323 
    324     return Color(static_cast<int>(multiplier * r * scaleFactor),
    325                  static_cast<int>(multiplier * g * scaleFactor),
    326                  static_cast<int>(multiplier * b * scaleFactor),
    327                  alpha());
    328 }
    329 
    330 Color Color::combineWithAlpha(float otherAlpha) const
    331 {
    332     return colorWithOverrideAlpha(rgb(), (alpha() / 255.f) * otherAlpha);
    333 }
    334 
    335 static int blendComponent(int c, int a)
    336 {
    337     // We use white.
    338     float alpha = a / 255.0f;
    339     int whiteBlend = 255 - a;
    340     c -= whiteBlend;
    341     return static_cast<int>(c / alpha);
    342 }
    343 
    344 const int cStartAlpha = 153; // 60%
    345 const int cEndAlpha = 204; // 80%;
    346 const int cAlphaIncrement = 17; // Increments in between.
    347 
    348 Color Color::blend(const Color& source) const
    349 {
    350     if (!alpha() || !source.hasAlpha())
    351         return source;
    352 
    353     if (!source.alpha())
    354         return *this;
    355 
    356     int d = 255 * (alpha() + source.alpha()) - alpha() * source.alpha();
    357     int a = d / 255;
    358     int r = (red() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.red()) / d;
    359     int g = (green() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.green()) / d;
    360     int b = (blue() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.blue()) / d;
    361     return Color(r, g, b, a);
    362 }
    363 
    364 Color Color::blendWithWhite() const
    365 {
    366     // If the color contains alpha already, we leave it alone.
    367     if (hasAlpha())
    368         return *this;
    369 
    370     Color newColor;
    371     for (int alpha = cStartAlpha; alpha <= cEndAlpha; alpha += cAlphaIncrement) {
    372         // We have a solid color.  Convert to an equivalent color that looks the same when blended with white
    373         // at the current alpha.  Try using less transparency if the numbers end up being negative.
    374         int r = blendComponent(red(), alpha);
    375         int g = blendComponent(green(), alpha);
    376         int b = blendComponent(blue(), alpha);
    377 
    378         newColor = Color(r, g, b, alpha);
    379 
    380         if (r >= 0 && g >= 0 && b >= 0)
    381             break;
    382     }
    383     return newColor;
    384 }
    385 
    386 void Color::getRGBA(float& r, float& g, float& b, float& a) const
    387 {
    388     r = red() / 255.0f;
    389     g = green() / 255.0f;
    390     b = blue() / 255.0f;
    391     a = alpha() / 255.0f;
    392 }
    393 
    394 void Color::getRGBA(double& r, double& g, double& b, double& a) const
    395 {
    396     r = red() / 255.0;
    397     g = green() / 255.0;
    398     b = blue() / 255.0;
    399     a = alpha() / 255.0;
    400 }
    401 
    402 void Color::getHSL(double& hue, double& saturation, double& lightness) const
    403 {
    404     // http://en.wikipedia.org/wiki/HSL_color_space. This is a direct copy of
    405     // the algorithm therein, although it's 360^o based and we end up wanting
    406     // [0...1) based. It's clearer if we stick to 360^o until the end.
    407     double r = static_cast<double>(red()) / 255.0;
    408     double g = static_cast<double>(green()) / 255.0;
    409     double b = static_cast<double>(blue()) / 255.0;
    410     double max = std::max(std::max(r, g), b);
    411     double min = std::min(std::min(r, g), b);
    412 
    413     if (max == min)
    414         hue = 0.0;
    415     else if (max == r)
    416         hue = (60.0 * ((g - b) / (max - min))) + 360.0;
    417     else if (max == g)
    418         hue = (60.0 * ((b - r) / (max - min))) + 120.0;
    419     else
    420         hue = (60.0 * ((r - g) / (max - min))) + 240.0;
    421 
    422     if (hue >= 360.0)
    423         hue -= 360.0;
    424 
    425     // makeRGBAFromHSLA assumes that hue is in [0...1).
    426     hue /= 360.0;
    427 
    428     lightness = 0.5 * (max + min);
    429     if (max == min)
    430         saturation = 0.0;
    431     else if (lightness <= 0.5)
    432         saturation = ((max - min) / (max + min));
    433     else
    434         saturation = ((max - min) / (2.0 - (max + min)));
    435 }
    436 
    437 Color colorFromPremultipliedARGB(RGBA32 pixelColor)
    438 {
    439     int alpha = alphaChannel(pixelColor);
    440     if (alpha && alpha < 255) {
    441         return Color::createUnchecked(
    442             redChannel(pixelColor) * 255 / alpha,
    443             greenChannel(pixelColor) * 255 / alpha,
    444             blueChannel(pixelColor) * 255 / alpha,
    445             alpha);
    446     } else
    447         return Color(pixelColor);
    448 }
    449 
    450 RGBA32 premultipliedARGBFromColor(const Color& color)
    451 {
    452     unsigned pixelColor;
    453 
    454     unsigned alpha = color.alpha();
    455     if (alpha < 255) {
    456         pixelColor = Color::createUnchecked(
    457             (color.red() * alpha  + 254) / 255,
    458             (color.green() * alpha  + 254) / 255,
    459             (color.blue() * alpha  + 254) / 255,
    460             alpha).rgb();
    461     } else
    462          pixelColor = color.rgb();
    463 
    464     return pixelColor;
    465 }
    466 
    467 } // namespace WebCore
    468