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 "Color.h"
     28 
     29 #include "HashTools.h"
     30 #include <wtf/Assertions.h>
     31 #include <wtf/HexNumber.h>
     32 #include <wtf/MathExtras.h>
     33 #include <wtf/text/StringBuilder.h>
     34 
     35 using namespace std;
     36 
     37 namespace WebCore {
     38 
     39 #if !COMPILER(MSVC)
     40 const RGBA32 Color::black;
     41 const RGBA32 Color::white;
     42 const RGBA32 Color::darkGray;
     43 const RGBA32 Color::gray;
     44 const RGBA32 Color::lightGray;
     45 const RGBA32 Color::transparent;
     46 #endif
     47 
     48 static const RGBA32 lightenedBlack = 0xFF545454;
     49 static const RGBA32 darkenedWhite = 0xFFABABAB;
     50 
     51 RGBA32 makeRGB(int r, int g, int b)
     52 {
     53     return 0xFF000000 | max(0, min(r, 255)) << 16 | max(0, min(g, 255)) << 8 | max(0, min(b, 255));
     54 }
     55 
     56 RGBA32 makeRGBA(int r, int g, int b, int a)
     57 {
     58     return max(0, min(a, 255)) << 24 | max(0, min(r, 255)) << 16 | max(0, min(g, 255)) << 8 | max(0, min(b, 255));
     59 }
     60 
     61 static int colorFloatToRGBAByte(float f)
     62 {
     63     // We use lroundf and 255 instead of nextafterf(256, 0) to match CG's rounding
     64     return max(0, min(static_cast<int>(lroundf(255.0f * f)), 255));
     65 }
     66 
     67 RGBA32 makeRGBA32FromFloats(float r, float g, float b, float a)
     68 {
     69     return colorFloatToRGBAByte(a) << 24 | colorFloatToRGBAByte(r) << 16 | colorFloatToRGBAByte(g) << 8 | colorFloatToRGBAByte(b);
     70 }
     71 
     72 RGBA32 colorWithOverrideAlpha(RGBA32 color, float overrideAlpha)
     73 {
     74     RGBA32 rgbOnly = color & 0x00FFFFFF;
     75     RGBA32 rgba = rgbOnly | colorFloatToRGBAByte(overrideAlpha) << 24;
     76     return rgba;
     77 }
     78 
     79 static double calcHue(double temp1, double temp2, double hueVal)
     80 {
     81     if (hueVal < 0.0)
     82         hueVal++;
     83     else if (hueVal > 1.0)
     84         hueVal--;
     85     if (hueVal * 6.0 < 1.0)
     86         return temp1 + (temp2 - temp1) * hueVal * 6.0;
     87     if (hueVal * 2.0 < 1.0)
     88         return temp2;
     89     if (hueVal * 3.0 < 2.0)
     90         return temp1 + (temp2 - temp1) * (2.0 / 3.0 - hueVal) * 6.0;
     91     return temp1;
     92 }
     93 
     94 // Explanation of this algorithm can be found in the CSS3 Color Module
     95 // specification at http://www.w3.org/TR/css3-color/#hsl-color with further
     96 // explanation available at http://en.wikipedia.org/wiki/HSL_color_space
     97 
     98 // all values are in the range of 0 to 1.0
     99 RGBA32 makeRGBAFromHSLA(double hue, double saturation, double lightness, double alpha)
    100 {
    101     const double scaleFactor = nextafter(256.0, 0.0);
    102 
    103     if (!saturation) {
    104         int greyValue = static_cast<int>(lightness * scaleFactor);
    105         return makeRGBA(greyValue, greyValue, greyValue, static_cast<int>(alpha * scaleFactor));
    106     }
    107 
    108     double temp2 = lightness < 0.5 ? lightness * (1.0 + saturation) : lightness + saturation - lightness * saturation;
    109     double temp1 = 2.0 * lightness - temp2;
    110 
    111     return makeRGBA(static_cast<int>(calcHue(temp1, temp2, hue + 1.0 / 3.0) * scaleFactor),
    112                     static_cast<int>(calcHue(temp1, temp2, hue) * scaleFactor),
    113                     static_cast<int>(calcHue(temp1, temp2, hue - 1.0 / 3.0) * scaleFactor),
    114                     static_cast<int>(alpha * scaleFactor));
    115 }
    116 
    117 RGBA32 makeRGBAFromCMYKA(float c, float m, float y, float k, float a)
    118 {
    119     double colors = 1 - k;
    120     int r = static_cast<int>(nextafter(256, 0) * (colors * (1 - c)));
    121     int g = static_cast<int>(nextafter(256, 0) * (colors * (1 - m)));
    122     int b = static_cast<int>(nextafter(256, 0) * (colors * (1 - y)));
    123     return makeRGBA(r, g, b, static_cast<float>(nextafter(256, 0) * a));
    124 }
    125 
    126 // originally moved here from the CSS parser
    127 bool Color::parseHexColor(const UChar* name, unsigned length, RGBA32& rgb)
    128 {
    129     if (length != 3 && length != 6)
    130         return false;
    131     unsigned value = 0;
    132     for (unsigned i = 0; i < length; ++i) {
    133         if (!isASCIIHexDigit(name[i]))
    134             return false;
    135         value <<= 4;
    136         value |= toASCIIHexValue(name[i]);
    137     }
    138     if (length == 6) {
    139         rgb = 0xFF000000 | value;
    140         return true;
    141     }
    142     // #abc converts to #aabbcc
    143     rgb = 0xFF000000
    144         | (value & 0xF00) << 12 | (value & 0xF00) << 8
    145         | (value & 0xF0) << 8 | (value & 0xF0) << 4
    146         | (value & 0xF) << 4 | (value & 0xF);
    147     return true;
    148 }
    149 
    150 bool Color::parseHexColor(const String& name, RGBA32& rgb)
    151 {
    152     return parseHexColor(name.characters(), name.length(), rgb);
    153 }
    154 
    155 int differenceSquared(const Color& c1, const Color& c2)
    156 {
    157     int dR = c1.red() - c2.red();
    158     int dG = c1.green() - c2.green();
    159     int dB = c1.blue() - c2.blue();
    160     return dR * dR + dG * dG + dB * dB;
    161 }
    162 
    163 Color::Color(const String& name)
    164 {
    165     if (name[0] == '#')
    166         m_valid = parseHexColor(name.characters() + 1, name.length() - 1, m_color);
    167     else
    168         setNamedColor(name);
    169 }
    170 
    171 Color::Color(const char* name)
    172 {
    173     if (name[0] == '#')
    174         m_valid = parseHexColor(&name[1], m_color);
    175     else {
    176         const NamedColor* foundColor = findColor(name, strlen(name));
    177         m_color = foundColor ? foundColor->ARGBValue : 0;
    178         m_valid = foundColor;
    179     }
    180 }
    181 
    182 String Color::serialized() const
    183 {
    184     DEFINE_STATIC_LOCAL(const String, commaSpace, (", "));
    185     DEFINE_STATIC_LOCAL(const String, rgbaParen, ("rgba("));
    186     DEFINE_STATIC_LOCAL(const String, zeroPointZero, ("0.0"));
    187 
    188     if (!hasAlpha()) {
    189         StringBuilder builder;
    190         builder.reserveCapacity(7);
    191         builder.append('#');
    192         appendByteAsHex(red(), builder, Lowercase);
    193         appendByteAsHex(green(), builder, Lowercase);
    194         appendByteAsHex(blue(), builder, Lowercase);
    195         return builder.toString();
    196     }
    197 
    198     Vector<UChar> result;
    199     result.reserveInitialCapacity(28);
    200 
    201     append(result, rgbaParen);
    202     appendNumber(result, red());
    203     append(result, commaSpace);
    204     appendNumber(result, green());
    205     append(result, commaSpace);
    206     appendNumber(result, blue());
    207     append(result, commaSpace);
    208 
    209     // Match Gecko ("0.0" for zero, 5 decimals for anything else)
    210     if (!alpha())
    211         append(result, zeroPointZero);
    212     else
    213         append(result, String::format("%.5f", alpha() / 255.0f));
    214 
    215     result.append(')');
    216     return String::adopt(result);
    217 }
    218 
    219 String Color::nameForRenderTreeAsText() const
    220 {
    221     if (alpha() < 0xFF)
    222         return String::format("#%02X%02X%02X%02X", red(), green(), blue(), alpha());
    223     return String::format("#%02X%02X%02X", red(), green(), blue());
    224 }
    225 
    226 static inline const NamedColor* findNamedColor(const String& name)
    227 {
    228     char buffer[64]; // easily big enough for the longest color name
    229     unsigned length = name.length();
    230     if (length > sizeof(buffer) - 1)
    231         return 0;
    232     for (unsigned i = 0; i < length; ++i) {
    233         UChar c = name[i];
    234         if (!c || c > 0x7F)
    235             return 0;
    236         buffer[i] = toASCIILower(static_cast<char>(c));
    237     }
    238     buffer[length] = '\0';
    239     return findColor(buffer, length);
    240 }
    241 
    242 void Color::setNamedColor(const String& name)
    243 {
    244     const NamedColor* foundColor = findNamedColor(name);
    245     m_color = foundColor ? foundColor->ARGBValue : 0;
    246     m_valid = foundColor;
    247 }
    248 
    249 Color Color::light() const
    250 {
    251     // Hardcode this common case for speed.
    252     if (m_color == black)
    253         return lightenedBlack;
    254 
    255     const float scaleFactor = nextafterf(256.0f, 0.0f);
    256 
    257     float r, g, b, a;
    258     getRGBA(r, g, b, a);
    259 
    260     float v = max(r, max(g, b));
    261 
    262     if (v == 0.0f)
    263         // Lightened black with alpha.
    264         return Color(0x54, 0x54, 0x54, alpha());
    265 
    266     float multiplier = min(1.0f, v + 0.33f) / v;
    267 
    268     return Color(static_cast<int>(multiplier * r * scaleFactor),
    269                  static_cast<int>(multiplier * g * scaleFactor),
    270                  static_cast<int>(multiplier * b * scaleFactor),
    271                  alpha());
    272 }
    273 
    274 Color Color::dark() const
    275 {
    276     // Hardcode this common case for speed.
    277     if (m_color == white)
    278         return darkenedWhite;
    279 
    280     const float scaleFactor = nextafterf(256.0f, 0.0f);
    281 
    282     float r, g, b, a;
    283     getRGBA(r, g, b, a);
    284 
    285     float v = max(r, max(g, b));
    286     float multiplier = max(0.0f, (v - 0.33f) / v);
    287 
    288     return Color(static_cast<int>(multiplier * r * scaleFactor),
    289                  static_cast<int>(multiplier * g * scaleFactor),
    290                  static_cast<int>(multiplier * b * scaleFactor),
    291                  alpha());
    292 }
    293 
    294 static int blendComponent(int c, int a)
    295 {
    296     // We use white.
    297     float alpha = a / 255.0f;
    298     int whiteBlend = 255 - a;
    299     c -= whiteBlend;
    300     return static_cast<int>(c / alpha);
    301 }
    302 
    303 const int cStartAlpha = 153; // 60%
    304 const int cEndAlpha = 204; // 80%;
    305 const int cAlphaIncrement = 17; // Increments in between.
    306 
    307 Color Color::blend(const Color& source) const
    308 {
    309     if (!alpha() || !source.hasAlpha())
    310         return source;
    311 
    312     if (!source.alpha())
    313         return *this;
    314 
    315     int d = 255 * (alpha() + source.alpha()) - alpha() * source.alpha();
    316     int a = d / 255;
    317     int r = (red() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.red()) / d;
    318     int g = (green() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.green()) / d;
    319     int b = (blue() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.blue()) / d;
    320     return Color(r, g, b, a);
    321 }
    322 
    323 Color Color::blendWithWhite() const
    324 {
    325     // If the color contains alpha already, we leave it alone.
    326     if (hasAlpha())
    327         return *this;
    328 
    329     Color newColor;
    330     for (int alpha = cStartAlpha; alpha <= cEndAlpha; alpha += cAlphaIncrement) {
    331         // We have a solid color.  Convert to an equivalent color that looks the same when blended with white
    332         // at the current alpha.  Try using less transparency if the numbers end up being negative.
    333         int r = blendComponent(red(), alpha);
    334         int g = blendComponent(green(), alpha);
    335         int b = blendComponent(blue(), alpha);
    336 
    337         newColor = Color(r, g, b, alpha);
    338 
    339         if (r >= 0 && g >= 0 && b >= 0)
    340             break;
    341     }
    342     return newColor;
    343 }
    344 
    345 void Color::getRGBA(float& r, float& g, float& b, float& a) const
    346 {
    347     r = red() / 255.0f;
    348     g = green() / 255.0f;
    349     b = blue() / 255.0f;
    350     a = alpha() / 255.0f;
    351 }
    352 
    353 void Color::getRGBA(double& r, double& g, double& b, double& a) const
    354 {
    355     r = red() / 255.0;
    356     g = green() / 255.0;
    357     b = blue() / 255.0;
    358     a = alpha() / 255.0;
    359 }
    360 
    361 void Color::getHSL(double& hue, double& saturation, double& lightness) const
    362 {
    363     // http://en.wikipedia.org/wiki/HSL_color_space. This is a direct copy of
    364     // the algorithm therein, although it's 360^o based and we end up wanting
    365     // [0...1) based. It's clearer if we stick to 360^o until the end.
    366     double r = static_cast<double>(red()) / 255.0;
    367     double g = static_cast<double>(green()) / 255.0;
    368     double b = static_cast<double>(blue()) / 255.0;
    369     double max = std::max(std::max(r, g), b);
    370     double min = std::min(std::min(r, g), b);
    371 
    372     if (max == min)
    373         hue = 0.0;
    374     else if (max == r)
    375         hue = (60.0 * ((g - b) / (max - min))) + 360.0;
    376     else if (max == g)
    377         hue = (60.0 * ((b - r) / (max - min))) + 120.0;
    378     else
    379         hue = (60.0 * ((r - g) / (max - min))) + 240.0;
    380 
    381     if (hue >= 360.0)
    382         hue -= 360.0;
    383 
    384     // makeRGBAFromHSLA assumes that hue is in [0...1).
    385     hue /= 360.0;
    386 
    387     lightness = 0.5 * (max + min);
    388     if (max == min)
    389         saturation = 0.0;
    390     else if (lightness <= 0.5)
    391         saturation = ((max - min) / (max + min));
    392     else
    393         saturation = ((max - min) / (2.0 - (max + min)));
    394 }
    395 
    396 Color colorFromPremultipliedARGB(unsigned pixelColor)
    397 {
    398     RGBA32 rgba;
    399 
    400     if (unsigned alpha = (pixelColor & 0xFF000000) >> 24) {
    401         rgba = makeRGBA(((pixelColor & 0x00FF0000) >> 16) * 255 / alpha,
    402                         ((pixelColor & 0x0000FF00) >> 8) * 255 / alpha,
    403                          (pixelColor & 0x000000FF) * 255 / alpha,
    404                           alpha);
    405     } else
    406         rgba = pixelColor;
    407 
    408     return Color(rgba);
    409 }
    410 
    411 unsigned premultipliedARGBFromColor(const Color& color)
    412 {
    413     unsigned pixelColor;
    414 
    415     if (unsigned alpha = color.alpha()) {
    416         pixelColor = alpha << 24 |
    417              ((color.red() * alpha  + 254) / 255) << 16 |
    418              ((color.green() * alpha  + 254) / 255) << 8 |
    419              ((color.blue() * alpha  + 254) / 255);
    420     } else
    421          pixelColor = color.rgb();
    422 
    423     return pixelColor;
    424 }
    425 
    426 } // namespace WebCore
    427