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)); |
danakj
2016/03/04 01:54:49
This is a behaviour change, can this be a separate
Peter Kasting
2016/03/04 02:10:52
It's a behavior change, but only for GetReadableCo
danakj
2016/03/04 19:05:55
Ah, ok then.
| |
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 ContrastRatio(SkColor color_a, SkColor color_b) { |
82 return ContrastRatio(RelativeLuminance(color_a), RelativeLuminance(color_b)); | 68 return ContrastRatio(RelativeLuminance(color_a), RelativeLuminance(color_b)); |
83 } | 69 } |
84 | 70 |
85 unsigned char GetLuminanceForColor(SkColor color) { | 71 double ContrastRatio(double luminance_a, double luminance_b) { |
86 return base::saturated_cast<unsigned char>( | 72 DCHECK_GE(luminance_a, 0.0); |
87 (0.3 * SkColorGetR(color)) + | 73 DCHECK_GE(luminance_b, 0.0); |
88 (0.59 * SkColorGetG(color)) + | 74 luminance_a += 0.05; |
89 (0.11 * SkColorGetB(color))); | 75 luminance_b += 0.05; |
76 return (luminance_a > luminance_b) ? (luminance_a / luminance_b) | |
77 : (luminance_b / luminance_a); | |
90 } | 78 } |
91 | 79 |
92 double RelativeLuminance(SkColor color) { | 80 double RelativeLuminance(SkColor color) { |
93 return (0.2126 * ConvertSRGB(SkColorGetR(color))) + | 81 return (0.2126 * Linearize(SkColorGetR(color))) + |
94 (0.7152 * ConvertSRGB(SkColorGetG(color))) + | 82 (0.7152 * Linearize(SkColorGetG(color))) + |
95 (0.0722 * ConvertSRGB(SkColorGetB(color))); | 83 (0.0722 * Linearize(SkColorGetB(color))); |
84 } | |
85 | |
86 uint8_t Luma(SkColor color) { | |
87 return static_cast<uint8_t>(std::round((0.299 * SkColorGetR(color)) + | |
danakj
2016/03/04 01:54:49
These constants are diff too, similar request for
Peter Kasting
2016/03/04 02:10:52
It's true, this is a behavior change. That said,
danakj
2016/03/04 19:05:55
Yeh, it's just good practice IMO. Like maybe they
Peter Kasting
2016/03/04 20:28:57
I agree in general principle.
In this specific ca
| |
88 (0.587 * SkColorGetG(color)) + | |
89 (0.114 * SkColorGetB(color)))); | |
96 } | 90 } |
97 | 91 |
98 void SkColorToHSL(SkColor c, HSL* hsl) { | 92 void SkColorToHSL(SkColor c, HSL* hsl) { |
99 double r = static_cast<double>(SkColorGetR(c)) / 255.0; | 93 double r = static_cast<double>(SkColorGetR(c)) / 255.0; |
100 double g = static_cast<double>(SkColorGetG(c)) / 255.0; | 94 double g = static_cast<double>(SkColorGetG(c)) / 255.0; |
101 double b = static_cast<double>(SkColorGetB(c)) / 255.0; | 95 double b = static_cast<double>(SkColorGetB(c)) / 255.0; |
102 double vmax = std::max(std::max(r, g), b); | 96 double vmax = std::max(std::max(r, g), b); |
103 double vmin = std::min(std::min(r, g), b); | 97 double vmin = std::min(std::min(r, g), b); |
104 double delta = vmax - vmin; | 98 double delta = vmax - vmin; |
105 hsl->l = (vmax + vmin) / 2; | 99 hsl->l = (vmax + vmin) / 2; |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
235 | 229 |
236 void BuildLumaHistogram(const SkBitmap& bitmap, int histogram[256]) { | 230 void BuildLumaHistogram(const SkBitmap& bitmap, int histogram[256]) { |
237 DCHECK_EQ(kN32_SkColorType, bitmap.colorType()); | 231 DCHECK_EQ(kN32_SkColorType, bitmap.colorType()); |
238 | 232 |
239 SkAutoLockPixels bitmap_lock(bitmap); | 233 SkAutoLockPixels bitmap_lock(bitmap); |
240 | 234 |
241 int pixel_width = bitmap.width(); | 235 int pixel_width = bitmap.width(); |
242 int pixel_height = bitmap.height(); | 236 int pixel_height = bitmap.height(); |
243 for (int y = 0; y < pixel_height; ++y) { | 237 for (int y = 0; y < pixel_height; ++y) { |
244 for (int x = 0; x < pixel_width; ++x) | 238 for (int x = 0; x < pixel_width; ++x) |
245 ++histogram[GetLuminanceForColor(bitmap.getColor(x, y))]; | 239 ++histogram[Luma(bitmap.getColor(x, y))]; |
246 } | 240 } |
247 } | 241 } |
248 | 242 |
249 double CalculateBoringScore(const SkBitmap& bitmap) { | 243 double CalculateBoringScore(const SkBitmap& bitmap) { |
250 if (bitmap.isNull() || bitmap.empty()) | 244 if (bitmap.isNull() || bitmap.empty()) |
251 return 1.0; | 245 return 1.0; |
252 int histogram[256] = {0}; | 246 int histogram[256] = {0}; |
253 BuildLumaHistogram(bitmap, histogram); | 247 BuildLumaHistogram(bitmap, histogram); |
254 | 248 |
255 int color_count = *std::max_element(histogram, histogram + 256); | 249 int color_count = *std::max_element(histogram, histogram + 256); |
(...skipping 24 matching lines...) Expand all Loading... | |
280 double b = (SkColorGetB(foreground) * f_weight + | 274 double b = (SkColorGetB(foreground) * f_weight + |
281 SkColorGetB(background) * b_weight) / 255.0; | 275 SkColorGetB(background) * b_weight) / 255.0; |
282 | 276 |
283 return SkColorSetARGB(static_cast<int>(std::round(normalizer)), | 277 return SkColorSetARGB(static_cast<int>(std::round(normalizer)), |
284 static_cast<int>(std::round(r)), | 278 static_cast<int>(std::round(r)), |
285 static_cast<int>(std::round(g)), | 279 static_cast<int>(std::round(g)), |
286 static_cast<int>(std::round(b))); | 280 static_cast<int>(std::round(b))); |
287 } | 281 } |
288 | 282 |
289 bool IsDark(SkColor color) { | 283 bool IsDark(SkColor color) { |
290 return GetLuminanceForColor(color) < 128; | 284 return Luma(color) < 128; |
291 } | 285 } |
292 | 286 |
293 SkColor BlendTowardOppositeLuminance(SkColor color, SkAlpha alpha) { | 287 SkColor BlendTowardOppositeLuma(SkColor color, SkAlpha alpha) { |
294 return AlphaBlend(IsDark(color) ? SK_ColorWHITE : SK_ColorBLACK, color, | 288 return AlphaBlend(IsDark(color) ? SK_ColorWHITE : SK_ColorBLACK, color, |
295 alpha); | 289 alpha); |
296 } | 290 } |
297 | 291 |
298 SkColor GetReadableColor(SkColor foreground, SkColor background) { | 292 SkColor GetReadableColor(SkColor foreground, SkColor background) { |
299 const SkColor foreground2 = LumaInvertColor(foreground); | 293 return PickContrastingColor(foreground, LightnessInvertColor(foreground), |
294 background); | |
295 } | |
296 | |
297 SkColor PickContrastingColor(SkColor foreground1, | |
298 SkColor foreground2, | |
299 SkColor background) { | |
300 const double background_luminance = RelativeLuminance(background); | 300 const double background_luminance = RelativeLuminance(background); |
301 return (ContrastRatio(RelativeLuminance(foreground), background_luminance) >= | 301 return (ContrastRatio(RelativeLuminance(foreground1), background_luminance) >= |
302 ContrastRatio(RelativeLuminance(foreground2), background_luminance)) ? | 302 ContrastRatio(RelativeLuminance(foreground2), background_luminance)) ? |
303 foreground : foreground2; | 303 foreground1 : foreground2; |
304 } | 304 } |
305 | 305 |
306 SkColor InvertColor(SkColor color) { | 306 SkColor InvertColor(SkColor color) { |
307 return SkColorSetARGB(SkColorGetA(color), 255 - SkColorGetR(color), | 307 return SkColorSetARGB(SkColorGetA(color), 255 - SkColorGetR(color), |
308 255 - SkColorGetG(color), 255 - SkColorGetB(color)); | 308 255 - SkColorGetG(color), 255 - SkColorGetB(color)); |
309 } | 309 } |
310 | 310 |
311 SkColor GetSysSkColor(int which) { | 311 SkColor GetSysSkColor(int which) { |
312 #if defined(OS_WIN) | 312 #if defined(OS_WIN) |
313 return skia::COLORREFToSkColor(GetSysColor(which)); | 313 return skia::COLORREFToSkColor(GetSysColor(which)); |
(...skipping 16 matching lines...) Expand all Loading... | |
330 if (IsDark(text_color)) { | 330 if (IsDark(text_color)) { |
331 // For black text, this comes out to kChromeIconGrey. | 331 // For black text, this comes out to kChromeIconGrey. |
332 return color_utils::AlphaBlend(SK_ColorWHITE, text_color, | 332 return color_utils::AlphaBlend(SK_ColorWHITE, text_color, |
333 SkColorGetR(gfx::kChromeIconGrey)); | 333 SkColorGetR(gfx::kChromeIconGrey)); |
334 } | 334 } |
335 // The dimming is less dramatic when darkening a light color. | 335 // The dimming is less dramatic when darkening a light color. |
336 return color_utils::AlphaBlend(SK_ColorBLACK, text_color, 0x33); | 336 return color_utils::AlphaBlend(SK_ColorBLACK, text_color, 0x33); |
337 } | 337 } |
338 | 338 |
339 } // namespace color_utils | 339 } // namespace color_utils |
OLD | NEW |