Back to home page

Android Cross Reference

 
 

    


0001 /*
0002  * Copyright (C) 2003, 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
0003  *
0004  * Redistribution and use in source and binary forms, with or without
0005  * modification, are permitted provided that the following conditions
0006  * are met:
0007  * 1. Redistributions of source code must retain the above copyright
0008  *    notice, this list of conditions and the following disclaimer.
0009  * 2. Redistributions in binary form must reproduce the above copyright
0010  *    notice, this list of conditions and the following disclaimer in the
0011  *    documentation and/or other materials provided with the distribution.
0012  *
0013  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
0014  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0015  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
0016  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
0017  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0018  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0019  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
0020  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
0021  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0022  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0023  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
0024  */
0025 
0026 #include "config.h"
0027 #include "Color.h"
0028 
0029 #include "HashTools.h"
0030 #include <wtf/Assertions.h>
0031 #include <wtf/HexNumber.h>
0032 #include <wtf/MathExtras.h>
0033 #include <wtf/text/StringBuilder.h>
0034 
0035 using namespace std;
0036 
0037 namespace WebCore {
0038 
0039 #if !COMPILER(MSVC)
0040 const RGBA32 Color::black;
0041 const RGBA32 Color::white;
0042 const RGBA32 Color::darkGray;
0043 const RGBA32 Color::gray;
0044 const RGBA32 Color::lightGray;
0045 const RGBA32 Color::transparent;
0046 #endif
0047 
0048 static const RGBA32 lightenedBlack = 0xFF545454;
0049 static const RGBA32 darkenedWhite = 0xFFABABAB;
0050 
0051 RGBA32 makeRGB(int r, int g, int b)
0052 {
0053     return 0xFF000000 | max(0, min(r, 255)) << 16 | max(0, min(g, 255)) << 8 | max(0, min(b, 255));
0054 }
0055 
0056 RGBA32 makeRGBA(int r, int g, int b, int a)
0057 {
0058     return max(0, min(a, 255)) << 24 | max(0, min(r, 255)) << 16 | max(0, min(g, 255)) << 8 | max(0, min(b, 255));
0059 }
0060 
0061 static int colorFloatToRGBAByte(float f)
0062 {
0063     // We use lroundf and 255 instead of nextafterf(256, 0) to match CG's rounding
0064     return max(0, min(static_cast<int>(lroundf(255.0f * f)), 255));
0065 }
0066 
0067 RGBA32 makeRGBA32FromFloats(float r, float g, float b, float a)
0068 {
0069     return colorFloatToRGBAByte(a) << 24 | colorFloatToRGBAByte(r) << 16 | colorFloatToRGBAByte(g) << 8 | colorFloatToRGBAByte(b);
0070 }
0071 
0072 RGBA32 colorWithOverrideAlpha(RGBA32 color, float overrideAlpha)
0073 {
0074     RGBA32 rgbOnly = color & 0x00FFFFFF;
0075     RGBA32 rgba = rgbOnly | colorFloatToRGBAByte(overrideAlpha) << 24;
0076     return rgba;
0077 }
0078 
0079 static double calcHue(double temp1, double temp2, double hueVal)
0080 {
0081     if (hueVal < 0.0)
0082         hueVal++;
0083     else if (hueVal > 1.0)
0084         hueVal--;
0085     if (hueVal * 6.0 < 1.0)
0086         return temp1 + (temp2 - temp1) * hueVal * 6.0;
0087     if (hueVal * 2.0 < 1.0)
0088         return temp2;
0089     if (hueVal * 3.0 < 2.0)
0090         return temp1 + (temp2 - temp1) * (2.0 / 3.0 - hueVal) * 6.0;
0091     return temp1;
0092 }
0093 
0094 // Explanation of this algorithm can be found in the CSS3 Color Module
0095 // specification at http://www.w3.org/TR/css3-color/#hsl-color with further
0096 // explanation available at http://en.wikipedia.org/wiki/HSL_color_space 
0097 
0098 // all values are in the range of 0 to 1.0
0099 RGBA32 makeRGBAFromHSLA(double hue, double saturation, double lightness, double alpha)
0100 {
0101     const double scaleFactor = nextafter(256.0, 0.0);
0102 
0103     if (!saturation) {
0104         int greyValue = static_cast<int>(lightness * scaleFactor);
0105         return makeRGBA(greyValue, greyValue, greyValue, static_cast<int>(alpha * scaleFactor));
0106     }
0107 
0108     double temp2 = lightness < 0.5 ? lightness * (1.0 + saturation) : lightness + saturation - lightness * saturation;
0109     double temp1 = 2.0 * lightness - temp2;
0110     
0111     return makeRGBA(static_cast<int>(calcHue(temp1, temp2, hue + 1.0 / 3.0) * scaleFactor), 
0112                     static_cast<int>(calcHue(temp1, temp2, hue) * scaleFactor),
0113                     static_cast<int>(calcHue(temp1, temp2, hue - 1.0 / 3.0) * scaleFactor),
0114                     static_cast<int>(alpha * scaleFactor));
0115 }
0116 
0117 RGBA32 makeRGBAFromCMYKA(float c, float m, float y, float k, float a)
0118 {
0119     double colors = 1 - k;
0120     int r = static_cast<int>(nextafter(256, 0) * (colors * (1 - c)));
0121     int g = static_cast<int>(nextafter(256, 0) * (colors * (1 - m)));
0122     int b = static_cast<int>(nextafter(256, 0) * (colors * (1 - y)));
0123     return makeRGBA(r, g, b, static_cast<float>(nextafter(256, 0) * a));
0124 }
0125 
0126 // originally moved here from the CSS parser
0127 bool Color::parseHexColor(const UChar* name, unsigned length, RGBA32& rgb)
0128 {
0129     if (length != 3 && length != 6)
0130         return false;
0131     unsigned value = 0;
0132     for (unsigned i = 0; i < length; ++i) {
0133         if (!isASCIIHexDigit(name[i]))
0134             return false;
0135         value <<= 4;
0136         value |= toASCIIHexValue(name[i]);
0137     }
0138     if (length == 6) {
0139         rgb = 0xFF000000 | value;
0140         return true;
0141     }
0142     // #abc converts to #aabbcc
0143     rgb = 0xFF000000
0144         | (value & 0xF00) << 12 | (value & 0xF00) << 8
0145         | (value & 0xF0) << 8 | (value & 0xF0) << 4
0146         | (value & 0xF) << 4 | (value & 0xF);
0147     return true;
0148 }
0149 
0150 bool Color::parseHexColor(const String& name, RGBA32& rgb)
0151 {
0152     return parseHexColor(name.characters(), name.length(), rgb);
0153 }
0154 
0155 int differenceSquared(const Color& c1, const Color& c2)
0156 {
0157     int dR = c1.red() - c2.red();
0158     int dG = c1.green() - c2.green();
0159     int dB = c1.blue() - c2.blue();
0160     return dR * dR + dG * dG + dB * dB;
0161 }
0162 
0163 Color::Color(const String& name)
0164 {
0165     if (name[0] == '#')
0166         m_valid = parseHexColor(name.characters() + 1, name.length() - 1, m_color);
0167     else
0168         setNamedColor(name);
0169 }
0170 
0171 Color::Color(const char* name)
0172 {
0173     if (name[0] == '#')
0174         m_valid = parseHexColor(&name[1], m_color);
0175     else {
0176         const NamedColor* foundColor = findColor(name, strlen(name));
0177         m_color = foundColor ? foundColor->ARGBValue : 0;
0178         m_valid = foundColor;
0179     }
0180 }
0181 
0182 String Color::serialized() const
0183 {
0184     DEFINE_STATIC_LOCAL(const String, commaSpace, (", "));
0185     DEFINE_STATIC_LOCAL(const String, rgbaParen, ("rgba("));
0186     DEFINE_STATIC_LOCAL(const String, zeroPointZero, ("0.0"));
0187 
0188     if (!hasAlpha()) {
0189         StringBuilder builder;
0190         builder.reserveCapacity(7);
0191         builder.append('#');
0192         appendByteAsHex(red(), builder, Lowercase);
0193         appendByteAsHex(green(), builder, Lowercase);
0194         appendByteAsHex(blue(), builder, Lowercase);
0195         return builder.toString();
0196     }
0197 
0198     Vector<UChar> result;
0199     result.reserveInitialCapacity(28);
0200 
0201     append(result, rgbaParen);
0202     appendNumber(result, red());
0203     append(result, commaSpace);
0204     appendNumber(result, green());
0205     append(result, commaSpace);
0206     appendNumber(result, blue());
0207     append(result, commaSpace);
0208 
0209     // Match Gecko ("0.0" for zero, 5 decimals for anything else)
0210     if (!alpha())
0211         append(result, zeroPointZero);
0212     else
0213         append(result, String::format("%.5f", alpha() / 255.0f));
0214 
0215     result.append(')');
0216     return String::adopt(result);
0217 }
0218 
0219 String Color::nameForRenderTreeAsText() const
0220 {
0221     if (alpha() < 0xFF)
0222         return String::format("#%02X%02X%02X%02X", red(), green(), blue(), alpha());
0223     return String::format("#%02X%02X%02X", red(), green(), blue());
0224 }
0225 
0226 static inline const NamedColor* findNamedColor(const String& name)
0227 {
0228     char buffer[64]; // easily big enough for the longest color name
0229     unsigned length = name.length();
0230     if (length > sizeof(buffer) - 1)
0231         return 0;
0232     for (unsigned i = 0; i < length; ++i) {
0233         UChar c = name[i];
0234         if (!c || c > 0x7F)
0235             return 0;
0236         buffer[i] = toASCIILower(static_cast<char>(c));
0237     }
0238     buffer[length] = '\0';
0239     return findColor(buffer, length);
0240 }
0241 
0242 void Color::setNamedColor(const String& name)
0243 {
0244     const NamedColor* foundColor = findNamedColor(name);
0245     m_color = foundColor ? foundColor->ARGBValue : 0;
0246     m_valid = foundColor;
0247 }
0248 
0249 Color Color::light() const
0250 {
0251     // Hardcode this common case for speed.
0252     if (m_color == black)
0253         return lightenedBlack;
0254     
0255     const float scaleFactor = nextafterf(256.0f, 0.0f);
0256 
0257     float r, g, b, a;
0258     getRGBA(r, g, b, a);
0259 
0260     float v = max(r, max(g, b));
0261 
0262     if (v == 0.0f)
0263         // Lightened black with alpha.
0264         return Color(0x54, 0x54, 0x54, alpha());
0265 
0266     float multiplier = min(1.0f, v + 0.33f) / v;
0267 
0268     return Color(static_cast<int>(multiplier * r * scaleFactor),
0269                  static_cast<int>(multiplier * g * scaleFactor),
0270                  static_cast<int>(multiplier * b * scaleFactor),
0271                  alpha());
0272 }
0273 
0274 Color Color::dark() const
0275 {
0276     // Hardcode this common case for speed.
0277     if (m_color == white)
0278         return darkenedWhite;
0279     
0280     const float scaleFactor = nextafterf(256.0f, 0.0f);
0281 
0282     float r, g, b, a;
0283     getRGBA(r, g, b, a);
0284 
0285     float v = max(r, max(g, b));
0286     float multiplier = max(0.0f, (v - 0.33f) / v);
0287 
0288     return Color(static_cast<int>(multiplier * r * scaleFactor),
0289                  static_cast<int>(multiplier * g * scaleFactor),
0290                  static_cast<int>(multiplier * b * scaleFactor),
0291                  alpha());
0292 }
0293 
0294 static int blendComponent(int c, int a)
0295 {
0296     // We use white.
0297     float alpha = a / 255.0f;
0298     int whiteBlend = 255 - a;
0299     c -= whiteBlend;
0300     return static_cast<int>(c / alpha);
0301 }
0302 
0303 const int cStartAlpha = 153; // 60%
0304 const int cEndAlpha = 204; // 80%;
0305 const int cAlphaIncrement = 17; // Increments in between.
0306 
0307 Color Color::blend(const Color& source) const
0308 {
0309     if (!alpha() || !source.hasAlpha())
0310         return source;
0311 
0312     if (!source.alpha())
0313         return *this;
0314 
0315     int d = 255 * (alpha() + source.alpha()) - alpha() * source.alpha();
0316     int a = d / 255;
0317     int r = (red() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.red()) / d;
0318     int g = (green() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.green()) / d;
0319     int b = (blue() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.blue()) / d;
0320     return Color(r, g, b, a);
0321 }
0322 
0323 Color Color::blendWithWhite() const
0324 {
0325     // If the color contains alpha already, we leave it alone.
0326     if (hasAlpha())
0327         return *this;
0328 
0329     Color newColor;
0330     for (int alpha = cStartAlpha; alpha <= cEndAlpha; alpha += cAlphaIncrement) {
0331         // We have a solid color.  Convert to an equivalent color that looks the same when blended with white
0332         // at the current alpha.  Try using less transparency if the numbers end up being negative.
0333         int r = blendComponent(red(), alpha);
0334         int g = blendComponent(green(), alpha);
0335         int b = blendComponent(blue(), alpha);
0336         
0337         newColor = Color(r, g, b, alpha);
0338 
0339         if (r >= 0 && g >= 0 && b >= 0)
0340             break;
0341     }
0342     return newColor;
0343 }
0344 
0345 void Color::getRGBA(float& r, float& g, float& b, float& a) const
0346 {
0347     r = red() / 255.0f;
0348     g = green() / 255.0f;
0349     b = blue() / 255.0f;
0350     a = alpha() / 255.0f;
0351 }
0352 
0353 void Color::getRGBA(double& r, double& g, double& b, double& a) const
0354 {
0355     r = red() / 255.0;
0356     g = green() / 255.0;
0357     b = blue() / 255.0;
0358     a = alpha() / 255.0;
0359 }
0360 
0361 void Color::getHSL(double& hue, double& saturation, double& lightness) const
0362 {
0363     // http://en.wikipedia.org/wiki/HSL_color_space. This is a direct copy of
0364     // the algorithm therein, although it's 360^o based and we end up wanting
0365     // [0...1) based. It's clearer if we stick to 360^o until the end.
0366     double r = static_cast<double>(red()) / 255.0;
0367     double g = static_cast<double>(green()) / 255.0;
0368     double b = static_cast<double>(blue()) / 255.0;
0369     double max = std::max(std::max(r, g), b);
0370     double min = std::min(std::min(r, g), b);
0371 
0372     if (max == min)
0373         hue = 0.0;
0374     else if (max == r)
0375         hue = (60.0 * ((g - b) / (max - min))) + 360.0;
0376     else if (max == g)
0377         hue = (60.0 * ((b - r) / (max - min))) + 120.0;
0378     else
0379         hue = (60.0 * ((r - g) / (max - min))) + 240.0;
0380 
0381     if (hue >= 360.0)
0382         hue -= 360.0;
0383 
0384     // makeRGBAFromHSLA assumes that hue is in [0...1).
0385     hue /= 360.0;
0386 
0387     lightness = 0.5 * (max + min);
0388     if (max == min)
0389         saturation = 0.0;
0390     else if (lightness <= 0.5)
0391         saturation = ((max - min) / (max + min));
0392     else
0393         saturation = ((max - min) / (2.0 - (max + min)));
0394 }
0395 
0396 Color colorFromPremultipliedARGB(unsigned pixelColor)
0397 {
0398     RGBA32 rgba;
0399 
0400     if (unsigned alpha = (pixelColor & 0xFF000000) >> 24) {
0401         rgba = makeRGBA(((pixelColor & 0x00FF0000) >> 16) * 255 / alpha,
0402                         ((pixelColor & 0x0000FF00) >> 8) * 255 / alpha,
0403                          (pixelColor & 0x000000FF) * 255 / alpha,
0404                           alpha);
0405     } else
0406         rgba = pixelColor;
0407 
0408     return Color(rgba);
0409 }
0410 
0411 unsigned premultipliedARGBFromColor(const Color& color)
0412 {
0413     unsigned pixelColor;
0414 
0415     if (unsigned alpha = color.alpha()) {
0416         pixelColor = alpha << 24 |
0417              ((color.red() * alpha  + 254) / 255) << 16 | 
0418              ((color.green() * alpha  + 254) / 255) << 8 | 
0419              ((color.blue() * alpha  + 254) / 255);
0420     } else
0421          pixelColor = color.rgb();
0422 
0423     return pixelColor;
0424 }
0425 
0426 } // namespace WebCore