| // 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); |
| } |