15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/color_utils.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <math.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "build/build_config.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "skia/ext/skia_utils_win.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace color_utils {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper functions -----------------------------------------------------------
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int calcHue(double temp1, double temp2, double hue) {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (hue < 0.0)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++hue;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else if (hue > 1.0)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    --hue;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double result = temp1;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (hue * 6.0 < 1.0)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = temp1 + (temp2 - temp1) * hue * 6.0;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else if (hue * 2.0 < 1.0)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = temp2;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else if (hue * 3.0 < 2.0)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = temp1 + (temp2 - temp1) * (2.0 / 3.0 - hue) * 6.0;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Scale the result from 0 - 255 and round off the value.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<int>(result * 255 + .5);
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Next two functions' formulas from:
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://www.w3.org/TR/WCAG20/#relativeluminancedef
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://www.w3.org/TR/WCAG20/#contrast-ratiodef
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)double ConvertSRGB(double eight_bit_component) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const double component = eight_bit_component / 255.0;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (component <= 0.03928) ?
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (component / 12.92) : pow((component + 0.055) / 1.055, 2.4);
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SkColor LumaInvertColor(SkColor color) {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HSL hsl;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkColorToHSL(color, &hsl);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hsl.l = 1.0 - hsl.l;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return HSLToSkColor(hsl, 255);
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)double ContrastRatio(double foreground_luminance, double background_luminance) {
6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_GE(foreground_luminance, 0.0);
6690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_GE(background_luminance, 0.0);
6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  foreground_luminance += 0.05;
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  background_luminance += 0.05;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (foreground_luminance > background_luminance) ?
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (foreground_luminance / background_luminance) :
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (background_luminance / foreground_luminance);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)unsigned char GetLuminanceForColor(SkColor color) {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int luma = static_cast<int>((0.3 * SkColorGetR(color)) +
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              (0.59 * SkColorGetG(color)) +
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              (0.11 * SkColorGetB(color)));
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::max(std::min(luma, 255), 0);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)double RelativeLuminance(SkColor color) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (0.2126 * ConvertSRGB(SkColorGetR(color))) +
8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)         (0.7152 * ConvertSRGB(SkColorGetG(color))) +
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)         (0.0722 * ConvertSRGB(SkColorGetB(color)));
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SkColorToHSL(SkColor c, HSL* hsl) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double r = static_cast<double>(SkColorGetR(c)) / 255.0;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double g = static_cast<double>(SkColorGetG(c)) / 255.0;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double b = static_cast<double>(SkColorGetB(c)) / 255.0;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double vmax = std::max(std::max(r, g), b);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double vmin = std::min(std::min(r, g), b);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double delta = vmax - vmin;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hsl->l = (vmax + vmin) / 2;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (SkColorGetR(c) == SkColorGetG(c) && SkColorGetR(c) == SkColorGetB(c)) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hsl->h = hsl->s = 0;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    double dr = (((vmax - r) / 6.0) + (delta / 2.0)) / delta;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    double dg = (((vmax - g) / 6.0) + (delta / 2.0)) / delta;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    double db = (((vmax - b) / 6.0) + (delta / 2.0)) / delta;
10690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // We need to compare for the max value because comparing vmax to r, g, or b
10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // can sometimes result in values overflowing registers.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (r >= g && r >= b)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hsl->h = db - dg;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else if (g >= r && g >= b)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hsl->h = (1.0 / 3.0) + dr - db;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else  // (b >= r && b >= g)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hsl->h = (2.0 / 3.0) + dg - dr;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (hsl->h < 0.0)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++hsl->h;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else if (hsl->h > 1.0)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      --hsl->h;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hsl->s = delta / ((hsl->l < 0.5) ? (vmax + vmin) : (2 - vmax - vmin));
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SkColor HSLToSkColor(const HSL& hsl, SkAlpha alpha) {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double hue = hsl.h;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double saturation = hsl.s;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double lightness = hsl.l;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // If there's no color, we don't care about hue and can do everything based on
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // brightness.
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!saturation) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint8 light;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (lightness < 0)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      light = 0;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else if (lightness >= 1.0)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      light = 255;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      light = SkDoubleToFixed(lightness) >> 8;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SkColorSetARGB(alpha, light, light, light);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double temp2 = (lightness < 0.5) ?
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (lightness * (1.0 + saturation)) :
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (lightness + saturation - (lightness * saturation));
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double temp1 = 2.0 * lightness - temp2;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SkColorSetARGB(alpha,
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      calcHue(temp1, temp2, hue + 1.0 / 3.0),
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      calcHue(temp1, temp2, hue),
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      calcHue(temp1, temp2, hue - 1.0 / 3.0));
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)bool IsWithinHSLRange(const HSL& hsl,
15546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      const HSL& lower_bound,
15646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      const HSL& upper_bound) {
15746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(hsl.h >= 0 && hsl.h <= 1) << hsl.h;
15846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(hsl.s >= 0 && hsl.s <= 1) << hsl.s;
15946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(hsl.l >= 0 && hsl.l <= 1) << hsl.l;
16046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(lower_bound.h < 0 || upper_bound.h < 0 ||
16146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)         (lower_bound.h <= 1 && upper_bound.h <= lower_bound.h + 1))
16246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      << "lower_bound.h: " << lower_bound.h
16346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      << ", upper_bound.h: " << upper_bound.h;
16446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(lower_bound.s < 0 || upper_bound.s < 0 ||
16546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)         (lower_bound.s <= upper_bound.s && upper_bound.s <= 1))
16646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      << "lower_bound.s: " << lower_bound.s
16746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      << ", upper_bound.s: " << upper_bound.s;
16846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(lower_bound.l < 0 || upper_bound.l < 0 ||
16946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)         (lower_bound.l <= upper_bound.l && upper_bound.l <= 1))
17046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      << "lower_bound.l: " << lower_bound.l
17146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      << ", upper_bound.l: " << upper_bound.l;
17246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
17346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // If the upper hue is >1, the given hue bounds wrap around at 1.
17446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  bool matches_hue = upper_bound.h > 1
17546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                         ? hsl.h >= lower_bound.h || hsl.h <= upper_bound.h - 1
17646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                         : hsl.h >= lower_bound.h && hsl.h <= upper_bound.h;
17746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return (upper_bound.h < 0 || lower_bound.h < 0 || matches_hue) &&
17846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)         (upper_bound.s < 0 || lower_bound.s < 0 ||
17946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          (hsl.s >= lower_bound.s && hsl.s <= upper_bound.s)) &&
18046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)         (upper_bound.l < 0 || lower_bound.l < 0 ||
18146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          (hsl.l >= lower_bound.l && hsl.l <= upper_bound.l));
18246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
18346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SkColor HSLShift(SkColor color, const HSL& shift) {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HSL hsl;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int alpha = SkColorGetA(color);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkColorToHSL(color, &hsl);
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Replace the hue with the tint's hue.
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (shift.h >= 0)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hsl.h = shift.h;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Change the saturation.
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (shift.s >= 0) {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (shift.s <= 0.5)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hsl.s *= shift.s * 2.0;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hsl.s += (1.0 - hsl.s) * ((shift.s - 0.5) * 2.0);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkColor result = HSLToSkColor(hsl, alpha);
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (shift.l < 0)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Lightness shifts in the style of popular image editors aren't actually
20790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // represented in HSL - the L value does have some effect on saturation.
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double r = static_cast<double>(SkColorGetR(result));
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double g = static_cast<double>(SkColorGetG(result));
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double b = static_cast<double>(SkColorGetB(result));
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (shift.l <= 0.5) {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    r *= (shift.l * 2.0);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g *= (shift.l * 2.0);
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    b *= (shift.l * 2.0);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    r += (255.0 - r) * ((shift.l - 0.5) * 2.0);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g += (255.0 - g) * ((shift.l - 0.5) * 2.0);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    b += (255.0 - b) * ((shift.l - 0.5) * 2.0);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SkColorSetARGB(alpha,
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        static_cast<int>(r),
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        static_cast<int>(g),
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        static_cast<int>(b));
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BuildLumaHistogram(const SkBitmap& bitmap, int histogram[256]) {
227116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK_EQ(kN32_SkColorType, bitmap.colorType());
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SkAutoLockPixels bitmap_lock(bitmap);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int pixel_width = bitmap.width();
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int pixel_height = bitmap.height();
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int y = 0; y < pixel_height; ++y) {
23490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for (int x = 0; x < pixel_width; ++x)
23590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      ++histogram[GetLuminanceForColor(bitmap.getColor(x, y))];
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SkColor AlphaBlend(SkColor foreground, SkColor background, SkAlpha alpha) {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (alpha == 0)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return background;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (alpha == 255)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return foreground;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int f_alpha = SkColorGetA(foreground);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int b_alpha = SkColorGetA(background);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double normalizer = (f_alpha * alpha + b_alpha * (255 - alpha)) / 255.0;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (normalizer == 0.0)
25090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return SK_ColorTRANSPARENT;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double f_weight = f_alpha * alpha / normalizer;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double b_weight = b_alpha * (255 - alpha) / normalizer;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double r = (SkColorGetR(foreground) * f_weight +
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              SkColorGetR(background) * b_weight) / 255.0;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double g = (SkColorGetG(foreground) * f_weight +
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              SkColorGetG(background) * b_weight) / 255.0;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double b = (SkColorGetB(foreground) * f_weight +
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              SkColorGetB(background) * b_weight) / 255.0;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SkColorSetARGB(static_cast<int>(normalizer),
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        static_cast<int>(r),
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        static_cast<int>(g),
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        static_cast<int>(b));
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)SkColor BlendTowardOppositeLuminance(SkColor color, SkAlpha alpha) {
2697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  unsigned char background_luminance =
2707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      color_utils::GetLuminanceForColor(color);
2717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const SkColor blend_color =
2727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      (background_luminance < 128) ? SK_ColorWHITE : SK_ColorBLACK;
2737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return color_utils::AlphaBlend(blend_color, color, alpha);
2747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
2757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SkColor GetReadableColor(SkColor foreground, SkColor background) {
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const SkColor foreground2 = LumaInvertColor(foreground);
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const double background_luminance = RelativeLuminance(background);
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (ContrastRatio(RelativeLuminance(foreground), background_luminance) >=
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ContrastRatio(RelativeLuminance(foreground2), background_luminance)) ?
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      foreground : foreground2;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SkColor InvertColor(SkColor color) {
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SkColorSetARGB(
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SkColorGetA(color),
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      255 - SkColorGetR(color),
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      255 - SkColorGetG(color),
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      255 - SkColorGetB(color));
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SkColor GetSysSkColor(int which) {
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return skia::COLORREFToSkColor(GetSysColor(which));
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTIMPLEMENTED();
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SK_ColorLTGRAY;
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace color_utils
302