OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/gfx/color_utils.h" | 5 #include "ui/gfx/color_utils.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <cmath> | 10 #include <cmath> |
(...skipping 24 matching lines...) Expand all Loading... |
35 --hue; | 35 --hue; |
36 | 36 |
37 double result = temp1; | 37 double result = temp1; |
38 if (hue * 6.0 < 1.0) | 38 if (hue * 6.0 < 1.0) |
39 result = temp1 + (temp2 - temp1) * hue * 6.0; | 39 result = temp1 + (temp2 - temp1) * hue * 6.0; |
40 else if (hue * 2.0 < 1.0) | 40 else if (hue * 2.0 < 1.0) |
41 result = temp2; | 41 result = temp2; |
42 else if (hue * 3.0 < 2.0) | 42 else if (hue * 3.0 < 2.0) |
43 result = temp1 + (temp2 - temp1) * (2.0 / 3.0 - hue) * 6.0; | 43 result = temp1 + (temp2 - temp1) * (2.0 / 3.0 - hue) * 6.0; |
44 | 44 |
45 // Scale the result from 0 - 255 and round off the value. | 45 return static_cast<int>(std::round(result * 255)); |
46 return static_cast<int>(result * 255 + .5); | |
47 } | 46 } |
48 | 47 |
49 // Next two functions' formulas from: | 48 // Assumes sRGB. |
50 // http://www.w3.org/TR/WCAG20/#relativeluminancedef | 49 double Linearize(double eight_bit_component) { |
51 // http://www.w3.org/TR/WCAG20/#contrast-ratiodef | |
52 | |
53 double ConvertSRGB(double eight_bit_component) { | |
54 const double component = eight_bit_component / 255.0; | 50 const double component = eight_bit_component / 255.0; |
55 return (component <= 0.03928) ? | 51 return (component <= 0.03928) ? |
56 (component / 12.92) : pow((component + 0.055) / 1.055, 2.4); | 52 (component / 12.92) : pow((component + 0.055) / 1.055, 2.4); |
57 } | 53 } |
58 | 54 |
59 SkColor LumaInvertColor(SkColor color) { | 55 SkColor LightnessInvertColor(SkColor color) { |
60 HSL hsl; | 56 HSL hsl; |
61 SkColorToHSL(color, &hsl); | 57 SkColorToHSL(color, &hsl); |
62 hsl.l = 1.0 - hsl.l; | 58 hsl.l = 1.0 - hsl.l; |
63 return HSLToSkColor(hsl, 255); | 59 return HSLToSkColor(hsl, SkColorGetA(color)); |
64 } | |
65 | |
66 double ContrastRatio(double foreground_luminance, double background_luminance) { | |
67 DCHECK_GE(foreground_luminance, 0.0); | |
68 DCHECK_GE(background_luminance, 0.0); | |
69 foreground_luminance += 0.05; | |
70 background_luminance += 0.05; | |
71 return (foreground_luminance > background_luminance) ? | |
72 (foreground_luminance / background_luminance) : | |
73 (background_luminance / foreground_luminance); | |
74 } | 60 } |
75 | 61 |
76 } // namespace | 62 } // namespace |
77 | 63 |
78 | 64 |
79 // ---------------------------------------------------------------------------- | 65 // ---------------------------------------------------------------------------- |
80 | 66 |
81 double GetContrastRatio(SkColor color_a, SkColor color_b) { | 67 double GetContrastRatio(SkColor color_a, SkColor color_b) { |
82 return ContrastRatio(RelativeLuminance(color_a), RelativeLuminance(color_b)); | 68 return GetContrastRatio(GetRelativeLuminance(color_a), |
| 69 GetRelativeLuminance(color_b)); |
83 } | 70 } |
84 | 71 |
85 unsigned char GetLuminanceForColor(SkColor color) { | 72 double GetContrastRatio(double luminance_a, double luminance_b) { |
86 return base::saturated_cast<unsigned char>( | 73 DCHECK_GE(luminance_a, 0.0); |
87 (0.3 * SkColorGetR(color)) + | 74 DCHECK_GE(luminance_b, 0.0); |
88 (0.59 * SkColorGetG(color)) + | 75 luminance_a += 0.05; |
89 (0.11 * SkColorGetB(color))); | 76 luminance_b += 0.05; |
| 77 return (luminance_a > luminance_b) ? (luminance_a / luminance_b) |
| 78 : (luminance_b / luminance_a); |
90 } | 79 } |
91 | 80 |
92 double RelativeLuminance(SkColor color) { | 81 double GetRelativeLuminance(SkColor color) { |
93 return (0.2126 * ConvertSRGB(SkColorGetR(color))) + | 82 return (0.2126 * Linearize(SkColorGetR(color))) + |
94 (0.7152 * ConvertSRGB(SkColorGetG(color))) + | 83 (0.7152 * Linearize(SkColorGetG(color))) + |
95 (0.0722 * ConvertSRGB(SkColorGetB(color))); | 84 (0.0722 * Linearize(SkColorGetB(color))); |
| 85 } |
| 86 |
| 87 uint8_t GetLuma(SkColor color) { |
| 88 return static_cast<uint8_t>(std::round((0.299 * SkColorGetR(color)) + |
| 89 (0.587 * SkColorGetG(color)) + |
| 90 (0.114 * SkColorGetB(color)))); |
96 } | 91 } |
97 | 92 |
98 void SkColorToHSL(SkColor c, HSL* hsl) { | 93 void SkColorToHSL(SkColor c, HSL* hsl) { |
99 double r = static_cast<double>(SkColorGetR(c)) / 255.0; | 94 double r = static_cast<double>(SkColorGetR(c)) / 255.0; |
100 double g = static_cast<double>(SkColorGetG(c)) / 255.0; | 95 double g = static_cast<double>(SkColorGetG(c)) / 255.0; |
101 double b = static_cast<double>(SkColorGetB(c)) / 255.0; | 96 double b = static_cast<double>(SkColorGetB(c)) / 255.0; |
102 double vmax = std::max(std::max(r, g), b); | 97 double vmax = std::max(std::max(r, g), b); |
103 double vmin = std::min(std::min(r, g), b); | 98 double vmin = std::min(std::min(r, g), b); |
104 double delta = vmax - vmin; | 99 double delta = vmax - vmin; |
105 hsl->l = (vmax + vmin) / 2; | 100 hsl->l = (vmax + vmin) / 2; |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
235 | 230 |
236 void BuildLumaHistogram(const SkBitmap& bitmap, int histogram[256]) { | 231 void BuildLumaHistogram(const SkBitmap& bitmap, int histogram[256]) { |
237 DCHECK_EQ(kN32_SkColorType, bitmap.colorType()); | 232 DCHECK_EQ(kN32_SkColorType, bitmap.colorType()); |
238 | 233 |
239 SkAutoLockPixels bitmap_lock(bitmap); | 234 SkAutoLockPixels bitmap_lock(bitmap); |
240 | 235 |
241 int pixel_width = bitmap.width(); | 236 int pixel_width = bitmap.width(); |
242 int pixel_height = bitmap.height(); | 237 int pixel_height = bitmap.height(); |
243 for (int y = 0; y < pixel_height; ++y) { | 238 for (int y = 0; y < pixel_height; ++y) { |
244 for (int x = 0; x < pixel_width; ++x) | 239 for (int x = 0; x < pixel_width; ++x) |
245 ++histogram[GetLuminanceForColor(bitmap.getColor(x, y))]; | 240 ++histogram[GetLuma(bitmap.getColor(x, y))]; |
246 } | 241 } |
247 } | 242 } |
248 | 243 |
249 double CalculateBoringScore(const SkBitmap& bitmap) { | 244 double CalculateBoringScore(const SkBitmap& bitmap) { |
250 if (bitmap.isNull() || bitmap.empty()) | 245 if (bitmap.isNull() || bitmap.empty()) |
251 return 1.0; | 246 return 1.0; |
252 int histogram[256] = {0}; | 247 int histogram[256] = {0}; |
253 BuildLumaHistogram(bitmap, histogram); | 248 BuildLumaHistogram(bitmap, histogram); |
254 | 249 |
255 int color_count = *std::max_element(histogram, histogram + 256); | 250 int color_count = *std::max_element(histogram, histogram + 256); |
(...skipping 24 matching lines...) Expand all Loading... |
280 double b = (SkColorGetB(foreground) * f_weight + | 275 double b = (SkColorGetB(foreground) * f_weight + |
281 SkColorGetB(background) * b_weight) / 255.0; | 276 SkColorGetB(background) * b_weight) / 255.0; |
282 | 277 |
283 return SkColorSetARGB(static_cast<int>(std::round(normalizer)), | 278 return SkColorSetARGB(static_cast<int>(std::round(normalizer)), |
284 static_cast<int>(std::round(r)), | 279 static_cast<int>(std::round(r)), |
285 static_cast<int>(std::round(g)), | 280 static_cast<int>(std::round(g)), |
286 static_cast<int>(std::round(b))); | 281 static_cast<int>(std::round(b))); |
287 } | 282 } |
288 | 283 |
289 bool IsDark(SkColor color) { | 284 bool IsDark(SkColor color) { |
290 return GetLuminanceForColor(color) < 128; | 285 return GetLuma(color) < 128; |
291 } | 286 } |
292 | 287 |
293 SkColor BlendTowardOppositeLuminance(SkColor color, SkAlpha alpha) { | 288 SkColor BlendTowardOppositeLuma(SkColor color, SkAlpha alpha) { |
294 return AlphaBlend(IsDark(color) ? SK_ColorWHITE : SK_ColorBLACK, color, | 289 return AlphaBlend(IsDark(color) ? SK_ColorWHITE : SK_ColorBLACK, color, |
295 alpha); | 290 alpha); |
296 } | 291 } |
297 | 292 |
298 SkColor GetReadableColor(SkColor foreground, SkColor background) { | 293 SkColor GetReadableColor(SkColor foreground, SkColor background) { |
299 const SkColor foreground2 = LumaInvertColor(foreground); | 294 return PickContrastingColor(foreground, LightnessInvertColor(foreground), |
300 const double background_luminance = RelativeLuminance(background); | 295 background); |
301 return (ContrastRatio(RelativeLuminance(foreground), background_luminance) >= | 296 } |
302 ContrastRatio(RelativeLuminance(foreground2), background_luminance)) ? | 297 |
303 foreground : foreground2; | 298 SkColor PickContrastingColor(SkColor foreground1, |
| 299 SkColor foreground2, |
| 300 SkColor background) { |
| 301 const double background_luminance = GetRelativeLuminance(background); |
| 302 return (GetContrastRatio(GetRelativeLuminance(foreground1), |
| 303 background_luminance) >= |
| 304 GetContrastRatio(GetRelativeLuminance(foreground2), |
| 305 background_luminance)) ? |
| 306 foreground1 : foreground2; |
304 } | 307 } |
305 | 308 |
306 SkColor InvertColor(SkColor color) { | 309 SkColor InvertColor(SkColor color) { |
307 return SkColorSetARGB(SkColorGetA(color), 255 - SkColorGetR(color), | 310 return SkColorSetARGB(SkColorGetA(color), 255 - SkColorGetR(color), |
308 255 - SkColorGetG(color), 255 - SkColorGetB(color)); | 311 255 - SkColorGetG(color), 255 - SkColorGetB(color)); |
309 } | 312 } |
310 | 313 |
311 SkColor GetSysSkColor(int which) { | 314 SkColor GetSysSkColor(int which) { |
312 #if defined(OS_WIN) | 315 #if defined(OS_WIN) |
313 return skia::COLORREFToSkColor(GetSysColor(which)); | 316 return skia::COLORREFToSkColor(GetSysColor(which)); |
(...skipping 16 matching lines...) Expand all Loading... |
330 if (IsDark(text_color)) { | 333 if (IsDark(text_color)) { |
331 // For black text, this comes out to kChromeIconGrey. | 334 // For black text, this comes out to kChromeIconGrey. |
332 return color_utils::AlphaBlend(SK_ColorWHITE, text_color, | 335 return color_utils::AlphaBlend(SK_ColorWHITE, text_color, |
333 SkColorGetR(gfx::kChromeIconGrey)); | 336 SkColorGetR(gfx::kChromeIconGrey)); |
334 } | 337 } |
335 // The dimming is less dramatic when darkening a light color. | 338 // The dimming is less dramatic when darkening a light color. |
336 return color_utils::AlphaBlend(SK_ColorBLACK, text_color, 0x33); | 339 return color_utils::AlphaBlend(SK_ColorBLACK, text_color, 0x33); |
337 } | 340 } |
338 | 341 |
339 } // namespace color_utils | 342 } // namespace color_utils |
OLD | NEW |