Adds the ability for BubbleGtk widgets to specify both input and popup attributes.
[chromium-blink-merge.git] / ui / gfx / color_utils.cc
blob027bc784bf0a18437bc6b034a9b3b3c5928ed2d8
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
3 // found in the LICENSE file.
5 #include "ui/gfx/color_utils.h"
7 #include <math.h>
8 #if defined(OS_WIN)
9 #include <windows.h>
10 #endif
12 #include <algorithm>
14 #include "base/basictypes.h"
15 #include "base/logging.h"
16 #include "build/build_config.h"
17 #if defined(OS_WIN)
18 #include "skia/ext/skia_utils_win.h"
19 #endif
20 #include "third_party/skia/include/core/SkBitmap.h"
22 namespace color_utils {
24 // Helper functions -----------------------------------------------------------
26 namespace {
28 int calcHue(double temp1, double temp2, double hue) {
29 if (hue < 0.0)
30 ++hue;
31 else if (hue > 1.0)
32 --hue;
34 double result = temp1;
35 if (hue * 6.0 < 1.0)
36 result = temp1 + (temp2 - temp1) * hue * 6.0;
37 else if (hue * 2.0 < 1.0)
38 result = temp2;
39 else if (hue * 3.0 < 2.0)
40 result = temp1 + (temp2 - temp1) * (2.0 / 3.0 - hue) * 6.0;
42 // Scale the result from 0 - 255 and round off the value.
43 return static_cast<int>(result * 255 + .5);
46 // Next two functions' formulas from:
47 // http://www.w3.org/TR/WCAG20/#relativeluminancedef
48 // http://www.w3.org/TR/WCAG20/#contrast-ratiodef
50 double ConvertSRGB(double eight_bit_component) {
51 const double component = eight_bit_component / 255.0;
52 return (component <= 0.03928) ?
53 (component / 12.92) : pow((component + 0.055) / 1.055, 2.4);
56 SkColor LumaInvertColor(SkColor color) {
57 HSL hsl;
58 SkColorToHSL(color, &hsl);
59 hsl.l = 1.0 - hsl.l;
60 return HSLToSkColor(hsl, 255);
63 double ContrastRatio(double foreground_luminance, double background_luminance) {
64 // NOTE: Only pass in numbers obtained from RelativeLuminance(), since those
65 // are guaranteed to be > 0 and thus not cause a divide-by-zero error here.
66 return (foreground_luminance > background_luminance) ?
67 (foreground_luminance / background_luminance) :
68 (background_luminance / foreground_luminance);
71 } // namespace
73 // ----------------------------------------------------------------------------
75 unsigned char GetLuminanceForColor(SkColor color) {
76 int luma = static_cast<int>((0.3 * SkColorGetR(color)) +
77 (0.59 * SkColorGetG(color)) +
78 (0.11 * SkColorGetB(color)));
79 return std::max(std::min(luma, 255), 0);
82 double RelativeLuminance(SkColor color) {
83 return (0.2126 * ConvertSRGB(SkColorGetR(color))) +
84 (0.7152 * ConvertSRGB(SkColorGetG(color))) +
85 (0.0722 * ConvertSRGB(SkColorGetB(color))) + 0.05;
88 void SkColorToHSL(SkColor c, HSL* hsl) {
89 double r = static_cast<double>(SkColorGetR(c)) / 255.0;
90 double g = static_cast<double>(SkColorGetG(c)) / 255.0;
91 double b = static_cast<double>(SkColorGetB(c)) / 255.0;
92 double vmax = std::max(std::max(r, g), b);
93 double vmin = std::min(std::min(r, g), b);
94 double delta = vmax - vmin;
95 hsl->l = (vmax + vmin) / 2;
96 if (SkColorGetR(c) == SkColorGetG(c) && SkColorGetR(c) == SkColorGetB(c)) {
97 hsl->h = hsl->s = 0;
98 } else {
99 double dr = (((vmax - r) / 6.0) + (delta / 2.0)) / delta;
100 double dg = (((vmax - g) / 6.0) + (delta / 2.0)) / delta;
101 double db = (((vmax - b) / 6.0) + (delta / 2.0)) / delta;
102 // We need to compare for the max value because comparing vmax to r,
103 // g or b can sometimes result in values overflowing registers.
104 if (r >= g && r >= b)
105 hsl->h = db - dg;
106 else if (g >= r && g >= b)
107 hsl->h = (1.0 / 3.0) + dr - db;
108 else // (b >= r && b >= g)
109 hsl->h = (2.0 / 3.0) + dg - dr;
111 if (hsl->h < 0.0)
112 ++hsl->h;
113 else if (hsl->h > 1.0)
114 --hsl->h;
116 hsl->s = delta / ((hsl->l < 0.5) ? (vmax + vmin) : (2 - vmax - vmin));
120 SkColor HSLToSkColor(const HSL& hsl, SkAlpha alpha) {
121 double hue = hsl.h;
122 double saturation = hsl.s;
123 double lightness = hsl.l;
125 // If there's no color, we don't care about hue and can do everything based
126 // on brightness.
127 if (!saturation) {
128 uint8 light;
130 if (lightness < 0)
131 light = 0;
132 else if (lightness >= 1.0)
133 light = 255;
134 else
135 light = SkDoubleToFixed(lightness) >> 8;
137 return SkColorSetARGB(alpha, light, light, light);
140 double temp2 = (lightness < 0.5) ?
141 (lightness * (1.0 + saturation)) :
142 (lightness + saturation - (lightness * saturation));
143 double temp1 = 2.0 * lightness - temp2;
144 return SkColorSetARGB(alpha,
145 calcHue(temp1, temp2, hue + 1.0 / 3.0),
146 calcHue(temp1, temp2, hue),
147 calcHue(temp1, temp2, hue - 1.0 / 3.0));
150 SkColor HSLShift(SkColor color, const HSL& shift) {
151 HSL hsl;
152 int alpha = SkColorGetA(color);
153 SkColorToHSL(color, &hsl);
155 // Replace the hue with the tint's hue.
156 if (shift.h >= 0)
157 hsl.h = shift.h;
159 // Change the saturation.
160 if (shift.s >= 0) {
161 if (shift.s <= 0.5)
162 hsl.s *= shift.s * 2.0;
163 else
164 hsl.s += (1.0 - hsl.s) * ((shift.s - 0.5) * 2.0);
167 SkColor result = HSLToSkColor(hsl, alpha);
169 if (shift.l < 0)
170 return result;
172 // Lightness shifts in the style of popular image editors aren't
173 // actually represented in HSL - the L value does have some effect
174 // on saturation.
175 double r = static_cast<double>(SkColorGetR(result));
176 double g = static_cast<double>(SkColorGetG(result));
177 double b = static_cast<double>(SkColorGetB(result));
178 if (shift.l <= 0.5) {
179 r *= (shift.l * 2.0);
180 g *= (shift.l * 2.0);
181 b *= (shift.l * 2.0);
182 } else {
183 r += (255.0 - r) * ((shift.l - 0.5) * 2.0);
184 g += (255.0 - g) * ((shift.l - 0.5) * 2.0);
185 b += (255.0 - b) * ((shift.l - 0.5) * 2.0);
187 return SkColorSetARGB(alpha,
188 static_cast<int>(r),
189 static_cast<int>(g),
190 static_cast<int>(b));
193 bool IsColorCloseToTransparent(SkAlpha alpha) {
194 const int kCloseToBoundary = 64;
195 return alpha < kCloseToBoundary;
198 bool IsColorCloseToGrey(int r, int g, int b) {
199 const int kAverageBoundary = 15;
200 int average = (r + g + b) / 3;
201 return (abs(r - average) < kAverageBoundary) &&
202 (abs(g - average) < kAverageBoundary) &&
203 (abs(b - average) < kAverageBoundary);
206 SkColor GetAverageColorOfFavicon(SkBitmap* favicon, SkAlpha alpha) {
207 int r = 0, g = 0, b = 0;
209 SkAutoLockPixels favicon_lock(*favicon);
210 SkColor* pixels = static_cast<SkColor*>(favicon->getPixels());
211 if (!pixels)
212 return SkColorSetARGB(alpha, 0, 0, 0);
214 // Assume ARGB_8888 format.
215 DCHECK(favicon->config() == SkBitmap::kARGB_8888_Config);
216 SkColor* current_color = pixels;
218 DCHECK(favicon->width() <= 16 && favicon->height() <= 16);
220 int pixel_count = favicon->width() * favicon->height();
221 int color_count = 0;
222 for (int i = 0; i < pixel_count; ++i, ++current_color) {
223 // Disregard this color if it is close to black, close to white, or close
224 // to transparent since any of those pixels do not contribute much to the
225 // color makeup of this icon.
226 int cr = SkColorGetR(*current_color);
227 int cg = SkColorGetG(*current_color);
228 int cb = SkColorGetB(*current_color);
230 if (IsColorCloseToTransparent(SkColorGetA(*current_color)) ||
231 IsColorCloseToGrey(cr, cg, cb))
232 continue;
234 r += cr;
235 g += cg;
236 b += cb;
237 ++color_count;
240 return color_count ?
241 SkColorSetARGB(alpha, r / color_count, g / color_count, b / color_count) :
242 SkColorSetARGB(alpha, 0, 0, 0);
245 void BuildLumaHistogram(const SkBitmap& bitmap, int histogram[256]) {
246 SkAutoLockPixels bitmap_lock(bitmap);
247 if (!bitmap.getPixels())
248 return;
250 // Assume ARGB_8888 format.
251 DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config);
253 int pixel_width = bitmap.width();
254 int pixel_height = bitmap.height();
255 for (int y = 0; y < pixel_height; ++y) {
256 SkColor* current_color = static_cast<uint32_t*>(bitmap.getAddr32(0, y));
257 for (int x = 0; x < pixel_width; ++x, ++current_color)
258 histogram[GetLuminanceForColor(*current_color)]++;
262 SkColor AlphaBlend(SkColor foreground, SkColor background, SkAlpha alpha) {
263 if (alpha == 0)
264 return background;
265 if (alpha == 255)
266 return foreground;
268 int f_alpha = SkColorGetA(foreground);
269 int b_alpha = SkColorGetA(background);
271 double normalizer = (f_alpha * alpha + b_alpha * (255 - alpha)) / 255.0;
272 if (normalizer == 0.0)
273 return SkColorSetARGB(0, 0, 0, 0);
275 double f_weight = f_alpha * alpha / normalizer;
276 double b_weight = b_alpha * (255 - alpha) / normalizer;
278 double r = (SkColorGetR(foreground) * f_weight +
279 SkColorGetR(background) * b_weight) / 255.0;
280 double g = (SkColorGetG(foreground) * f_weight +
281 SkColorGetG(background) * b_weight) / 255.0;
282 double b = (SkColorGetB(foreground) * f_weight +
283 SkColorGetB(background) * b_weight) / 255.0;
285 return SkColorSetARGB(static_cast<int>(normalizer),
286 static_cast<int>(r),
287 static_cast<int>(g),
288 static_cast<int>(b));
291 SkColor GetReadableColor(SkColor foreground, SkColor background) {
292 const SkColor foreground2 = LumaInvertColor(foreground);
293 const double background_luminance = RelativeLuminance(background);
294 return (ContrastRatio(RelativeLuminance(foreground), background_luminance) >=
295 ContrastRatio(RelativeLuminance(foreground2), background_luminance)) ?
296 foreground : foreground2;
299 SkColor InvertColor(SkColor color) {
300 return SkColorSetARGB(
301 SkColorGetA(color),
302 255 - SkColorGetR(color),
303 255 - SkColorGetG(color),
304 255 - SkColorGetB(color));
307 SkColor GetSysSkColor(int which) {
308 #if defined(OS_WIN)
309 return skia::COLORREFToSkColor(GetSysColor(which));
310 #else
311 NOTIMPLEMENTED();
312 return SK_ColorLTGRAY;
313 #endif
316 } // namespace color_utils