0

Revert "Paint controls using Page's color provider"

This reverts commit 73317c46c9.

Reason for revert: Causing a crasher in Lacros, See: crbug.com/1519536

Original change's description:
> Paint controls using Page's color provider
>
> This CL is a follow up on CL:5042390 and CL:5046572, where we plumbed
> the page's color providers and added color provider support for tests.
> This CL uses the plumbed provider to paint by passing it as an argument
> to the NativeTheme Paint function in WebThemeEngineDefault::Paint.
>
> This CL cleans up the previous pipeline which originally saw color
> provider instances exist in Blink::WebThemeEngineDefault. This clean up
> also saw us change the ExecutePageBroadcastMethod call to
> ExecutePageBroadcastMethodForAllPages in
> WebContentsImpl::OnColorProviderChanged.
>
> Additionally, this CL moves the logic of determining the color scheme
> based on the accent color to the ThemePainterDefault and ensures the
> correct color scheme is calculated before painting.
>
> Bug: 1430181
> Change-Id: I0c492bd6c37f63033afbfb6ead1ea6b78387d737
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5068491
> Reviewed-by: Thomas Lukaszewicz <tluk@chromium.org>
> Reviewed-by: Nasko Oskov <nasko@chromium.org>
> Reviewed-by: Alison Maher <almaher@microsoft.com>
> Reviewed-by: Daniel Cheng <dcheng@chromium.org>
> Commit-Queue: Sam Davis Omekara <samomekarajr@microsoft.com>
> Cr-Commit-Position: refs/heads/main@{#1248508}

Bug: 1430181
Change-Id: I6bbf8e37204569a499f03a3cab70f51ea68b7c38
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5212311
Reviewed-by: Thomas Lukaszewicz <tluk@chromium.org>
Commit-Queue: Sam Davis Omekara <samomekarajr@microsoft.com>
Reviewed-by: Nasko Oskov <nasko@chromium.org>
Owners-Override: Nasko Oskov <nasko@chromium.org>
Reviewed-by: Alison Maher <almaher@microsoft.com>
Cr-Commit-Position: refs/heads/main@{#1249044}
This commit is contained in:
Thomas Lukaszewicz
2024-01-18 21:27:30 +00:00
committed by Chromium LUCI CQ
parent 96f9569fd4
commit 5e9733a9e1
19 changed files with 309 additions and 194 deletions

@ -8,6 +8,8 @@
#include "build/build_config.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/common/renderer.mojom.h"
#include "ui/color/color_provider_key.h"
#include "ui/color/color_provider_utils.h"
namespace content {
@ -36,6 +38,38 @@ mojom::UpdateSystemColorInfoParamsPtr MakeUpdateSystemColorInfoParams(
params->accent_color = native_theme->user_color();
#endif
// TODO(crbug.com/1251637): We should not be using ColorProviders sourced from
// the global NativeTheme web instance and instead have WebContents instances
// propagate their specific ColorProviders to hosted frames.
const auto get_renderer_color_map =
[](ui::ColorProviderKey::ColorMode color_mode,
bool override_forced_colors) {
auto key =
ui::NativeTheme::GetInstanceForWeb()->GetColorProviderKey(nullptr);
key.color_mode = color_mode;
// TODO(samomekarajr): Currently, the light/dark providers are used to
// paint controls when the OS triggers forced colors mode. To keep
// current behavior, we shouldn't modify the `forced_colors` key. We
// should remove the conditional check when we use the forced colors
// provider for painitng.
if (override_forced_colors) {
key.forced_colors = ui::ColorProviderKey::ForcedColors::kActive;
}
const auto* color_provider =
ui::ColorProviderManager::Get().GetColorProviderFor(key);
DCHECK(color_provider);
return ui::CreateRendererColorMap(*color_provider);
};
params->light_colors =
get_renderer_color_map(ui::ColorProviderKey::ColorMode::kLight,
/*override_forced_colors=*/false);
params->dark_colors = get_renderer_color_map(
ui::ColorProviderKey::ColorMode::kDark, /*override_forced_colors=*/false);
params->forced_colors_map =
get_renderer_color_map(native_theme->ShouldUseDarkColors()
? ui::ColorProviderKey::ColorMode::kDark
: ui::ColorProviderKey::ColorMode::kLight,
/*override_forced_colors=*/true);
return params;
}

@ -10142,7 +10142,7 @@ void WebContentsImpl::OnColorProviderChanged() {
}
blink::ColorProviderColorMaps color_map = GetColorProviderColorMaps();
ExecutePageBroadcastMethodForAllPages(base::BindRepeating(
ExecutePageBroadcastMethod(base::BindRepeating(
[](const blink::ColorProviderColorMaps& color_map,
RenderViewHostImpl* rvh) {
if (auto& broadcast = rvh->GetAssociatedPageBroadcast()) {

@ -723,6 +723,7 @@ mojom("mojo_bindings") {
"//ui/accessibility/mojom",
"//ui/base/ime/mojom",
"//ui/base/mojom",
"//ui/color:mojom",
"//ui/display/mojom",
"//ui/events/mojom",
"//ui/events/mojom:event_latency_metadata_mojom",

@ -10,9 +10,11 @@ import "ipc/ipc.mojom";
import "mojo/public/mojom/base/generic_pending_receiver.mojom";
import "mojo/public/mojom/base/time.mojom";
import "services/network/public/mojom/network_types.mojom";
import "skia/public/mojom/skcolor.mojom";
import "third_party/blink/public/mojom/browser_interface_broker.mojom";
import "third_party/blink/public/mojom/origin_trials/origin_trials_settings.mojom";
import "third_party/blink/public/mojom/user_agent/user_agent_metadata.mojom";
import "ui/color/color_id.mojom";
struct UpdateScrollbarThemeParams {
// TODO(avi): Update these to optional values when optional numeric types are
@ -40,6 +42,11 @@ struct UpdateSystemColorInfoParams {
// Accent color used by the system. Currently only set on ChromeOS.
uint32? accent_color;
// Maps used to reconstruct ColorProvider instances in the renderer.
map<color.mojom.RendererColorId, skia.mojom.SkColor> light_colors;
map<color.mojom.RendererColorId, skia.mojom.SkColor> dark_colors;
map<color.mojom.RendererColorId, skia.mojom.SkColor> forced_colors_map;
};
// The background state for the render process. When backgrounded the process's

@ -1488,6 +1488,17 @@ void RenderThreadImpl::OnSystemColorsChanged(int32_t aqua_color_variant) {
void RenderThreadImpl::UpdateSystemColorInfo(
mojom::UpdateSystemColorInfoParamsPtr params) {
bool color_providers_changed =
blink_platform_impl_->ThemeEngine()->UpdateColorProviders(
params->light_colors, params->dark_colors, params->forced_colors_map);
if (color_providers_changed) {
// Notify blink that the global ColorProvider instances for this renderer
// have changed. These color providers are only used to paint native
// controls and only require us to invalidate paint for local frames in this
// renderer.
blink::ColorProvidersChanged();
}
auto* native_theme = ui::NativeTheme::GetInstanceForWeb();
bool did_system_color_info_change = native_theme->UpdateSystemColorInfo(

@ -311,6 +311,17 @@ class WebThemeEngine {
SystemColorInfoState state;
return state;
}
virtual void EmulateForcedColors(bool is_dark_theme, bool is_web_test) {}
// Updates the WebThemeEngine's global light, dark and forced colors
// ColorProvider instances using the RendererColorMaps provided. Returns true
// if new ColorProviders were created, returns false otherwise.
virtual bool UpdateColorProviders(
const ui::RendererColorMap& light_colors,
const ui::RendererColorMap& dark_colors,
const ui::RendererColorMap& forced_colors_map) {
return false;
}
};
} // namespace blink

@ -9174,12 +9174,8 @@ const ui::ColorProvider* Document::GetColorProviderForPainting(
return nullptr;
}
// TODO(crbug.com/1516529): This should be changed to use
// `in_forced_colors_mode_` once forced colors becomes a web setting in Blink.
return GetPage()->GetColorProviderForPainting(
color_scheme,
WebThemeEngineHelper::GetNativeThemeEngine()->GetForcedColors() !=
ForcedColors::kNone);
return GetPage()->GetColorProviderForPainting(color_scheme,
in_forced_colors_mode_);
}
void Document::CountUse(mojom::WebFeature feature) const {

@ -67,4 +67,8 @@ void ColorSchemeChanged() {
LayoutTheme::GetTheme().ColorSchemeDidChange();
}
void ColorProvidersChanged() {
LayoutTheme::GetTheme().ColorProvidersDidChange();
}
} // namespace blink

@ -517,6 +517,10 @@ void LayoutTheme::ColorSchemeDidChange() {
Page::ColorSchemeChanged();
}
void LayoutTheme::ColorProvidersDidChange() {
Page::ColorProvidersChanged();
}
void LayoutTheme::SetCaretBlinkInterval(base::TimeDelta interval) {
caret_blink_interval_ = interval;
}

@ -471,7 +471,9 @@ void Page::ColorSchemeChanged() {
}
void Page::ColorProvidersChanged() {
InvalidatePaint();
for (Page* page : AllPages()) {
page->InvalidatePaint();
}
}
void Page::EmulateForcedColors(bool is_dark_theme) {
@ -493,38 +495,21 @@ void Page::UpdateColorProviders(
return;
}
bool did_color_provider_update = false;
if (!ui::IsRendererColorMappingEquivalent(
light_color_provider_.get(),
color_provider_colors.light_colors_map)) {
light_color_provider_ = std::make_unique<ui::ColorProvider>(
ui::CreateColorProviderFromRendererColorMap(
color_provider_colors.light_colors_map));
did_color_provider_update = true;
}
if (!ui::IsRendererColorMappingEquivalent(
dark_color_provider_.get(), color_provider_colors.dark_colors_map)) {
dark_color_provider_ = std::make_unique<ui::ColorProvider>(
ui::CreateColorProviderFromRendererColorMap(
color_provider_colors.dark_colors_map));
did_color_provider_update = true;
}
if (!ui::IsRendererColorMappingEquivalent(
forced_colors_color_provider_.get(),
color_provider_colors.forced_colors_map)) {
forced_colors_color_provider_ =
WebTestSupport::IsRunningWebTest()
? std::make_unique<ui::ColorProvider>(
ui::CreateEmulatedForcedColorsColorProviderForTest())
: std::make_unique<ui::ColorProvider>(
ui::CreateColorProviderFromRendererColorMap(
color_provider_colors.forced_colors_map));
did_color_provider_update = true;
}
if (did_color_provider_update) {
ColorProvidersChanged();
}
// TODO(samomekarajr): Might want to only create new ColorProviders if the
// renderer color maps do not match the existing ColorProviders.
light_color_provider_ = std::make_unique<ui::ColorProvider>(
ui::CreateColorProviderFromRendererColorMap(
color_provider_colors.light_colors_map));
dark_color_provider_ = std::make_unique<ui::ColorProvider>(
ui::CreateColorProviderFromRendererColorMap(
color_provider_colors.dark_colors_map));
forced_colors_color_provider_ =
WebTestSupport::IsRunningWebTest()
? std::make_unique<ui::ColorProvider>(
ui::CreateEmulatedForcedColorsColorProviderForTest())
: std::make_unique<ui::ColorProvider>(
ui::CreateColorProviderFromRendererColorMap(
color_provider_colors.forced_colors_map));
}
void Page::UpdateColorProvidersForTest() {

@ -160,7 +160,7 @@ class CORE_EXPORT Page final : public GarbageCollected<Page>,
static void UsesOverlayScrollbarsChanged();
static void PlatformColorsChanged();
static void ColorSchemeChanged();
void ColorProvidersChanged();
static void ColorProvidersChanged();
void EmulateForcedColors(bool is_dark_theme);
void DisableEmulatedForcedColors();

@ -77,79 +77,6 @@ WebThemeEngine::State GetWebThemeState(const Element& element) {
return WebThemeEngine::kStateNormal;
}
SkColor GetContrastingColorFor(const Element& element,
const mojom::ColorScheme color_scheme,
WebThemeEngine::Part part) {
WebThemeEngine::State state = GetWebThemeState(element);
const ui::ColorProvider* color_provider =
element.GetDocument().GetColorProviderForPainting(color_scheme);
const bool is_disabled = (state == WebThemeEngine::kStateDisabled);
switch (part) {
case WebThemeEngine::kPartCheckbox:
case WebThemeEngine::kPartRadio:
return is_disabled ? color_provider->GetColor(
ui::kColorWebNativeControlBackgroundDisabled)
: color_provider->GetColor(
ui::kColorWebNativeControlBackground);
case WebThemeEngine::kPartSliderTrack:
case WebThemeEngine::kPartSliderThumb:
case WebThemeEngine::kPartProgressBar:
// We use `kStateNormal` here because the user hovering or clicking on the
// slider will change the state to something else, and we don't want the
// color-scheme to flicker back and forth when the user interacts with it.
return color_provider->GetColor(ui::kColorWebNativeControlFill);
default:
NOTREACHED_NORETURN();
}
}
mojom::ColorScheme CalculateColorSchemeForAccentColor(
absl::optional<SkColor> accent_color,
mojom::ColorScheme color_scheme,
SkColor light_contrasting_color,
SkColor dark_contrasting_color) {
if (!accent_color) {
return color_scheme;
}
const float contrast_with_light =
color_utils::GetContrastRatio(*accent_color, light_contrasting_color);
const float contrast_with_dark =
color_utils::GetContrastRatio(*accent_color, dark_contrasting_color);
// If there is enough contrast between `accent_color` and `color_scheme`, then
// let's keep it the same. Otherwise, flip the `color_scheme` to guarantee
// contrast.
if (color_scheme == mojom::ColorScheme::kDark) {
if (contrast_with_dark < color_utils::kMinimumVisibleContrastRatio &&
contrast_with_dark < contrast_with_light) {
// TODO(crbug.com/1216137): what if `contrast_with_light` is less than
// `kMinimumContrast`? Should we modify `accent_color`...?
return mojom::ColorScheme::kLight;
}
} else {
if (contrast_with_light < color_utils::kMinimumVisibleContrastRatio &&
contrast_with_light < contrast_with_dark) {
return mojom::ColorScheme::kDark;
}
}
return color_scheme;
}
mojom::blink::ColorScheme GetColorSchemeForAccentColor(
const Element& element,
const mojom::blink::ColorScheme color_scheme,
const absl::optional<SkColor> accent_color,
WebThemeEngine::Part part) {
return CalculateColorSchemeForAccentColor(
accent_color, color_scheme,
GetContrastingColorFor(element, mojom::blink::ColorScheme::kLight, part),
GetContrastingColorFor(element, mojom::blink::ColorScheme::kDark, part));
}
class DirectionFlippingScope {
STACK_ALLOCATED();
@ -304,20 +231,6 @@ bool ThemePainterDefault::PaintCheckbox(const Element& element,
ApplyZoomToRect(rect, paint_info, state_saver, zoom_level);
WebThemeEngine::ExtraParams extra_params(button);
mojom::blink::ColorScheme color_scheme = style.UsedColorScheme();
// This is used for `kPartCheckbox`, which gets drawn adjacent to
// `accent_color`. In order to guarantee contrast between `kPartCheckbox` and
// `accent_color`, we choose the `color_scheme` here based on the two possible
// color values for `kPartCheckbox`.
bool accent_color_affects_color_scheme =
button.checked &&
GetWebThemeState(element) != WebThemeEngine::kStateDisabled;
if (accent_color_affects_color_scheme) {
color_scheme = GetColorSchemeForAccentColor(element, color_scheme,
GetAccentColor(style, document),
WebThemeEngine::kPartCheckbox);
}
const ui::ColorProvider* color_provider =
document.GetColorProviderForPainting(color_scheme);
WebThemeEngineHelper::GetNativeThemeEngine()->Paint(
@ -342,20 +255,6 @@ bool ThemePainterDefault::PaintRadio(const Element& element,
gfx::Rect unzoomed_rect =
ApplyZoomToRect(rect, paint_info, state_saver, zoom_level);
mojom::blink::ColorScheme color_scheme = style.UsedColorScheme();
// This is used for `kPartRadio`, which gets drawn adjacent to `accent_color`.
// In order to guarantee contrast between `kPartRadio` and `accent_color`, we
// choose the `color_scheme` here based on the two possible color values for
// `kPartRadio`.
bool accent_color_affects_color_scheme =
button.checked &&
GetWebThemeState(element) != WebThemeEngine::kStateDisabled;
if (accent_color_affects_color_scheme) {
color_scheme = GetColorSchemeForAccentColor(element, color_scheme,
GetAccentColor(style, document),
WebThemeEngine::kPartRadio);
}
const ui::ColorProvider* color_provider =
document.GetColorProviderForPainting(color_scheme);
WebThemeEngineHelper::GetNativeThemeEngine()->Paint(
@ -589,19 +488,6 @@ bool ThemePainterDefault::PaintSliderTrack(const Element& element,
}
WebThemeEngine::ExtraParams extra_params(slider);
mojom::blink::ColorScheme color_scheme = style.UsedColorScheme();
// This is used for `kPartSliderTrack`, which gets drawn adjacent to
// `accent_color`. In order to guarantee contrast between `kPartSliderTrack`
// and `accent_color`, we choose the `color_scheme` here based on the two
// possible color values for `kPartSliderTrack`.
bool accent_color_affects_color_scheme =
GetWebThemeState(element) != WebThemeEngine::kStateDisabled;
if (accent_color_affects_color_scheme) {
color_scheme = GetColorSchemeForAccentColor(
element, color_scheme, GetAccentColor(style, element.GetDocument()),
WebThemeEngine::kPartSliderTrack);
}
const ui::ColorProvider* color_provider =
element.GetDocument().GetColorProviderForPainting(color_scheme);
@ -638,19 +524,6 @@ bool ThemePainterDefault::PaintSliderThumb(const Element& element,
element.GetDocument());
WebThemeEngine::ExtraParams extra_params(slider);
mojom::blink::ColorScheme color_scheme = style.UsedColorScheme();
// This is used for `kPartSliderThumb`, which gets drawn adjacent to
// `accent_color`. In order to guarantee contrast between `kPartSliderThumb`
// and `accent_color`, we choose the `color_scheme` here based on the two
// possible color values for `kPartSliderThumb`.
bool accent_color_affects_color_scheme =
GetWebThemeState(element) != WebThemeEngine::kStateDisabled;
if (accent_color_affects_color_scheme) {
color_scheme = GetColorSchemeForAccentColor(
element, color_scheme, GetAccentColor(style, element.GetDocument()),
WebThemeEngine::kPartSliderThumb);
}
const ui::ColorProvider* color_provider =
element.GetDocument().GetColorProviderForPainting(color_scheme);
@ -719,15 +592,6 @@ bool ThemePainterDefault::PaintProgressBar(const Element& element,
WebThemeEngine::ExtraParams extra_params(progress_bar);
DirectionFlippingScope scope(layout_object, paint_info, rect);
mojom::blink::ColorScheme color_scheme = style.UsedColorScheme();
// This is used for `kPartProgressBar`, which gets drawn adjacent to
// `accent_color`. In order to guarantee contrast between `kPartProgressBar`
// and `accent_color`, we choose the `color_scheme` here based on the two
// possible color values for `kPartProgressBar`.
color_scheme = GetColorSchemeForAccentColor(
element, color_scheme, GetAccentColor(style, element.GetDocument()),
WebThemeEngine::kPartProgressBar);
const ui::ColorProvider* color_provider =
element.GetDocument().GetColorProviderForPainting(color_scheme);
WebThemeEngineHelper::GetNativeThemeEngine()->Paint(

@ -60,6 +60,7 @@ void ColorSchemeHelper::SetForcedColors(Page& page,
void ColorSchemeHelper::SetEmulatedForcedColors(Document& document,
bool is_dark_theme) {
web_theme_engine_->EmulateForcedColors(is_dark_theme, /*is_web_test=*/true);
document.GetPage()->EmulateForcedColors(is_dark_theme);
document.ColorSchemeChanged();
}

@ -200,7 +200,12 @@ static ui::NativeTheme::ExtraParams GetNativeThemeExtraParams(
}
}
WebThemeEngineDefault::WebThemeEngineDefault() = default;
WebThemeEngineDefault::WebThemeEngineDefault() {
light_color_provider_.GenerateColorMap();
dark_color_provider_.GenerateColorMap();
emulated_forced_colors_provider_.GenerateColorMap();
forced_colors_provider_.GenerateColorMap();
}
WebThemeEngineDefault::~WebThemeEngineDefault() = default;
@ -243,10 +248,21 @@ void WebThemeEngineDefault::Paint(
ui::NativeTheme::ExtraParams native_theme_extra_params =
GetNativeThemeExtraParams(part, state, extra_params);
if (ShouldPartBeAffectedByAccentColor(part, state, extra_params)) {
// This is used for `part`, which gets drawn adjacent to `accent_color`. In
// order to guarantee contrast between `part` and `accent_color`, we choose
// the `color_scheme` here based on the two possible color values for
// `part`.
color_scheme = CalculateColorSchemeForAccentColor(
accent_color, color_scheme,
GetContrastingColorFor(mojom::ColorScheme::kLight, part, state),
GetContrastingColorFor(mojom::ColorScheme::kDark, part, state));
}
ui::NativeTheme::GetInstanceForWeb()->Paint(
canvas, color_provider, NativeThemePart(part), NativeThemeState(state),
rect, native_theme_extra_params, NativeColorScheme(color_scheme),
accent_color);
canvas, GetColorProviderForPainting(color_scheme), NativeThemePart(part),
NativeThemeState(state), rect, native_theme_extra_params,
NativeColorScheme(color_scheme), accent_color);
}
void WebThemeEngineDefault::GetOverlayScrollbarStyle(ScrollbarStyle* style) {
@ -344,10 +360,18 @@ void WebThemeEngineDefault::OverrideForcedColorsTheme(bool is_dark_theme) {
{ui::NativeTheme::SystemThemeColor::kWindow, 0xFFFFFFFF},
{ui::NativeTheme::SystemThemeColor::kWindowText, 0xFF000000},
};
EmulateForcedColors(is_dark_theme, /*is_web_test=*/false);
ui::NativeTheme::GetInstanceForWeb()->UpdateSystemColorInfo(
false, true, is_dark_theme ? dark_theme : light_theme);
}
void WebThemeEngineDefault::EmulateForcedColors(bool is_dark_theme,
bool is_web_test) {
SetEmulateForcedColors(true);
emulated_forced_colors_provider_ =
is_web_test ? ui::CreateEmulatedForcedColorsColorProviderForTest()
: ui::CreateEmulatedForcedColorsColorProvider(is_dark_theme);
}
void WebThemeEngineDefault::SetForcedColors(const ForcedColors forced_colors) {
ui::NativeTheme::GetInstanceForWeb()->set_forced_colors(
@ -366,6 +390,7 @@ void WebThemeEngineDefault::ResetToSystemColors(
system_color_info_state.is_dark_mode,
system_color_info_state.forced_colors, colors);
SetEmulateForcedColors(false);
}
WebThemeEngine::SystemColorInfoState
@ -387,4 +412,133 @@ WebThemeEngineDefault::GetSystemColorInfo() {
return state;
}
bool WebThemeEngineDefault::UpdateColorProviders(
const ui::RendererColorMap& light_colors,
const ui::RendererColorMap& dark_colors,
const ui::RendererColorMap& forced_colors_map) {
if (WebTestSupport::IsRunningWebTest() &&
GetForcedColors() == ForcedColors::kActive) {
// Web tests use a different set of colors when determining which system
// colors to render in forced colors mode.
EmulateForcedColors(/*is_dark_theme=*/false, /*is_web_test=*/true);
}
// Do not create new ColorProviders if the renderer color maps match the
// existing ColorProviders.
bool did_color_provider_update = false;
if (!IsRendererColorMappingEquivalent(light_color_provider_, light_colors)) {
light_color_provider_ =
ui::CreateColorProviderFromRendererColorMap(light_colors);
did_color_provider_update = true;
}
if (!IsRendererColorMappingEquivalent(dark_color_provider_, dark_colors)) {
dark_color_provider_ =
ui::CreateColorProviderFromRendererColorMap(dark_colors);
did_color_provider_update = true;
}
if (!IsRendererColorMappingEquivalent(forced_colors_provider_,
forced_colors_map)) {
forced_colors_provider_ =
ui::CreateColorProviderFromRendererColorMap(forced_colors_map);
did_color_provider_update = true;
}
return did_color_provider_update;
}
bool WebThemeEngineDefault::ShouldPartBeAffectedByAccentColor(
WebThemeEngine::Part part,
WebThemeEngine::State state,
const WebThemeEngine::ExtraParams* extra_params) const {
switch (part) {
case WebThemeEngine::kPartCheckbox:
case WebThemeEngine::kPartRadio: {
const auto& button =
absl::get<WebThemeEngine::ButtonExtraParams>(*extra_params);
return button.checked && state != WebThemeEngine::kStateDisabled;
}
case WebThemeEngine::kPartSliderTrack:
case WebThemeEngine::kPartSliderThumb:
return state != WebThemeEngine::kStateDisabled;
case WebThemeEngine::kPartProgressBar:
return true;
default:
return false;
}
}
SkColor WebThemeEngineDefault::GetContrastingColorFor(
mojom::ColorScheme color_scheme,
WebThemeEngine::Part part,
WebThemeEngine::State state) const {
const ui::ColorProvider* color_provider =
color_scheme == mojom::ColorScheme::kLight ? &light_color_provider_
: &dark_color_provider_;
bool isDisabled = (state == WebThemeEngine::kStateDisabled);
switch (part) {
case WebThemeEngine::kPartCheckbox:
case WebThemeEngine::kPartRadio:
return isDisabled ? color_provider->GetColor(
ui::kColorWebNativeControlBackgroundDisabled)
: color_provider->GetColor(
ui::kColorWebNativeControlBackground);
case WebThemeEngine::kPartSliderTrack:
case WebThemeEngine::kPartSliderThumb:
case WebThemeEngine::kPartProgressBar:
// We use `kStateNormal` here because the user hovering or clicking on the
// slider will change the state to something else, and we don't want the
// color-scheme to flicker back and forth when the user interacts with it.
return color_provider->GetColor(ui::kColorWebNativeControlFill);
default:
NOTREACHED_NORETURN();
}
}
mojom::ColorScheme WebThemeEngineDefault::CalculateColorSchemeForAccentColor(
absl::optional<SkColor> accent_color,
mojom::ColorScheme color_scheme,
SkColor light_contrasting_color,
SkColor dark_contrasting_color) const {
if (!accent_color) {
return color_scheme;
}
float contrast_with_light =
color_utils::GetContrastRatio(*accent_color, light_contrasting_color);
float contrast_with_dark =
color_utils::GetContrastRatio(*accent_color, dark_contrasting_color);
// If there is enough contrast between `accent_color` and `color_scheme`, then
// let's keep it the same. Otherwise, flip the `color_scheme` to guarantee
// contrast.
if (color_scheme == mojom::ColorScheme::kDark) {
if (contrast_with_dark < color_utils::kMinimumVisibleContrastRatio &&
contrast_with_dark < contrast_with_light) {
// TODO(crbug.com/1216137): what if `contrast_with_light` is less than
// `kMinimumContrast`? Should we modify `accent_color`...?
return mojom::ColorScheme::kLight;
}
} else {
if (contrast_with_light < color_utils::kMinimumVisibleContrastRatio &&
contrast_with_light < contrast_with_dark) {
return mojom::ColorScheme::kDark;
}
}
return color_scheme;
}
const ui::ColorProvider* WebThemeEngineDefault::GetColorProviderForPainting(
mojom::ColorScheme color_scheme) const {
if (GetForcedColors() == ForcedColors::kActive) {
if (emulate_forced_colors_) {
return &emulated_forced_colors_provider_;
}
return &forced_colors_provider_;
}
return color_scheme == mojom::ColorScheme::kLight ? &light_color_provider_
: &dark_color_provider_;
}
} // namespace blink

@ -50,9 +50,57 @@ class WebThemeEngineDefault : public WebThemeEngine {
void ResetToSystemColors(
WebThemeEngine::SystemColorInfoState system_color_info_state) override;
WebThemeEngine::SystemColorInfoState GetSystemColorInfo() override;
bool UpdateColorProviders(
const ui::RendererColorMap& light_colors,
const ui::RendererColorMap& dark_colors,
const ui::RendererColorMap& forced_colors_map) override;
void EmulateForcedColors(bool is_dark_theme, bool is_web_test) override;
bool IsFluentOverlayScrollbarEnabled() const override;
int GetPaintedScrollbarTrackInset() const override;
protected:
const ui::ColorProvider* GetColorProviderForPainting(
mojom::ColorScheme color_scheme) const;
private:
void SetEmulateForcedColors(bool emulate_forced_colors) {
emulate_forced_colors_ = emulate_forced_colors;
}
// Returns whether `part` should be affected by the accent color depending on
// the type of part and its state.
bool ShouldPartBeAffectedByAccentColor(
WebThemeEngine::Part part,
WebThemeEngine::State state,
const WebThemeEngine::ExtraParams* extra_params) const;
SkColor GetContrastingColorFor(mojom::ColorScheme color_scheme,
WebThemeEngine::Part part,
WebThemeEngine::State state) const;
// This returns a color scheme which provides enough contrast with the custom
// `accent_color` to make it easy to see. `light_contrasting_color` is the
// color which is used to paint adjacent to `accent_color` from the
// `light_color_provider_`, and `dark_contrasting_color` is the one used from
// `dark_color_provider_`.
mojom::ColorScheme CalculateColorSchemeForAccentColor(
absl::optional<SkColor> accent_color,
mojom::ColorScheme color_scheme,
SkColor light_contrasting_color,
SkColor dark_contrasting_color) const;
bool emulate_forced_colors_ = false;
// These providers are kept in sync with ColorProviders in the browser and
// will be updated when the theme changes.
// TODO(crbug.com/1251637): Currently these reflect the ColorProviders
// corresponding to the global NativeTheme for web instance in the browser. We
// should instead update blink to use ColorProviders that correspond to their
// hosting Page.
ui::ColorProvider light_color_provider_;
ui::ColorProvider dark_color_provider_;
ui::ColorProvider forced_colors_provider_;
// This provider is used when forced color emulation is enabled, overriding
// the light, dark or forced colors color providers.
// TODO(samomekarajr): Remove this provider when we figure out how to change
// the ForcedColors key from the renderer.
ui::ColorProvider emulated_forced_colors_provider_;
};
} // namespace blink

@ -18,8 +18,8 @@ void WebThemeEngineMac::Paint(cc::PaintCanvas* canvas,
const ui::ColorProvider* color_provider,
const absl::optional<SkColor>& accent_color) {
if (IsScrollbarPart(part)) {
PaintMacScrollBarParts(canvas, color_provider, part, state, rect,
extra_params, color_scheme);
PaintMacScrollBarParts(canvas, GetColorProviderForPainting(color_scheme),
part, state, rect, extra_params, color_scheme);
return;
}

@ -668,17 +668,12 @@ void CompleteControlsForcedColorsDefinition(ui::ColorMixer& mixer) {
}
bool IsRendererColorMappingEquivalent(
const ColorProvider* color_provider,
const ColorProvider& color_provider,
const RendererColorMap& renderer_color_map) {
if (!color_provider) {
return false;
}
CHECK(!renderer_color_map.empty());
for (const auto& table : kRendererColorIdMap) {
// The `renderer_color_map_` should map the full set of renderer color ids.
DCHECK(base::Contains(renderer_color_map, table.renderer_color_id));
if (color_provider->GetColor(table.color_id) !=
if (color_provider.GetColor(table.color_id) !=
renderer_color_map.at(table.renderer_color_id)) {
return false;
}

@ -108,7 +108,7 @@ void COMPONENT_EXPORT(COLOR)
// Returns true if `color_provider` and `renderer_color_map` map renderer
// color ids to the same SkColor.
bool COMPONENT_EXPORT(COLOR) IsRendererColorMappingEquivalent(
const ColorProvider* color_provider,
const ColorProvider& color_provider,
const RendererColorMap& renderer_color_map);
// Sets the callback for converting a ChromeColorId to a string name. This is

@ -79,12 +79,12 @@ TEST_F(ColorProviderUtilsTest, ColorProviderRendererColorMapEquivalence) {
ui::RendererColorMap renderer_color_map =
ui::CreateRendererColorMap(color_provider);
EXPECT_TRUE(
IsRendererColorMappingEquivalent(&color_provider, renderer_color_map));
IsRendererColorMappingEquivalent(color_provider, renderer_color_map));
// Providers with different renderer color mappings should not be flagged as
// equivalent.
ui::ColorProvider new_color_provider;
new_color_provider.GenerateColorMap();
EXPECT_FALSE(IsRendererColorMappingEquivalent(&new_color_provider,
renderer_color_map));
EXPECT_FALSE(
IsRendererColorMappingEquivalent(new_color_provider, renderer_color_map));
}