blob: 2f577ef9470101852ea4c2e466135a285228552f [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/color/chrome_color_provider_utils.h"
#include <string>
#include "base/containers/fixed_flat_map.h"
#include "base/notreached.h"
#include "build/build_config.h"
#include "build/buildflag.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/ui/color/chrome_color_id.h"
#include "ui/base/buildflags.h"
#include "ui/base/ui_base_features.h"
#include "ui/color/color_id_map_macros.inc"
std::string ChromeColorIdName(ui::ColorId color_id) {
static constexpr const auto color_id_map =
base::MakeFixedFlatMap<ui::ColorId, const char*>({CHROME_COLOR_IDS});
auto* i = color_id_map.find(color_id);
DCHECK(i != color_id_map.cend());
return {i->second};
}
color_utils::HSL GetThemeTint(int id, const ui::ColorProviderKey& key) {
#if !BUILDFLAG(IS_ANDROID)
color_utils::HSL hsl;
if (key.custom_theme && key.custom_theme->GetTint(id, &hsl))
return hsl;
using ThemeType = ui::ColorProviderKey::ThemeInitializerSupplier::ThemeType;
const bool is_custom_theme =
key.custom_theme &&
(key.custom_theme->get_theme_type() == ThemeType::kExtension ||
key.custom_theme->get_theme_type() == ThemeType::kAutogenerated);
return ThemeProperties::GetDefaultTint(
id, false,
key.color_mode == ui::ColorProviderKey::ColorMode::kDark &&
!is_custom_theme);
#else
return {-1, -1, -1};
#endif // !BUILDFLAG(IS_ANDROID)
}
// Note that this second include is not redundant. The second inclusion of the
// .inc file serves to undefine the macros the first inclusion defined.
#include "ui/color/color_id_map_macros.inc"
SkColor GetToolbarTopSeparatorColor(SkColor toolbar_color,
SkColor frame_color) {
constexpr float kContrastRatio = 2.0f;
// Used to generate the initial alpha blended separator color.
const auto generate_separator_color = [&]() {
// In most cases, if the tab is lighter than the frame, we darken the frame;
// if the tab is darker than the frame, we lighten the frame.
// However, if the frame is already very dark or very light, respectively,
// this won't contrast sufficiently with the frame color, so we'll need to
// reverse when we're lightening and darkening.
SkColor separator_color = SK_ColorWHITE;
if (color_utils::GetRelativeLuminance(toolbar_color) >=
color_utils::GetRelativeLuminance(frame_color)) {
separator_color = color_utils::GetColorWithMaxContrast(separator_color);
}
{
const auto result = color_utils::BlendForMinContrast(
frame_color, frame_color, separator_color, kContrastRatio);
if (color_utils::GetContrastRatio(result.color, frame_color) >=
kContrastRatio) {
return SkColorSetA(separator_color, result.alpha);
}
}
separator_color = color_utils::GetColorWithMaxContrast(separator_color);
// If the above call failed to create sufficient contrast, the frame color
// is already very dark or very light. Since separators are only used when
// the tab has low contrast against the frame, the tab color is similarly
// very dark or very light, just not quite as much so as the frame color.
// Blend towards the opposite separator color, and compute the contrast
// against the tab instead of the frame to ensure both contrasts hit the
// desired minimum.
const auto result = color_utils::BlendForMinContrast(
frame_color, toolbar_color, separator_color, kContrastRatio);
return SkColorSetA(separator_color, result.alpha);
};
// The vertical tab separator might show through the stroke if the stroke
// color is translucent. To prevent this, always use an opaque stroke color.
return color_utils::GetResultingPaintColor(generate_separator_color(),
frame_color);
}
ui::ColorTransform AdjustHighlightColorForContrast(ui::ColorTransform fg,
ui::ColorTransform bg) {
auto candidate_fg =
ui::PickGoogleColor(fg, bg, color_utils::kMinimumReadableContrastRatio);
// Setting highlight color will set the text to the highlight color, and the
// background to the same color with an alpha of
// kToolbarInkDropHighlightVisibleOpacity. This means that our target contrast
// is between the text (the highlight color) and a blend of the highlight
// color and the background color.
auto candidate_bg =
ui::AlphaBlend(candidate_fg, bg, kToolbarInkDropHighlightVisibleAlpha);
// Add a fudge factor to the minimum contrast ratio since we'll actually be
// blending with the adjusted color.
return ui::PickGoogleColor(
candidate_fg, candidate_bg,
color_utils::kMinimumReadableContrastRatio * 1.05f);
}
bool ShouldApplyHighContrastColors(const ui::ColorProviderKey& key) {
// Only apply custom high contrast handling on platforms where we are not
// using the system theme for high contrast.
#if BUILDFLAG(USE_GTK) || BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_WIN)
return false;
#else
return key.contrast_mode == ui::ColorProviderKey::ContrastMode::kHigh;
#endif
}
bool ShouldApplyChromeMaterialOverrides(const ui::ColorProviderKey& key) {
// Only apply material overrides when not using a custom theme or high
// contrast.
// TODO(tluk): Switch to using the high contrast configuration for ref tokens
// generated by the material_color_utilities when supported.
return features::IsChromeRefresh2023() && !key.custom_theme &&
!ShouldApplyHighContrastColors(key);
}