blob: 177ecda56732fc44af1491d1538973726bbdd672 [file] [log] [blame]
// Copyright 2022 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/tab_strip_color_mixer.h"
#include "base/containers/fixed_flat_map.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/ui/color/chrome_color_id.h"
#include "chrome/browser/ui/color/chrome_color_provider_utils.h"
#include "ui/color/color_id.h"
#include "ui/color/color_mixer.h"
#include "ui/color/color_provider.h"
#include "ui/color/color_recipe.h"
#include "ui/color/color_transform.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/color_utils.h"
void AddTabStripColorMixer(ui::ColorProvider* provider,
const ui::ColorProviderKey& key) {
using TP = ThemeProperties;
struct ColorPropertiesMapEntry {
int property_id;
ChromeColorIds color_id;
};
static constexpr ColorPropertiesMapEntry kFgPropertiesMap[] = {
{TP::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE,
kColorTabForegroundActiveFrameActive},
{TP::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_INACTIVE,
kColorTabForegroundActiveFrameInactive},
{TP::COLOR_TAB_FOREGROUND_INACTIVE_FRAME_ACTIVE,
kColorTabForegroundInactiveFrameActive},
{TP::COLOR_TAB_FOREGROUND_INACTIVE_FRAME_INACTIVE,
kColorTabForegroundInactiveFrameInactive},
};
static constexpr ColorPropertiesMapEntry kBgPropertiesMap[]{
{TP::COLOR_TAB_BACKGROUND_ACTIVE_FRAME_ACTIVE,
kColorTabBackgroundActiveFrameActive},
{TP::COLOR_TAB_BACKGROUND_ACTIVE_FRAME_INACTIVE,
kColorTabBackgroundActiveFrameInactive},
{TP::COLOR_TAB_BACKGROUND_INACTIVE_FRAME_ACTIVE,
kColorTabBackgroundInactiveFrameActive},
{TP::COLOR_TAB_BACKGROUND_INACTIVE_FRAME_INACTIVE,
kColorTabBackgroundInactiveFrameInactive},
};
// These are the default tab fore/background color mappings.
static constexpr const auto kBgColorMap =
base::MakeFixedFlatMap<ChromeColorIds, int>(
{{kColorTabBackgroundActiveFrameActive, kColorToolbar},
{kColorTabBackgroundActiveFrameInactive,
kColorTabBackgroundActiveFrameActive},
{kColorTabBackgroundInactiveFrameActive, ui::kColorFrameActive},
{kColorTabBackgroundInactiveFrameInactive,
ui::kColorFrameInactive}});
static constexpr const auto kFgColorMap =
base::MakeFixedFlatMap<ChromeColorIds, ChromeColorIds>(
{{kColorTabForegroundActiveFrameActive, kColorToolbarText},
{kColorTabForegroundActiveFrameInactive,
kColorTabForegroundActiveFrameActive},
{kColorTabForegroundInactiveFrameActive, kColorToolbarText},
{kColorTabForegroundInactiveFrameInactive,
kColorTabForegroundInactiveFrameActive}});
static constexpr const auto kTabFgToBgMap =
base::MakeFixedFlatMap<ChromeColorIds, ChromeColorIds>(
{{kColorTabForegroundActiveFrameActive,
kColorTabBackgroundActiveFrameActive},
{kColorTabForegroundActiveFrameInactive,
kColorTabBackgroundActiveFrameInactive},
{kColorTabForegroundInactiveFrameActive,
kColorTabBackgroundInactiveFrameActive},
{kColorTabForegroundInactiveFrameInactive,
kColorTabBackgroundInactiveFrameInactive}});
// These contrast ratios should match the actual ratios in the default theme
// colors when no system colors are involved, except for the inactive tab/
// inactive frame case, which has been raised from 4.48 to 4.5 to meet
// accessibility guidelines.
static constexpr const auto kTabFgToContrastMap =
base::MakeFixedFlatMap<ChromeColorIds, float>(
{{kColorTabForegroundActiveFrameActive, 10.46f},
{kColorTabForegroundActiveFrameInactive, 5.0f},
{kColorTabForegroundInactiveFrameActive, 7.98f},
{kColorTabForegroundInactiveFrameInactive, 4.5f}});
ui::ColorMixer& mixer = provider->AddMixer();
SkColor color;
for (auto& entry : kFgPropertiesMap) {
ui::ColorTransform color_transform = {kFgColorMap.at(entry.color_id)};
if (key.custom_theme &&
key.custom_theme->GetColor(entry.property_id, &color)) {
mixer[entry.color_id] = {color};
} else {
if (entry.color_id == kColorTabForegroundInactiveFrameInactive &&
key.custom_theme &&
key.custom_theme->GetColor(
TP::COLOR_TAB_FOREGROUND_INACTIVE_FRAME_ACTIVE, &color)) {
color_transform = {color};
}
ui::ColorTransform background_color_transform = {
kTabFgToBgMap.at(entry.color_id)};
// If a custom theme sets a background tab text color for active but not
// inactive windows, generate the inactive color by blending the active
// one at 75% as we do in the default theme.
if (entry.color_id == kColorTabForegroundInactiveFrameInactive ||
entry.color_id == kColorTabForegroundActiveFrameInactive) {
color_transform =
ui::AlphaBlend(color_transform, background_color_transform,
0.75f * SK_AlphaOPAQUE);
}
// To minimize any readability cost of custom system frame colors, try
// to make the text reach the same contrast ratio that it would in the
// default theme.
auto target_transform =
ui::GetColorWithMaxContrast(background_color_transform);
mixer[entry.color_id] = ui::BlendForMinContrast(
color_transform, background_color_transform, target_transform,
kTabFgToContrastMap.at(entry.color_id));
}
}
for (auto& entry : kBgPropertiesMap) {
if (key.custom_theme &&
key.custom_theme->GetColor(entry.property_id, &color)) {
mixer[entry.color_id] = {color};
} else if (entry.color_id == kColorTabBackgroundInactiveFrameActive ||
entry.color_id == kColorTabBackgroundInactiveFrameInactive) {
mixer[entry.color_id] = {ui::HSLShift(
kBgColorMap.at(entry.color_id),
GetThemeTint(ThemeProperties::TINT_BACKGROUND_TAB, key))};
} else {
mixer[entry.color_id] = {kBgColorMap.at(entry.color_id)};
}
}
// Fallbacks for ChromeRefresh2023, these colors dont exist in the
// GM2TabStyleViews version of the tabstrip. They approximately replicate GM2
// behavior. The main difference is that the tab hover color in GM2 depends on
// the tab width - narrower tabs have more opacity. We must chooses a single
// opacity, so we go with one towards the more opaque end of the GM2 range.
mixer[kColorTabBackgroundInactiveHoverFrameActive] = {
ui::AlphaBlend(kColorTabBackgroundActiveFrameActive,
kColorTabBackgroundInactiveFrameActive,
/* 40% opacity */ 0.4 * SK_AlphaOPAQUE)};
mixer[kColorTabBackgroundInactiveHoverFrameInactive] = {
ui::AlphaBlend(kColorTabBackgroundActiveFrameInactive,
kColorTabBackgroundInactiveFrameInactive,
/* 40% opacity */ 0.4 * SK_AlphaOPAQUE)};
mixer[kColorTabBackgroundSelectedFrameActive] = {
ui::AlphaBlend(kColorTabBackgroundActiveFrameActive,
kColorTabBackgroundInactiveFrameActive,
/* 75% opacity */ 0.75 * SK_AlphaOPAQUE)};
mixer[kColorTabBackgroundSelectedFrameInactive] = {
ui::AlphaBlend(kColorTabBackgroundActiveFrameInactive,
kColorTabBackgroundInactiveFrameInactive,
/* 75% opacity */ 0.75 * SK_AlphaOPAQUE)};
mixer[kColorTabBackgroundSelectedHoverFrameActive] = {
ui::AlphaBlend(kColorTabBackgroundActiveFrameActive,
kColorTabBackgroundInactiveFrameActive,
/* 85% opacity */ 0.85 * SK_AlphaOPAQUE)};
mixer[kColorTabBackgroundSelectedHoverFrameInactive] = {
ui::AlphaBlend(kColorTabBackgroundActiveFrameInactive,
kColorTabBackgroundInactiveFrameInactive,
/* 85% opacity */ 0.85 * SK_AlphaOPAQUE)};
mixer[kColorTabDividerFrameActive] = {kColorToolbar};
mixer[kColorTabDividerFrameInactive] = {kColorToolbar};
// This is not used for text and this contrast ratio most closely matches the
// approved ChromeRefresh2023 colors
mixer[kColorTabDiscardRingFrameActive] = ui::PickGoogleColor(
gfx::kGoogleGrey500, kColorTabBackgroundInactiveFrameActive, 2.0);
mixer[kColorTabDiscardRingFrameInactive] = ui::PickGoogleColor(
gfx::kGoogleGrey500, kColorTabBackgroundInactiveFrameInactive, 2.0);
mixer[kColorNewTabButtonForegroundFrameActive] = {
kColorTabForegroundActiveFrameActive};
mixer[kColorNewTabButtonForegroundFrameInactive] = {
kColorTabForegroundActiveFrameInactive};
mixer[kColorNewTabButtonBackgroundFrameActive] = {
kColorTabBackgroundInactiveFrameActive};
mixer[kColorNewTabButtonBackgroundFrameInactive] = {
kColorTabBackgroundInactiveFrameInactive};
mixer[kColorNewTabButtonFocusRing] = ui::PickGoogleColorTwoBackgrounds(
ui::kColorFocusableBorderFocused,
ui::GetResultingPaintColor(kColorNewTabButtonBackgroundFrameActive,
ui::kColorFrameActive),
ui::kColorFrameActive, color_utils::kMinimumVisibleContrastRatio);
mixer[kColorNewTabButtonInkDropFrameActive] =
ui::GetColorWithMaxContrast(kColorNewTabButtonBackgroundFrameActive);
mixer[kColorNewTabButtonInkDropFrameInactive] =
ui::GetColorWithMaxContrast(kColorNewTabButtonBackgroundFrameInactive);
// TODO (crbug.com/1399942): consolidate the new tab button color ids once the
// refresh flag is enabled by default.
mixer[kColorNewTabButtonCRForegroundFrameActive] = {kColorToolbarButtonIcon};
mixer[kColorNewTabButtonCRForegroundFrameInactive] = {
kColorToolbarButtonIconInactive};
mixer[kColorNewTabButtonCRBackgroundFrameActive] = {kColorToolbar};
mixer[kColorNewTabButtonCRBackgroundFrameInactive] = {kColorToolbar};
mixer[kColorTabSearchButtonCRForegroundFrameActive] = {
kColorToolbarButtonIcon};
mixer[kColorTabSearchButtonCRForegroundFrameInactive] = {
kColorToolbarButtonIconInactive};
mixer[kColorTabStripControlButtonInkDrop] = ui::SetAlpha(
kColorNewTabButtonInkDropFrameActive, std::ceil(0.16f * 255.0f));
mixer[kColorTabStripControlButtonInkDropRipple] = ui::SetAlpha(
kColorNewTabButtonInkDropFrameActive, std::ceil(0.14f * 255.0f));
/* WebUI Tab Strip colors. */
// TODO(https://crbug.com/1060398): Update the tab strip color to respond
// appopriately to activation changes.
mixer[kColorWebUiTabStripBackground] = {ui::kColorFrameActive};
mixer[kColorWebUiTabStripFocusOutline] = {ui::kColorFocusableBorderFocused};
mixer[kColorWebUiTabStripIndicatorRecording] = {ui::kColorAlertHighSeverity};
mixer[kColorWebUiTabStripIndicatorPip] = {kColorTabThrobber};
mixer[kColorWebUiTabStripIndicatorCapturing] = {kColorTabThrobber};
mixer[kColorWebUiTabStripScrollbarThumb] =
ui::SetAlpha(ui::GetColorWithMaxContrast(ui::kColorFrameActive),
/* 70% opacity */ 0.7 * 255);
mixer[kColorWebUiTabStripTabActiveTitleBackground] = {
kColorThumbnailTabBackground};
mixer[kColorWebUiTabStripTabActiveTitleContent] = {
kColorThumbnailTabForeground};
mixer[kColorWebUiTabStripTabBackground] = {kColorToolbar};
mixer[kColorWebUiTabStripTabBlocked] = {ui::kColorButtonBackgroundProminent};
mixer[kColorWebUiTabStripTabLoadingSpinning] = {kColorTabThrobber};
mixer[kColorWebUiTabStripTabSeparator] =
ui::SetAlpha(kColorTabForegroundActiveFrameActive,
/* 16% opacity */ 0.16 * 255);
mixer[kColorWebUiTabStripTabText] = {kColorTabForegroundActiveFrameActive};
mixer[kColorWebUiTabStripTabWaitingSpinning] = {kColorTabThrobberPreconnect};
}