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