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"
43 #include "gfxPlatform.h"
50 using namespace mozilla
;
52 using IntID
= mozilla::LookAndFeel::IntID
;
53 using FloatID
= mozilla::LookAndFeel::FloatID
;
54 using ColorID
= mozilla::LookAndFeel::ColorID
;
55 using FontID
= mozilla::LookAndFeel::FontID
;
57 template <typename Index
, typename Value
, Index kEnd
>
58 class EnumeratedCache
{
59 mozilla::EnumeratedArray
<Index
, kEnd
, Value
> mEntries
;
60 std::bitset
<size_t(kEnd
)> mValidity
;
63 constexpr EnumeratedCache() = default;
65 bool IsValid(Index aIndex
) const { return mValidity
[size_t(aIndex
)]; }
67 const Value
* Get(Index aIndex
) const {
68 return IsValid(aIndex
) ? &mEntries
[aIndex
] : nullptr;
71 void Insert(Index aIndex
, Value aValue
) {
72 mValidity
[size_t(aIndex
)] = true;
73 mEntries
[aIndex
] = aValue
;
76 void Remove(Index aIndex
) {
77 mValidity
[size_t(aIndex
)] = false;
78 mEntries
[aIndex
] = Value();
83 for (auto& entry
: mEntries
) {
89 using ColorCache
= EnumeratedCache
<ColorID
, Maybe
<nscolor
>, ColorID::End
>;
92 using UseStandins
= LookAndFeel::UseStandins
;
94 ColorCache mCaches
[2][2];
96 constexpr ColorCaches() = default;
98 ColorCache
& Get(ColorScheme aScheme
, UseStandins aUseStandins
) {
99 return mCaches
[aScheme
== ColorScheme::Dark
]
100 [aUseStandins
== UseStandins::Yes
];
104 for (auto& c
: mCaches
) {
105 for (auto& cache
: c
) {
112 static ColorCaches sColorCaches
;
114 static EnumeratedCache
<FloatID
, Maybe
<float>, FloatID::End
> sFloatCache
;
115 static EnumeratedCache
<IntID
, Maybe
<int32_t>, IntID::End
> sIntCache
;
116 static EnumeratedCache
<FontID
, widget::LookAndFeelFont
, FontID::End
> sFontCache
;
118 // To make one of these prefs toggleable from a reftest add a user
119 // pref in testing/profiles/reftest/user.js. For example, to make
120 // ui.useAccessibilityTheme toggleable, add:
122 // user_pref("ui.useAccessibilityTheme", 0);
124 // This needs to be of the same length and in the same order as
125 // LookAndFeel::IntID values.
126 static const char sIntPrefs
[][45] = {
128 "ui.caretBlinkCount",
130 "ui.caretVisibleWithSelection",
131 "ui.selectTextfieldsOnKeyFocus",
133 "ui.menusCanOverlapOSBar",
134 "ui.useOverlayScrollbars",
135 "ui.allowOverlayScrollbarsOverlap",
136 "ui.skipNavigatingDisabledMenuItem",
139 "ui.useAccessibilityTheme",
140 "ui.scrollArrowStyle",
141 "ui.scrollButtonLeftMouseButtonAction",
142 "ui.scrollButtonMiddleMouseButtonAction",
143 "ui.scrollButtonRightMouseButtonAction",
146 "ui.treeLazyScrollDelay",
147 "ui.treeScrollDelay",
148 "ui.treeScrollLinesMax",
149 "accessibility.tabfocus", // Weird one...
150 "ui.chosenMenuItemsShouldBlink",
151 "ui.windowsAccentColorInTitlebar",
152 "ui.windowsDefaultTheme",
153 "ui.macGraphiteTheme",
156 "ui.alertNotificationOrigin",
158 "ui.IMERawInputUnderlineStyle",
159 "ui.IMESelectedRawTextUnderlineStyle",
160 "ui.IMEConvertedTextUnderlineStyle",
161 "ui.IMESelectedConvertedTextUnderlineStyle",
162 "ui.SpellCheckerUnderlineStyle",
164 "ui.scrollbarButtonAutoRepeatBehavior",
166 "ui.swipeAnimationEnabled",
167 "ui.scrollbarDisplayOnMouseMove",
168 "ui.scrollbarFadeBeginDelay",
169 "ui.scrollbarFadeDuration",
170 "ui.contextMenuOffsetVertical",
171 "ui.contextMenuOffsetHorizontal",
172 "ui.GtkCSDAvailable",
173 "ui.GtkCSDMinimizeButton",
174 "ui.GtkCSDMaximizeButton",
175 "ui.GtkCSDCloseButton",
176 "ui.GtkCSDMinimizeButtonPosition",
177 "ui.GtkCSDMaximizeButtonPosition",
178 "ui.GtkCSDCloseButtonPosition",
179 "ui.GtkCSDReversedPlacement",
180 "ui.systemUsesDarkTheme",
181 "ui.prefersReducedMotion",
182 "ui.prefersReducedTransparency",
184 "ui.primaryPointerCapabilities",
185 "ui.allPointerCapabilities",
186 "ui.systemScrollbarSize",
187 "ui.touchDeviceSupportPresent",
190 "ui.videoDynamicRange",
191 "ui.panelAnimations",
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-dragtargetzone",
256 "ui.-moz-cellhighlight",
257 "ui.-moz_cellhighlighttext",
259 "ui.selecteditemtext",
260 "ui.-moz-buttonhoverface",
261 "ui.-moz_buttonhovertext",
263 "ui.-moz_menuhoverdisabled",
264 "ui.-moz_menuhovertext",
265 "ui.-moz_menubarhovertext",
267 "ui.-moz-headerbartext",
268 "ui.-moz-headerbarinactive",
269 "ui.-moz-headerbarinactivetext",
270 "ui.-moz_eventreerow",
271 "ui.-moz_oddtreerow",
272 "ui.-moz-buttonactivetext",
273 "ui.-moz-buttonactiveface",
274 "ui.-moz-buttondisabledface",
275 "ui.-moz_mac_chrome_active",
276 "ui.-moz_mac_chrome_inactive",
277 "ui.-moz-mac-defaultbuttontext",
278 "ui.-moz-mac-focusring",
279 "ui.-moz-mac-menuselect",
280 "ui.-moz-mac-menushadow",
281 "ui.-moz-mac-menutextdisable",
282 "ui.-moz-mac-menutextselect",
283 "ui.-moz_mac_disabledtoolbartext",
284 "ui.-moz-mac-secondaryhighlight",
285 "ui.-moz-mac-menupopup",
286 "ui.-moz-mac-menuitem",
287 "ui.-moz-mac-active-menuitem",
288 "ui.-moz-mac-source-list",
289 "ui.-moz-mac-source-list-selection",
290 "ui.-moz-mac-active-source-list-selection",
291 "ui.-moz-mac-tooltip",
293 "ui.accentcolortext",
294 "ui.-moz-autofill-background",
295 "ui.-moz-win-mediatext",
296 "ui.-moz-win-communicationstext",
297 "ui.-moz-nativehyperlinktext",
298 "ui.-moz-nativevisitedhyperlinktext",
299 "ui.-moz-hyperlinktext",
300 "ui.-moz-activehyperlinktext",
301 "ui.-moz-visitedhyperlinktext",
302 "ui.-moz-colheadertext",
303 "ui.-moz-colheaderhovertext",
304 "ui.textSelectDisabledBackground",
305 "ui.textSelectAttentionBackground",
306 "ui.textSelectAttentionForeground",
307 "ui.textHighlightBackground",
308 "ui.textHighlightForeground",
309 "ui.IMERawInputBackground",
310 "ui.IMERawInputForeground",
311 "ui.IMERawInputUnderline",
312 "ui.IMESelectedRawTextBackground",
313 "ui.IMESelectedRawTextForeground",
314 "ui.IMESelectedRawTextUnderline",
315 "ui.IMEConvertedTextBackground",
316 "ui.IMEConvertedTextForeground",
317 "ui.IMEConvertedTextUnderline",
318 "ui.IMESelectedConvertedTextBackground",
319 "ui.IMESelectedConvertedTextForeground",
320 "ui.IMESelectedConvertedTextUnderline",
321 "ui.SpellCheckerUnderline",
322 "ui.themedScrollbar",
323 "ui.themedScrollbarInactive",
324 "ui.themedScrollbarThumb",
325 "ui.themedScrollbarThumbHover",
326 "ui.themedScrollbarThumbActive",
327 "ui.themedScrollbarThumbInactive",
330 static_assert(ArrayLength(sColorPrefs
) == size_t(LookAndFeel::ColorID::End
),
331 "Should have a pref for each color value");
333 // This array MUST be kept in the same order as the SystemFont enum.
334 static const char sFontPrefs
[][41] = {
338 "ui.font.message-box",
339 "ui.font.small-caption",
340 "ui.font.status-bar",
341 "ui.font.-moz-pull-down-menu",
342 "ui.font.-moz-button",
344 "ui.font.-moz-field",
347 static_assert(ArrayLength(sFontPrefs
) == size_t(LookAndFeel::FontID::End
),
348 "Should have a pref for each font value");
350 const char* nsXPLookAndFeel::GetColorPrefName(ColorID aId
) {
351 return sColorPrefs
[size_t(aId
)];
354 bool nsXPLookAndFeel::sInitialized
= false;
356 nsXPLookAndFeel
* nsXPLookAndFeel::sInstance
= nullptr;
357 bool nsXPLookAndFeel::sShutdown
= false;
359 auto LookAndFeel::SystemZoomSettings() -> ZoomSettings
{
360 ZoomSettings settings
;
361 switch (StaticPrefs::browser_display_os_zoom_behavior()) {
366 settings
.mFullZoom
= GetTextScaleFactor();
369 settings
.mTextZoom
= GetTextScaleFactor();
376 nsXPLookAndFeel
* nsXPLookAndFeel::GetInstance() {
381 NS_ENSURE_TRUE(!sShutdown
, nullptr);
383 // If we're in a content process, then the parent process will have supplied
384 // us with an initial FullLookAndFeel object.
385 // We grab this data from the ContentChild,
386 // where it's been temporarily stashed, and initialize our new LookAndFeel
389 FullLookAndFeel
* lnf
= nullptr;
391 if (auto* cc
= mozilla::dom::ContentChild::GetSingleton()) {
392 lnf
= &cc
->BorrowLookAndFeelData();
396 sInstance
= new widget::RemoteLookAndFeel(std::move(*lnf
));
397 } else if (gfxPlatform::IsHeadless()) {
398 sInstance
= new widget::HeadlessLookAndFeel();
400 sInstance
= new nsLookAndFeel();
403 // This is only ever used once during initialization, and can be cleared now.
408 widget::Theme::Init();
413 void nsXPLookAndFeel::Shutdown() {
422 // This keeps strings alive, so need to clear to make leak checking happy.
425 widget::Theme::Shutdown();
428 static void IntPrefChanged(const nsACString
& aPref
) {
429 // Most Int prefs can't change our system colors or fonts, but
430 // ui.systemUsesDarkTheme can, since it affects the effective color-scheme
431 // (affecting system colors).
432 auto changeKind
= aPref
.EqualsLiteral("ui.systemUsesDarkTheme")
433 ? widget::ThemeChangeKind::Style
434 : widget::ThemeChangeKind::MediaQueriesOnly
;
435 LookAndFeel::NotifyChangedAllWindows(changeKind
);
438 static void FloatPrefChanged(const nsACString
& aPref
) {
439 // Most float prefs can't change our system colors or fonts, but
440 // textScaleFactor affects layout.
441 auto changeKind
= aPref
.EqualsLiteral("ui.textScaleFactor")
442 ? widget::ThemeChangeKind::StyleAndLayout
443 : widget::ThemeChangeKind::MediaQueriesOnly
;
444 LookAndFeel::NotifyChangedAllWindows(changeKind
);
447 static void ColorPrefChanged() {
448 // Color prefs affect style, because they by definition change system colors.
449 LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind::Style
);
452 static void FontPrefChanged() {
453 // Color prefs affect style, because they by definition change system fonts.
454 LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind::Style
);
458 void nsXPLookAndFeel::OnPrefChanged(const char* aPref
, void* aClosure
) {
459 nsDependentCString
prefName(aPref
);
460 for (const char* pref
: sIntPrefs
) {
461 if (prefName
.Equals(pref
)) {
462 IntPrefChanged(prefName
);
467 for (const char* pref
: sFloatPrefs
) {
468 if (prefName
.Equals(pref
)) {
469 FloatPrefChanged(prefName
);
474 for (const char* pref
: sColorPrefs
) {
475 // We use StringBeginsWith to handle .dark prefs too.
476 if (StringBeginsWith(prefName
, nsDependentCString(pref
))) {
482 for (const char* pref
: sFontPrefs
) {
483 if (StringBeginsWith(prefName
, nsDependentCString(pref
))) {
490 static constexpr struct {
491 nsLiteralCString mName
;
492 widget::ThemeChangeKind mChangeKind
=
493 widget::ThemeChangeKind::MediaQueriesOnly
;
494 } kMediaQueryPrefs
[] = {
495 // Affects whether standins are used for the accent color.
496 {"widget.non-native-theme.use-theme-accent"_ns
,
497 widget::ThemeChangeKind::Style
},
498 // These two affect system colors on Windows.
499 {"widget.windows.uwp-system-colors.enabled"_ns
,
500 widget::ThemeChangeKind::Style
},
501 // These two affect system colors on Windows.
502 {"widget.windows.uwp-system-colors.highlight-accent"_ns
,
503 widget::ThemeChangeKind::Style
},
505 {"layout.css.prefers-color-scheme.content-override"_ns
,
506 widget::ThemeChangeKind::Style
},
507 // Affects media queries and scrollbar sizes, so gotta relayout.
508 {"widget.gtk.overlay-scrollbars.enabled"_ns
,
509 widget::ThemeChangeKind::StyleAndLayout
},
510 // Affects zoom settings which includes text and full zoom.
511 {"browser.display.os-zoom-behavior"_ns
,
512 widget::ThemeChangeKind::StyleAndLayout
},
513 // This affects not only the media query, but also the native theme, so we
514 // need to re-layout.
515 {"browser.theme.toolbar-theme"_ns
, widget::ThemeChangeKind::AllBits
},
516 {"browser.theme.content-theme"_ns
},
517 {"mathml.legacy_maction_and_semantics_implementations.disabled"_ns
},
518 {"mathml.ms_lquote_rquote_attributes.disabled"_ns
},
519 {"dom.element.popover.enabled"_ns
},
520 {"mathml.legacy_mathvariant_attribute.disabled"_ns
},
523 // Read values from the user's preferences.
524 // This is done once at startup, but since the user's preferences
525 // haven't actually been read yet at that time, we also have to
526 // set a callback to inform us of changes to each pref.
527 void nsXPLookAndFeel::Init() {
528 MOZ_RELEASE_ASSERT(NS_IsMainThread());
530 // Say we're already initialized, and take the chance that it might fail;
531 // protects against some other process writing to our static variables.
534 RecomputeColorSchemes();
536 if (XRE_IsParentProcess()) {
537 nsLayoutUtils::RecomputeSmoothScrollDefault();
540 // XXX If we could reorganize the pref names, we should separate the branch
541 // for each types. Then, we could reduce the unnecessary loop from
542 // nsXPLookAndFeel::OnPrefChanged().
543 Preferences::RegisterPrefixCallback(OnPrefChanged
, "ui.");
544 // We really do just want the accessibility.tabfocus pref, not other prefs
545 // that start with that string.
546 Preferences::RegisterCallback(OnPrefChanged
, "accessibility.tabfocus");
548 for (auto& pref
: kMediaQueryPrefs
) {
549 Preferences::RegisterCallback(
550 [](const char*, void* aChangeKind
) {
552 widget::ThemeChangeKind(reinterpret_cast<uintptr_t>(aChangeKind
));
553 LookAndFeel::NotifyChangedAllWindows(changeKind
);
555 pref
.mName
, reinterpret_cast<void*>(uintptr_t(pref
.mChangeKind
)));
559 nsXPLookAndFeel::~nsXPLookAndFeel() {
560 NS_ASSERTION(sInstance
== this,
561 "This destroying instance isn't the singleton instance");
565 static bool IsSpecialColor(LookAndFeel::ColorID aID
, nscolor aColor
) {
566 using ColorID
= LookAndFeel::ColorID
;
568 if (aColor
== NS_SAME_AS_FOREGROUND_COLOR
) {
573 case ColorID::IMESelectedRawTextBackground
:
574 case ColorID::IMESelectedConvertedTextBackground
:
575 case ColorID::IMERawInputBackground
:
576 case ColorID::IMEConvertedTextBackground
:
577 case ColorID::IMESelectedRawTextForeground
:
578 case ColorID::IMESelectedConvertedTextForeground
:
579 case ColorID::IMERawInputForeground
:
580 case ColorID::IMEConvertedTextForeground
:
581 case ColorID::IMERawInputUnderline
:
582 case ColorID::IMEConvertedTextUnderline
:
583 case ColorID::IMESelectedRawTextUnderline
:
584 case ColorID::IMESelectedConvertedTextUnderline
:
585 case ColorID::SpellCheckerUnderline
:
586 return NS_IS_SELECTION_SPECIAL_COLOR(aColor
);
591 * In GetColor(), every color that is not a special color is color
592 * corrected. Use false to make other colors color corrected.
597 nscolor
nsXPLookAndFeel::GetStandinForNativeColor(ColorID aID
,
598 ColorScheme aScheme
) {
599 if (aScheme
== ColorScheme::Dark
) {
600 if (auto color
= GenericDarkColor(aID
)) {
605 // The stand-in colors are taken from what the non-native theme needs (for
606 // field/button colors), the Windows 7 Aero theme except Mac-specific colors
607 // which are taken from Mac OS 10.7.
609 #define COLOR(name_, r, g, b) \
610 case ColorID::name_: \
611 return NS_RGB(r, g, b);
613 #define COLORA(name_, r, g, b, a) \
614 case ColorID::name_: \
615 return NS_RGBA(r, g, b, a);
618 // These are here for the purposes of headless mode.
619 case ColorID::IMESelectedRawTextBackground
:
620 case ColorID::IMESelectedConvertedTextBackground
:
621 case ColorID::IMERawInputBackground
:
622 case ColorID::IMEConvertedTextBackground
:
623 return NS_TRANSPARENT
;
624 case ColorID::IMESelectedRawTextForeground
:
625 case ColorID::IMESelectedConvertedTextForeground
:
626 case ColorID::IMERawInputForeground
:
627 case ColorID::IMEConvertedTextForeground
:
628 return NS_SAME_AS_FOREGROUND_COLOR
;
629 case ColorID::IMERawInputUnderline
:
630 case ColorID::IMEConvertedTextUnderline
:
631 return NS_40PERCENT_FOREGROUND_COLOR
;
632 case ColorID::Accentcolor
:
633 return widget::sDefaultAccent
.ToABGR();
634 case ColorID::Accentcolortext
:
635 return widget::sDefaultAccentText
.ToABGR();
636 COLOR(SpellCheckerUnderline
, 0xff, 0x00, 0x00)
637 COLOR(TextSelectDisabledBackground
, 0xaa, 0xaa, 0xaa)
640 COLOR(Activeborder
, 0xB4, 0xB4, 0xB4)
641 COLOR(Activecaption
, 0x99, 0xB4, 0xD1)
642 COLOR(Appworkspace
, 0xAB, 0xAB, 0xAB)
643 COLOR(Background
, 0x00, 0x00, 0x00)
644 COLOR(Buttonhighlight
, 0xFF, 0xFF, 0xFF)
645 COLOR(Buttonshadow
, 0xA0, 0xA0, 0xA0)
647 // Buttons and comboboxes should be kept in sync since they are drawn with
648 // the same colors by the non-native theme.
649 COLOR(Buttonface
, 0xe9, 0xe9, 0xed)
650 COLORA(MozButtondisabledface
, 0xe9, 0xe9, 0xed, 128)
652 COLOR(MozCombobox
, 0xe9, 0xe9, 0xed)
654 COLOR(Buttontext
, 0x00, 0x00, 0x00)
655 COLOR(MozComboboxtext
, 0x00, 0x00, 0x00)
657 COLOR(Captiontext
, 0x00, 0x00, 0x00)
658 COLOR(Graytext
, 0x6D, 0x6D, 0x6D)
659 COLOR(Highlight
, 0x33, 0x99, 0xFF)
660 COLOR(Highlighttext
, 0xFF, 0xFF, 0xFF)
661 COLOR(Inactiveborder
, 0xF4, 0xF7, 0xFC)
662 COLOR(Inactivecaption
, 0xBF, 0xCD, 0xDB)
663 COLOR(Inactivecaptiontext
, 0x43, 0x4E, 0x54)
664 COLOR(Infobackground
, 0xFF, 0xFF, 0xE1)
665 COLOR(Infotext
, 0x00, 0x00, 0x00)
666 COLOR(Menu
, 0xF0, 0xF0, 0xF0)
667 COLOR(Menutext
, 0x00, 0x00, 0x00)
668 COLOR(Scrollbar
, 0xC8, 0xC8, 0xC8)
669 COLOR(Threeddarkshadow
, 0x69, 0x69, 0x69)
670 COLOR(Threedface
, 0xF0, 0xF0, 0xF0)
671 COLOR(Threedhighlight
, 0xFF, 0xFF, 0xFF)
672 COLOR(Threedlightshadow
, 0xE3, 0xE3, 0xE3)
673 COLOR(Threedshadow
, 0xA0, 0xA0, 0xA0)
674 COLOR(Buttonborder
, 0xE3, 0xE3, 0xE3)
675 COLOR(Mark
, 0xFF, 0xFF, 0x00)
676 COLOR(Marktext
, 0x00, 0x00, 0x00)
677 COLOR(Window
, 0xFF, 0xFF, 0xFF)
678 COLOR(Windowframe
, 0x64, 0x64, 0x64)
679 COLOR(Windowtext
, 0x00, 0x00, 0x00)
680 COLOR(Field
, 0xFF, 0xFF, 0xFF)
681 COLORA(MozDisabledfield
, 0xFF, 0xFF, 0xFF, 128)
682 COLOR(Fieldtext
, 0x00, 0x00, 0x00)
683 COLOR(MozDialog
, 0xF0, 0xF0, 0xF0)
684 COLOR(MozDialogtext
, 0x00, 0x00, 0x00)
685 COLOR(MozColheadertext
, 0x00, 0x00, 0x00)
686 COLOR(MozColheaderhovertext
, 0x00, 0x00, 0x00)
687 COLOR(MozDragtargetzone
, 0xFF, 0xFF, 0xFF)
688 COLOR(MozCellhighlight
, 0xF0, 0xF0, 0xF0)
689 COLOR(MozCellhighlighttext
, 0x00, 0x00, 0x00)
690 COLOR(Selecteditem
, 0x33, 0x99, 0xFF)
691 COLOR(Selecteditemtext
, 0xFF, 0xFF, 0xFF)
692 COLOR(MozButtonhoverface
, 0xd0, 0xd0, 0xd7)
693 COLOR(MozButtonhovertext
, 0x00, 0x00, 0x00)
694 COLOR(MozButtonactiveface
, 0xb1, 0xb1, 0xb9)
695 COLOR(MozButtonactivetext
, 0x00, 0x00, 0x00)
696 COLOR(MozMenuhover
, 0x33, 0x99, 0xFF)
697 COLOR(MozMenuhovertext
, 0x00, 0x00, 0x00)
698 COLOR(MozMenubarhovertext
, 0x00, 0x00, 0x00)
699 COLOR(MozMenuhoverdisabled
, 0xF0, 0xF0, 0xF0)
700 COLOR(MozEventreerow
, 0xFF, 0xFF, 0xFF)
701 COLOR(MozOddtreerow
, 0xFF, 0xFF, 0xFF)
702 COLOR(MozMacChromeActive
, 0xB2, 0xB2, 0xB2)
703 COLOR(MozMacChromeInactive
, 0xE1, 0xE1, 0xE1)
704 COLOR(MozMacFocusring
, 0x60, 0x9D, 0xD7)
705 COLOR(MozMacMenuselect
, 0x38, 0x75, 0xD7)
706 COLOR(MozMacMenushadow
, 0xA3, 0xA3, 0xA3)
707 COLOR(MozMacMenutextdisable
, 0x88, 0x88, 0x88)
708 COLOR(MozMacMenutextselect
, 0xFF, 0xFF, 0xFF)
709 COLOR(MozMacDisabledtoolbartext
, 0x3F, 0x3F, 0x3F)
710 COLOR(MozMacSecondaryhighlight
, 0xD4, 0xD4, 0xD4)
711 COLOR(MozMacMenupopup
, 0xe6, 0xe6, 0xe6)
712 COLOR(MozMacMenuitem
, 0xe6, 0xe6, 0xe6)
713 COLOR(MozMacActiveMenuitem
, 0x0a, 0x64, 0xdc)
714 COLOR(MozMacSourceList
, 0xf7, 0xf7, 0xf7)
715 COLOR(MozMacSourceListSelection
, 0xc8, 0xc8, 0xc8)
716 COLOR(MozMacActiveSourceListSelection
, 0x0a, 0x64, 0xdc)
717 COLOR(MozMacTooltip
, 0xf7, 0xf7, 0xf7)
718 // Seems to be the default color (hardcoded because of bug 1065998)
719 COLOR(MozWinMediatext
, 0xFF, 0xFF, 0xFF)
720 COLOR(MozWinCommunicationstext
, 0xFF, 0xFF, 0xFF)
721 COLOR(MozNativehyperlinktext
, 0x00, 0x66, 0xCC)
722 COLOR(MozNativevisitedhyperlinktext
, 0x55, 0x1A, 0x8B)
726 return NS_RGB(0xFF, 0xFF, 0xFF);
732 // Taken from in-content/common.inc.css's dark theme.
733 Maybe
<nscolor
> nsXPLookAndFeel::GenericDarkColor(ColorID aID
) {
734 nscolor color
= NS_RGB(0, 0, 0);
735 static constexpr nscolor kWindowBackground
= NS_RGB(28, 27, 34);
736 static constexpr nscolor kWindowText
= NS_RGB(251, 251, 254);
738 case ColorID::Window
: // --in-content-page-background
739 case ColorID::Background
:
740 color
= kWindowBackground
;
744 color
= NS_RGB(0x2b, 0x2a, 0x33);
747 case ColorID::MozMenuhovertext
:
748 case ColorID::MozMenubarhovertext
:
749 case ColorID::Menutext
:
750 color
= NS_RGB(0xfb, 0xfb, 0xfe);
753 case ColorID::MozMenuhover
:
754 color
= NS_RGB(0x52, 0x52, 0x5e);
757 case ColorID::MozMenuhoverdisabled
:
758 color
= NS_RGB(0x3a, 0x39, 0x44);
761 case ColorID::MozOddtreerow
:
762 case ColorID::MozDialog
: // --in-content-box-background
763 color
= NS_RGB(35, 34, 43);
765 case ColorID::Windowtext
: // --in-content-page-color
766 case ColorID::MozDialogtext
:
767 case ColorID::Fieldtext
:
768 case ColorID::Buttontext
: // --in-content-button-text-color (via
769 // --in-content-page-color)
770 case ColorID::MozComboboxtext
:
771 case ColorID::MozButtonhovertext
:
772 case ColorID::MozButtonactivetext
:
775 case ColorID::Buttonshadow
:
776 case ColorID::Threedshadow
:
777 case ColorID::Threedlightshadow
:
778 case ColorID::Buttonborder
: // --in-content-box-border-color computed
779 // with kWindowText above
780 // kWindowBackground.
781 case ColorID::Graytext
: // opacity: 0.4 of kWindowText blended over the
782 // "Window" background color, which happens to be
784 color
= NS_ComposeColors(kWindowBackground
, NS_RGBA(251, 251, 254, 102));
786 case ColorID::MozCellhighlight
:
787 case ColorID::Selecteditem
: // --in-content-primary-button-background /
788 // --in-content-item-selected
789 color
= NS_RGB(0, 221, 255);
792 case ColorID::Buttonface
: // --in-content-button-background
793 case ColorID::Threedface
:
794 case ColorID::MozCombobox
:
795 case ColorID::MozCellhighlighttext
:
796 case ColorID::Selecteditemtext
: // --in-content-primary-button-text-color /
797 // --in-content-item-selected-text
798 color
= NS_RGB(43, 42, 51);
800 case ColorID::Threeddarkshadow
: // Same as Threedlightshadow but with the
802 case ColorID::MozDisabledfield
: // opacity: 0.4 of the face above blended
803 // over the "Window" background color.
804 case ColorID::MozButtondisabledface
:
805 color
= NS_ComposeColors(kWindowBackground
, NS_RGBA(43, 42, 51, 102));
807 case ColorID::MozButtonhoverface
: // --in-content-button-background-hover
808 color
= NS_RGB(82, 82, 94);
810 case ColorID::MozButtonactiveface
: // --in-content-button-background-active
811 color
= NS_RGB(91, 91, 102);
813 case ColorID::Highlight
:
814 color
= NS_RGBA(0, 221, 255, 78);
816 case ColorID::Highlighttext
:
817 color
= NS_SAME_AS_FOREGROUND_COLOR
;
819 case ColorID::MozNativehyperlinktext
:
820 // If you change this color, you probably also want to change the default
821 // value of browser.anchor_color.dark.
822 color
= NS_RGB(0x8c, 0x8c, 0xff);
824 case ColorID::MozNativevisitedhyperlinktext
:
825 // If you change this color, you probably also want to change the default
826 // value of browser.visited_color.dark.
827 color
= NS_RGB(0xff, 0xad, 0xff);
829 case ColorID::SpellCheckerUnderline
:
830 // This is the default for active links in dark mode as well
831 // (browser.active_color.dark). See bug 1755564 for some analysis and
832 // other options too.
833 color
= NS_RGB(0xff, 0x66, 0x66);
841 // Uncomment the #define below if you want to debug system color use in a skin
842 // that uses them. When set, it will make all system color pairs that are
843 // appropriate for foreground/background pairing the same. This means if the
844 // skin is using system colors correctly you will not be able to see *any* text.
846 // #define DEBUG_SYSTEM_COLOR_USE
848 #ifdef DEBUG_SYSTEM_COLOR_USE
849 static nsresult
SystemColorUseDebuggingColor(LookAndFeel::ColorID aID
,
851 using ColorID
= LookAndFeel::ColorID
;
854 // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
855 case ColorID::Activecaption
:
856 // active window caption background
857 case ColorID::Captiontext
:
858 // text in active window caption
859 aResult
= NS_RGB(0xff, 0x00, 0x00);
862 case ColorID::Highlight
:
863 // background of selected item
864 case ColorID::Highlighttext
:
865 // text of selected item
866 aResult
= NS_RGB(0xff, 0xff, 0x00);
869 case ColorID::Inactivecaption
:
870 // inactive window caption
871 case ColorID::Inactivecaptiontext
:
872 // text in inactive window caption
873 aResult
= NS_RGB(0x66, 0x66, 0x00);
876 case ColorID::Infobackground
:
877 // tooltip background color
878 case ColorID::Infotext
:
879 // tooltip text color
880 aResult
= NS_RGB(0x00, 0xff, 0x00);
885 case ColorID::Menutext
:
887 aResult
= NS_RGB(0x00, 0xff, 0xff);
890 case ColorID::Threedface
:
891 case ColorID::Buttonface
:
893 case ColorID::Buttontext
:
894 // text on push buttons
895 aResult
= NS_RGB(0x00, 0x66, 0x66);
898 case ColorID::Window
:
899 case ColorID::Windowtext
:
900 aResult
= NS_RGB(0x00, 0x00, 0xff);
903 // from the CSS3 working draft (not yet finalized)
904 // http://www.w3.org/tr/2000/wd-css3-userint-20000216.html#color
907 case ColorID::Fieldtext
:
908 aResult
= NS_RGB(0xff, 0x00, 0xff);
911 case ColorID::MozDialog
:
912 case ColorID::MozDialogtext
:
913 aResult
= NS_RGB(0x66, 0x00, 0x66);
917 return NS_ERROR_NOT_AVAILABLE
;
924 static nsresult
GetPrefColor(const char* aPref
, nscolor
& aResult
) {
925 nsAutoCString colorStr
;
926 MOZ_TRY(Preferences::GetCString(aPref
, colorStr
));
927 if (!ServoCSSParser::ComputeColor(nullptr, NS_RGB(0, 0, 0), colorStr
,
929 return NS_ERROR_FAILURE
;
934 static nsresult
GetColorFromPref(LookAndFeel::ColorID aID
, ColorScheme aScheme
,
936 const char* prefName
= sColorPrefs
[size_t(aID
)];
937 if (aScheme
== ColorScheme::Dark
) {
938 nsAutoCString
darkPrefName(prefName
);
939 darkPrefName
.Append(".dark");
940 if (NS_SUCCEEDED(GetPrefColor(darkPrefName
.get(), aResult
))) {
944 return GetPrefColor(prefName
, aResult
);
947 // All these routines will return NS_OK if they have a value,
948 // in which case the nsLookAndFeel should use that value;
949 // otherwise we'll return NS_ERROR_NOT_AVAILABLE, in which case, the
950 // platform-specific nsLookAndFeel should use its own values instead.
951 nsresult
nsXPLookAndFeel::GetColorValue(ColorID aID
, ColorScheme aScheme
,
952 UseStandins aUseStandins
,
958 #ifdef DEBUG_SYSTEM_COLOR_USE
959 if (NS_SUCCEEDED(SystemColorUseDebuggingColor(aID
, aResult
))) {
964 auto& cache
= sColorCaches
.Get(aScheme
, aUseStandins
);
965 if (const auto* cached
= cache
.Get(aID
)) {
966 if (cached
->isNothing()) {
967 return NS_ERROR_FAILURE
;
969 aResult
= cached
->value();
973 // NOTE: Servo holds a lock and the main thread is paused, so writing to the
974 // global cache here is fine.
975 auto result
= GetUncachedColor(aID
, aScheme
, aUseStandins
);
976 cache
.Insert(aID
, result
);
978 return NS_ERROR_FAILURE
;
984 Maybe
<nscolor
> nsXPLookAndFeel::GetUncachedColor(ColorID aID
,
986 UseStandins aUseStandins
) {
987 if (aUseStandins
== UseStandins::Yes
) {
988 return Some(GetStandinForNativeColor(aID
, aScheme
));
991 if (NS_SUCCEEDED(GetColorFromPref(aID
, aScheme
, r
))) {
994 if (NS_SUCCEEDED(NativeGetColor(aID
, aScheme
, r
))) {
995 if (gfxPlatform::GetCMSMode() == CMSMode::All
&& !IsSpecialColor(aID
, r
)) {
996 qcms_transform
* transform
= gfxPlatform::GetCMSInverseRGBTransform();
999 color
[0] = NS_GET_R(r
);
1000 color
[1] = NS_GET_G(r
);
1001 color
[2] = NS_GET_B(r
);
1002 color
[3] = NS_GET_A(r
);
1003 qcms_transform_data(transform
, color
, color
, 1);
1004 r
= NS_RGBA(color
[0], color
[1], color
[2], color
[3]);
1013 nsresult
nsXPLookAndFeel::GetIntValue(IntID aID
, int32_t& aResult
) {
1014 if (!sInitialized
) {
1018 if (const auto* cached
= sIntCache
.Get(aID
)) {
1019 if (cached
->isNothing()) {
1020 return NS_ERROR_FAILURE
;
1022 aResult
= cached
->value();
1026 if (NS_SUCCEEDED(Preferences::GetInt(sIntPrefs
[size_t(aID
)], &aResult
))) {
1027 sIntCache
.Insert(aID
, Some(aResult
));
1031 if (NS_FAILED(NativeGetInt(aID
, aResult
))) {
1032 sIntCache
.Insert(aID
, Nothing());
1033 return NS_ERROR_FAILURE
;
1036 sIntCache
.Insert(aID
, Some(aResult
));
1040 nsresult
nsXPLookAndFeel::GetFloatValue(FloatID aID
, float& aResult
) {
1041 if (!sInitialized
) {
1045 if (const auto* cached
= sFloatCache
.Get(aID
)) {
1046 if (cached
->isNothing()) {
1047 return NS_ERROR_FAILURE
;
1049 aResult
= cached
->value();
1054 if (NS_SUCCEEDED(Preferences::GetInt(sFloatPrefs
[size_t(aID
)], &pref
))) {
1055 aResult
= float(pref
) / 100.0f
;
1056 sFloatCache
.Insert(aID
, Some(aResult
));
1060 if (NS_FAILED(NativeGetFloat(aID
, aResult
))) {
1061 sFloatCache
.Insert(aID
, Nothing());
1062 return NS_ERROR_FAILURE
;
1065 sFloatCache
.Insert(aID
, Some(aResult
));
1069 bool nsXPLookAndFeel::LookAndFeelFontToStyle(const LookAndFeelFont
& aFont
,
1071 gfxFontStyle
& aStyle
) {
1072 if (!aFont
.haveFont()) {
1075 aName
= aFont
.name();
1076 aStyle
= gfxFontStyle();
1077 aStyle
.size
= aFont
.size();
1078 aStyle
.weight
= FontWeight::FromInt(aFont
.weight());
1080 aFont
.italic() ? FontSlantStyle::ITALIC
: FontSlantStyle::NORMAL
;
1081 aStyle
.systemFont
= true;
1085 widget::LookAndFeelFont
nsXPLookAndFeel::StyleToLookAndFeelFont(
1086 const nsAString
& aName
, const gfxFontStyle
& aStyle
) {
1087 LookAndFeelFont font
;
1088 font
.haveFont() = true;
1089 font
.name() = aName
;
1090 font
.size() = aStyle
.size
;
1091 font
.weight() = aStyle
.weight
.ToFloat();
1092 font
.italic() = aStyle
.style
.IsItalic();
1093 MOZ_ASSERT(aStyle
.style
.IsNormal() || aStyle
.style
.IsItalic(),
1094 "Cannot handle oblique font style");
1097 // Assert that all the remaining font style properties have their
1099 gfxFontStyle candidate
= aStyle
;
1100 gfxFontStyle defaults
{};
1101 candidate
.size
= defaults
.size
;
1102 candidate
.weight
= defaults
.weight
;
1103 candidate
.style
= defaults
.style
;
1104 MOZ_ASSERT(candidate
.Equals(defaults
),
1105 "Some font style properties not supported");
1111 bool nsXPLookAndFeel::GetFontValue(FontID aID
, nsString
& aName
,
1112 gfxFontStyle
& aStyle
) {
1113 if (const LookAndFeelFont
* cached
= sFontCache
.Get(aID
)) {
1114 return LookAndFeelFontToStyle(*cached
, aName
, aStyle
);
1117 LookAndFeelFont font
;
1118 auto GetFontsFromPrefs
= [&]() -> bool {
1119 nsDependentCString
pref(sFontPrefs
[size_t(aID
)]);
1120 if (NS_FAILED(Preferences::GetString(pref
.get(), aName
))) {
1123 font
.haveFont() = true;
1124 font
.name() = aName
;
1125 font
.size() = Preferences::GetFloat(nsAutoCString(pref
+ ".size"_ns
).get());
1126 // This is written this way rather than using the fallback so that an empty
1127 // pref (such like the one about:config creates) doesn't cause system fonts
1128 // to have zero-size.
1129 if (font
.size() < 1.0f
) {
1130 font
.size() = StyleFONT_MEDIUM_PX
;
1132 font
.weight() = Preferences::GetFloat(
1133 nsAutoCString(pref
+ ".weight"_ns
).get(), FontWeight::NORMAL
.ToFloat());
1135 Preferences::GetBool(nsAutoCString(pref
+ ".italic"_ns
).get());
1139 if (GetFontsFromPrefs()) {
1140 LookAndFeelFontToStyle(font
, aName
, aStyle
);
1141 } else if (NativeGetFont(aID
, aName
, aStyle
)) {
1142 font
= StyleToLookAndFeelFont(aName
, aStyle
);
1144 MOZ_ASSERT(!font
.haveFont());
1146 bool success
= font
.haveFont();
1147 sFontCache
.Insert(aID
, std::move(font
));
1151 void nsXPLookAndFeel::RefreshImpl() {
1152 // Wipe out our caches.
1153 sColorCaches
.Clear();
1155 sFloatCache
.Clear();
1157 RecomputeColorSchemes();
1159 if (XRE_IsParentProcess()) {
1160 nsLayoutUtils::RecomputeSmoothScrollDefault();
1161 // Clear any cached FullLookAndFeel data, which is now invalid.
1162 widget::RemoteLookAndFeel::ClearCachedData();
1166 static bool sRecordedLookAndFeelTelemetry
= false;
1168 void nsXPLookAndFeel::RecordTelemetry() {
1169 if (!XRE_IsParentProcess()) {
1173 if (sRecordedLookAndFeelTelemetry
) {
1177 sRecordedLookAndFeelTelemetry
= true;
1180 Telemetry::ScalarSet(
1181 Telemetry::ScalarID::WIDGET_DARK_MODE
,
1182 NS_SUCCEEDED(GetIntValue(IntID::SystemUsesDarkTheme
, i
)) && i
!= 0);
1184 RecordLookAndFeelSpecificTelemetry();
1189 static widget::ThemeChangeKind sGlobalThemeChangeKind
{0};
1191 void LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind aKind
) {
1192 sGlobalThemeChanged
= true;
1193 sGlobalThemeChangeKind
|= aKind
;
1195 if (nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService()) {
1196 const char16_t kind
[] = {char16_t(aKind
), 0};
1197 obs
->NotifyObservers(nullptr, "internal-look-and-feel-changed", kind
);
1201 void LookAndFeel::DoHandleGlobalThemeChange() {
1202 MOZ_ASSERT(sGlobalThemeChanged
);
1203 sGlobalThemeChanged
= false;
1204 auto kind
= std::exchange(sGlobalThemeChangeKind
, widget::ThemeChangeKind(0));
1206 // Tell the theme that it changed, so it can flush any handles to stale theme
1209 // We can use the *DoNotUseDirectly functions directly here, because we want
1210 // to notify all possible themes in a given process (but just once).
1211 if (XRE_IsParentProcess() ||
1212 !StaticPrefs::widget_non_native_theme_enabled()) {
1213 if (nsCOMPtr
<nsITheme
> theme
= do_GetNativeThemeDoNotUseDirectly()) {
1214 theme
->ThemeChanged();
1217 if (nsCOMPtr
<nsITheme
> theme
= do_GetBasicNativeThemeDoNotUseDirectly()) {
1218 theme
->ThemeChanged();
1221 // Clear all cached LookAndFeel colors.
1222 LookAndFeel::Refresh();
1224 // Reset default background and foreground colors for the document since they
1225 // may be using system colors.
1226 PreferenceSheet::Refresh();
1228 // Vector images (SVG) may be using theme colors so we discard all cached
1229 // surfaces. (We could add a vector image only version of DiscardAll, but
1230 // in bug 940625 we decided theme changes are rare enough not to bother.)
1231 image::SurfaceCacheUtils::DiscardAll();
1233 if (XRE_IsParentProcess()) {
1234 dom::ContentParent::BroadcastThemeUpdate(kind
);
1237 nsContentUtils::AddScriptRunner(
1238 NS_NewRunnableFunction("HandleGlobalThemeChange", [] {
1239 if (nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService()) {
1240 obs
->NotifyObservers(nullptr, "look-and-feel-changed", nullptr);
1245 #define BIT_FOR(_c) (1ull << size_t(ColorID::_c))
1247 // We want to use a non-native color scheme for the non-native theme (except in
1248 // high-contrast mode), so spoof some of the colors with stand-ins to prevent
1249 // lack of contrast.
1250 static constexpr std::bitset
<size_t(ColorID::End
)> sNonNativeThemeStandinColors
{
1251 // Used by default button styles.
1252 BIT_FOR(Buttonface
) | BIT_FOR(Buttontext
) | BIT_FOR(MozButtonhoverface
) |
1253 BIT_FOR(MozButtonhovertext
) | BIT_FOR(MozButtonactiveface
) |
1254 BIT_FOR(MozButtonactivetext
) | BIT_FOR(MozButtondisabledface
) |
1255 BIT_FOR(Buttonborder
) |
1256 // Used by select elements.
1257 BIT_FOR(MozCombobox
) | BIT_FOR(MozComboboxtext
) |
1258 BIT_FOR(Threedlightshadow
) |
1259 // For symmetry with the above.
1260 BIT_FOR(Threeddarkshadow
) |
1261 // Used by fieldset borders.
1262 BIT_FOR(Threedface
) |
1263 // Used by input / textarea.
1264 BIT_FOR(Field
) | BIT_FOR(Fieldtext
) |
1265 // Used by disabled form controls.
1266 BIT_FOR(MozDisabledfield
) | BIT_FOR(Graytext
) |
1267 // Some pages expect these to return windows-like colors, see bug 1773795.
1268 // Also, per spec these should match Canvas/CanvasText, see
1269 // https://drafts.csswg.org/css-color-4/#window
1270 BIT_FOR(Window
) | BIT_FOR(Windowtext
)};
1273 static bool ShouldUseStandinsForNativeColorForNonNativeTheme(
1274 const dom::Document
& aDoc
, LookAndFeel::ColorID aColor
,
1275 const PreferenceSheet::Prefs
& aPrefs
) {
1276 const bool shouldUseStandinsForColor
= [&] {
1277 if (sNonNativeThemeStandinColors
[size_t(aColor
)]) {
1280 // There are platforms where we want the content-exposed accent color to be
1281 // the windows blue rather than the system accent color, for now.
1282 return !StaticPrefs::widget_non_native_theme_use_theme_accent() &&
1283 (aColor
== LookAndFeel::ColorID::Accentcolor
||
1284 aColor
== LookAndFeel::ColorID::Accentcolortext
);
1287 return shouldUseStandinsForColor
&& aDoc
.ShouldAvoidNativeTheme() &&
1288 !aPrefs
.NonNativeThemeShouldBeHighContrast();
1291 ColorScheme
LookAndFeel::sChromeColorScheme
;
1292 ColorScheme
LookAndFeel::sContentColorScheme
;
1293 bool LookAndFeel::sColorSchemeInitialized
;
1294 bool LookAndFeel::sGlobalThemeChanged
;
1296 bool LookAndFeel::IsDarkColor(nscolor aColor
) {
1297 // Given https://www.w3.org/TR/WCAG20/#contrast-ratiodef, this is the
1298 // threshold that tells us whether contrast is better against white or black.
1300 // Contrast ratio against black is: (L + 0.05) / 0.05
1301 // Contrast ratio against white is: 1.05 / (L + 0.05)
1303 // So the intersection is:
1305 // (L + 0.05) / 0.05 = 1.05 / (L + 0.05)
1307 // And the solution to that equation is:
1309 // sqrt(1.05 * 0.05) - 0.05
1311 // So we consider a color dark if the contrast is below this threshold, and
1312 // it's at least half-opaque.
1313 constexpr float kThreshold
= 0.179129;
1314 return NS_GET_A(aColor
) > 127 &&
1315 RelativeLuminanceUtils::Compute(aColor
) < kThreshold
;
1318 auto LookAndFeel::ColorSchemeSettingForChrome() -> ChromeColorSchemeSetting
{
1319 switch (StaticPrefs::browser_theme_toolbar_theme()) {
1321 return ChromeColorSchemeSetting::Dark
;
1323 return ChromeColorSchemeSetting::Light
;
1325 return ChromeColorSchemeSetting::System
;
1329 ColorScheme
LookAndFeel::ThemeDerivedColorSchemeForContent() {
1330 switch (StaticPrefs::browser_theme_content_theme()) {
1332 return ColorScheme::Dark
;
1334 return ColorScheme::Light
;
1336 return SystemColorScheme();
1340 void LookAndFeel::RecomputeColorSchemes() {
1341 sColorSchemeInitialized
= true;
1343 sChromeColorScheme
= [] {
1344 switch (ColorSchemeSettingForChrome()) {
1345 case ChromeColorSchemeSetting::Light
:
1346 return ColorScheme::Light
;
1347 case ChromeColorSchemeSetting::Dark
:
1348 return ColorScheme::Dark
;
1349 case ChromeColorSchemeSetting::System
:
1352 return SystemColorScheme();
1355 sContentColorScheme
= [] {
1356 switch (StaticPrefs::layout_css_prefers_color_scheme_content_override()) {
1358 return ColorScheme::Dark
;
1360 return ColorScheme::Light
;
1362 return ThemeDerivedColorSchemeForContent();
1367 ColorScheme
LookAndFeel::ColorSchemeForStyle(
1368 const dom::Document
& aDoc
, const StyleColorSchemeFlags
& aFlags
,
1369 ColorSchemeMode aMode
) {
1370 using Choice
= PreferenceSheet::Prefs::ColorSchemeChoice
;
1372 const auto& prefs
= PreferenceSheet::PrefsFor(aDoc
);
1373 switch (prefs
.mColorSchemeChoice
) {
1374 case Choice::Standard
:
1376 case Choice::UserPreferred
:
1377 return aDoc
.PreferredColorScheme();
1379 return ColorScheme::Light
;
1381 return ColorScheme::Dark
;
1384 StyleColorSchemeFlags
style(aFlags
);
1386 style
.bits
= aDoc
.GetColorSchemeBits();
1388 const bool supportsDark
= bool(style
& StyleColorSchemeFlags::DARK
);
1389 const bool supportsLight
= bool(style
& StyleColorSchemeFlags::LIGHT
);
1390 if (supportsLight
&& supportsDark
) {
1391 // Both color-schemes are explicitly supported, use the preferred one.
1392 return aDoc
.PreferredColorScheme();
1394 if (supportsDark
|| supportsLight
) {
1395 // One color-scheme is explicitly supported and one isn't, so use the one
1396 // the content supports.
1397 return supportsDark
? ColorScheme::Dark
: ColorScheme::Light
;
1399 // No value specified. Chrome docs always supports both, so use the preferred
1401 if (aMode
== ColorSchemeMode::Preferred
||
1402 nsContentUtils::IsChromeDoc(&aDoc
)) {
1403 return aDoc
.PreferredColorScheme();
1405 // Default content to light.
1406 return ColorScheme::Light
;
1409 LookAndFeel::ColorScheme
LookAndFeel::ColorSchemeForFrame(
1410 const nsIFrame
* aFrame
, ColorSchemeMode aMode
) {
1411 return ColorSchemeForStyle(*aFrame
->PresContext()->Document(),
1412 aFrame
->StyleUI()->mColorScheme
.bits
, aMode
);
1416 Maybe
<nscolor
> LookAndFeel::GetColor(ColorID aId
, ColorScheme aScheme
,
1417 UseStandins aUseStandins
) {
1419 nsresult rv
= nsLookAndFeel::GetInstance()->GetColorValue(
1420 aId
, aScheme
, aUseStandins
, result
);
1421 if (NS_FAILED(rv
)) {
1424 return Some(result
);
1427 // Returns whether there is a CSS color name for this color.
1428 static bool ColorIsCSSAccessible(LookAndFeel::ColorID aId
) {
1429 using ColorID
= LookAndFeel::ColorID
;
1432 case ColorID::TextSelectDisabledBackground
:
1433 case ColorID::TextSelectAttentionBackground
:
1434 case ColorID::TextSelectAttentionForeground
:
1435 case ColorID::TextHighlightBackground
:
1436 case ColorID::TextHighlightForeground
:
1437 case ColorID::ThemedScrollbar
:
1438 case ColorID::ThemedScrollbarInactive
:
1439 case ColorID::ThemedScrollbarThumb
:
1440 case ColorID::ThemedScrollbarThumbActive
:
1441 case ColorID::ThemedScrollbarThumbInactive
:
1442 case ColorID::ThemedScrollbarThumbHover
:
1443 case ColorID::IMERawInputBackground
:
1444 case ColorID::IMERawInputForeground
:
1445 case ColorID::IMERawInputUnderline
:
1446 case ColorID::IMESelectedRawTextBackground
:
1447 case ColorID::IMESelectedRawTextForeground
:
1448 case ColorID::IMESelectedRawTextUnderline
:
1449 case ColorID::IMEConvertedTextBackground
:
1450 case ColorID::IMEConvertedTextForeground
:
1451 case ColorID::IMEConvertedTextUnderline
:
1452 case ColorID::IMESelectedConvertedTextBackground
:
1453 case ColorID::IMESelectedConvertedTextForeground
:
1454 case ColorID::IMESelectedConvertedTextUnderline
:
1455 case ColorID::SpellCheckerUnderline
:
1464 LookAndFeel::UseStandins
LookAndFeel::ShouldUseStandins(
1465 const dom::Document
& aDoc
, ColorID aId
) {
1466 const auto& prefs
= PreferenceSheet::PrefsFor(aDoc
);
1467 if (ShouldUseStandinsForNativeColorForNonNativeTheme(aDoc
, aId
, prefs
)) {
1468 return UseStandins::Yes
;
1470 if (prefs
.mUseStandins
&& ColorIsCSSAccessible(aId
)) {
1471 return UseStandins::Yes
;
1473 return UseStandins::No
;
1476 Maybe
<nscolor
> LookAndFeel::GetColor(ColorID aId
, const nsIFrame
* aFrame
) {
1477 const auto* doc
= aFrame
->PresContext()->Document();
1478 return GetColor(aId
, ColorSchemeForFrame(aFrame
),
1479 ShouldUseStandins(*doc
, aId
));
1483 nsresult
LookAndFeel::GetInt(IntID aID
, int32_t* aResult
) {
1484 return nsLookAndFeel::GetInstance()->GetIntValue(aID
, *aResult
);
1488 nsresult
LookAndFeel::GetFloat(FloatID aID
, float* aResult
) {
1489 return nsLookAndFeel::GetInstance()->GetFloatValue(aID
, *aResult
);
1493 bool LookAndFeel::GetFont(FontID aID
, nsString
& aName
, gfxFontStyle
& aStyle
) {
1494 return nsLookAndFeel::GetInstance()->GetFontValue(aID
, aName
, aStyle
);
1498 char16_t
LookAndFeel::GetPasswordCharacter() {
1499 return nsLookAndFeel::GetInstance()->GetPasswordCharacterImpl();
1503 bool LookAndFeel::GetEchoPassword() {
1504 if (StaticPrefs::editor_password_mask_delay() >= 0) {
1505 return StaticPrefs::editor_password_mask_delay() > 0;
1507 return nsLookAndFeel::GetInstance()->GetEchoPasswordImpl();
1511 uint32_t LookAndFeel::GetPasswordMaskDelay() {
1512 int32_t delay
= StaticPrefs::editor_password_mask_delay();
1514 return nsLookAndFeel::GetInstance()->GetPasswordMaskDelayImpl();
1519 bool LookAndFeel::DrawInTitlebar() {
1520 switch (StaticPrefs::browser_tabs_inTitlebar()) {
1528 return nsLookAndFeel::GetInstance()->GetDefaultDrawInTitlebar();
1531 void LookAndFeel::GetThemeInfo(nsACString
& aOut
) {
1532 nsLookAndFeel::GetInstance()->GetThemeInfo(aOut
);
1535 uint32_t LookAndFeel::GetMenuAccessKey() {
1536 return StaticPrefs::ui_key_menuAccessKey();
1539 Modifiers
LookAndFeel::GetMenuAccessKeyModifiers() {
1540 switch (GetMenuAccessKey()) {
1541 case dom::KeyboardEvent_Binding::DOM_VK_SHIFT
:
1542 return MODIFIER_SHIFT
;
1543 case dom::KeyboardEvent_Binding::DOM_VK_CONTROL
:
1544 return MODIFIER_CONTROL
;
1545 case dom::KeyboardEvent_Binding::DOM_VK_ALT
:
1546 return MODIFIER_ALT
;
1547 case dom::KeyboardEvent_Binding::DOM_VK_META
:
1548 return MODIFIER_META
;
1549 case dom::KeyboardEvent_Binding::DOM_VK_WIN
:
1557 void LookAndFeel::Refresh() {
1558 nsLookAndFeel::GetInstance()->RefreshImpl();
1559 widget::Theme::LookAndFeelChanged();
1563 void LookAndFeel::NativeInit() { nsLookAndFeel::GetInstance()->NativeInit(); }
1566 void LookAndFeel::SetData(widget::FullLookAndFeel
&& aTables
) {
1567 nsLookAndFeel::GetInstance()->SetDataImpl(std::move(aTables
));
1570 } // namespace mozilla