| // Copyright 2013 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/native_theme/native_theme_mac.h" |
| |
| #import <Cocoa/Cocoa.h> |
| #include <MediaAccessibility/MediaAccessibility.h> |
| #include <stddef.h> |
| |
| #include <vector> |
| |
| #include "base/command_line.h" |
| #include "base/mac/mac_util.h" |
| #include "base/no_destructor.h" |
| #include "cc/paint/paint_shader.h" |
| #include "ui/base/cocoa/defaults_utils.h" |
| #include "ui/base/ui_base_features.h" |
| #include "ui/base/ui_base_switches.h" |
| #include "ui/color/color_provider.h" |
| #include "ui/gfx/canvas.h" |
| #include "ui/gfx/color_palette.h" |
| #include "ui/gfx/color_utils.h" |
| #include "ui/gfx/geometry/insets.h" |
| #include "ui/gfx/geometry/rect.h" |
| #include "ui/gfx/geometry/skia_conversions.h" |
| #include "ui/native_theme/native_theme.h" |
| #include "ui/native_theme/native_theme_aura.h" |
| #include "ui/native_theme/native_theme_features.h" |
| |
| namespace { |
| |
| bool IsDarkMode() { |
| NSAppearanceName appearance = |
| [NSApp.effectiveAppearance bestMatchFromAppearancesWithNames:@[ |
| NSAppearanceNameAqua, NSAppearanceNameDarkAqua |
| ]]; |
| return [appearance isEqual:NSAppearanceNameDarkAqua]; |
| } |
| |
| bool PrefersReducedTransparency() { |
| return NSWorkspace.sharedWorkspace |
| .accessibilityDisplayShouldReduceTransparency; |
| } |
| |
| bool IsHighContrast() { |
| return NSWorkspace.sharedWorkspace.accessibilityDisplayShouldIncreaseContrast; |
| } |
| |
| bool InvertedColors() { |
| return NSWorkspace.sharedWorkspace.accessibilityDisplayShouldInvertColors; |
| } |
| |
| } // namespace |
| |
| // Helper object to respond to light mode/dark mode changeovers. |
| @interface NativeThemeEffectiveAppearanceObserver : NSObject |
| @end |
| |
| @implementation NativeThemeEffectiveAppearanceObserver { |
| void (^_handler)() __strong; |
| } |
| |
| - (instancetype)initWithHandler:(void (^)())handler { |
| self = [super init]; |
| if (self) { |
| _handler = handler; |
| [NSApp addObserver:self |
| forKeyPath:@"effectiveAppearance" |
| options:0 |
| context:nullptr]; |
| } |
| return self; |
| } |
| |
| - (void)dealloc { |
| [NSApp removeObserver:self forKeyPath:@"effectiveAppearance"]; |
| } |
| |
| - (void)observeValueForKeyPath:(NSString*)forKeyPath |
| ofObject:(id)object |
| change:(NSDictionary*)change |
| context:(void*)context { |
| _handler(); |
| } |
| |
| @end |
| |
| namespace { |
| |
| // Helper to make indexing an array by an enum class easier. |
| template <class KEY, class VALUE> |
| struct EnumArray { |
| VALUE& operator[](const KEY& key) { return array[static_cast<size_t>(key)]; } |
| VALUE array[static_cast<size_t>(KEY::COUNT)]; |
| }; |
| |
| } // namespace |
| |
| namespace ui { |
| |
| // static |
| NativeTheme* NativeTheme::GetInstanceForWeb() { |
| return NativeThemeMacWeb::instance(); |
| } |
| |
| // static |
| NativeTheme* NativeTheme::GetInstanceForNativeUi() { |
| return NativeThemeMac::instance(); |
| } |
| |
| NativeTheme* NativeTheme::GetInstanceForDarkUI() { |
| static base::NoDestructor<NativeThemeMac> s_native_theme( |
| /*configure_web_instance=*/false, /*should_only_use_dark_colors=*/true); |
| return s_native_theme.get(); |
| } |
| |
| // static |
| bool NativeTheme::SystemDarkModeSupported() { |
| return true; |
| } |
| |
| // static |
| NativeThemeMac* NativeThemeMac::instance() { |
| static base::NoDestructor<NativeThemeMac> s_native_theme( |
| /*configure_web_instance=*/true, /*should_only_use_dark_colors=*/false); |
| return s_native_theme.get(); |
| } |
| |
| NativeThemeAura::PreferredContrast NativeThemeMac::CalculatePreferredContrast() |
| const { |
| return IsHighContrast() ? NativeThemeAura::PreferredContrast::kMore |
| : NativeThemeAura::PreferredContrast::kNoPreference; |
| } |
| |
| void NativeThemeMac::Paint(cc::PaintCanvas* canvas, |
| const ColorProvider* color_provider, |
| Part part, |
| State state, |
| const gfx::Rect& rect, |
| const ExtraParams& extra, |
| ColorScheme color_scheme, |
| bool in_forced_colors, |
| const std::optional<SkColor>& accent_color) const { |
| ColorScheme color_scheme_updated = color_scheme; |
| if (color_scheme_updated == ColorScheme::kDefault) |
| color_scheme_updated = GetDefaultSystemColorScheme(); |
| |
| if (rect.IsEmpty()) |
| return; |
| |
| switch (part) { |
| case kScrollbarHorizontalThumb: |
| case kScrollbarVerticalThumb: |
| PaintMacScrollbarThumb(canvas, part, state, rect, |
| absl::get<ScrollbarExtraParams>(extra), |
| color_scheme_updated); |
| break; |
| case kScrollbarHorizontalTrack: |
| case kScrollbarVerticalTrack: |
| PaintMacScrollBarTrackOrCorner(canvas, part, state, |
| absl::get<ScrollbarExtraParams>(extra), |
| rect, color_scheme_updated, false); |
| break; |
| case kScrollbarCorner: |
| PaintMacScrollBarTrackOrCorner(canvas, part, state, |
| absl::get<ScrollbarExtraParams>(extra), |
| rect, color_scheme_updated, true); |
| break; |
| default: |
| NativeThemeBase::Paint(canvas, color_provider, part, state, rect, extra, |
| color_scheme, in_forced_colors, accent_color); |
| break; |
| } |
| } |
| |
| void ConstrainInsets(int old_width, int min_width, int* left, int* right) { |
| int requested_total_inset = *left + *right; |
| if (requested_total_inset == 0) |
| return; |
| int max_total_inset = old_width - min_width; |
| if (requested_total_inset < max_total_inset) |
| return; |
| if (max_total_inset < 0) { |
| *left = *right = 0; |
| return; |
| } |
| // Multiply the right/bottom inset by the ratio by which we need to shrink the |
| // total inset. This has the effect of rounding down the right/bottom inset, |
| // if the two sides are to be affected unevenly. |
| // This is done instead of using inset scale functions to maintain expected |
| // behavior and to map to how it looks like other scrollbars work on MacOS. |
| *right *= max_total_inset * 1.0f / requested_total_inset; |
| *left = max_total_inset - *right; |
| } |
| |
| void ConstrainedInset(gfx::Rect* rect, |
| gfx::Size min_size, |
| gfx::Insets initial_insets) { |
| int inset_left = initial_insets.left(); |
| int inset_right = initial_insets.right(); |
| int inset_top = initial_insets.top(); |
| int inset_bottom = initial_insets.bottom(); |
| |
| ConstrainInsets(rect->width(), min_size.width(), &inset_left, &inset_right); |
| ConstrainInsets(rect->height(), min_size.height(), &inset_top, &inset_bottom); |
| rect->Inset( |
| gfx::Insets::TLBR(inset_top, inset_left, inset_bottom, inset_right)); |
| } |
| |
| void NativeThemeMac::PaintMacScrollBarTrackOrCorner( |
| cc::PaintCanvas* canvas, |
| Part part, |
| State state, |
| const ScrollbarExtraParams& extra_params, |
| const gfx::Rect& rect, |
| ColorScheme color_scheme, |
| bool is_corner) const { |
| if (is_corner && extra_params.is_overlay) |
| return; |
| PaintScrollBarTrackGradient(canvas, rect, extra_params, is_corner, |
| color_scheme); |
| PaintScrollbarTrackInnerBorder(canvas, rect, extra_params, is_corner, |
| color_scheme); |
| PaintScrollbarTrackOuterBorder(canvas, rect, extra_params, is_corner, |
| color_scheme); |
| } |
| |
| void NativeThemeMac::PaintScrollBarTrackGradient( |
| cc::PaintCanvas* canvas, |
| const gfx::Rect& rect, |
| const ScrollbarExtraParams& extra_params, |
| bool is_corner, |
| ColorScheme color_scheme) const { |
| gfx::Canvas paint_canvas(canvas, 1.0f); |
| // Select colors. |
| std::vector<SkColor4f> gradient_colors; |
| bool dark_mode = color_scheme == ColorScheme::kDark; |
| if (extra_params.is_overlay) { |
| if (dark_mode) { |
| gradient_colors = {SkColor4f{0.847f, 0.847f, 0.847f, 0.157f}, |
| SkColor4f{0.8f, 0.8f, 0.8f, 0.149f}, |
| SkColor4f{0.8f, 0.8f, 0.8f, 0.149f}, |
| SkColor4f{0.8f, 0.8f, 0.8f, 0.149f}}; |
| } else { |
| gradient_colors = {SkColor4f{0.973f, 0.973f, 0.973f, 0.776f}, |
| SkColor4f{0.973f, 0.973f, 0.973f, 0.761f}, |
| SkColor4f{0.973f, 0.973f, 0.973f, 0.761f}, |
| SkColor4f{0.973f, 0.973f, 0.973f, 0.761f}}; |
| } |
| } else { |
| // Non-overlay scroller track colors are not transparent. On Safari, they |
| // are, but on all other macOS applications they are not. |
| if (dark_mode) { |
| gradient_colors = {SkColor4f{0.176f, 0.176f, 0.176f, 1.0f}, |
| SkColor4f{0.169f, 0.169f, 0.169f, 1.0f}}; |
| } else { |
| gradient_colors = {SkColor4f{0.98f, 0.98f, 0.98f, 1.0f}, |
| SkColor4f{0.98f, 0.98f, 0.98f, 1.0f}}; |
| } |
| } |
| |
| // Set the gradient direction. |
| std::vector<SkPoint> gradient_bounds; |
| if (is_corner) { |
| if (extra_params.orientation == ScrollbarOrientation::kVerticalOnRight) { |
| gradient_bounds = {gfx::PointToSkPoint(rect.origin()), |
| gfx::PointToSkPoint(rect.bottom_right())}; |
| } else { |
| gradient_bounds = {gfx::PointToSkPoint(rect.top_right()), |
| gfx::PointToSkPoint(rect.bottom_left())}; |
| } |
| } else { |
| if (extra_params.orientation == ScrollbarOrientation::kHorizontal) { |
| gradient_bounds = {gfx::PointToSkPoint(rect.origin()), |
| gfx::PointToSkPoint(rect.top_right())}; |
| } else { |
| gradient_bounds = {gfx::PointToSkPoint(rect.origin()), |
| gfx::PointToSkPoint(rect.bottom_left())}; |
| } |
| } |
| |
| // And draw. |
| cc::PaintFlags flags; |
| std::optional<SkColor> track_color = |
| GetScrollbarColor(ScrollbarPart::kTrack, color_scheme, extra_params); |
| if (track_color.has_value()) { |
| flags.setAntiAlias(true); |
| flags.setStyle(cc::PaintFlags::kFill_Style); |
| flags.setColor(track_color.value()); |
| } else { |
| flags.setShader(cc::PaintShader::MakeLinearGradient( |
| gradient_bounds.data(), gradient_colors.data(), nullptr, |
| gradient_colors.size(), SkTileMode::kClamp)); |
| } |
| paint_canvas.DrawRect(rect, flags); |
| } |
| |
| void NativeThemeMac::PaintScrollbarTrackInnerBorder( |
| cc::PaintCanvas* canvas, |
| const gfx::Rect& rect, |
| const ScrollbarExtraParams& extra_params, |
| bool is_corner, |
| ColorScheme color_scheme) const { |
| gfx::Canvas paint_canvas(canvas, 1.0f); |
| |
| // Compute the rect for the border. |
| gfx::Rect inner_border(rect); |
| if (extra_params.orientation == ScrollbarOrientation::kVerticalOnLeft) |
| inner_border.set_x(rect.right() - |
| ScrollbarTrackBorderWidth(extra_params.scale_from_dip)); |
| if (is_corner || |
| extra_params.orientation == ScrollbarOrientation::kHorizontal) |
| inner_border.set_height( |
| ScrollbarTrackBorderWidth(extra_params.scale_from_dip)); |
| if (is_corner || |
| extra_params.orientation != ScrollbarOrientation::kHorizontal) |
| inner_border.set_width( |
| ScrollbarTrackBorderWidth(extra_params.scale_from_dip)); |
| |
| // And draw. |
| cc::PaintFlags flags; |
| SkColor inner_border_color = |
| GetScrollbarColor(ScrollbarPart::kTrackInnerBorder, color_scheme, |
| extra_params) |
| .value(); |
| flags.setColor(inner_border_color); |
| paint_canvas.DrawRect(inner_border, flags); |
| } |
| |
| void NativeThemeMac::PaintScrollbarTrackOuterBorder( |
| cc::PaintCanvas* canvas, |
| const gfx::Rect& rect, |
| const ScrollbarExtraParams& extra_params, |
| bool is_corner, |
| ColorScheme color_scheme) const { |
| gfx::Canvas paint_canvas(canvas, 1.0f); |
| cc::PaintFlags flags; |
| SkColor outer_border_color = |
| GetScrollbarColor(ScrollbarPart::kTrackOuterBorder, color_scheme, |
| extra_params) |
| .value(); |
| flags.setColor(outer_border_color); |
| |
| // Draw the horizontal outer border. |
| if (is_corner || |
| extra_params.orientation == ScrollbarOrientation::kHorizontal) { |
| gfx::Rect outer_border(rect); |
| outer_border.set_height( |
| ScrollbarTrackBorderWidth(extra_params.scale_from_dip)); |
| outer_border.set_y(rect.bottom() - |
| ScrollbarTrackBorderWidth(extra_params.scale_from_dip)); |
| paint_canvas.DrawRect(outer_border, flags); |
| } |
| |
| // Draw the vertical outer border. |
| if (is_corner || |
| extra_params.orientation != ScrollbarOrientation::kHorizontal) { |
| gfx::Rect outer_border(rect); |
| outer_border.set_width( |
| ScrollbarTrackBorderWidth(extra_params.scale_from_dip)); |
| if (extra_params.orientation == ScrollbarOrientation::kVerticalOnRight) |
| outer_border.set_x(rect.right() - ScrollbarTrackBorderWidth( |
| extra_params.scale_from_dip)); |
| paint_canvas.DrawRect(outer_border, flags); |
| } |
| } |
| |
| gfx::Size NativeThemeMac::GetThumbMinSize(bool vertical, float scale) const { |
| const int kLength = 18 * scale; |
| const int kGirth = 6 * scale; |
| |
| return vertical ? gfx::Size(kGirth, kLength) : gfx::Size(kLength, kGirth); |
| } |
| |
| void NativeThemeMac::PaintMacScrollbarThumb( |
| cc::PaintCanvas* canvas, |
| Part part, |
| State state, |
| const gfx::Rect& rect, |
| const ScrollbarExtraParams& scroll_thumb, |
| ColorScheme color_scheme) const { |
| gfx::Canvas paint_canvas(canvas, 1.0f); |
| |
| // Compute the bounds for the rounded rect for the thumb from the bounds of |
| // the thumb. |
| gfx::Rect bounds(rect); |
| { |
| // Shrink the thumb evenly in length and girth to fit within the track. |
| gfx::Insets thumb_insets(GetScrollbarThumbInset( |
| scroll_thumb.is_overlay, scroll_thumb.scale_from_dip)); |
| |
| // Also shrink the thumb in girth to not touch the border. |
| if (scroll_thumb.orientation == ScrollbarOrientation::kHorizontal) { |
| thumb_insets.set_top( |
| thumb_insets.top() + |
| ScrollbarTrackBorderWidth(scroll_thumb.scale_from_dip)); |
| ConstrainedInset(&bounds, |
| GetThumbMinSize(false, scroll_thumb.scale_from_dip), |
| thumb_insets); |
| } else { |
| thumb_insets.set_left( |
| thumb_insets.left() + |
| ScrollbarTrackBorderWidth(scroll_thumb.scale_from_dip)); |
| ConstrainedInset(&bounds, |
| GetThumbMinSize(true, scroll_thumb.scale_from_dip), |
| thumb_insets); |
| } |
| } |
| |
| // Draw. |
| cc::PaintFlags flags; |
| flags.setAntiAlias(true); |
| flags.setStyle(cc::PaintFlags::kFill_Style); |
| SkColor thumb_color = |
| GetScrollbarColor(ScrollbarPart::kThumb, color_scheme, scroll_thumb) |
| .value(); |
| flags.setColor(thumb_color); |
| const SkScalar radius = std::min(bounds.width(), bounds.height()); |
| paint_canvas.DrawRoundRect(bounds, radius, flags); |
| } |
| |
| std::optional<SkColor> NativeThemeMac::GetScrollbarColor( |
| ScrollbarPart part, |
| ColorScheme color_scheme, |
| const ScrollbarExtraParams& extra_params) const { |
| // This function is called from the renderer process through the scrollbar |
| // drawing functions. Due to this, it cannot use any of the dynamic NS system |
| // colors. |
| bool dark_mode = color_scheme == ColorScheme::kDark; |
| if (part == ScrollbarPart::kThumb) { |
| if (extra_params.thumb_color.has_value()) { |
| return extra_params.thumb_color.value(); |
| } |
| if (extra_params.is_overlay) |
| return dark_mode ? SkColorSetARGB(0x80, 0xFF, 0xFF, 0xFF) |
| : SkColorSetARGB(0x80, 0, 0, 0); |
| |
| if (dark_mode) |
| return extra_params.is_hovering ? SkColorSetRGB(0x93, 0x93, 0x93) |
| : SkColorSetRGB(0x6B, 0x6B, 0x6B); |
| |
| return extra_params.is_hovering ? SkColorSetARGB(0x80, 0, 0, 0) |
| : SkColorSetARGB(0x3A, 0, 0, 0); |
| } else if (part == ScrollbarPart::kTrackInnerBorder) { |
| if (extra_params.track_color.has_value()) { |
| return extra_params.track_color.value(); |
| } |
| |
| if (extra_params.is_overlay) |
| return dark_mode ? SkColorSetARGB(0x33, 0xE5, 0xE5, 0xE5) |
| : SkColorSetARGB(0xF9, 0xDF, 0xDF, 0xDF); |
| |
| return dark_mode ? SkColorSetRGB(0x3D, 0x3D, 0x3D) |
| : SkColorSetRGB(0xE8, 0xE8, 0xE8); |
| } else if (part == ScrollbarPart::kTrackOuterBorder) { |
| if (extra_params.track_color.has_value()) { |
| return extra_params.track_color.value(); |
| } |
| if (extra_params.is_overlay) |
| return dark_mode ? SkColorSetARGB(0x28, 0xD8, 0xD8, 0xD8) |
| : SkColorSetARGB(0xC6, 0xE8, 0xE8, 0xE8); |
| |
| return dark_mode ? SkColorSetRGB(0x51, 0x51, 0x51) |
| : SkColorSetRGB(0xED, 0xED, 0xED); |
| } else if (part == ScrollbarPart::kTrack) { |
| if (extra_params.track_color.has_value()) { |
| return extra_params.track_color.value(); |
| } |
| } |
| |
| return std::nullopt; |
| } |
| |
| SkColor NativeThemeMac::GetSystemButtonPressedColor(SkColor base_color) const { |
| // TODO crbug.com/1003612: This should probably be replaced with a color |
| // transform. |
| // Mac has a different "pressed button" styling because it doesn't use |
| // ripples. |
| return color_utils::GetResultingPaintColor(SkColorSetA(SK_ColorBLACK, 0x10), |
| base_color); |
| } |
| |
| void NativeThemeMac::PaintMenuPopupBackground( |
| cc::PaintCanvas* canvas, |
| const ColorProvider* color_provider, |
| const gfx::Size& size, |
| const MenuBackgroundExtraParams& menu_background, |
| ColorScheme color_scheme) const { |
| DCHECK(color_provider); |
| cc::PaintFlags flags; |
| flags.setAntiAlias(true); |
| flags.setColor(color_provider->GetColor(kColorMenuBackground)); |
| const SkScalar radius = SkIntToScalar(menu_background.corner_radius); |
| SkRect rect = gfx::RectToSkRect(gfx::Rect(size)); |
| canvas->drawRoundRect(rect, radius, radius, flags); |
| } |
| |
| void NativeThemeMac::PaintMenuItemBackground( |
| cc::PaintCanvas* canvas, |
| const ColorProvider* color_provider, |
| State state, |
| const gfx::Rect& rect, |
| const MenuItemExtraParams& menu_item, |
| ColorScheme color_scheme) const { |
| switch (state) { |
| case NativeTheme::kNormal: |
| case NativeTheme::kDisabled: |
| // Draw nothing over the regular background. |
| break; |
| case NativeTheme::kHovered: |
| PaintSelectedMenuItem(canvas, color_provider, rect, menu_item); |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| } |
| |
| // static |
| static void CaptionSettingsChangedNotificationCallback(CFNotificationCenterRef, |
| void*, |
| CFStringRef, |
| const void*, |
| CFDictionaryRef) { |
| NativeTheme::GetInstanceForWeb()->NotifyOnCaptionStyleUpdated(); |
| } |
| |
| NativeThemeMac::NativeThemeMac(bool configure_web_instance, |
| bool should_only_use_dark_colors) |
| : NativeThemeBase(should_only_use_dark_colors) { |
| if (!should_only_use_dark_colors) |
| InitializeDarkModeStateAndObserver(); |
| |
| set_prefers_reduced_transparency(PrefersReducedTransparency()); |
| set_inverted_colors(InvertedColors()); |
| if (!IsForcedHighContrast()) { |
| SetPreferredContrast(CalculatePreferredContrast()); |
| } |
| __block auto theme = this; |
| display_accessibility_notification_token_ = |
| [NSWorkspace.sharedWorkspace.notificationCenter |
| addObserverForName: |
| NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification |
| object:nil |
| queue:nil |
| usingBlock:^(NSNotification* notification) { |
| if (!IsForcedHighContrast()) { |
| theme->SetPreferredContrast(CalculatePreferredContrast()); |
| } |
| theme->set_prefers_reduced_transparency( |
| PrefersReducedTransparency()); |
| theme->set_inverted_colors(InvertedColors()); |
| theme->NotifyOnNativeThemeUpdated(); |
| }]; |
| |
| if (configure_web_instance) |
| ConfigureWebInstance(); |
| } |
| |
| NativeThemeMac::~NativeThemeMac() { |
| [NSNotificationCenter.defaultCenter |
| removeObserver:display_accessibility_notification_token_]; |
| } |
| |
| std::optional<base::TimeDelta> NativeThemeMac::GetPlatformCaretBlinkInterval() |
| const { |
| // If there's insertion point flash rate info in NSUserDefaults, use the |
| // blink period derived from that. |
| return ui::TextInsertionCaretBlinkPeriodFromDefaults(); |
| } |
| |
| void NativeThemeMac::PaintSelectedMenuItem( |
| cc::PaintCanvas* canvas, |
| const ColorProvider* color_provider, |
| const gfx::Rect& rect, |
| const MenuItemExtraParams& extra_params) const { |
| DCHECK(color_provider); |
| // Draw the background. |
| cc::PaintFlags flags; |
| flags.setAntiAlias(true); |
| flags.setColor(color_provider->GetColor(kColorMenuItemBackgroundSelected)); |
| const SkScalar radius = SkIntToScalar(extra_params.corner_radius); |
| canvas->drawRoundRect(gfx::RectToSkRect(rect), radius, radius, flags); |
| } |
| |
| void NativeThemeMac::InitializeDarkModeStateAndObserver() { |
| __block auto theme = this; |
| set_use_dark_colors(IsDarkMode()); |
| set_preferred_color_scheme(CalculatePreferredColorScheme()); |
| appearance_observer_ = |
| [[NativeThemeEffectiveAppearanceObserver alloc] initWithHandler:^{ |
| theme->set_use_dark_colors(IsDarkMode()); |
| theme->set_preferred_color_scheme(CalculatePreferredColorScheme()); |
| theme->NotifyOnNativeThemeUpdated(); |
| }]; |
| } |
| |
| void NativeThemeMac::ConfigureWebInstance() { |
| // NativeThemeAura is used as web instance so we need to initialize its state. |
| NativeTheme* web_instance = NativeTheme::GetInstanceForWeb(); |
| web_instance->set_use_dark_colors(IsDarkMode()); |
| web_instance->set_preferred_color_scheme(CalculatePreferredColorScheme()); |
| web_instance->SetPreferredContrast(CalculatePreferredContrast()); |
| web_instance->set_prefers_reduced_transparency(PrefersReducedTransparency()); |
| web_instance->set_inverted_colors(InvertedColors()); |
| |
| // Add the web native theme as an observer to stay in sync with color scheme |
| // changes. |
| color_scheme_observer_ = |
| std::make_unique<NativeTheme::ColorSchemeNativeThemeObserver>( |
| NativeTheme::GetInstanceForWeb()); |
| AddObserver(color_scheme_observer_.get()); |
| |
| // Observe caption style changes. |
| CFNotificationCenterAddObserver( |
| CFNotificationCenterGetLocalCenter(), this, |
| CaptionSettingsChangedNotificationCallback, |
| kMACaptionAppearanceSettingsChangedNotification, nullptr, |
| CFNotificationSuspensionBehaviorDeliverImmediately); |
| } |
| |
| NativeThemeMacWeb::NativeThemeMacWeb() |
| : NativeThemeAura(/*use_overlay_scrollbars=*/IsOverlayScrollbarEnabled(), |
| /*should_only_use_dark_colors=*/false) {} |
| |
| // static |
| NativeThemeMacWeb* NativeThemeMacWeb::instance() { |
| static base::NoDestructor<NativeThemeMacWeb> s_native_theme; |
| return s_native_theme.get(); |
| } |
| |
| } // namespace ui |