native_theme_mac.mm 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. // Copyright (c) 2013 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ui/native_theme/native_theme_mac.h"
  5. #import <Cocoa/Cocoa.h>
  6. #include <MediaAccessibility/MediaAccessibility.h>
  7. #include <stddef.h>
  8. #include <vector>
  9. #include "base/command_line.h"
  10. #include "base/mac/mac_util.h"
  11. #include "base/mac/scoped_block.h"
  12. #include "base/no_destructor.h"
  13. #include "cc/paint/paint_shader.h"
  14. #include "ui/base/ui_base_features.h"
  15. #include "ui/base/ui_base_switches.h"
  16. #include "ui/color/color_provider.h"
  17. #include "ui/color/mac/scoped_current_nsappearance.h"
  18. #include "ui/gfx/canvas.h"
  19. #include "ui/gfx/color_palette.h"
  20. #include "ui/gfx/color_utils.h"
  21. #include "ui/gfx/geometry/insets.h"
  22. #include "ui/gfx/geometry/rect.h"
  23. #include "ui/gfx/geometry/skia_conversions.h"
  24. #include "ui/native_theme/common_theme.h"
  25. #include "ui/native_theme/native_theme_aura.h"
  26. #include "ui/native_theme/native_theme_features.h"
  27. namespace {
  28. bool IsDarkMode() {
  29. if (@available(macOS 10.14, *)) {
  30. NSAppearanceName appearance =
  31. [[NSApp effectiveAppearance] bestMatchFromAppearancesWithNames:@[
  32. NSAppearanceNameAqua, NSAppearanceNameDarkAqua
  33. ]];
  34. return [appearance isEqual:NSAppearanceNameDarkAqua];
  35. }
  36. return false;
  37. }
  38. bool IsHighContrast() {
  39. return NSWorkspace.sharedWorkspace.accessibilityDisplayShouldIncreaseContrast;
  40. }
  41. } // namespace
  42. // Helper object to respond to light mode/dark mode changeovers.
  43. @interface NativeThemeEffectiveAppearanceObserver : NSObject
  44. @end
  45. @implementation NativeThemeEffectiveAppearanceObserver {
  46. base::mac::ScopedBlock<void (^)()> _handler;
  47. }
  48. - (instancetype)initWithHandler:(void (^)())handler {
  49. self = [super init];
  50. if (self) {
  51. _handler.reset([handler copy]);
  52. if (@available(macOS 10.14, *)) {
  53. [NSApp addObserver:self
  54. forKeyPath:@"effectiveAppearance"
  55. options:0
  56. context:nullptr];
  57. }
  58. }
  59. return self;
  60. }
  61. - (void)dealloc {
  62. if (@available(macOS 10.14, *)) {
  63. [NSApp removeObserver:self forKeyPath:@"effectiveAppearance"];
  64. }
  65. [super dealloc];
  66. }
  67. - (void)observeValueForKeyPath:(NSString*)forKeyPath
  68. ofObject:(id)object
  69. change:(NSDictionary*)change
  70. context:(void*)context {
  71. _handler.get()();
  72. }
  73. @end
  74. namespace {
  75. // Helper to make indexing an array by an enum class easier.
  76. template <class KEY, class VALUE>
  77. struct EnumArray {
  78. VALUE& operator[](const KEY& key) { return array[static_cast<size_t>(key)]; }
  79. VALUE array[static_cast<size_t>(KEY::COUNT)];
  80. };
  81. } // namespace
  82. namespace ui {
  83. // static
  84. NativeTheme* NativeTheme::GetInstanceForWeb() {
  85. return NativeThemeMacWeb::instance();
  86. }
  87. // static
  88. NativeTheme* NativeTheme::GetInstanceForNativeUi() {
  89. return NativeThemeMac::instance();
  90. }
  91. NativeTheme* NativeTheme::GetInstanceForDarkUI() {
  92. static base::NoDestructor<NativeThemeMac> s_native_theme(false, true);
  93. return s_native_theme.get();
  94. }
  95. // static
  96. bool NativeTheme::SystemDarkModeSupported() {
  97. if (@available(macOS 10.14, *)) {
  98. return true;
  99. }
  100. return false;
  101. }
  102. // static
  103. NativeThemeMac* NativeThemeMac::instance() {
  104. static base::NoDestructor<NativeThemeMac> s_native_theme(true, false);
  105. return s_native_theme.get();
  106. }
  107. NativeThemeAura::PreferredContrast NativeThemeMac::CalculatePreferredContrast()
  108. const {
  109. return IsHighContrast() ? NativeThemeAura::PreferredContrast::kMore
  110. : NativeThemeAura::PreferredContrast::kNoPreference;
  111. }
  112. void NativeThemeMac::Paint(cc::PaintCanvas* canvas,
  113. const ColorProvider* color_provider,
  114. Part part,
  115. State state,
  116. const gfx::Rect& rect,
  117. const ExtraParams& extra,
  118. ColorScheme color_scheme,
  119. const absl::optional<SkColor>& accent_color) const {
  120. ColorScheme color_scheme_updated = color_scheme;
  121. if (color_scheme_updated == ColorScheme::kDefault)
  122. color_scheme_updated = GetDefaultSystemColorScheme();
  123. if (rect.IsEmpty())
  124. return;
  125. switch (part) {
  126. case kScrollbarHorizontalThumb:
  127. case kScrollbarVerticalThumb:
  128. PaintMacScrollbarThumb(canvas, part, state, rect, extra.scrollbar_extra,
  129. color_scheme_updated);
  130. break;
  131. case kScrollbarHorizontalTrack:
  132. case kScrollbarVerticalTrack:
  133. PaintMacScrollBarTrackOrCorner(canvas, part, state, extra.scrollbar_extra,
  134. rect, color_scheme_updated, false);
  135. break;
  136. case kScrollbarCorner:
  137. PaintMacScrollBarTrackOrCorner(canvas, part, state, extra.scrollbar_extra,
  138. rect, color_scheme_updated, true);
  139. break;
  140. default:
  141. NativeThemeBase::Paint(canvas, color_provider, part, state, rect, extra,
  142. color_scheme, accent_color);
  143. break;
  144. }
  145. }
  146. void ConstrainInsets(int old_width, int min_width, int* left, int* right) {
  147. int requested_total_inset = *left + *right;
  148. if (requested_total_inset == 0)
  149. return;
  150. int max_total_inset = old_width - min_width;
  151. if (requested_total_inset < max_total_inset)
  152. return;
  153. if (max_total_inset < 0) {
  154. *left = *right = 0;
  155. return;
  156. }
  157. // Multiply the right/bottom inset by the ratio by which we need to shrink the
  158. // total inset. This has the effect of rounding down the right/bottom inset,
  159. // if the two sides are to be affected unevenly.
  160. // This is done instead of using inset scale functions to maintain expected
  161. // behavior and to map to how it looks like other scrollbars work on MacOS.
  162. *right *= max_total_inset * 1.0f / requested_total_inset;
  163. *left = max_total_inset - *right;
  164. }
  165. void ConstrainedInset(gfx::Rect* rect,
  166. gfx::Size min_size,
  167. gfx::Insets initial_insets) {
  168. int inset_left = initial_insets.left();
  169. int inset_right = initial_insets.right();
  170. int inset_top = initial_insets.top();
  171. int inset_bottom = initial_insets.bottom();
  172. ConstrainInsets(rect->width(), min_size.width(), &inset_left, &inset_right);
  173. ConstrainInsets(rect->height(), min_size.height(), &inset_top, &inset_bottom);
  174. rect->Inset(
  175. gfx::Insets::TLBR(inset_top, inset_left, inset_bottom, inset_right));
  176. }
  177. void NativeThemeMac::PaintMacScrollBarTrackOrCorner(
  178. cc::PaintCanvas* canvas,
  179. Part part,
  180. State state,
  181. const ScrollbarExtraParams& extra_params,
  182. const gfx::Rect& rect,
  183. ColorScheme color_scheme,
  184. bool is_corner) const {
  185. if (is_corner && extra_params.is_overlay)
  186. return;
  187. PaintScrollBarTrackGradient(canvas, rect, extra_params, is_corner,
  188. color_scheme);
  189. PaintScrollbarTrackInnerBorder(canvas, rect, extra_params, is_corner,
  190. color_scheme);
  191. PaintScrollbarTrackOuterBorder(canvas, rect, extra_params, is_corner,
  192. color_scheme);
  193. }
  194. void NativeThemeMac::PaintScrollBarTrackGradient(
  195. cc::PaintCanvas* canvas,
  196. const gfx::Rect& rect,
  197. const ScrollbarExtraParams& extra_params,
  198. bool is_corner,
  199. ColorScheme color_scheme) const {
  200. gfx::Canvas paint_canvas(canvas, 1.0f);
  201. // Select colors.
  202. std::vector<SkColor4f> gradient_colors;
  203. bool dark_mode = color_scheme == ColorScheme::kDark;
  204. if (extra_params.is_overlay) {
  205. if (dark_mode) {
  206. gradient_colors = {SkColor4f{0.847f, 0.847f, 0.847f, 0.157f},
  207. SkColor4f{0.8f, 0.8f, 0.8f, 0.149f},
  208. SkColor4f{0.8f, 0.8f, 0.8f, 0.149f},
  209. SkColor4f{0.8f, 0.8f, 0.8f, 0.149f}};
  210. } else {
  211. gradient_colors = {SkColor4f{0.973f, 0.973f, 0.973f, 0.776f},
  212. SkColor4f{0.973f, 0.973f, 0.973f, 0.761f},
  213. SkColor4f{0.973f, 0.973f, 0.973f, 0.761f},
  214. SkColor4f{0.973f, 0.973f, 0.973f, 0.761f}};
  215. }
  216. } else {
  217. // Non-overlay scroller track colors are not transparent. On Safari, they
  218. // are, but on all other macOS applications they are not.
  219. if (dark_mode) {
  220. gradient_colors = {SkColor4f{0.176f, 0.176f, 0.176f, 1.0f},
  221. SkColor4f{0.169f, 0.169f, 0.169f, 1.0f}};
  222. } else {
  223. gradient_colors = {SkColor4f{0.98f, 0.98f, 0.98f, 1.0f},
  224. SkColor4f{0.98f, 0.98f, 0.98f, 1.0f}};
  225. }
  226. }
  227. // Set the gradient direction.
  228. std::vector<SkPoint> gradient_bounds;
  229. if (is_corner) {
  230. if (extra_params.orientation == ScrollbarOrientation::kVerticalOnRight) {
  231. gradient_bounds = {gfx::PointToSkPoint(rect.origin()),
  232. gfx::PointToSkPoint(rect.bottom_right())};
  233. } else {
  234. gradient_bounds = {gfx::PointToSkPoint(rect.top_right()),
  235. gfx::PointToSkPoint(rect.bottom_left())};
  236. }
  237. } else {
  238. if (extra_params.orientation == ScrollbarOrientation::kHorizontal) {
  239. gradient_bounds = {gfx::PointToSkPoint(rect.origin()),
  240. gfx::PointToSkPoint(rect.top_right())};
  241. } else {
  242. gradient_bounds = {gfx::PointToSkPoint(rect.origin()),
  243. gfx::PointToSkPoint(rect.bottom_left())};
  244. }
  245. }
  246. // And draw.
  247. cc::PaintFlags gradient;
  248. gradient.setShader(cc::PaintShader::MakeLinearGradient(
  249. gradient_bounds.data(), gradient_colors.data(), nullptr,
  250. gradient_colors.size(), SkTileMode::kClamp));
  251. paint_canvas.DrawRect(rect, gradient);
  252. }
  253. void NativeThemeMac::PaintScrollbarTrackInnerBorder(
  254. cc::PaintCanvas* canvas,
  255. const gfx::Rect& rect,
  256. const ScrollbarExtraParams& extra_params,
  257. bool is_corner,
  258. ColorScheme color_scheme) const {
  259. gfx::Canvas paint_canvas(canvas, 1.0f);
  260. // Compute the rect for the border.
  261. gfx::Rect inner_border(rect);
  262. if (extra_params.orientation == ScrollbarOrientation::kVerticalOnLeft)
  263. inner_border.set_x(rect.right() -
  264. ScrollbarTrackBorderWidth(extra_params.scale_from_dip));
  265. if (is_corner ||
  266. extra_params.orientation == ScrollbarOrientation::kHorizontal)
  267. inner_border.set_height(
  268. ScrollbarTrackBorderWidth(extra_params.scale_from_dip));
  269. if (is_corner ||
  270. extra_params.orientation != ScrollbarOrientation::kHorizontal)
  271. inner_border.set_width(
  272. ScrollbarTrackBorderWidth(extra_params.scale_from_dip));
  273. // And draw.
  274. cc::PaintFlags flags;
  275. SkColor inner_border_color =
  276. GetScrollbarColor(ScrollbarPart::kTrackInnerBorder, color_scheme,
  277. extra_params)
  278. .value();
  279. flags.setColor(inner_border_color);
  280. paint_canvas.DrawRect(inner_border, flags);
  281. }
  282. void NativeThemeMac::PaintScrollbarTrackOuterBorder(
  283. cc::PaintCanvas* canvas,
  284. const gfx::Rect& rect,
  285. const ScrollbarExtraParams& extra_params,
  286. bool is_corner,
  287. ColorScheme color_scheme) const {
  288. gfx::Canvas paint_canvas(canvas, 1.0f);
  289. cc::PaintFlags flags;
  290. SkColor outer_border_color =
  291. GetScrollbarColor(ScrollbarPart::kTrackOuterBorder, color_scheme,
  292. extra_params)
  293. .value();
  294. flags.setColor(outer_border_color);
  295. // Draw the horizontal outer border.
  296. if (is_corner ||
  297. extra_params.orientation == ScrollbarOrientation::kHorizontal) {
  298. gfx::Rect outer_border(rect);
  299. outer_border.set_height(
  300. ScrollbarTrackBorderWidth(extra_params.scale_from_dip));
  301. outer_border.set_y(rect.bottom() -
  302. ScrollbarTrackBorderWidth(extra_params.scale_from_dip));
  303. paint_canvas.DrawRect(outer_border, flags);
  304. }
  305. // Draw the vertial outer border.
  306. if (is_corner ||
  307. extra_params.orientation != ScrollbarOrientation::kHorizontal) {
  308. gfx::Rect outer_border(rect);
  309. outer_border.set_width(
  310. ScrollbarTrackBorderWidth(extra_params.scale_from_dip));
  311. if (extra_params.orientation == ScrollbarOrientation::kVerticalOnRight)
  312. outer_border.set_x(rect.right() - ScrollbarTrackBorderWidth(
  313. extra_params.scale_from_dip));
  314. paint_canvas.DrawRect(outer_border, flags);
  315. }
  316. }
  317. gfx::Size NativeThemeMac::GetThumbMinSize(bool vertical, float scale) const {
  318. const int kLength = 18 * scale;
  319. const int kGirth = 6 * scale;
  320. return vertical ? gfx::Size(kGirth, kLength) : gfx::Size(kLength, kGirth);
  321. }
  322. void NativeThemeMac::PaintMacScrollbarThumb(
  323. cc::PaintCanvas* canvas,
  324. Part part,
  325. State state,
  326. const gfx::Rect& rect,
  327. const ScrollbarExtraParams& scroll_thumb,
  328. ColorScheme color_scheme) const {
  329. gfx::Canvas paint_canvas(canvas, 1.0f);
  330. // Compute the bounds for the rounded rect for the thumb from the bounds of
  331. // the thumb.
  332. gfx::Rect bounds(rect);
  333. {
  334. // Shrink the thumb evenly in length and girth to fit within the track.
  335. gfx::Insets thumb_insets(GetScrollbarThumbInset(
  336. scroll_thumb.is_overlay, scroll_thumb.scale_from_dip));
  337. // Also shrink the thumb in girth to not touch the border.
  338. if (scroll_thumb.orientation == ScrollbarOrientation::kHorizontal) {
  339. thumb_insets.set_top(
  340. thumb_insets.top() +
  341. ScrollbarTrackBorderWidth(scroll_thumb.scale_from_dip));
  342. ConstrainedInset(&bounds,
  343. GetThumbMinSize(false, scroll_thumb.scale_from_dip),
  344. thumb_insets);
  345. } else {
  346. thumb_insets.set_left(
  347. thumb_insets.left() +
  348. ScrollbarTrackBorderWidth(scroll_thumb.scale_from_dip));
  349. ConstrainedInset(&bounds,
  350. GetThumbMinSize(true, scroll_thumb.scale_from_dip),
  351. thumb_insets);
  352. }
  353. }
  354. // Draw.
  355. cc::PaintFlags flags;
  356. flags.setAntiAlias(true);
  357. flags.setStyle(cc::PaintFlags::kFill_Style);
  358. SkColor thumb_color =
  359. GetScrollbarColor(ScrollbarPart::kThumb, color_scheme, scroll_thumb)
  360. .value();
  361. flags.setColor(thumb_color);
  362. const SkScalar radius = std::min(bounds.width(), bounds.height());
  363. paint_canvas.DrawRoundRect(bounds, radius, flags);
  364. }
  365. absl::optional<SkColor> NativeThemeMac::GetScrollbarColor(
  366. ScrollbarPart part,
  367. ColorScheme color_scheme,
  368. const ScrollbarExtraParams& extra_params) const {
  369. // This function is called from the renderer process through the scrollbar
  370. // drawing functions. Due to this, it cannot use any of the dynamic NS system
  371. // colors.
  372. bool dark_mode = color_scheme == ColorScheme::kDark;
  373. if (part == ScrollbarPart::kThumb) {
  374. if (extra_params.is_overlay)
  375. return dark_mode ? SkColorSetARGB(0x80, 0xFF, 0xFF, 0xFF)
  376. : SkColorSetARGB(0x80, 0, 0, 0);
  377. if (dark_mode)
  378. return extra_params.is_hovering ? SkColorSetRGB(0x93, 0x93, 0x93)
  379. : SkColorSetRGB(0x6B, 0x6B, 0x6B);
  380. return extra_params.is_hovering ? SkColorSetARGB(0x80, 0, 0, 0)
  381. : SkColorSetARGB(0x3A, 0, 0, 0);
  382. } else if (part == ScrollbarPart::kTrackInnerBorder) {
  383. if (extra_params.is_overlay)
  384. return dark_mode ? SkColorSetARGB(0x33, 0xE5, 0xE5, 0xE5)
  385. : SkColorSetARGB(0xF9, 0xDF, 0xDF, 0xDF);
  386. return dark_mode ? SkColorSetRGB(0x3D, 0x3D, 0x3D)
  387. : SkColorSetRGB(0xE8, 0xE8, 0xE8);
  388. } else if (part == ScrollbarPart::kTrackOuterBorder) {
  389. if (extra_params.is_overlay)
  390. return dark_mode ? SkColorSetARGB(0x28, 0xD8, 0xD8, 0xD8)
  391. : SkColorSetARGB(0xC6, 0xE8, 0xE8, 0xE8);
  392. return dark_mode ? SkColorSetRGB(0x51, 0x51, 0x51)
  393. : SkColorSetRGB(0xED, 0xED, 0xED);
  394. }
  395. return absl::nullopt;
  396. }
  397. SkColor NativeThemeMac::GetSystemButtonPressedColor(SkColor base_color) const {
  398. // TODO crbug.com/1003612: This should probably be replaced with a color
  399. // transform.
  400. // Mac has a different "pressed button" styling because it doesn't use
  401. // ripples.
  402. return color_utils::GetResultingPaintColor(SkColorSetA(SK_ColorBLACK, 0x10),
  403. base_color);
  404. }
  405. void NativeThemeMac::PaintMenuPopupBackground(
  406. cc::PaintCanvas* canvas,
  407. const ColorProvider* color_provider,
  408. const gfx::Size& size,
  409. const MenuBackgroundExtraParams& menu_background,
  410. ColorScheme color_scheme) const {
  411. DCHECK(color_provider);
  412. cc::PaintFlags flags;
  413. flags.setAntiAlias(true);
  414. flags.setColor(color_provider->GetColor(kColorMenuBackground));
  415. const SkScalar radius = SkIntToScalar(menu_background.corner_radius);
  416. SkRect rect = gfx::RectToSkRect(gfx::Rect(size));
  417. canvas->drawRoundRect(rect, radius, radius, flags);
  418. }
  419. void NativeThemeMac::PaintMenuItemBackground(
  420. cc::PaintCanvas* canvas,
  421. const ColorProvider* color_provider,
  422. State state,
  423. const gfx::Rect& rect,
  424. const MenuItemExtraParams& menu_item,
  425. ColorScheme color_scheme) const {
  426. switch (state) {
  427. case NativeTheme::kNormal:
  428. case NativeTheme::kDisabled:
  429. // Draw nothing over the regular background.
  430. break;
  431. case NativeTheme::kHovered:
  432. PaintSelectedMenuItem(canvas, color_provider, rect);
  433. break;
  434. default:
  435. NOTREACHED();
  436. break;
  437. }
  438. }
  439. // static
  440. static void CaptionSettingsChangedNotificationCallback(CFNotificationCenterRef,
  441. void*,
  442. CFStringRef,
  443. const void*,
  444. CFDictionaryRef) {
  445. NativeTheme::GetInstanceForWeb()->NotifyOnCaptionStyleUpdated();
  446. }
  447. NativeThemeMac::NativeThemeMac(bool configure_web_instance,
  448. bool should_only_use_dark_colors)
  449. : NativeThemeBase(should_only_use_dark_colors) {
  450. if (!should_only_use_dark_colors)
  451. InitializeDarkModeStateAndObserver();
  452. if (!IsForcedHighContrast()) {
  453. set_preferred_contrast(CalculatePreferredContrast());
  454. __block auto theme = this;
  455. high_contrast_notification_token_ =
  456. [[[NSWorkspace sharedWorkspace] notificationCenter]
  457. addObserverForName:
  458. NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification
  459. object:nil
  460. queue:nil
  461. usingBlock:^(NSNotification* notification) {
  462. theme->set_preferred_contrast(
  463. CalculatePreferredContrast());
  464. theme->NotifyOnNativeThemeUpdated();
  465. }];
  466. }
  467. if (configure_web_instance)
  468. ConfigureWebInstance();
  469. }
  470. NativeThemeMac::~NativeThemeMac() {
  471. [[NSNotificationCenter defaultCenter]
  472. removeObserver:high_contrast_notification_token_];
  473. }
  474. void NativeThemeMac::PaintSelectedMenuItem(cc::PaintCanvas* canvas,
  475. const ColorProvider* color_provider,
  476. const gfx::Rect& rect) const {
  477. DCHECK(color_provider);
  478. // Draw the background.
  479. cc::PaintFlags flags;
  480. flags.setColor(color_provider->GetColor(kColorMenuItemBackgroundSelected));
  481. canvas->drawRect(gfx::RectToSkRect(rect), flags);
  482. }
  483. void NativeThemeMac::InitializeDarkModeStateAndObserver() {
  484. __block auto theme = this;
  485. set_use_dark_colors(IsDarkMode());
  486. set_preferred_color_scheme(CalculatePreferredColorScheme());
  487. appearance_observer_.reset(
  488. [[NativeThemeEffectiveAppearanceObserver alloc] initWithHandler:^{
  489. theme->set_use_dark_colors(IsDarkMode());
  490. theme->set_preferred_color_scheme(CalculatePreferredColorScheme());
  491. theme->NotifyOnNativeThemeUpdated();
  492. }]);
  493. }
  494. void NativeThemeMac::ConfigureWebInstance() {
  495. // NativeThemeAura is used as web instance so we need to initialize its state.
  496. NativeTheme* web_instance = NativeTheme::GetInstanceForWeb();
  497. web_instance->set_use_dark_colors(IsDarkMode());
  498. web_instance->set_preferred_color_scheme(CalculatePreferredColorScheme());
  499. web_instance->set_preferred_contrast(CalculatePreferredContrast());
  500. // Add the web native theme as an observer to stay in sync with color scheme
  501. // changes.
  502. color_scheme_observer_ =
  503. std::make_unique<NativeTheme::ColorSchemeNativeThemeObserver>(
  504. NativeTheme::GetInstanceForWeb());
  505. AddObserver(color_scheme_observer_.get());
  506. // Observe caption style changes.
  507. CFNotificationCenterAddObserver(
  508. CFNotificationCenterGetLocalCenter(), this,
  509. CaptionSettingsChangedNotificationCallback,
  510. kMACaptionAppearanceSettingsChangedNotification, nullptr,
  511. CFNotificationSuspensionBehaviorDeliverImmediately);
  512. }
  513. NativeThemeMacWeb::NativeThemeMacWeb()
  514. : NativeThemeAura(IsOverlayScrollbarEnabled(), false) {}
  515. // static
  516. NativeThemeMacWeb* NativeThemeMacWeb::instance() {
  517. static base::NoDestructor<NativeThemeMacWeb> s_native_theme;
  518. return s_native_theme.get();
  519. }
  520. } // namespace ui