blob: 6a6b8d74fd70bb61fdd28de597e3027ca0706920 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/common/themes/autogenerated_theme_util.h"
#include "ui/gfx/color_utils.h"
// Decreases the lightness of the given color.
SkColor DarkenColor(SkColor color, float change) {
color_utils::HSL hsl;
SkColorToHSL(color, &hsl);
hsl.l -= change;
if (hsl.l >= 0.0f)
return HSLToSkColor(hsl, 255);
return color;
// Increases the lightness of |source| until it reaches |contrast_ratio| with
// |base| or reaches |white_contrast| with white. This avoids decreasing
// saturation, as the alternative contrast-guaranteeing functions in color_utils
// would do.
SkColor LightenUntilContrast(SkColor source,
SkColor base,
float contrast_ratio,
float white_contrast) {
const float kBaseLuminance = color_utils::GetRelativeLuminance(base);
constexpr float kWhiteLuminance = 1.0f;
color_utils::HSL hsl;
SkColorToHSL(source, &hsl);
float min_l = hsl.l;
float max_l = 1.0f;
// Need only precision of 2 digits.
while (max_l - min_l > 0.01) {
hsl.l = min_l + (max_l - min_l) / 2;
float luminance = color_utils::GetRelativeLuminance(HSLToSkColor(hsl, 255));
if (color_utils::GetContrastRatio(kBaseLuminance, luminance) >=
contrast_ratio ||
(color_utils::GetContrastRatio(kWhiteLuminance, luminance) <
white_contrast)) {
max_l = hsl.l;
} else {
min_l = hsl.l;
hsl.l = max_l;
return HSLToSkColor(hsl, 255);
AutogeneratedThemeColors GetAutogeneratedThemeColors(SkColor color) {
SkColor frame_color = color;
SkColor frame_text_color;
SkColor active_tab_color = color;
SkColor active_tab_text_color;
constexpr float kDarkenStep = 0.03f;
constexpr float kMinWhiteContrast = 1.3f;
constexpr float kNoWhiteContrast = 0.0f;
// Used to determine what we consider a very dark color.
constexpr float kMaxLuminosityForDark = 0.05f;
// Increasingly darken frame color and calculate the rest until colors with
// sufficient contrast are found.
while (true) {
// Calculate frame color to have sufficient contrast with white or dark grey
// text.
frame_text_color = color_utils::GetColorWithMaxContrast(frame_color);
SkColor blend_target =
frame_color = color_utils::BlendForMinContrast(
frame_color, frame_text_color, blend_target,
// Generate active tab color so that it has enough contrast with the
// |frame_color| to avoid the isolation line in the tab strip.
active_tab_color = LightenUntilContrast(
frame_color, frame_color, kAutogeneratedThemeActiveTabMinContrast,
// We want more contrast between frame and active tab for dark colors.
color_utils::HSL hsl;
SkColorToHSL(frame_color, &hsl);
float preferred_contrast =
hsl.l <= kMaxLuminosityForDark
? kAutogeneratedThemeActiveTabPreferredContrastForDark
: kAutogeneratedThemeActiveTabPreferredContrast;
// Try lightening the color to get more contrast with frame without getting
// too close to white.
active_tab_color = LightenUntilContrast(
active_tab_color, frame_color, preferred_contrast, kMinWhiteContrast);
// If we didn't succeed in generating active tab color with minimum
// contrast with frame, then darken the frame color and try again.
if (color_utils::GetContrastRatio(frame_color, active_tab_color) <
kAutogeneratedThemeActiveTabMinContrast) {
frame_color = DarkenColor(frame_color, kDarkenStep);
// Select active tab text color, if possible.
active_tab_text_color =
if (!color_utils::IsDark(active_tab_color)) {
// If active tab is light color then continue lightening it until enough
// contrast with dark text is reached.
active_tab_text_color =
active_tab_color = LightenUntilContrast(
active_tab_color, active_tab_text_color,
kAutogeneratedThemeTextPreferredContrast, kNoWhiteContrast);
// If the active tab color is dark and has enough contrast with white text.
// Then we are all set.
if (color_utils::GetContrastRatio(active_tab_color, SK_ColorWHITE) >=
// If the active tab color is a dark color but the contrast with white is
// not enough then we should darken the active tab color to reach the
// contrast with white. But to keep the contrast with the frame we should
// also darken the frame color. Therefore, just darken the frame color and
// try again.
frame_color = DarkenColor(frame_color, kDarkenStep);
return {frame_color, frame_text_color, active_tab_color,