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 "third_party/blink/renderer/platform/graphics/color.h"
27
28 #include "build/build_config.h"
29 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
30 #include "third_party/blink/renderer/platform/wtf/assertions.h"
31 #include "third_party/blink/renderer/platform/wtf/decimal.h"
32 #include "third_party/blink/renderer/platform/wtf/dtoa.h"
33 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
34 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
35 #include "third_party/blink/renderer/platform/wtf/text/string_view.h"
36 #include "third_party/skia/include/core/SkColor.h"
37
38 namespace blink {
39
40 // VS 2015 and above allow these definitions and in this case require them
41 #if !defined(COMPILER_MSVC) || _MSC_VER >= 1900
42 // FIXME: Use C++11 enum classes to avoid static data member initializer
43 // definition problems.
44 const RGBA32 Color::kBlack;
45 const RGBA32 Color::kWhite;
46 const RGBA32 Color::kDarkGray;
47 const RGBA32 Color::kGray;
48 const RGBA32 Color::kLightGray;
49 const RGBA32 Color::kTransparent;
50 #endif
51
52 namespace {
53
54 const RGBA32 kLightenedBlack = 0xFF545454;
55 const RGBA32 kDarkenedWhite = 0xFFABABAB;
56
57 const int kCStartAlpha = 153; // 60%
58 const int kCEndAlpha = 204; // 80%;
59 const int kCAlphaIncrement = 17; // Increments in between.
60
BlendComponent(int c,int a)61 int BlendComponent(int c, int a) {
62 // We use white.
63 float alpha = a / 255.0f;
64 int white_blend = 255 - a;
65 c -= white_blend;
66 return static_cast<int>(c / alpha);
67 }
68
CalcHue(double temp1,double temp2,double hue_val)69 double CalcHue(double temp1, double temp2, double hue_val) {
70 if (hue_val < 0.0)
71 hue_val += 6.0;
72 else if (hue_val >= 6.0)
73 hue_val -= 6.0;
74 if (hue_val < 1.0)
75 return temp1 + (temp2 - temp1) * hue_val;
76 if (hue_val < 3.0)
77 return temp2;
78 if (hue_val < 4.0)
79 return temp1 + (temp2 - temp1) * (4.0 - hue_val);
80 return temp1;
81 }
82
ColorFloatToRGBAByte(float f)83 int ColorFloatToRGBAByte(float f) {
84 return clampTo(static_cast<int>(lroundf(255.0f * f)), 0, 255);
85 }
86
87 // originally moved here from the CSS parser
88 template <typename CharacterType>
ParseHexColorInternal(const CharacterType * name,unsigned length,RGBA32 & rgb)89 inline bool ParseHexColorInternal(const CharacterType* name,
90 unsigned length,
91 RGBA32& rgb) {
92 if (length != 3 && length != 4 && length != 6 && length != 8)
93 return false;
94 if ((length == 8 || length == 4) &&
95 !RuntimeEnabledFeatures::CSSHexAlphaColorEnabled())
96 return false;
97 unsigned value = 0;
98 for (unsigned i = 0; i < length; ++i) {
99 if (!IsASCIIHexDigit(name[i]))
100 return false;
101 value <<= 4;
102 value |= ToASCIIHexValue(name[i]);
103 }
104 if (length == 6) {
105 rgb = 0xFF000000 | value;
106 return true;
107 }
108 if (length == 8) {
109 // We parsed the values into RGBA order, but the RGBA32 type
110 // expects them to be in ARGB order, so we right rotate eight bits.
111 rgb = value << 24 | value >> 8;
112 return true;
113 }
114 if (length == 4) {
115 // #abcd converts to ddaabbcc in RGBA32.
116 rgb = (value & 0xF) << 28 | (value & 0xF) << 24 | (value & 0xF000) << 8 |
117 (value & 0xF000) << 4 | (value & 0xF00) << 4 | (value & 0xF00) |
118 (value & 0xF0) | (value & 0xF0) >> 4;
119 return true;
120 }
121 // #abc converts to #aabbcc
122 rgb = 0xFF000000 | (value & 0xF00) << 12 | (value & 0xF00) << 8 |
123 (value & 0xF0) << 8 | (value & 0xF0) << 4 | (value & 0xF) << 4 |
124 (value & 0xF);
125 return true;
126 }
127
FindNamedColor(const String & name)128 inline const NamedColor* FindNamedColor(const String& name) {
129 char buffer[64]; // easily big enough for the longest color name
130 unsigned length = name.length();
131 if (length > sizeof(buffer) - 1)
132 return nullptr;
133 for (unsigned i = 0; i < length; ++i) {
134 UChar c = name[i];
135 if (!c || c > 0x7F)
136 return nullptr;
137 buffer[i] = ToASCIILower(static_cast<char>(c));
138 }
139 buffer[length] = '\0';
140 return FindColor(buffer, length);
141 }
142
143 } // namespace
144
MakeRGB(int r,int g,int b)145 RGBA32 MakeRGB(int r, int g, int b) {
146 return 0xFF000000 | clampTo(r, 0, 255) << 16 | clampTo(g, 0, 255) << 8 |
147 clampTo(b, 0, 255);
148 }
149
MakeRGBA(int r,int g,int b,int a)150 RGBA32 MakeRGBA(int r, int g, int b, int a) {
151 return clampTo(a, 0, 255) << 24 | clampTo(r, 0, 255) << 16 |
152 clampTo(g, 0, 255) << 8 | clampTo(b, 0, 255);
153 }
154
MakeRGBA32FromFloats(float r,float g,float b,float a)155 RGBA32 MakeRGBA32FromFloats(float r, float g, float b, float a) {
156 return ColorFloatToRGBAByte(a) << 24 | ColorFloatToRGBAByte(r) << 16 |
157 ColorFloatToRGBAByte(g) << 8 | ColorFloatToRGBAByte(b);
158 }
159
160 // Explanation of this algorithm can be found in the CSS Color 4 Module
161 // specification at https://drafts.csswg.org/css-color-4/#hsl-to-rgb with
162 // further explanation available at http://en.wikipedia.org/wiki/HSL_color_space
163
164 // Hue is in the range of 0 to 6.0, the remainder are in the range 0 to 1.0
MakeRGBAFromHSLA(double hue,double saturation,double lightness,double alpha)165 RGBA32 MakeRGBAFromHSLA(double hue,
166 double saturation,
167 double lightness,
168 double alpha) {
169 const double scale_factor = 255.0;
170
171 if (!saturation) {
172 int grey_value = static_cast<int>(round(lightness * scale_factor));
173 return MakeRGBA(grey_value, grey_value, grey_value,
174 static_cast<int>(round(alpha * scale_factor)));
175 }
176
177 double temp2 = lightness <= 0.5
178 ? lightness * (1.0 + saturation)
179 : lightness + saturation - lightness * saturation;
180 double temp1 = 2.0 * lightness - temp2;
181
182 return MakeRGBA(
183 static_cast<int>(round(CalcHue(temp1, temp2, hue + 2.0) * scale_factor)),
184 static_cast<int>(round(CalcHue(temp1, temp2, hue) * scale_factor)),
185 static_cast<int>(round(CalcHue(temp1, temp2, hue - 2.0) * scale_factor)),
186 static_cast<int>(round(alpha * scale_factor)));
187 }
188
MakeRGBAFromCMYKA(float c,float m,float y,float k,float a)189 RGBA32 MakeRGBAFromCMYKA(float c, float m, float y, float k, float a) {
190 double colors = 1 - k;
191 int r = static_cast<int>(nextafter(256, 0) * (colors * (1 - c)));
192 int g = static_cast<int>(nextafter(256, 0) * (colors * (1 - m)));
193 int b = static_cast<int>(nextafter(256, 0) * (colors * (1 - y)));
194 return MakeRGBA(r, g, b, static_cast<float>(nextafter(256, 0) * a));
195 }
196
ParseHexColor(const LChar * name,unsigned length,RGBA32 & rgb)197 bool Color::ParseHexColor(const LChar* name, unsigned length, RGBA32& rgb) {
198 return ParseHexColorInternal(name, length, rgb);
199 }
200
ParseHexColor(const UChar * name,unsigned length,RGBA32 & rgb)201 bool Color::ParseHexColor(const UChar* name, unsigned length, RGBA32& rgb) {
202 return ParseHexColorInternal(name, length, rgb);
203 }
204
ParseHexColor(const StringView & name,RGBA32 & rgb)205 bool Color::ParseHexColor(const StringView& name, RGBA32& rgb) {
206 if (name.IsEmpty())
207 return false;
208 if (name.Is8Bit())
209 return ParseHexColor(name.Characters8(), name.length(), rgb);
210 return ParseHexColor(name.Characters16(), name.length(), rgb);
211 }
212
DifferenceSquared(const Color & c1,const Color & c2)213 int DifferenceSquared(const Color& c1, const Color& c2) {
214 int d_r = c1.Red() - c2.Red();
215 int d_g = c1.Green() - c2.Green();
216 int d_b = c1.Blue() - c2.Blue();
217 return d_r * d_r + d_g * d_g + d_b * d_b;
218 }
219
SetFromString(const String & name)220 bool Color::SetFromString(const String& name) {
221 if (name[0] != '#')
222 return SetNamedColor(name);
223 if (name.Is8Bit())
224 return ParseHexColor(name.Characters8() + 1, name.length() - 1, color_);
225 return ParseHexColor(name.Characters16() + 1, name.length() - 1, color_);
226 }
227
Serialized() const228 String Color::Serialized() const {
229 if (!HasAlpha())
230 return String::Format("#%02x%02x%02x", Red(), Green(), Blue());
231
232 StringBuilder result;
233 result.ReserveCapacity(28);
234
235 result.Append("rgba(");
236 result.AppendNumber(Red());
237 result.Append(", ");
238 result.AppendNumber(Green());
239 result.Append(", ");
240 result.AppendNumber(Blue());
241 result.Append(", ");
242
243 if (!Alpha())
244 result.Append('0');
245 else {
246 result.Append(Decimal::FromDouble(Alpha() / 255.0).ToString());
247 }
248
249 result.Append(')');
250 return result.ToString();
251 }
252
NameForLayoutTreeAsText() const253 String Color::NameForLayoutTreeAsText() const {
254 if (Alpha() < 0xFF)
255 return String::Format("#%02X%02X%02X%02X", Red(), Green(), Blue(), Alpha());
256 return String::Format("#%02X%02X%02X", Red(), Green(), Blue());
257 }
258
SetNamedColor(const String & name)259 bool Color::SetNamedColor(const String& name) {
260 const NamedColor* found_color = FindNamedColor(name);
261 color_ = found_color ? found_color->argb_value : 0;
262 return found_color;
263 }
264
operator SkColor() const265 Color::operator SkColor() const {
266 return SkColorSetARGB(Alpha(), Red(), Green(), Blue());
267 }
268
Light() const269 Color Color::Light() const {
270 // Hardcode this common case for speed.
271 if (color_ == kBlack)
272 return kLightenedBlack;
273
274 const float scale_factor = nextafterf(256.0f, 0.0f);
275
276 float r, g, b, a;
277 GetRGBA(r, g, b, a);
278
279 float v = std::max(r, std::max(g, b));
280
281 if (v == 0.0f)
282 // Lightened black with alpha.
283 return Color(0x54, 0x54, 0x54, Alpha());
284
285 float multiplier = std::min(1.0f, v + 0.33f) / v;
286
287 return Color(static_cast<int>(multiplier * r * scale_factor),
288 static_cast<int>(multiplier * g * scale_factor),
289 static_cast<int>(multiplier * b * scale_factor), Alpha());
290 }
291
Dark() const292 Color Color::Dark() const {
293 // Hardcode this common case for speed.
294 if (color_ == kWhite)
295 return kDarkenedWhite;
296
297 const float scale_factor = nextafterf(256.0f, 0.0f);
298
299 float r, g, b, a;
300 GetRGBA(r, g, b, a);
301
302 float v = std::max(r, std::max(g, b));
303 float multiplier = (v == 0.0f) ? 0.0f : std::max(0.0f, (v - 0.33f) / v);
304
305 return Color(static_cast<int>(multiplier * r * scale_factor),
306 static_cast<int>(multiplier * g * scale_factor),
307 static_cast<int>(multiplier * b * scale_factor), Alpha());
308 }
309
CombineWithAlpha(float other_alpha) const310 Color Color::CombineWithAlpha(float other_alpha) const {
311 RGBA32 rgb_only = Rgb() & 0x00FFFFFF;
312 float override_alpha = (Alpha() / 255.f) * other_alpha;
313 return rgb_only | ColorFloatToRGBAByte(override_alpha) << 24;
314 }
315
Blend(const Color & source) const316 Color Color::Blend(const Color& source) const {
317 if (!Alpha() || !source.HasAlpha())
318 return source;
319
320 if (!source.Alpha())
321 return *this;
322
323 int d = 255 * (Alpha() + source.Alpha()) - Alpha() * source.Alpha();
324 int a = d / 255;
325 int r = (Red() * Alpha() * (255 - source.Alpha()) +
326 255 * source.Alpha() * source.Red()) /
327 d;
328 int g = (Green() * Alpha() * (255 - source.Alpha()) +
329 255 * source.Alpha() * source.Green()) /
330 d;
331 int b = (Blue() * Alpha() * (255 - source.Alpha()) +
332 255 * source.Alpha() * source.Blue()) /
333 d;
334 return Color(r, g, b, a);
335 }
336
BlendWithWhite() const337 Color Color::BlendWithWhite() const {
338 // If the color contains alpha already, we leave it alone.
339 if (HasAlpha())
340 return *this;
341
342 Color new_color;
343 for (int alpha = kCStartAlpha; alpha <= kCEndAlpha;
344 alpha += kCAlphaIncrement) {
345 // We have a solid color. Convert to an equivalent color that looks the
346 // same when blended with white at the current alpha. Try using less
347 // transparency if the numbers end up being negative.
348 int r = BlendComponent(Red(), alpha);
349 int g = BlendComponent(Green(), alpha);
350 int b = BlendComponent(Blue(), alpha);
351
352 new_color = Color(r, g, b, alpha);
353
354 if (r >= 0 && g >= 0 && b >= 0)
355 break;
356 }
357 return new_color;
358 }
359
GetRGBA(float & r,float & g,float & b,float & a) const360 void Color::GetRGBA(float& r, float& g, float& b, float& a) const {
361 r = Red() / 255.0f;
362 g = Green() / 255.0f;
363 b = Blue() / 255.0f;
364 a = Alpha() / 255.0f;
365 }
366
GetRGBA(double & r,double & g,double & b,double & a) const367 void Color::GetRGBA(double& r, double& g, double& b, double& a) const {
368 r = Red() / 255.0;
369 g = Green() / 255.0;
370 b = Blue() / 255.0;
371 a = Alpha() / 255.0;
372 }
373
GetHSL(double & hue,double & saturation,double & lightness) const374 void Color::GetHSL(double& hue, double& saturation, double& lightness) const {
375 // http://en.wikipedia.org/wiki/HSL_color_space. This is a direct copy of
376 // the algorithm therein, although it's 360^o based and we end up wanting
377 // [0...1) based. It's clearer if we stick to 360^o until the end.
378 double r = static_cast<double>(Red()) / 255.0;
379 double g = static_cast<double>(Green()) / 255.0;
380 double b = static_cast<double>(Blue()) / 255.0;
381 double max = std::max(std::max(r, g), b);
382 double min = std::min(std::min(r, g), b);
383
384 if (max == min)
385 hue = 0.0;
386 else if (max == r)
387 hue = (60.0 * ((g - b) / (max - min))) + 360.0;
388 else if (max == g)
389 hue = (60.0 * ((b - r) / (max - min))) + 120.0;
390 else
391 hue = (60.0 * ((r - g) / (max - min))) + 240.0;
392
393 if (hue >= 360.0)
394 hue -= 360.0;
395
396 // makeRGBAFromHSLA assumes that hue is in [0...1).
397 hue /= 360.0;
398
399 lightness = 0.5 * (max + min);
400 if (max == min)
401 saturation = 0.0;
402 else if (lightness <= 0.5)
403 saturation = ((max - min) / (max + min));
404 else
405 saturation = ((max - min) / (2.0 - (max + min)));
406 }
407
ColorFromPremultipliedARGB(RGBA32 pixel_color)408 Color ColorFromPremultipliedARGB(RGBA32 pixel_color) {
409 int alpha = AlphaChannel(pixel_color);
410 if (alpha && alpha < 255) {
411 return Color::CreateUnchecked(RedChannel(pixel_color) * 255 / alpha,
412 GreenChannel(pixel_color) * 255 / alpha,
413 BlueChannel(pixel_color) * 255 / alpha,
414 alpha);
415 } else
416 return Color(pixel_color);
417 }
418
PremultipliedARGBFromColor(const Color & color)419 RGBA32 PremultipliedARGBFromColor(const Color& color) {
420 unsigned pixel_color;
421
422 unsigned alpha = color.Alpha();
423 if (alpha < 255) {
424 pixel_color =
425 Color::CreateUnchecked((color.Red() * alpha + 254) / 255,
426 (color.Green() * alpha + 254) / 255,
427 (color.Blue() * alpha + 254) / 255, alpha)
428 .Rgb();
429 } else
430 pixel_color = color.Rgb();
431
432 return pixel_color;
433 }
434
435 } // namespace blink
436