Commit c79e032b authored by Leonard Grey's avatar Leonard Grey Committed by Commit Bot

Cache dark mode and high contrast status in NativeTheme

This gets called a *lot* when fetching colors while painting which assumes it's cheap.

In fact, it's responsible for about 25% of paint time on Windows and ~6% on Mac (per profiling in the field).

Bug: 950063
Change-Id: I57905fffeb51b884a0e94bac28e10b05caacd180
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1565063Reviewed-by: default avatarElly Fong-Jones <ellyjones@chromium.org>
Reviewed-by: default avatarRobert Liao <robliao@chromium.org>
Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Commit-Queue: Leonard Grey <lgrey@chromium.org>
Cr-Commit-Position: refs/heads/master@{#654848}
parent 85abeb6d
...@@ -44,14 +44,32 @@ void NativeTheme::NotifyObservers() { ...@@ -44,14 +44,32 @@ void NativeTheme::NotifyObservers() {
NativeTheme::NativeTheme() NativeTheme::NativeTheme()
: thumb_inactive_color_(0xeaeaea), : thumb_inactive_color_(0xeaeaea),
thumb_active_color_(0xf4f4f4), thumb_active_color_(0xf4f4f4),
track_color_(0xd3d3d3) { track_color_(0xd3d3d3),
} is_dark_mode_(IsForcedDarkMode()),
is_high_contrast_(IsForcedHighContrast()) {}
NativeTheme::~NativeTheme() {} NativeTheme::~NativeTheme() {}
bool NativeTheme::SystemDarkModeEnabled() const { bool NativeTheme::SystemDarkModeEnabled() const {
return base::CommandLine::ForCurrentProcess()->HasSwitch( return is_dark_mode_;
switches::kForceDarkMode); }
bool NativeTheme::UsesHighContrastColors() const {
return is_high_contrast_;
}
bool NativeTheme::IsForcedDarkMode() const {
static bool kIsForcedDarkMode =
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kForceDarkMode);
return kIsForcedDarkMode;
}
bool NativeTheme::IsForcedHighContrast() const {
static bool kIsForcedHighContrast =
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kForceHighContrast);
return kIsForcedHighContrast;
} }
CaptionStyle NativeTheme::GetSystemCaptionStyle() const { CaptionStyle NativeTheme::GetSystemCaptionStyle() const {
......
...@@ -415,7 +415,7 @@ class NATIVE_THEME_EXPORT NativeTheme { ...@@ -415,7 +415,7 @@ class NATIVE_THEME_EXPORT NativeTheme {
// Returns whether this NativeTheme uses higher-contrast colors, controlled by // Returns whether this NativeTheme uses higher-contrast colors, controlled by
// system accessibility settings and the system theme. // system accessibility settings and the system theme.
virtual bool UsesHighContrastColors() const = 0; virtual bool UsesHighContrastColors() const;
// Whether OS-level dark mode (as in macOS Mojave or Windows 10) is enabled. // Whether OS-level dark mode (as in macOS Mojave or Windows 10) is enabled.
virtual bool SystemDarkModeEnabled() const; virtual bool SystemDarkModeEnabled() const;
...@@ -427,6 +427,16 @@ class NATIVE_THEME_EXPORT NativeTheme { ...@@ -427,6 +427,16 @@ class NATIVE_THEME_EXPORT NativeTheme {
NativeTheme(); NativeTheme();
virtual ~NativeTheme(); virtual ~NativeTheme();
// Whether high contrast is forced via command-line flag.
bool IsForcedHighContrast() const;
// Whether dark mode is forced via command-line flag.
bool IsForcedDarkMode() const;
void set_dark_mode(bool is_dark_mode) { is_dark_mode_ = is_dark_mode; }
void set_high_contrast(bool is_high_contrast) {
is_high_contrast_ = is_high_contrast;
}
unsigned int thumb_inactive_color_; unsigned int thumb_inactive_color_;
unsigned int thumb_active_color_; unsigned int thumb_active_color_;
unsigned int track_color_; unsigned int track_color_;
...@@ -435,6 +445,9 @@ class NATIVE_THEME_EXPORT NativeTheme { ...@@ -435,6 +445,9 @@ class NATIVE_THEME_EXPORT NativeTheme {
// Observers to notify when the native theme changes. // Observers to notify when the native theme changes.
base::ObserverList<NativeThemeObserver>::Unchecked native_theme_observers_; base::ObserverList<NativeThemeObserver>::Unchecked native_theme_observers_;
bool is_dark_mode_ = false;
bool is_high_contrast_ = false;
DISALLOW_COPY_AND_ASSIGN(NativeTheme); DISALLOW_COPY_AND_ASSIGN(NativeTheme);
}; };
......
...@@ -264,11 +264,6 @@ gfx::Rect NativeThemeBase::GetNinePatchAperture(Part part) const { ...@@ -264,11 +264,6 @@ gfx::Rect NativeThemeBase::GetNinePatchAperture(Part part) const {
return gfx::Rect(); return gfx::Rect();
} }
bool NativeThemeBase::UsesHighContrastColors() const {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kForceHighContrast);
}
NativeThemeBase::NativeThemeBase() NativeThemeBase::NativeThemeBase()
: scrollbar_width_(kDefaultScrollbarWidth), : scrollbar_width_(kDefaultScrollbarWidth),
scrollbar_button_length_(kDefaultScrollbarButtonLength) { scrollbar_button_length_(kDefaultScrollbarButtonLength) {
......
...@@ -36,7 +36,6 @@ class NATIVE_THEME_EXPORT NativeThemeBase : public NativeTheme { ...@@ -36,7 +36,6 @@ class NATIVE_THEME_EXPORT NativeThemeBase : public NativeTheme {
bool SupportsNinePatch(Part part) const override; bool SupportsNinePatch(Part part) const override;
gfx::Size GetNinePatchCanvasSize(Part part) const override; gfx::Size GetNinePatchCanvasSize(Part part) const override;
gfx::Rect GetNinePatchAperture(Part part) const override; gfx::Rect GetNinePatchAperture(Part part) const override;
bool UsesHighContrastColors() const override;
protected: protected:
NativeThemeBase(); NativeThemeBase();
......
...@@ -56,8 +56,6 @@ class NATIVE_THEME_EXPORT NativeThemeMac : public NativeThemeBase { ...@@ -56,8 +56,6 @@ class NATIVE_THEME_EXPORT NativeThemeMac : public NativeThemeBase {
State state, State state,
const gfx::Rect& rect, const gfx::Rect& rect,
const MenuItemExtraParams& menu_item) const override; const MenuItemExtraParams& menu_item) const override;
bool UsesHighContrastColors() const override;
bool SystemDarkModeEnabled() const override;
// Paints the styled button shape used for default controls on Mac. The basic // Paints the styled button shape used for default controls on Mac. The basic
// style is used for dialog buttons, comboboxes, and tabbed pane tabs. // style is used for dialog buttons, comboboxes, and tabbed pane tabs.
...@@ -70,9 +68,6 @@ class NATIVE_THEME_EXPORT NativeThemeMac : public NativeThemeBase { ...@@ -70,9 +68,6 @@ class NATIVE_THEME_EXPORT NativeThemeMac : public NativeThemeBase {
bool round_right, bool round_right,
bool focus); bool focus);
// Updates cached dark mode status and notifies observers if it has changed.
void UpdateDarkModeStatus();
protected: protected:
friend class NativeTheme; friend class NativeTheme;
friend class base::NoDestructor<NativeThemeMac>; friend class base::NoDestructor<NativeThemeMac>;
...@@ -91,8 +86,6 @@ class NATIVE_THEME_EXPORT NativeThemeMac : public NativeThemeBase { ...@@ -91,8 +86,6 @@ class NATIVE_THEME_EXPORT NativeThemeMac : public NativeThemeBase {
appearance_observer_; appearance_observer_;
id high_contrast_notification_token_; id high_contrast_notification_token_;
bool is_dark_mode_ = false;
DISALLOW_COPY_AND_ASSIGN(NativeThemeMac); DISALLOW_COPY_AND_ASSIGN(NativeThemeMac);
}; };
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/command_line.h" #include "base/command_line.h"
#include "base/mac/mac_util.h" #include "base/mac/mac_util.h"
#include "base/mac/scoped_block.h"
#include "base/mac/sdk_forward_declarations.h" #include "base/mac/sdk_forward_declarations.h"
#include "base/macros.h" #include "base/macros.h"
#import "skia/ext/skia_utils_mac.h" #import "skia/ext/skia_utils_mac.h"
...@@ -29,7 +30,15 @@ bool IsDarkMode() { ...@@ -29,7 +30,15 @@ bool IsDarkMode() {
]]; ]];
return [appearance isEqual:NSAppearanceNameDarkAqua]; return [appearance isEqual:NSAppearanceNameDarkAqua];
} }
return false;
}
bool IsHighContrast() {
NSWorkspace* workspace = [NSWorkspace sharedWorkspace];
if ([workspace respondsToSelector:@selector
(accessibilityDisplayShouldIncreaseContrast)]) {
return workspace.accessibilityDisplayShouldIncreaseContrast;
}
return false; return false;
} }
} // namespace } // namespace
...@@ -45,13 +54,13 @@ bool IsDarkMode() { ...@@ -45,13 +54,13 @@ bool IsDarkMode() {
@end @end
@implementation NativeThemeEffectiveAppearanceObserver { @implementation NativeThemeEffectiveAppearanceObserver {
ui::NativeThemeMac* owner_; base::mac::ScopedBlock<void (^)()> handler_;
} }
- (instancetype)initWithOwner:(ui::NativeThemeMac*)owner { - (instancetype)initWithHandler:(void (^)())handler {
self = [super init]; self = [super init];
if (self) { if (self) {
owner_ = owner; handler_.reset([handler copy]);
if (@available(macOS 10.14, *)) { if (@available(macOS 10.14, *)) {
[NSApp addObserver:self [NSApp addObserver:self
forKeyPath:@"effectiveAppearance" forKeyPath:@"effectiveAppearance"
...@@ -73,7 +82,7 @@ bool IsDarkMode() { ...@@ -73,7 +82,7 @@ bool IsDarkMode() {
ofObject:(id)object ofObject:(id)object
change:(NSDictionary*)change change:(NSDictionary*)change
context:(void*)context { context:(void*)context {
owner_->UpdateDarkModeStatus(); handler_.get()();
} }
@end @end
...@@ -267,42 +276,31 @@ void NativeThemeMac::PaintMenuItemBackground( ...@@ -267,42 +276,31 @@ void NativeThemeMac::PaintMenuItemBackground(
} }
} }
bool NativeThemeMac::UsesHighContrastColors() const {
if (NativeThemeBase::UsesHighContrastColors())
return true;
NSWorkspace* workspace = [NSWorkspace sharedWorkspace];
if ([workspace respondsToSelector:@selector
(accessibilityDisplayShouldIncreaseContrast)]) {
return workspace.accessibilityDisplayShouldIncreaseContrast;
}
return false;
}
bool NativeThemeMac::SystemDarkModeEnabled() const {
if (@available(macOS 10.14, *)) {
return is_dark_mode_;
} else {
// Support "--force-dark-mode" in macOS < 10.14.
return NativeThemeBase::SystemDarkModeEnabled();
}
}
NativeThemeMac::NativeThemeMac() { NativeThemeMac::NativeThemeMac() {
if (base::FeatureList::IsEnabled(features::kDarkMode)) { if (base::FeatureList::IsEnabled(features::kDarkMode)) {
is_dark_mode_ = IsDarkMode(); __block auto theme = this;
set_dark_mode(IsDarkMode());
appearance_observer_.reset( appearance_observer_.reset(
[[NativeThemeEffectiveAppearanceObserver alloc] initWithOwner:this]); [[NativeThemeEffectiveAppearanceObserver alloc] initWithHandler:^{
theme->set_dark_mode(IsDarkMode());
theme->NotifyObservers();
}]);
} }
if (@available(macOS 10.10, *)) { if (@available(macOS 10.10, *)) {
high_contrast_notification_token_ = [[[NSWorkspace sharedWorkspace] if (!IsForcedHighContrast()) {
notificationCenter] set_high_contrast(IsHighContrast());
addObserverForName: __block auto theme = this;
NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification high_contrast_notification_token_ =
object:nil [[[NSWorkspace sharedWorkspace] notificationCenter]
queue:nil addObserverForName:
usingBlock:^(NSNotification* notification) { NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification
ui::NativeTheme::GetInstanceForNativeUi()->NotifyObservers(); object:nil
}]; queue:nil
usingBlock:^(NSNotification* notification) {
theme->set_high_contrast(IsHighContrast());
theme->NotifyObservers();
}];
}
} }
} }
...@@ -319,11 +317,4 @@ void NativeThemeMac::PaintSelectedMenuItem(cc::PaintCanvas* canvas, ...@@ -319,11 +317,4 @@ void NativeThemeMac::PaintSelectedMenuItem(cc::PaintCanvas* canvas,
canvas->drawRect(gfx::RectToSkRect(rect), flags); canvas->drawRect(gfx::RectToSkRect(rect), flags);
} }
void NativeThemeMac::UpdateDarkModeStatus() {
bool was_dark_mode = is_dark_mode_;
is_dark_mode_ = IsDarkMode();
if (was_dark_mode != is_dark_mode_)
NotifyObservers();
}
} // namespace ui } // namespace ui
...@@ -238,9 +238,7 @@ NativeThemeWin::NativeThemeWin() ...@@ -238,9 +238,7 @@ NativeThemeWin::NativeThemeWin()
open_theme_(NULL), open_theme_(NULL),
close_theme_(NULL), close_theme_(NULL),
theme_dll_(LoadLibrary(L"uxtheme.dll")), theme_dll_(LoadLibrary(L"uxtheme.dll")),
color_change_listener_(this), color_change_listener_(this) {
is_using_high_contrast_(false),
is_using_high_contrast_valid_(false) {
if (theme_dll_) { if (theme_dll_) {
draw_theme_ = reinterpret_cast<DrawThemeBackgroundPtr>( draw_theme_ = reinterpret_cast<DrawThemeBackgroundPtr>(
GetProcAddress(theme_dll_, "DrawThemeBackground")); GetProcAddress(theme_dll_, "DrawThemeBackground"));
...@@ -255,7 +253,9 @@ NativeThemeWin::NativeThemeWin() ...@@ -255,7 +253,9 @@ NativeThemeWin::NativeThemeWin()
close_theme_ = reinterpret_cast<CloseThemeDataPtr>( close_theme_ = reinterpret_cast<CloseThemeDataPtr>(
GetProcAddress(theme_dll_, "CloseThemeData")); GetProcAddress(theme_dll_, "CloseThemeData"));
} }
if (base::FeatureList::IsEnabled(features::kDarkMode)) {
if (!IsForcedDarkMode() && !IsForcedHighContrast() &&
base::FeatureList::IsEnabled(features::kDarkMode)) {
// Dark Mode currently targets UWP apps, which means Win32 apps need to use // Dark Mode currently targets UWP apps, which means Win32 apps need to use
// alternate, less reliable means of detecting the state. The following // alternate, less reliable means of detecting the state. The following
// can break in future Windows versions. // can break in future Windows versions.
...@@ -265,9 +265,13 @@ NativeThemeWin::NativeThemeWin() ...@@ -265,9 +265,13 @@ NativeThemeWin::NativeThemeWin()
L"Software\\Microsoft\\Windows\\CurrentVersion\\" L"Software\\Microsoft\\Windows\\CurrentVersion\\"
L"Themes\\Personalize", L"Themes\\Personalize",
KEY_READ | KEY_NOTIFY) == ERROR_SUCCESS; KEY_READ | KEY_NOTIFY) == ERROR_SUCCESS;
if (key_open_succeeded) if (key_open_succeeded) {
UpdateDarkModeStatus();
RegisterThemeRegkeyObserver(); RegisterThemeRegkeyObserver();
}
} }
if (!IsForcedHighContrast())
set_high_contrast(IsUsingHighContrastThemeInternal());
memset(theme_handles_, 0, sizeof(theme_handles_)); memset(theme_handles_, 0, sizeof(theme_handles_));
// Initialize the cached system colors. // Initialize the cached system colors.
...@@ -284,15 +288,10 @@ NativeThemeWin::~NativeThemeWin() { ...@@ -284,15 +288,10 @@ NativeThemeWin::~NativeThemeWin() {
} }
bool NativeThemeWin::IsUsingHighContrastThemeInternal() const { bool NativeThemeWin::IsUsingHighContrastThemeInternal() const {
if (is_using_high_contrast_valid_)
return is_using_high_contrast_;
HIGHCONTRAST result; HIGHCONTRAST result;
result.cbSize = sizeof(HIGHCONTRAST); result.cbSize = sizeof(HIGHCONTRAST);
is_using_high_contrast_ = return SystemParametersInfo(SPI_GETHIGHCONTRAST, result.cbSize, &result, 0) &&
SystemParametersInfo(SPI_GETHIGHCONTRAST, result.cbSize, &result, 0) && (result.dwFlags & HCF_HIGHCONTRASTON) == HCF_HIGHCONTRASTON;
(result.dwFlags & HCF_HIGHCONTRASTON) == HCF_HIGHCONTRASTON;
is_using_high_contrast_valid_ = true;
return is_using_high_contrast_;
} }
void NativeThemeWin::CloseHandlesInternal() { void NativeThemeWin::CloseHandlesInternal() {
...@@ -309,7 +308,8 @@ void NativeThemeWin::CloseHandlesInternal() { ...@@ -309,7 +308,8 @@ void NativeThemeWin::CloseHandlesInternal() {
void NativeThemeWin::OnSysColorChange() { void NativeThemeWin::OnSysColorChange() {
UpdateSystemColors(); UpdateSystemColors();
is_using_high_contrast_valid_ = false; if (!IsForcedHighContrast())
set_high_contrast(IsUsingHighContrastThemeInternal());
NotifyObservers(); NotifyObservers();
} }
...@@ -579,26 +579,13 @@ gfx::Rect NativeThemeWin::GetNinePatchAperture(Part part) const { ...@@ -579,26 +579,13 @@ gfx::Rect NativeThemeWin::GetNinePatchAperture(Part part) const {
return gfx::Rect(); return gfx::Rect();
} }
bool NativeThemeWin::UsesHighContrastColors() const {
bool force_enabled = base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kForceHighContrast);
return force_enabled || IsUsingHighContrastThemeInternal();
}
bool NativeThemeWin::SystemDarkModeEnabled() const { bool NativeThemeWin::SystemDarkModeEnabled() const {
// Windows high contrast modes are entirely different themes, // Windows high contrast modes are entirely different themes,
// so let them take priority over dark mode. // so let them take priority over dark mode.
// ...unless --force-dark-mode was specified in which case caveat emptor. // ...unless --force-dark-mode was specified in which case caveat emptor.
if (UsesHighContrastColors() && !NativeTheme::SystemDarkModeEnabled()) if (UsesHighContrastColors() && !IsForcedDarkMode())
return false; return false;
bool fDarkModeEnabled = false; return NativeTheme::SystemDarkModeEnabled();
if (hkcu_themes_regkey_.Valid()) {
DWORD apps_use_light_theme = 1;
hkcu_themes_regkey_.ReadValueDW(L"AppsUseLightTheme",
&apps_use_light_theme);
fDarkModeEnabled = (apps_use_light_theme == 0);
}
return fDarkModeEnabled || NativeTheme::SystemDarkModeEnabled();
} }
void NativeThemeWin::PaintIndirect(cc::PaintCanvas* destination_canvas, void NativeThemeWin::PaintIndirect(cc::PaintCanvas* destination_canvas,
...@@ -1933,6 +1920,7 @@ void NativeThemeWin::RegisterThemeRegkeyObserver() { ...@@ -1933,6 +1920,7 @@ void NativeThemeWin::RegisterThemeRegkeyObserver() {
DCHECK(hkcu_themes_regkey_.Valid()); DCHECK(hkcu_themes_regkey_.Valid());
hkcu_themes_regkey_.StartWatching(base::BindOnce( hkcu_themes_regkey_.StartWatching(base::BindOnce(
[](NativeThemeWin* native_theme) { [](NativeThemeWin* native_theme) {
native_theme->UpdateDarkModeStatus();
native_theme->NotifyObservers(); native_theme->NotifyObservers();
// RegKey::StartWatching only provides one notification. Reregistration // RegKey::StartWatching only provides one notification. Reregistration
// is required to get future notifications. // is required to get future notifications.
...@@ -1941,4 +1929,15 @@ void NativeThemeWin::RegisterThemeRegkeyObserver() { ...@@ -1941,4 +1929,15 @@ void NativeThemeWin::RegisterThemeRegkeyObserver() {
base::Unretained(this))); base::Unretained(this)));
} }
void NativeThemeWin::UpdateDarkModeStatus() {
bool fDarkModeEnabled = false;
if (hkcu_themes_regkey_.Valid()) {
DWORD apps_use_light_theme = 1;
hkcu_themes_regkey_.ReadValueDW(L"AppsUseLightTheme",
&apps_use_light_theme);
fDarkModeEnabled = (apps_use_light_theme == 0);
}
set_dark_mode(fDarkModeEnabled);
}
} // namespace ui } // namespace ui
...@@ -80,7 +80,6 @@ class NATIVE_THEME_EXPORT NativeThemeWin : public NativeTheme, ...@@ -80,7 +80,6 @@ class NATIVE_THEME_EXPORT NativeThemeWin : public NativeTheme,
bool SupportsNinePatch(Part part) const override; bool SupportsNinePatch(Part part) const override;
gfx::Size GetNinePatchCanvasSize(Part part) const override; gfx::Size GetNinePatchCanvasSize(Part part) const override;
gfx::Rect GetNinePatchAperture(Part part) const override; gfx::Rect GetNinePatchAperture(Part part) const override;
bool UsesHighContrastColors() const override;
bool SystemDarkModeEnabled() const override; bool SystemDarkModeEnabled() const override;
protected: protected:
...@@ -263,6 +262,7 @@ class NATIVE_THEME_EXPORT NativeThemeWin : public NativeTheme, ...@@ -263,6 +262,7 @@ class NATIVE_THEME_EXPORT NativeThemeWin : public NativeTheme,
HANDLE GetThemeHandle(ThemeName theme_name) const; HANDLE GetThemeHandle(ThemeName theme_name) const;
void RegisterThemeRegkeyObserver(); void RegisterThemeRegkeyObserver();
void UpdateDarkModeStatus();
typedef HRESULT (WINAPI* DrawThemeBackgroundPtr)(HANDLE theme, typedef HRESULT (WINAPI* DrawThemeBackgroundPtr)(HANDLE theme,
HDC hdc, HDC hdc,
...@@ -328,12 +328,6 @@ class NATIVE_THEME_EXPORT NativeThemeWin : public NativeTheme, ...@@ -328,12 +328,6 @@ class NATIVE_THEME_EXPORT NativeThemeWin : public NativeTheme,
gfx::ScopedSysColorChangeListener color_change_listener_; gfx::ScopedSysColorChangeListener color_change_listener_;
mutable std::map<int, SkColor> system_colors_; mutable std::map<int, SkColor> system_colors_;
// Is a high contrast theme active?
mutable bool is_using_high_contrast_;
// Is |is_using_high_contrast_| valid?
mutable bool is_using_high_contrast_valid_;
DISALLOW_COPY_AND_ASSIGN(NativeThemeWin); DISALLOW_COPY_AND_ASSIGN(NativeThemeWin);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment