1 /* -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/ArrayUtils.h"
8 #include "mozilla/LookAndFeel.h"
11 #include "nsXPLookAndFeel.h"
12 #include "nsLookAndFeel.h"
13 #include "HeadlessLookAndFeel.h"
14 #include "RemoteLookAndFeel.h"
15 #include "nsContentUtils.h"
19 #include "nsIXULRuntime.h"
20 #include "nsLayoutUtils.h"
22 #include "SurfaceCacheUtils.h"
23 #include "mozilla/dom/ContentParent.h"
24 #include "mozilla/dom/ContentChild.h"
25 #include "mozilla/Preferences.h"
26 #include "mozilla/Services.h"
27 #include "mozilla/ServoStyleSet.h"
28 #include "mozilla/ServoCSSParser.h"
29 #include "mozilla/StaticPrefs_browser.h"
30 #include "mozilla/StaticPrefs_editor.h"
31 #include "mozilla/StaticPrefs_layout.h"
32 #include "mozilla/StaticPrefs_ui.h"
33 #include "mozilla/StaticPrefs_widget.h"
34 #include "mozilla/dom/Document.h"
35 #include "mozilla/PreferenceSheet.h"
36 #include "mozilla/gfx/2D.h"
37 #include "mozilla/widget/WidgetMessageUtils.h"
38 #include "mozilla/dom/KeyboardEventBinding.h"
39 #include "mozilla/RelativeLuminanceUtils.h"
40 #include "mozilla/Telemetry.h"
41 #include "mozilla/TelemetryScalarEnums.h"
42 #include "mozilla/Try.h"
44 #include "gfxPlatform.h"
51 using namespace mozilla
;
53 using IntID
= mozilla::LookAndFeel::IntID
;
54 using FloatID
= mozilla::LookAndFeel::FloatID
;
55 using ColorID
= mozilla::LookAndFeel::ColorID
;
56 using FontID
= mozilla::LookAndFeel::FontID
;
58 template <typename Index
, typename Value
, Index kEnd
>
59 class EnumeratedCache
{
60 mozilla::EnumeratedArray
<Index
, kEnd
, Value
> mEntries
;
61 std::bitset
<size_t(kEnd
)> mValidity
;
64 constexpr EnumeratedCache() = default;
66 bool IsValid(Index aIndex
) const { return mValidity
[size_t(aIndex
)]; }
68 const Value
* Get(Index aIndex
) const {
69 return IsValid(aIndex
) ? &mEntries
[aIndex
] : nullptr;
72 void Insert(Index aIndex
, Value aValue
) {
73 mValidity
[size_t(aIndex
)] = true;
74 mEntries
[aIndex
] = aValue
;
77 void Remove(Index aIndex
) {
78 mValidity
[size_t(aIndex
)] = false;
79 mEntries
[aIndex
] = Value();
84 for (auto& entry
: mEntries
) {
90 using ColorCache
= EnumeratedCache
<ColorID
, Maybe
<nscolor
>, ColorID::End
>;
93 using UseStandins
= LookAndFeel::UseStandins
;
95 ColorCache mCaches
[2][2];
97 constexpr ColorCaches() = default;
99 ColorCache
& Get(ColorScheme aScheme
, UseStandins aUseStandins
) {
100 return mCaches
[aScheme
== ColorScheme::Dark
]
101 [aUseStandins
== UseStandins::Yes
];
105 for (auto& c
: mCaches
) {
106 for (auto& cache
: c
) {
113 static ColorCaches sColorCaches
;
115 static EnumeratedCache
<FloatID
, Maybe
<float>, FloatID::End
> sFloatCache
;
116 static EnumeratedCache
<IntID
, Maybe
<int32_t>, IntID::End
> sIntCache
;
117 static EnumeratedCache
<FontID
, widget::LookAndFeelFont
, FontID::End
> sFontCache
;
119 // To make one of these prefs toggleable from a reftest add a user
120 // pref in testing/profiles/reftest/user.js. For example, to make
121 // ui.useAccessibilityTheme toggleable, add:
123 // user_pref("ui.useAccessibilityTheme", 0);
125 // This needs to be of the same length and in the same order as
126 // LookAndFeel::IntID values.
127 static const char sIntPrefs
[][45] = {
129 "ui.caretBlinkCount",
131 "ui.caretVisibleWithSelection",
132 "ui.selectTextfieldsOnKeyFocus",
134 "ui.menusCanOverlapOSBar",
135 "ui.useOverlayScrollbars",
136 "ui.allowOverlayScrollbarsOverlap",
137 "ui.skipNavigatingDisabledMenuItem",
140 "ui.useAccessibilityTheme",
141 "ui.scrollArrowStyle",
142 "ui.scrollButtonLeftMouseButtonAction",
143 "ui.scrollButtonMiddleMouseButtonAction",
144 "ui.scrollButtonRightMouseButtonAction",
147 "ui.treeLazyScrollDelay",
148 "ui.treeScrollDelay",
149 "ui.treeScrollLinesMax",
150 "accessibility.tabfocus", // Weird one...
151 "ui.chosenMenuItemsShouldBlink",
152 "ui.windowsAccentColorInTitlebar",
155 "ui.alertNotificationOrigin",
157 "ui.IMERawInputUnderlineStyle",
158 "ui.IMESelectedRawTextUnderlineStyle",
159 "ui.IMEConvertedTextUnderlineStyle",
160 "ui.IMESelectedConvertedTextUnderlineStyle",
161 "ui.SpellCheckerUnderlineStyle",
163 "ui.scrollbarButtonAutoRepeatBehavior",
165 "ui.swipeAnimationEnabled",
166 "ui.scrollbarDisplayOnMouseMove",
167 "ui.scrollbarFadeBeginDelay",
168 "ui.scrollbarFadeDuration",
169 "ui.contextMenuOffsetVertical",
170 "ui.contextMenuOffsetHorizontal",
171 "ui.GtkCSDAvailable",
172 "ui.GtkCSDMinimizeButton",
173 "ui.GtkCSDMaximizeButton",
174 "ui.GtkCSDCloseButton",
175 "ui.GtkCSDMinimizeButtonPosition",
176 "ui.GtkCSDMaximizeButtonPosition",
177 "ui.GtkCSDCloseButtonPosition",
178 "ui.GtkCSDReversedPlacement",
179 "ui.systemUsesDarkTheme",
180 "ui.prefersReducedMotion",
181 "ui.prefersReducedTransparency",
183 "ui.primaryPointerCapabilities",
184 "ui.allPointerCapabilities",
185 "ui.systemScrollbarSize",
186 "ui.touchDeviceSupportPresent",
189 "ui.videoDynamicRange",
190 "ui.panelAnimations",
191 "ui.hideCursorWhileTyping",
194 static_assert(ArrayLength(sIntPrefs
) == size_t(LookAndFeel::IntID::End
),
195 "Should have a pref for each int value");
197 // This array MUST be kept in the same order as the float id list in
200 static const char sFloatPrefs
[][37] = {
201 "ui.IMEUnderlineRelativeSize",
202 "ui.SpellCheckerUnderlineRelativeSize",
203 "ui.caretAspectRatio",
204 "ui.textScaleFactor",
209 static_assert(ArrayLength(sFloatPrefs
) == size_t(LookAndFeel::FloatID::End
),
210 "Should have a pref for each float value");
212 // This array MUST be kept in the same order as the color list in
213 // specified/color.rs
214 static const char sColorPrefs
[][41] = {
220 "ui.buttonhighlight",
226 "ui.-moz-disabledfield",
230 "ui.-moz-comboboxtext",
236 "ui.inactivecaption",
237 "ui.inactivecaptiontext",
243 "ui.threeddarkshadow",
245 "ui.threedhighlight",
246 "ui.threedlightshadow",
251 "ui.-moz-default-color",
252 "ui.-moz-default-background-color",
254 "ui.-moz-dialogtext",
255 "ui.-moz-cellhighlight",
256 "ui.-moz_cellhighlighttext",
258 "ui.selecteditemtext",
259 "ui.-moz-buttonhoverface",
260 "ui.-moz_buttonhovertext",
262 "ui.-moz_menuhoverdisabled",
263 "ui.-moz_menuhovertext",
264 "ui.-moz_menubarhovertext",
265 "ui.-moz_eventreerow",
266 "ui.-moz_oddtreerow",
267 "ui.-moz-buttonactivetext",
268 "ui.-moz-buttonactiveface",
269 "ui.-moz-buttondisabledface",
271 "ui.-moz-headerbartext",
272 "ui.-moz-headerbarinactive",
273 "ui.-moz-headerbarinactivetext",
274 "ui.-moz-mac-defaultbuttontext",
275 "ui.-moz-mac-focusring",
276 "ui.-moz_mac_disabledtoolbartext",
277 "ui.-moz-mac-menupopup",
278 "ui.-moz-mac-menuitem",
279 "ui.-moz-mac-active-menuitem",
280 "ui.-moz-mac-source-list",
281 "ui.-moz-mac-source-list-selection",
282 "ui.-moz-mac-active-source-list-selection",
283 "ui.-moz-mac-tooltip",
285 "ui.accentcolortext",
286 "ui.-moz-autofill-background",
287 "ui.-moz-nativehyperlinktext",
288 "ui.-moz-nativevisitedhyperlinktext",
289 "ui.-moz-hyperlinktext",
290 "ui.-moz-activehyperlinktext",
291 "ui.-moz-visitedhyperlinktext",
292 "ui.-moz-colheadertext",
293 "ui.-moz-colheaderhovertext",
294 "ui.textSelectDisabledBackground",
295 "ui.textSelectAttentionBackground",
296 "ui.textSelectAttentionForeground",
297 "ui.textHighlightBackground",
298 "ui.textHighlightForeground",
299 "ui.IMERawInputBackground",
300 "ui.IMERawInputForeground",
301 "ui.IMERawInputUnderline",
302 "ui.IMESelectedRawTextBackground",
303 "ui.IMESelectedRawTextForeground",
304 "ui.IMESelectedRawTextUnderline",
305 "ui.IMEConvertedTextBackground",
306 "ui.IMEConvertedTextForeground",
307 "ui.IMEConvertedTextUnderline",
308 "ui.IMESelectedConvertedTextBackground",
309 "ui.IMESelectedConvertedTextForeground",
310 "ui.IMESelectedConvertedTextUnderline",
311 "ui.SpellCheckerUnderline",
312 "ui.themedScrollbar",
313 "ui.themedScrollbarInactive",
314 "ui.themedScrollbarThumb",
315 "ui.themedScrollbarThumbHover",
316 "ui.themedScrollbarThumbActive",
317 "ui.themedScrollbarThumbInactive",
320 static_assert(ArrayLength(sColorPrefs
) == size_t(LookAndFeel::ColorID::End
),
321 "Should have a pref for each color value");
323 // This array MUST be kept in the same order as the SystemFont enum.
324 static const char sFontPrefs
[][41] = {
328 "ui.font.message-box",
329 "ui.font.small-caption",
330 "ui.font.status-bar",
331 "ui.font.-moz-pull-down-menu",
332 "ui.font.-moz-button",
334 "ui.font.-moz-field",
337 static_assert(ArrayLength(sFontPrefs
) == size_t(LookAndFeel::FontID::End
),
338 "Should have a pref for each font value");
340 const char* nsXPLookAndFeel::GetColorPrefName(ColorID aId
) {
341 return sColorPrefs
[size_t(aId
)];
344 bool nsXPLookAndFeel::sInitialized
= false;
346 nsXPLookAndFeel
* nsXPLookAndFeel::sInstance
= nullptr;
347 bool nsXPLookAndFeel::sShutdown
= false;
349 auto LookAndFeel::SystemZoomSettings() -> ZoomSettings
{
350 ZoomSettings settings
;
351 switch (StaticPrefs::browser_display_os_zoom_behavior()) {
356 settings
.mFullZoom
= GetTextScaleFactor();
359 settings
.mTextZoom
= GetTextScaleFactor();
366 nsXPLookAndFeel
* nsXPLookAndFeel::GetInstance() {
371 NS_ENSURE_TRUE(!sShutdown
, nullptr);
373 // If we're in a content process, then the parent process will have supplied
374 // us with an initial FullLookAndFeel object.
375 // We grab this data from the ContentChild,
376 // where it's been temporarily stashed, and initialize our new LookAndFeel
379 FullLookAndFeel
* lnf
= nullptr;
381 if (auto* cc
= mozilla::dom::ContentChild::GetSingleton()) {
382 lnf
= &cc
->BorrowLookAndFeelData();
386 sInstance
= new widget::RemoteLookAndFeel(std::move(*lnf
));
387 } else if (gfxPlatform::IsHeadless()) {
388 sInstance
= new widget::HeadlessLookAndFeel();
390 sInstance
= new nsLookAndFeel();
393 // This is only ever used once during initialization, and can be cleared now.
398 widget::Theme::Init();
403 void nsXPLookAndFeel::Shutdown() {
412 // This keeps strings alive, so need to clear to make leak checking happy.
415 widget::Theme::Shutdown();
418 static void IntPrefChanged(const nsACString
& aPref
) {
419 // Most Int prefs can't change our system colors or fonts, but
420 // ui.systemUsesDarkTheme can, since it affects the effective color-scheme
421 // (affecting system colors).
422 auto changeKind
= aPref
.EqualsLiteral("ui.systemUsesDarkTheme")
423 ? widget::ThemeChangeKind::Style
424 : widget::ThemeChangeKind::MediaQueriesOnly
;
425 LookAndFeel::NotifyChangedAllWindows(changeKind
);
428 static void FloatPrefChanged(const nsACString
& aPref
) {
429 // Most float prefs can't change our system colors or fonts, but
430 // textScaleFactor affects layout.
431 auto changeKind
= aPref
.EqualsLiteral("ui.textScaleFactor")
432 ? widget::ThemeChangeKind::StyleAndLayout
433 : widget::ThemeChangeKind::MediaQueriesOnly
;
434 LookAndFeel::NotifyChangedAllWindows(changeKind
);
437 static void ColorPrefChanged() {
438 // Color prefs affect style, because they by definition change system colors.
439 LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind::Style
);
442 static void FontPrefChanged() {
443 // Color prefs affect style, because they by definition change system fonts.
444 LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind::Style
);
448 void nsXPLookAndFeel::OnPrefChanged(const char* aPref
, void* aClosure
) {
449 nsDependentCString
prefName(aPref
);
450 for (const char* pref
: sIntPrefs
) {
451 if (prefName
.Equals(pref
)) {
452 IntPrefChanged(prefName
);
457 for (const char* pref
: sFloatPrefs
) {
458 if (prefName
.Equals(pref
)) {
459 FloatPrefChanged(prefName
);
464 for (const char* pref
: sColorPrefs
) {
465 // We use StringBeginsWith to handle .dark prefs too.
466 if (StringBeginsWith(prefName
, nsDependentCString(pref
))) {
472 for (const char* pref
: sFontPrefs
) {
473 if (StringBeginsWith(prefName
, nsDependentCString(pref
))) {
480 static constexpr struct {
481 nsLiteralCString mName
;
482 widget::ThemeChangeKind mChangeKind
=
483 widget::ThemeChangeKind::MediaQueriesOnly
;
484 } kMediaQueryPrefs
[] = {
485 // Affects whether standins are used for the accent color.
486 {"widget.non-native-theme.use-theme-accent"_ns
,
487 widget::ThemeChangeKind::Style
},
488 // These three affect system colors on Windows.
489 {"widget.windows.uwp-system-colors.enabled"_ns
,
490 widget::ThemeChangeKind::Style
},
491 {"widget.windows.uwp-system-colors.highlight-accent"_ns
,
492 widget::ThemeChangeKind::Style
},
494 {"layout.css.prefers-color-scheme.content-override"_ns
,
495 widget::ThemeChangeKind::Style
},
496 // Affects media queries and scrollbar sizes, so gotta relayout.
497 {"widget.gtk.overlay-scrollbars.enabled"_ns
,
498 widget::ThemeChangeKind::StyleAndLayout
},
499 // Affects zoom settings which includes text and full zoom.
500 {"browser.display.os-zoom-behavior"_ns
,
501 widget::ThemeChangeKind::StyleAndLayout
},
502 // This affects not only the media query, but also the native theme, so we
503 // need to re-layout.
504 {"browser.theme.toolbar-theme"_ns
, widget::ThemeChangeKind::AllBits
},
505 {"browser.theme.content-theme"_ns
},
508 // Read values from the user's preferences.
509 // This is done once at startup, but since the user's preferences
510 // haven't actually been read yet at that time, we also have to
511 // set a callback to inform us of changes to each pref.
512 void nsXPLookAndFeel::Init() {
513 MOZ_RELEASE_ASSERT(NS_IsMainThread());
515 // Say we're already initialized, and take the chance that it might fail;
516 // protects against some other process writing to our static variables.
519 RecomputeColorSchemes();
521 if (XRE_IsParentProcess()) {
522 nsLayoutUtils::RecomputeSmoothScrollDefault();
525 // XXX If we could reorganize the pref names, we should separate the branch
526 // for each types. Then, we could reduce the unnecessary loop from
527 // nsXPLookAndFeel::OnPrefChanged().
528 Preferences::RegisterPrefixCallback(OnPrefChanged
, "ui.");
529 // We really do just want the accessibility.tabfocus pref, not other prefs
530 // that start with that string.
531 Preferences::RegisterCallback(OnPrefChanged
, "accessibility.tabfocus");
533 for (const auto& pref
: kMediaQueryPrefs
) {
534 Preferences::RegisterCallback(
535 [](const char*, void* aChangeKind
) {
537 widget::ThemeChangeKind(reinterpret_cast<uintptr_t>(aChangeKind
));
538 LookAndFeel::NotifyChangedAllWindows(changeKind
);
540 pref
.mName
, reinterpret_cast<void*>(uintptr_t(pref
.mChangeKind
)));
544 nsXPLookAndFeel::~nsXPLookAndFeel() {
545 NS_ASSERTION(sInstance
== this,
546 "This destroying instance isn't the singleton instance");
550 static bool IsSpecialColor(LookAndFeel::ColorID aID
, nscolor aColor
) {
551 using ColorID
= LookAndFeel::ColorID
;
553 if (aColor
== NS_SAME_AS_FOREGROUND_COLOR
) {
558 case ColorID::IMESelectedRawTextBackground
:
559 case ColorID::IMESelectedConvertedTextBackground
:
560 case ColorID::IMERawInputBackground
:
561 case ColorID::IMEConvertedTextBackground
:
562 case ColorID::IMESelectedRawTextForeground
:
563 case ColorID::IMESelectedConvertedTextForeground
:
564 case ColorID::IMERawInputForeground
:
565 case ColorID::IMEConvertedTextForeground
:
566 case ColorID::IMERawInputUnderline
:
567 case ColorID::IMEConvertedTextUnderline
:
568 case ColorID::IMESelectedRawTextUnderline
:
569 case ColorID::IMESelectedConvertedTextUnderline
:
570 case ColorID::SpellCheckerUnderline
:
571 return NS_IS_SELECTION_SPECIAL_COLOR(aColor
);
576 * In GetColor(), every color that is not a special color is color
577 * corrected. Use false to make other colors color corrected.
582 nscolor
nsXPLookAndFeel::GetStandinForNativeColor(ColorID aID
,
583 ColorScheme aScheme
) {
584 if (aScheme
== ColorScheme::Dark
) {
585 if (auto color
= GenericDarkColor(aID
)) {
590 // The stand-in colors are taken from what the non-native theme needs (for
591 // field/button colors), the Windows 7 Aero theme except Mac-specific colors
592 // which are taken from Mac OS 10.7.
594 #define COLOR(name_, r, g, b) \
595 case ColorID::name_: \
596 return NS_RGB(r, g, b);
598 #define COLORA(name_, r, g, b, a) \
599 case ColorID::name_: \
600 return NS_RGBA(r, g, b, a);
603 // These are here for the purposes of headless mode.
604 case ColorID::IMESelectedRawTextBackground
:
605 case ColorID::IMESelectedConvertedTextBackground
:
606 case ColorID::IMERawInputBackground
:
607 case ColorID::IMEConvertedTextBackground
:
608 return NS_TRANSPARENT
;
609 case ColorID::IMESelectedRawTextForeground
:
610 case ColorID::IMESelectedConvertedTextForeground
:
611 case ColorID::IMERawInputForeground
:
612 case ColorID::IMEConvertedTextForeground
:
613 return NS_SAME_AS_FOREGROUND_COLOR
;
614 case ColorID::IMERawInputUnderline
:
615 case ColorID::IMEConvertedTextUnderline
:
616 return NS_40PERCENT_FOREGROUND_COLOR
;
617 case ColorID::Accentcolor
:
618 return widget::sDefaultAccent
.ToABGR();
619 case ColorID::Accentcolortext
:
620 return widget::sDefaultAccentText
.ToABGR();
621 COLOR(SpellCheckerUnderline
, 0xff, 0x00, 0x00)
622 COLOR(TextSelectDisabledBackground
, 0xaa, 0xaa, 0xaa)
625 COLOR(Activeborder
, 0xB4, 0xB4, 0xB4)
626 COLOR(Inactiveborder
, 0xB4, 0xB4, 0xB4)
627 COLOR(Activecaption
, 0xF0, 0xF0, 0xF4)
628 COLOR(Inactivecaption
, 0xF0, 0xF0, 0xF4)
629 COLOR(Captiontext
, 0x00, 0x00, 0x00)
630 COLOR(Inactivecaptiontext
, 0x00, 0x00, 0x00)
633 COLOR(Appworkspace
, 0xAB, 0xAB, 0xAB)
634 COLOR(Background
, 0x00, 0x00, 0x00)
635 COLOR(Buttonhighlight
, 0xFF, 0xFF, 0xFF)
636 COLOR(Buttonshadow
, 0xA0, 0xA0, 0xA0)
638 // Buttons and comboboxes should be kept in sync since they are drawn with
639 // the same colors by the non-native theme.
640 COLOR(Buttonface
, 0xe9, 0xe9, 0xed)
641 COLORA(MozButtondisabledface
, 0xe9, 0xe9, 0xed, 128)
643 COLOR(MozCombobox
, 0xe9, 0xe9, 0xed)
645 COLOR(Buttontext
, 0x00, 0x00, 0x00)
646 COLOR(MozComboboxtext
, 0x00, 0x00, 0x00)
648 COLOR(Graytext
, 0x6D, 0x6D, 0x6D)
649 COLOR(Highlight
, 0x33, 0x99, 0xFF)
650 COLOR(Highlighttext
, 0xFF, 0xFF, 0xFF)
651 COLOR(Infobackground
, 0xFF, 0xFF, 0xE1)
652 COLOR(Infotext
, 0x00, 0x00, 0x00)
653 COLOR(Menu
, 0xF0, 0xF0, 0xF0)
654 COLOR(Menutext
, 0x00, 0x00, 0x00)
655 COLOR(Scrollbar
, 0xC8, 0xC8, 0xC8)
656 COLOR(Threeddarkshadow
, 0x69, 0x69, 0x69)
657 COLOR(Threedface
, 0xF0, 0xF0, 0xF0)
658 COLOR(Threedhighlight
, 0xFF, 0xFF, 0xFF)
659 COLOR(Threedlightshadow
, 0xE3, 0xE3, 0xE3)
660 COLOR(Threedshadow
, 0xA0, 0xA0, 0xA0)
661 COLOR(Buttonborder
, 0xE3, 0xE3, 0xE3)
662 COLOR(Mark
, 0xFF, 0xFF, 0x00)
663 COLOR(Marktext
, 0x00, 0x00, 0x00)
664 COLOR(Window
, 0xFF, 0xFF, 0xFF)
665 COLOR(Windowframe
, 0x64, 0x64, 0x64)
666 COLOR(Windowtext
, 0x00, 0x00, 0x00)
667 COLOR(Field
, 0xFF, 0xFF, 0xFF)
668 COLORA(MozDisabledfield
, 0xFF, 0xFF, 0xFF, 128)
669 COLOR(Fieldtext
, 0x00, 0x00, 0x00)
670 COLOR(MozDialog
, 0xF0, 0xF0, 0xF0)
671 COLOR(MozDialogtext
, 0x00, 0x00, 0x00)
672 COLOR(MozColheadertext
, 0x00, 0x00, 0x00)
673 COLOR(MozColheaderhovertext
, 0x00, 0x00, 0x00)
674 COLOR(MozCellhighlight
, 0xF0, 0xF0, 0xF0)
675 COLOR(MozCellhighlighttext
, 0x00, 0x00, 0x00)
676 COLOR(Selecteditem
, 0x33, 0x99, 0xFF)
677 COLOR(Selecteditemtext
, 0xFF, 0xFF, 0xFF)
678 COLOR(MozButtonhoverface
, 0xd0, 0xd0, 0xd7)
679 COLOR(MozButtonhovertext
, 0x00, 0x00, 0x00)
680 COLOR(MozButtonactiveface
, 0xb1, 0xb1, 0xb9)
681 COLOR(MozButtonactivetext
, 0x00, 0x00, 0x00)
682 COLOR(MozMenuhover
, 0x33, 0x99, 0xFF)
683 COLOR(MozMenuhovertext
, 0x00, 0x00, 0x00)
684 COLOR(MozMenubarhovertext
, 0x00, 0x00, 0x00)
685 COLOR(MozMenuhoverdisabled
, 0xF0, 0xF0, 0xF0)
686 COLOR(MozEventreerow
, 0xFF, 0xFF, 0xFF)
687 COLOR(MozOddtreerow
, 0xFF, 0xFF, 0xFF)
688 COLOR(MozMacFocusring
, 0x60, 0x9D, 0xD7)
689 COLOR(MozMacDisabledtoolbartext
, 0x3F, 0x3F, 0x3F)
690 COLOR(MozMacMenupopup
, 0xe6, 0xe6, 0xe6)
691 COLOR(MozMacMenuitem
, 0xe6, 0xe6, 0xe6)
692 COLOR(MozMacActiveMenuitem
, 0x0a, 0x64, 0xdc)
693 COLOR(MozMacSourceList
, 0xf7, 0xf7, 0xf7)
694 COLOR(MozMacSourceListSelection
, 0xc8, 0xc8, 0xc8)
695 COLOR(MozMacActiveSourceListSelection
, 0x0a, 0x64, 0xdc)
696 COLOR(MozMacTooltip
, 0xf7, 0xf7, 0xf7)
697 // Seems to be the default color (hardcoded because of bug 1065998)
698 COLOR(MozNativehyperlinktext
, 0x00, 0x66, 0xCC)
699 COLOR(MozNativevisitedhyperlinktext
, 0x55, 0x1A, 0x8B)
703 return NS_RGB(0xFF, 0xFF, 0xFF);
709 // Taken from in-content/common.inc.css's dark theme.
710 Maybe
<nscolor
> nsXPLookAndFeel::GenericDarkColor(ColorID aID
) {
711 nscolor color
= NS_RGB(0, 0, 0);
712 static constexpr nscolor kWindowBackground
= NS_RGB(28, 27, 34);
713 static constexpr nscolor kWindowText
= NS_RGB(251, 251, 254);
715 case ColorID::Window
: // --in-content-page-background
716 case ColorID::Background
:
717 color
= kWindowBackground
;
721 color
= NS_RGB(0x2b, 0x2a, 0x33);
724 case ColorID::MozMenuhovertext
:
725 case ColorID::MozMenubarhovertext
:
726 case ColorID::Menutext
:
727 color
= NS_RGB(0xfb, 0xfb, 0xfe);
730 case ColorID::MozMenuhover
:
731 color
= NS_RGB(0x52, 0x52, 0x5e);
734 case ColorID::MozMenuhoverdisabled
:
735 color
= NS_RGB(0x3a, 0x39, 0x44);
738 case ColorID::MozOddtreerow
:
739 case ColorID::MozDialog
: // --in-content-box-background
740 color
= NS_RGB(35, 34, 43);
742 case ColorID::Windowtext
: // --in-content-page-color
743 case ColorID::MozDialogtext
:
744 case ColorID::Fieldtext
:
745 case ColorID::Buttontext
: // --in-content-button-text-color (via
746 // --in-content-page-color)
747 case ColorID::MozComboboxtext
:
748 case ColorID::MozButtonhovertext
:
749 case ColorID::MozButtonactivetext
:
750 case ColorID::MozHeaderbartext
:
751 case ColorID::MozHeaderbarinactivetext
:
752 case ColorID::Captiontext
:
753 case ColorID::Inactivecaptiontext
: // TODO(emilio): Maybe make
754 // Inactivecaptiontext Graytext?
757 case ColorID::Buttonshadow
:
758 case ColorID::Threedshadow
:
759 case ColorID::Threedlightshadow
:
760 case ColorID::Buttonborder
: // --in-content-box-border-color computed
761 // with kWindowText above
762 // kWindowBackground.
763 case ColorID::Graytext
: // opacity: 0.4 of kWindowText blended over the
764 // "Window" background color, which happens to be
766 color
= NS_ComposeColors(kWindowBackground
, NS_RGBA(251, 251, 254, 102));
768 case ColorID::MozCellhighlight
:
769 case ColorID::Selecteditem
: // --in-content-primary-button-background /
770 // --in-content-item-selected
771 color
= NS_RGB(0, 221, 255);
774 case ColorID::Buttonface
: // --in-content-button-background
775 case ColorID::Threedface
:
776 case ColorID::MozCombobox
:
777 case ColorID::MozCellhighlighttext
:
778 case ColorID::Selecteditemtext
: // --in-content-primary-button-text-color /
779 // --in-content-item-selected-text
780 color
= NS_RGB(43, 42, 51);
782 case ColorID::Threeddarkshadow
: // Same as Threedlightshadow but with the
784 case ColorID::MozDisabledfield
: // opacity: 0.4 of the face above blended
785 // over the "Window" background color.
786 case ColorID::MozButtondisabledface
:
787 color
= NS_ComposeColors(kWindowBackground
, NS_RGBA(43, 42, 51, 102));
789 case ColorID::MozButtonhoverface
: // --in-content-button-background-hover
790 color
= NS_RGB(82, 82, 94);
792 case ColorID::MozButtonactiveface
: // --in-content-button-background-active
793 color
= NS_RGB(91, 91, 102);
795 case ColorID::Highlight
:
796 color
= NS_RGBA(0, 221, 255, 78);
798 case ColorID::Highlighttext
:
799 color
= NS_SAME_AS_FOREGROUND_COLOR
;
801 case ColorID::MozNativehyperlinktext
:
802 // If you change this color, you probably also want to change the default
803 // value of browser.anchor_color.dark.
804 color
= NS_RGB(0x8c, 0x8c, 0xff);
806 case ColorID::MozNativevisitedhyperlinktext
:
807 // If you change this color, you probably also want to change the default
808 // value of browser.visited_color.dark.
809 color
= NS_RGB(0xff, 0xad, 0xff);
811 case ColorID::SpellCheckerUnderline
:
812 // This is the default for active links in dark mode as well
813 // (browser.active_color.dark). See bug 1755564 for some analysis and
814 // other options too.
815 color
= NS_RGB(0xff, 0x66, 0x66);
817 case ColorID::Activeborder
:
818 case ColorID::Inactiveborder
:
819 color
= NS_RGB(57, 57, 57);
821 case ColorID::MozHeaderbar
:
822 case ColorID::MozHeaderbarinactive
:
823 case ColorID::Activecaption
:
824 case ColorID::Inactivecaption
:
825 color
= NS_RGB(28, 27, 34);
833 // Uncomment the #define below if you want to debug system color use in a skin
834 // that uses them. When set, it will make all system color pairs that are
835 // appropriate for foreground/background pairing the same. This means if the
836 // skin is using system colors correctly you will not be able to see *any* text.
838 // #define DEBUG_SYSTEM_COLOR_USE
840 #ifdef DEBUG_SYSTEM_COLOR_USE
841 static nsresult
SystemColorUseDebuggingColor(LookAndFeel::ColorID aID
,
843 using ColorID
= LookAndFeel::ColorID
;
846 // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
847 case ColorID::Activecaption
:
848 // active window caption background
849 case ColorID::Captiontext
:
850 // text in active window caption
851 aResult
= NS_RGB(0xff, 0x00, 0x00);
854 case ColorID::Highlight
:
855 // background of selected item
856 case ColorID::Highlighttext
:
857 // text of selected item
858 aResult
= NS_RGB(0xff, 0xff, 0x00);
861 case ColorID::Inactivecaption
:
862 // inactive window caption
863 case ColorID::Inactivecaptiontext
:
864 // text in inactive window caption
865 aResult
= NS_RGB(0x66, 0x66, 0x00);
868 case ColorID::Infobackground
:
869 // tooltip background color
870 case ColorID::Infotext
:
871 // tooltip text color
872 aResult
= NS_RGB(0x00, 0xff, 0x00);
877 case ColorID::Menutext
:
879 aResult
= NS_RGB(0x00, 0xff, 0xff);
882 case ColorID::Threedface
:
883 case ColorID::Buttonface
:
885 case ColorID::Buttontext
:
886 // text on push buttons
887 aResult
= NS_RGB(0x00, 0x66, 0x66);
890 case ColorID::Window
:
891 case ColorID::Windowtext
:
892 aResult
= NS_RGB(0x00, 0x00, 0xff);
895 // from the CSS3 working draft (not yet finalized)
896 // http://www.w3.org/tr/2000/wd-css3-userint-20000216.html#color
899 case ColorID::Fieldtext
:
900 aResult
= NS_RGB(0xff, 0x00, 0xff);
903 case ColorID::MozDialog
:
904 case ColorID::MozDialogtext
:
905 aResult
= NS_RGB(0x66, 0x00, 0x66);
909 return NS_ERROR_NOT_AVAILABLE
;
916 static nsresult
GetPrefColor(const char* aPref
, nscolor
& aResult
) {
917 nsAutoCString colorStr
;
918 MOZ_TRY(Preferences::GetCString(aPref
, colorStr
));
919 if (!ServoCSSParser::ComputeColor(nullptr, NS_RGB(0, 0, 0), colorStr
,
921 return NS_ERROR_FAILURE
;
926 static nsresult
GetColorFromPref(LookAndFeel::ColorID aID
, ColorScheme aScheme
,
928 const char* prefName
= sColorPrefs
[size_t(aID
)];
929 if (aScheme
== ColorScheme::Dark
) {
930 nsAutoCString
darkPrefName(prefName
);
931 darkPrefName
.Append(".dark");
932 if (NS_SUCCEEDED(GetPrefColor(darkPrefName
.get(), aResult
))) {
936 return GetPrefColor(prefName
, aResult
);
939 // All these routines will return NS_OK if they have a value,
940 // in which case the nsLookAndFeel should use that value;
941 // otherwise we'll return NS_ERROR_NOT_AVAILABLE, in which case, the
942 // platform-specific nsLookAndFeel should use its own values instead.
943 nsresult
nsXPLookAndFeel::GetColorValue(ColorID aID
, ColorScheme aScheme
,
944 UseStandins aUseStandins
,
950 #ifdef DEBUG_SYSTEM_COLOR_USE
951 if (NS_SUCCEEDED(SystemColorUseDebuggingColor(aID
, aResult
))) {
956 auto& cache
= sColorCaches
.Get(aScheme
, aUseStandins
);
957 if (const auto* cached
= cache
.Get(aID
)) {
958 if (cached
->isNothing()) {
959 return NS_ERROR_FAILURE
;
961 aResult
= cached
->value();
965 // NOTE: Servo holds a lock and the main thread is paused, so writing to the
966 // global cache here is fine.
967 auto result
= GetUncachedColor(aID
, aScheme
, aUseStandins
);
968 cache
.Insert(aID
, result
);
970 return NS_ERROR_FAILURE
;
976 Maybe
<nscolor
> nsXPLookAndFeel::GetUncachedColor(ColorID aID
,
978 UseStandins aUseStandins
) {
979 if (aUseStandins
== UseStandins::Yes
) {
980 return Some(GetStandinForNativeColor(aID
, aScheme
));
983 if (NS_SUCCEEDED(GetColorFromPref(aID
, aScheme
, r
))) {
986 if (NS_SUCCEEDED(NativeGetColor(aID
, aScheme
, r
))) {
987 if (gfxPlatform::GetCMSMode() == CMSMode::All
&& !IsSpecialColor(aID
, r
)) {
988 qcms_transform
* transform
= gfxPlatform::GetCMSInverseRGBTransform();
991 color
[0] = NS_GET_R(r
);
992 color
[1] = NS_GET_G(r
);
993 color
[2] = NS_GET_B(r
);
994 color
[3] = NS_GET_A(r
);
995 qcms_transform_data(transform
, color
, color
, 1);
996 r
= NS_RGBA(color
[0], color
[1], color
[2], color
[3]);
1005 nsresult
nsXPLookAndFeel::GetIntValue(IntID aID
, int32_t& aResult
) {
1006 if (!sInitialized
) {
1010 if (const auto* cached
= sIntCache
.Get(aID
)) {
1011 if (cached
->isNothing()) {
1012 return NS_ERROR_FAILURE
;
1014 aResult
= cached
->value();
1018 if (NS_SUCCEEDED(Preferences::GetInt(sIntPrefs
[size_t(aID
)], &aResult
))) {
1019 sIntCache
.Insert(aID
, Some(aResult
));
1023 if (NS_FAILED(NativeGetInt(aID
, aResult
))) {
1024 sIntCache
.Insert(aID
, Nothing());
1025 return NS_ERROR_FAILURE
;
1028 sIntCache
.Insert(aID
, Some(aResult
));
1032 nsresult
nsXPLookAndFeel::GetFloatValue(FloatID aID
, float& aResult
) {
1033 if (!sInitialized
) {
1037 if (const auto* cached
= sFloatCache
.Get(aID
)) {
1038 if (cached
->isNothing()) {
1039 return NS_ERROR_FAILURE
;
1041 aResult
= cached
->value();
1046 if (NS_SUCCEEDED(Preferences::GetInt(sFloatPrefs
[size_t(aID
)], &pref
))) {
1047 aResult
= float(pref
) / 100.0f
;
1048 sFloatCache
.Insert(aID
, Some(aResult
));
1052 if (NS_FAILED(NativeGetFloat(aID
, aResult
))) {
1053 sFloatCache
.Insert(aID
, Nothing());
1054 return NS_ERROR_FAILURE
;
1057 sFloatCache
.Insert(aID
, Some(aResult
));
1061 bool nsXPLookAndFeel::LookAndFeelFontToStyle(const LookAndFeelFont
& aFont
,
1063 gfxFontStyle
& aStyle
) {
1064 if (!aFont
.haveFont()) {
1067 aName
= aFont
.name();
1068 aStyle
= gfxFontStyle();
1069 aStyle
.size
= aFont
.size();
1070 aStyle
.weight
= FontWeight::FromInt(aFont
.weight());
1072 aFont
.italic() ? FontSlantStyle::ITALIC
: FontSlantStyle::NORMAL
;
1073 aStyle
.systemFont
= true;
1077 widget::LookAndFeelFont
nsXPLookAndFeel::StyleToLookAndFeelFont(
1078 const nsAString
& aName
, const gfxFontStyle
& aStyle
) {
1079 LookAndFeelFont font
;
1080 font
.haveFont() = true;
1081 font
.name() = aName
;
1082 font
.size() = aStyle
.size
;
1083 font
.weight() = aStyle
.weight
.ToFloat();
1084 font
.italic() = aStyle
.style
.IsItalic();
1085 MOZ_ASSERT(aStyle
.style
.IsNormal() || aStyle
.style
.IsItalic(),
1086 "Cannot handle oblique font style");
1089 // Assert that all the remaining font style properties have their
1091 gfxFontStyle candidate
= aStyle
;
1092 gfxFontStyle defaults
{};
1093 candidate
.size
= defaults
.size
;
1094 candidate
.weight
= defaults
.weight
;
1095 candidate
.style
= defaults
.style
;
1096 MOZ_ASSERT(candidate
.Equals(defaults
),
1097 "Some font style properties not supported");
1103 bool nsXPLookAndFeel::GetFontValue(FontID aID
, nsString
& aName
,
1104 gfxFontStyle
& aStyle
) {
1105 if (const LookAndFeelFont
* cached
= sFontCache
.Get(aID
)) {
1106 return LookAndFeelFontToStyle(*cached
, aName
, aStyle
);
1109 LookAndFeelFont font
;
1110 auto GetFontsFromPrefs
= [&]() -> bool {
1111 nsDependentCString
pref(sFontPrefs
[size_t(aID
)]);
1112 if (NS_FAILED(Preferences::GetString(pref
.get(), aName
))) {
1115 font
.haveFont() = true;
1116 font
.name() = aName
;
1117 font
.size() = Preferences::GetFloat(nsAutoCString(pref
+ ".size"_ns
).get());
1118 // This is written this way rather than using the fallback so that an empty
1119 // pref (such like the one about:config creates) doesn't cause system fonts
1120 // to have zero-size.
1121 if (font
.size() < 1.0f
) {
1122 font
.size() = StyleFONT_MEDIUM_PX
;
1124 font
.weight() = Preferences::GetFloat(
1125 nsAutoCString(pref
+ ".weight"_ns
).get(), FontWeight::NORMAL
.ToFloat());
1127 Preferences::GetBool(nsAutoCString(pref
+ ".italic"_ns
).get());
1131 if (GetFontsFromPrefs()) {
1132 LookAndFeelFontToStyle(font
, aName
, aStyle
);
1133 } else if (NativeGetFont(aID
, aName
, aStyle
)) {
1134 font
= StyleToLookAndFeelFont(aName
, aStyle
);
1136 MOZ_ASSERT(!font
.haveFont());
1138 bool success
= font
.haveFont();
1139 sFontCache
.Insert(aID
, std::move(font
));
1143 void nsXPLookAndFeel::RefreshImpl() {
1144 // Wipe out our caches.
1145 sColorCaches
.Clear();
1147 sFloatCache
.Clear();
1149 RecomputeColorSchemes();
1151 if (XRE_IsParentProcess()) {
1152 nsLayoutUtils::RecomputeSmoothScrollDefault();
1153 // Clear any cached FullLookAndFeel data, which is now invalid.
1154 widget::RemoteLookAndFeel::ClearCachedData();
1158 static bool sRecordedLookAndFeelTelemetry
= false;
1160 void nsXPLookAndFeel::RecordTelemetry() {
1161 if (!XRE_IsParentProcess()) {
1165 if (sRecordedLookAndFeelTelemetry
) {
1169 sRecordedLookAndFeelTelemetry
= true;
1172 Telemetry::ScalarSet(
1173 Telemetry::ScalarID::WIDGET_DARK_MODE
,
1174 NS_SUCCEEDED(GetIntValue(IntID::SystemUsesDarkTheme
, i
)) && i
!= 0);
1176 RecordLookAndFeelSpecificTelemetry();
1181 static widget::ThemeChangeKind sGlobalThemeChangeKind
{0};
1183 void LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind aKind
) {
1184 sGlobalThemeChanged
= true;
1185 sGlobalThemeChangeKind
|= aKind
;
1187 if (nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService()) {
1188 const char16_t kind
[] = {char16_t(aKind
), 0};
1189 obs
->NotifyObservers(nullptr, "internal-look-and-feel-changed", kind
);
1193 void LookAndFeel::DoHandleGlobalThemeChange() {
1194 MOZ_ASSERT(sGlobalThemeChanged
);
1195 sGlobalThemeChanged
= false;
1196 auto kind
= std::exchange(sGlobalThemeChangeKind
, widget::ThemeChangeKind(0));
1198 // Tell the theme that it changed, so it can flush any handles to stale theme
1201 // We can use the *DoNotUseDirectly functions directly here, because we want
1202 // to notify all possible themes in a given process (but just once).
1203 if (XRE_IsParentProcess() ||
1204 !StaticPrefs::widget_non_native_theme_enabled()) {
1205 if (nsCOMPtr
<nsITheme
> theme
= do_GetNativeThemeDoNotUseDirectly()) {
1206 theme
->ThemeChanged();
1209 if (nsCOMPtr
<nsITheme
> theme
= do_GetBasicNativeThemeDoNotUseDirectly()) {
1210 theme
->ThemeChanged();
1213 // Clear all cached LookAndFeel colors.
1214 LookAndFeel::Refresh();
1216 // Reset default background and foreground colors for the document since they
1217 // may be using system colors.
1218 PreferenceSheet::Refresh();
1220 // Vector images (SVG) may be using theme colors so we discard all cached
1221 // surfaces. (We could add a vector image only version of DiscardAll, but
1222 // in bug 940625 we decided theme changes are rare enough not to bother.)
1223 image::SurfaceCacheUtils::DiscardAll();
1225 if (XRE_IsParentProcess()) {
1226 dom::ContentParent::BroadcastThemeUpdate(kind
);
1229 nsContentUtils::AddScriptRunner(
1230 NS_NewRunnableFunction("HandleGlobalThemeChange", [] {
1231 if (nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService()) {
1232 obs
->NotifyObservers(nullptr, "look-and-feel-changed", nullptr);
1237 #define BIT_FOR(_c) (1ull << size_t(ColorID::_c))
1239 // We want to use a non-native color scheme for the non-native theme (except in
1240 // high-contrast mode), so spoof some of the colors with stand-ins to prevent
1241 // lack of contrast.
1242 static constexpr std::bitset
<size_t(ColorID::End
)> sNonNativeThemeStandinColors
{
1243 // Used by default button styles.
1244 BIT_FOR(Buttonface
) | BIT_FOR(Buttontext
) | BIT_FOR(MozButtonhoverface
) |
1245 BIT_FOR(MozButtonhovertext
) | BIT_FOR(MozButtonactiveface
) |
1246 BIT_FOR(MozButtonactivetext
) | BIT_FOR(MozButtondisabledface
) |
1247 BIT_FOR(Buttonborder
) |
1248 // Used by select elements.
1249 BIT_FOR(MozCombobox
) | BIT_FOR(MozComboboxtext
) |
1250 BIT_FOR(Threedlightshadow
) |
1251 // For symmetry with the above.
1252 BIT_FOR(Threeddarkshadow
) |
1253 // Used by fieldset borders.
1254 BIT_FOR(Threedface
) |
1255 // Used by input / textarea.
1256 BIT_FOR(Field
) | BIT_FOR(Fieldtext
) |
1257 // Used by disabled form controls.
1258 BIT_FOR(MozDisabledfield
) | BIT_FOR(Graytext
) |
1259 // Some pages expect these to return windows-like colors, see bug 1773795.
1260 // Also, per spec these should match Canvas/CanvasText, see
1261 // https://drafts.csswg.org/css-color-4/#window
1262 BIT_FOR(Window
) | BIT_FOR(Windowtext
)};
1265 static bool ShouldUseStandinsForNativeColorForNonNativeTheme(
1266 const dom::Document
& aDoc
, LookAndFeel::ColorID aColor
,
1267 const PreferenceSheet::Prefs
& aPrefs
) {
1268 const bool shouldUseStandinsForColor
= [&] {
1269 if (sNonNativeThemeStandinColors
[size_t(aColor
)]) {
1272 // There are platforms where we want the content-exposed accent color to be
1273 // the windows blue rather than the system accent color, for now.
1274 return !StaticPrefs::widget_non_native_theme_use_theme_accent() &&
1275 (aColor
== LookAndFeel::ColorID::Accentcolor
||
1276 aColor
== LookAndFeel::ColorID::Accentcolortext
);
1279 return shouldUseStandinsForColor
&& aDoc
.ShouldAvoidNativeTheme() &&
1280 !aPrefs
.NonNativeThemeShouldBeHighContrast();
1283 ColorScheme
LookAndFeel::sChromeColorScheme
;
1284 ColorScheme
LookAndFeel::sContentColorScheme
;
1285 bool LookAndFeel::sColorSchemeInitialized
;
1286 bool LookAndFeel::sGlobalThemeChanged
;
1288 bool LookAndFeel::IsDarkColor(nscolor aColor
) {
1289 // Given https://www.w3.org/TR/WCAG20/#contrast-ratiodef, this is the
1290 // threshold that tells us whether contrast is better against white or black.
1292 // Contrast ratio against black is: (L + 0.05) / 0.05
1293 // Contrast ratio against white is: 1.05 / (L + 0.05)
1295 // So the intersection is:
1297 // (L + 0.05) / 0.05 = 1.05 / (L + 0.05)
1299 // And the solution to that equation is:
1301 // sqrt(1.05 * 0.05) - 0.05
1303 // So we consider a color dark if the contrast is below this threshold, and
1304 // it's at least half-opaque.
1305 constexpr float kThreshold
= 0.179129;
1306 return NS_GET_A(aColor
) > 127 &&
1307 RelativeLuminanceUtils::Compute(aColor
) < kThreshold
;
1310 auto LookAndFeel::ColorSchemeSettingForChrome() -> ChromeColorSchemeSetting
{
1311 switch (StaticPrefs::browser_theme_toolbar_theme()) {
1313 return ChromeColorSchemeSetting::Dark
;
1315 return ChromeColorSchemeSetting::Light
;
1317 return ChromeColorSchemeSetting::System
;
1321 ColorScheme
LookAndFeel::ThemeDerivedColorSchemeForContent() {
1322 switch (StaticPrefs::browser_theme_content_theme()) {
1324 return ColorScheme::Dark
;
1326 return ColorScheme::Light
;
1328 return SystemColorScheme();
1332 void LookAndFeel::RecomputeColorSchemes() {
1333 sColorSchemeInitialized
= true;
1335 sChromeColorScheme
= [] {
1336 switch (ColorSchemeSettingForChrome()) {
1337 case ChromeColorSchemeSetting::Light
:
1338 return ColorScheme::Light
;
1339 case ChromeColorSchemeSetting::Dark
:
1340 return ColorScheme::Dark
;
1341 case ChromeColorSchemeSetting::System
:
1344 return SystemColorScheme();
1347 sContentColorScheme
= [] {
1348 switch (StaticPrefs::layout_css_prefers_color_scheme_content_override()) {
1350 return ColorScheme::Dark
;
1352 return ColorScheme::Light
;
1354 return ThemeDerivedColorSchemeForContent();
1359 ColorScheme
LookAndFeel::ColorSchemeForStyle(
1360 const dom::Document
& aDoc
, const StyleColorSchemeFlags
& aFlags
,
1361 ColorSchemeMode aMode
) {
1362 using Choice
= PreferenceSheet::Prefs::ColorSchemeChoice
;
1364 const auto& prefs
= PreferenceSheet::PrefsFor(aDoc
);
1365 switch (prefs
.mColorSchemeChoice
) {
1366 case Choice::Standard
:
1368 case Choice::UserPreferred
:
1369 return aDoc
.PreferredColorScheme();
1371 return ColorScheme::Light
;
1373 return ColorScheme::Dark
;
1376 StyleColorSchemeFlags
style(aFlags
);
1378 style
._0
= aDoc
.GetColorSchemeBits();
1380 const bool supportsDark
= bool(style
& StyleColorSchemeFlags::DARK
);
1381 const bool supportsLight
= bool(style
& StyleColorSchemeFlags::LIGHT
);
1382 if (supportsLight
&& supportsDark
) {
1383 // Both color-schemes are explicitly supported, use the preferred one.
1384 return aDoc
.PreferredColorScheme();
1386 if (supportsDark
|| supportsLight
) {
1387 // One color-scheme is explicitly supported and one isn't, so use the one
1388 // the content supports.
1389 return supportsDark
? ColorScheme::Dark
: ColorScheme::Light
;
1391 // No value specified. Chrome docs always supports both, so use the preferred
1393 if (aMode
== ColorSchemeMode::Preferred
|| aDoc
.ChromeRulesEnabled()) {
1394 return aDoc
.PreferredColorScheme();
1396 // Default content to light.
1397 return ColorScheme::Light
;
1400 LookAndFeel::ColorScheme
LookAndFeel::ColorSchemeForFrame(
1401 const nsIFrame
* aFrame
, ColorSchemeMode aMode
) {
1402 return ColorSchemeForStyle(*aFrame
->PresContext()->Document(),
1403 aFrame
->StyleUI()->mColorScheme
.bits
, aMode
);
1407 Maybe
<nscolor
> LookAndFeel::GetColor(ColorID aId
, ColorScheme aScheme
,
1408 UseStandins aUseStandins
) {
1410 nsresult rv
= nsLookAndFeel::GetInstance()->GetColorValue(
1411 aId
, aScheme
, aUseStandins
, result
);
1412 if (NS_FAILED(rv
)) {
1415 return Some(result
);
1418 // Returns whether there is a CSS color name for this color.
1419 static bool ColorIsCSSAccessible(LookAndFeel::ColorID aId
) {
1420 using ColorID
= LookAndFeel::ColorID
;
1423 case ColorID::TextSelectDisabledBackground
:
1424 case ColorID::TextSelectAttentionBackground
:
1425 case ColorID::TextSelectAttentionForeground
:
1426 case ColorID::TextHighlightBackground
:
1427 case ColorID::TextHighlightForeground
:
1428 case ColorID::ThemedScrollbar
:
1429 case ColorID::ThemedScrollbarInactive
:
1430 case ColorID::ThemedScrollbarThumb
:
1431 case ColorID::ThemedScrollbarThumbActive
:
1432 case ColorID::ThemedScrollbarThumbInactive
:
1433 case ColorID::ThemedScrollbarThumbHover
:
1434 case ColorID::IMERawInputBackground
:
1435 case ColorID::IMERawInputForeground
:
1436 case ColorID::IMERawInputUnderline
:
1437 case ColorID::IMESelectedRawTextBackground
:
1438 case ColorID::IMESelectedRawTextForeground
:
1439 case ColorID::IMESelectedRawTextUnderline
:
1440 case ColorID::IMEConvertedTextBackground
:
1441 case ColorID::IMEConvertedTextForeground
:
1442 case ColorID::IMEConvertedTextUnderline
:
1443 case ColorID::IMESelectedConvertedTextBackground
:
1444 case ColorID::IMESelectedConvertedTextForeground
:
1445 case ColorID::IMESelectedConvertedTextUnderline
:
1446 case ColorID::SpellCheckerUnderline
:
1455 LookAndFeel::UseStandins
LookAndFeel::ShouldUseStandins(
1456 const dom::Document
& aDoc
, ColorID aId
) {
1457 const auto& prefs
= PreferenceSheet::PrefsFor(aDoc
);
1458 if (ShouldUseStandinsForNativeColorForNonNativeTheme(aDoc
, aId
, prefs
)) {
1459 return UseStandins::Yes
;
1461 if (prefs
.mUseStandins
&& ColorIsCSSAccessible(aId
)) {
1462 return UseStandins::Yes
;
1464 return UseStandins::No
;
1467 Maybe
<nscolor
> LookAndFeel::GetColor(ColorID aId
, const nsIFrame
* aFrame
) {
1468 const auto* doc
= aFrame
->PresContext()->Document();
1469 return GetColor(aId
, ColorSchemeForFrame(aFrame
),
1470 ShouldUseStandins(*doc
, aId
));
1474 nsresult
LookAndFeel::GetInt(IntID aID
, int32_t* aResult
) {
1475 return nsLookAndFeel::GetInstance()->GetIntValue(aID
, *aResult
);
1479 nsresult
LookAndFeel::GetFloat(FloatID aID
, float* aResult
) {
1480 return nsLookAndFeel::GetInstance()->GetFloatValue(aID
, *aResult
);
1484 bool LookAndFeel::GetFont(FontID aID
, nsString
& aName
, gfxFontStyle
& aStyle
) {
1485 return nsLookAndFeel::GetInstance()->GetFontValue(aID
, aName
, aStyle
);
1489 char16_t
LookAndFeel::GetPasswordCharacter() {
1490 return nsLookAndFeel::GetInstance()->GetPasswordCharacterImpl();
1494 bool LookAndFeel::GetEchoPassword() {
1495 if (StaticPrefs::editor_password_mask_delay() >= 0) {
1496 return StaticPrefs::editor_password_mask_delay() > 0;
1498 return nsLookAndFeel::GetInstance()->GetEchoPasswordImpl();
1502 uint32_t LookAndFeel::GetPasswordMaskDelay() {
1503 int32_t delay
= StaticPrefs::editor_password_mask_delay();
1505 return nsLookAndFeel::GetInstance()->GetPasswordMaskDelayImpl();
1510 bool LookAndFeel::DrawInTitlebar() {
1511 switch (StaticPrefs::browser_tabs_inTitlebar()) {
1519 return nsLookAndFeel::GetInstance()->GetDefaultDrawInTitlebar();
1522 void LookAndFeel::GetThemeInfo(nsACString
& aOut
) {
1523 nsLookAndFeel::GetInstance()->GetThemeInfo(aOut
);
1526 uint32_t LookAndFeel::GetMenuAccessKey() {
1527 return StaticPrefs::ui_key_menuAccessKey();
1530 Modifiers
LookAndFeel::GetMenuAccessKeyModifiers() {
1531 switch (GetMenuAccessKey()) {
1532 case dom::KeyboardEvent_Binding::DOM_VK_SHIFT
:
1533 return MODIFIER_SHIFT
;
1534 case dom::KeyboardEvent_Binding::DOM_VK_CONTROL
:
1535 return MODIFIER_CONTROL
;
1536 case dom::KeyboardEvent_Binding::DOM_VK_ALT
:
1537 return MODIFIER_ALT
;
1538 case dom::KeyboardEvent_Binding::DOM_VK_META
:
1539 case dom::KeyboardEvent_Binding::DOM_VK_WIN
:
1540 return MODIFIER_META
;
1547 void LookAndFeel::Refresh() {
1548 nsLookAndFeel::GetInstance()->RefreshImpl();
1549 widget::Theme::LookAndFeelChanged();
1553 void LookAndFeel::NativeInit() { nsLookAndFeel::GetInstance()->NativeInit(); }
1556 void LookAndFeel::SetData(widget::FullLookAndFeel
&& aTables
) {
1557 nsLookAndFeel::GetInstance()->SetDataImpl(std::move(aTables
));
1560 } // namespace mozilla