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 "PlatformString.h"
30 #include <math.h>
31 #include <wtf/Assertions.h>
32 #include <wtf/MathExtras.h>
33
34 #include "ColorData.c"
35
36 using namespace std;
37 using namespace WTF;
38
39 namespace WebCore {
40
41 #if !COMPILER(MSVC)
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
makeRGB(int r,int g,int b)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
makeRGBA(int r,int g,int b,int a)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
colorFloatToRGBAByte(float f)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
makeRGBA32FromFloats(float r,float g,float b,float a)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
colorWithOverrideAlpha(RGBA32 color,float overrideAlpha)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
calcHue(double temp1,double temp2,double hueVal)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
makeRGBAFromHSLA(double hue,double saturation,double lightness,double alpha)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 // originally moved here from the CSS parser
parseHexColor(const String & name,RGBA32 & rgb)120 bool Color::parseHexColor(const String& name, RGBA32& rgb)
121 {
122 unsigned length = name.length();
123 if (length != 3 && length != 6)
124 return false;
125 unsigned value = 0;
126 for (unsigned i = 0; i < length; ++i) {
127 if (!isASCIIHexDigit(name[i]))
128 return false;
129 value <<= 4;
130 value |= toASCIIHexValue(name[i]);
131 }
132 if (length == 6) {
133 rgb = 0xFF000000 | value;
134 return true;
135 }
136 // #abc converts to #aabbcc
137 rgb = 0xFF000000
138 | (value & 0xF00) << 12 | (value & 0xF00) << 8
139 | (value & 0xF0) << 8 | (value & 0xF0) << 4
140 | (value & 0xF) << 4 | (value & 0xF);
141 return true;
142 }
143
differenceSquared(const Color & c1,const Color & c2)144 int differenceSquared(const Color& c1, const Color& c2)
145 {
146 int dR = c1.red() - c2.red();
147 int dG = c1.green() - c2.green();
148 int dB = c1.blue() - c2.blue();
149 return dR * dR + dG * dG + dB * dB;
150 }
151
Color(const String & name)152 Color::Color(const String& name)
153 {
154 if (name.startsWith("#"))
155 m_valid = parseHexColor(name.substring(1), m_color);
156 else
157 setNamedColor(name);
158 }
159
Color(const char * name)160 Color::Color(const char* name)
161 {
162 if (name[0] == '#')
163 m_valid = parseHexColor(&name[1], m_color);
164 else {
165 const NamedColor* foundColor = findColor(name, strlen(name));
166 m_color = foundColor ? foundColor->RGBValue : 0;
167 m_color |= 0xFF000000;
168 m_valid = foundColor;
169 }
170 }
171
name() const172 String Color::name() const
173 {
174 if (alpha() < 0xFF)
175 return String::format("#%02X%02X%02X%02X", red(), green(), blue(), alpha());
176 return String::format("#%02X%02X%02X", red(), green(), blue());
177 }
178
findNamedColor(const String & name)179 static inline const NamedColor* findNamedColor(const String& name)
180 {
181 char buffer[64]; // easily big enough for the longest color name
182 unsigned length = name.length();
183 if (length > sizeof(buffer) - 1)
184 return 0;
185 for (unsigned i = 0; i < length; ++i) {
186 UChar c = name[i];
187 if (!c || c > 0x7F)
188 return 0;
189 buffer[i] = toASCIILower(static_cast<char>(c));
190 }
191 buffer[length] = '\0';
192 return findColor(buffer, length);
193 }
194
setNamedColor(const String & name)195 void Color::setNamedColor(const String& name)
196 {
197 const NamedColor* foundColor = findNamedColor(name);
198 m_color = foundColor ? foundColor->RGBValue : 0;
199 m_color |= 0xFF000000;
200 m_valid = foundColor;
201 }
202
light() const203 Color Color::light() const
204 {
205 // Hardcode this common case for speed.
206 if (m_color == black)
207 return lightenedBlack;
208
209 const float scaleFactor = nextafterf(256.0f, 0.0f);
210
211 float r, g, b, a;
212 getRGBA(r, g, b, a);
213
214 float v = max(r, max(g, b));
215
216 if (v == 0.0f)
217 // Lightened black with alpha.
218 return Color(0x54, 0x54, 0x54, alpha());
219
220 float multiplier = min(1.0f, v + 0.33f) / v;
221
222 return Color(static_cast<int>(multiplier * r * scaleFactor),
223 static_cast<int>(multiplier * g * scaleFactor),
224 static_cast<int>(multiplier * b * scaleFactor),
225 alpha());
226 }
227
dark() const228 Color Color::dark() const
229 {
230 // Hardcode this common case for speed.
231 if (m_color == white)
232 return darkenedWhite;
233
234 const float scaleFactor = nextafterf(256.0f, 0.0f);
235
236 float r, g, b, a;
237 getRGBA(r, g, b, a);
238
239 float v = max(r, max(g, b));
240 float multiplier = max(0.0f, (v - 0.33f) / v);
241
242 return Color(static_cast<int>(multiplier * r * scaleFactor),
243 static_cast<int>(multiplier * g * scaleFactor),
244 static_cast<int>(multiplier * b * scaleFactor),
245 alpha());
246 }
247
blendComponent(int c,int a)248 static int blendComponent(int c, int a)
249 {
250 // We use white.
251 float alpha = a / 255.0f;
252 int whiteBlend = 255 - a;
253 c -= whiteBlend;
254 return static_cast<int>(c / alpha);
255 }
256
257 const int cStartAlpha = 153; // 60%
258 const int cEndAlpha = 204; // 80%;
259 const int cAlphaIncrement = 17; // Increments in between.
260
blend(const Color & source) const261 Color Color::blend(const Color& source) const
262 {
263 if (!alpha() || !source.hasAlpha())
264 return source;
265
266 if (!source.alpha())
267 return *this;
268
269 int d = 255 * (alpha() + source.alpha()) - alpha() * source.alpha();
270 int a = d / 255;
271 int r = (red() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.red()) / d;
272 int g = (green() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.green()) / d;
273 int b = (blue() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.blue()) / d;
274 return Color(r, g, b, a);
275 }
276
blendWithWhite() const277 Color Color::blendWithWhite() const
278 {
279 // If the color contains alpha already, we leave it alone.
280 if (hasAlpha())
281 return *this;
282
283 Color newColor;
284 for (int alpha = cStartAlpha; alpha <= cEndAlpha; alpha += cAlphaIncrement) {
285 // We have a solid color. Convert to an equivalent color that looks the same when blended with white
286 // at the current alpha. Try using less transparency if the numbers end up being negative.
287 int r = blendComponent(red(), alpha);
288 int g = blendComponent(green(), alpha);
289 int b = blendComponent(blue(), alpha);
290
291 newColor = Color(r, g, b, alpha);
292
293 if (r >= 0 && g >= 0 && b >= 0)
294 break;
295 }
296 return newColor;
297 }
298
getRGBA(float & r,float & g,float & b,float & a) const299 void Color::getRGBA(float& r, float& g, float& b, float& a) const
300 {
301 r = red() / 255.0f;
302 g = green() / 255.0f;
303 b = blue() / 255.0f;
304 a = alpha() / 255.0f;
305 }
306
getRGBA(double & r,double & g,double & b,double & a) const307 void Color::getRGBA(double& r, double& g, double& b, double& a) const
308 {
309 r = red() / 255.0;
310 g = green() / 255.0;
311 b = blue() / 255.0;
312 a = alpha() / 255.0;
313 }
314
315 } // namespace WebCore
316