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 if (XRE_IsParentProcess()) {
520 nsLayoutUtils::RecomputeSmoothScrollDefault();
523 // XXX If we could reorganize the pref names, we should separate the branch
524 // for each types. Then, we could reduce the unnecessary loop from
525 // nsXPLookAndFeel::OnPrefChanged().
526 Preferences::RegisterPrefixCallback(OnPrefChanged
, "ui.");
527 // We really do just want the accessibility.tabfocus pref, not other prefs
528 // that start with that string.
529 Preferences::RegisterCallback(OnPrefChanged
, "accessibility.tabfocus");
531 for (const auto& pref
: kMediaQueryPrefs
) {
532 Preferences::RegisterCallback(
533 [](const char*, void* aChangeKind
) {
535 widget::ThemeChangeKind(reinterpret_cast<uintptr_t>(aChangeKind
));
536 LookAndFeel::NotifyChangedAllWindows(changeKind
);
538 pref
.mName
, reinterpret_cast<void*>(uintptr_t(pref
.mChangeKind
)));
542 nsXPLookAndFeel::~nsXPLookAndFeel() {
543 NS_ASSERTION(sInstance
== this,
544 "This destroying instance isn't the singleton instance");
548 static bool IsSpecialColor(LookAndFeel::ColorID aID
, nscolor aColor
) {
549 using ColorID
= LookAndFeel::ColorID
;
551 if (aColor
== NS_SAME_AS_FOREGROUND_COLOR
) {
556 case ColorID::IMESelectedRawTextBackground
:
557 case ColorID::IMESelectedConvertedTextBackground
:
558 case ColorID::IMERawInputBackground
:
559 case ColorID::IMEConvertedTextBackground
:
560 case ColorID::IMESelectedRawTextForeground
:
561 case ColorID::IMESelectedConvertedTextForeground
:
562 case ColorID::IMERawInputForeground
:
563 case ColorID::IMEConvertedTextForeground
:
564 case ColorID::IMERawInputUnderline
:
565 case ColorID::IMEConvertedTextUnderline
:
566 case ColorID::IMESelectedRawTextUnderline
:
567 case ColorID::IMESelectedConvertedTextUnderline
:
568 case ColorID::SpellCheckerUnderline
:
569 return NS_IS_SELECTION_SPECIAL_COLOR(aColor
);
574 * In GetColor(), every color that is not a special color is color
575 * corrected. Use false to make other colors color corrected.
580 nscolor
nsXPLookAndFeel::GetStandinForNativeColor(ColorID aID
,
581 ColorScheme aScheme
) {
582 if (aScheme
== ColorScheme::Dark
) {
583 if (auto color
= GenericDarkColor(aID
)) {
588 // The stand-in colors are taken from what the non-native theme needs (for
589 // field/button colors), the Windows 7 Aero theme except Mac-specific colors
590 // which are taken from Mac OS 10.7.
592 #define COLOR(name_, r, g, b) \
593 case ColorID::name_: \
594 return NS_RGB(r, g, b);
596 #define COLORA(name_, r, g, b, a) \
597 case ColorID::name_: \
598 return NS_RGBA(r, g, b, a);
601 // These are here for the purposes of headless mode.
602 case ColorID::IMESelectedRawTextBackground
:
603 case ColorID::IMESelectedConvertedTextBackground
:
604 case ColorID::IMERawInputBackground
:
605 case ColorID::IMEConvertedTextBackground
:
606 return NS_TRANSPARENT
;
607 case ColorID::IMESelectedRawTextForeground
:
608 case ColorID::IMESelectedConvertedTextForeground
:
609 case ColorID::IMERawInputForeground
:
610 case ColorID::IMEConvertedTextForeground
:
611 return NS_SAME_AS_FOREGROUND_COLOR
;
612 case ColorID::IMERawInputUnderline
:
613 case ColorID::IMEConvertedTextUnderline
:
614 return NS_40PERCENT_FOREGROUND_COLOR
;
615 case ColorID::Accentcolor
:
616 return widget::sDefaultAccent
.ToABGR();
617 case ColorID::Accentcolortext
:
618 return widget::sDefaultAccentText
.ToABGR();
619 COLOR(SpellCheckerUnderline
, 0xff, 0x00, 0x00)
620 COLOR(TextSelectDisabledBackground
, 0xaa, 0xaa, 0xaa)
623 COLOR(Activeborder
, 0xB4, 0xB4, 0xB4)
624 COLOR(Inactiveborder
, 0xB4, 0xB4, 0xB4)
625 COLOR(Activecaption
, 0xF0, 0xF0, 0xF4)
626 COLOR(Inactivecaption
, 0xF0, 0xF0, 0xF4)
627 COLOR(Captiontext
, 0x00, 0x00, 0x00)
628 COLOR(Inactivecaptiontext
, 0x00, 0x00, 0x00)
631 COLOR(Appworkspace
, 0xAB, 0xAB, 0xAB)
632 COLOR(Background
, 0x00, 0x00, 0x00)
633 COLOR(Buttonhighlight
, 0xFF, 0xFF, 0xFF)
634 COLOR(Buttonshadow
, 0xA0, 0xA0, 0xA0)
636 // Buttons and comboboxes should be kept in sync since they are drawn with
637 // the same colors by the non-native theme.
638 COLOR(Buttonface
, 0xe9, 0xe9, 0xed)
639 COLORA(MozButtondisabledface
, 0xe9, 0xe9, 0xed, 128)
641 COLOR(MozCombobox
, 0xe9, 0xe9, 0xed)
643 COLOR(Buttontext
, 0x00, 0x00, 0x00)
644 COLOR(MozComboboxtext
, 0x00, 0x00, 0x00)
646 COLOR(Graytext
, 0x6D, 0x6D, 0x6D)
647 COLOR(Highlight
, 0x33, 0x99, 0xFF)
648 COLOR(Highlighttext
, 0xFF, 0xFF, 0xFF)
649 COLOR(Infobackground
, 0xFF, 0xFF, 0xE1)
650 COLOR(Infotext
, 0x00, 0x00, 0x00)
651 COLOR(Menu
, 0xF0, 0xF0, 0xF0)
652 COLOR(Menutext
, 0x00, 0x00, 0x00)
653 COLOR(Scrollbar
, 0xC8, 0xC8, 0xC8)
654 COLOR(Threeddarkshadow
, 0x69, 0x69, 0x69)
655 COLOR(Threedface
, 0xF0, 0xF0, 0xF0)
656 COLOR(Threedhighlight
, 0xFF, 0xFF, 0xFF)
657 COLOR(Threedlightshadow
, 0xE3, 0xE3, 0xE3)
658 COLOR(Threedshadow
, 0xA0, 0xA0, 0xA0)
659 COLOR(Buttonborder
, 0xE3, 0xE3, 0xE3)
660 COLOR(Mark
, 0xFF, 0xFF, 0x00)
661 COLOR(Marktext
, 0x00, 0x00, 0x00)
662 COLOR(Window
, 0xFF, 0xFF, 0xFF)
663 COLOR(Windowframe
, 0x64, 0x64, 0x64)
664 COLOR(Windowtext
, 0x00, 0x00, 0x00)
665 COLOR(Field
, 0xFF, 0xFF, 0xFF)
666 COLORA(MozDisabledfield
, 0xFF, 0xFF, 0xFF, 128)
667 COLOR(Fieldtext
, 0x00, 0x00, 0x00)
668 COLOR(MozDialog
, 0xF0, 0xF0, 0xF0)
669 COLOR(MozDialogtext
, 0x00, 0x00, 0x00)
670 COLOR(MozColheadertext
, 0x00, 0x00, 0x00)
671 COLOR(MozColheaderhovertext
, 0x00, 0x00, 0x00)
672 COLOR(MozCellhighlight
, 0xF0, 0xF0, 0xF0)
673 COLOR(MozCellhighlighttext
, 0x00, 0x00, 0x00)
674 COLOR(Selecteditem
, 0x33, 0x99, 0xFF)
675 COLOR(Selecteditemtext
, 0xFF, 0xFF, 0xFF)
676 COLOR(MozButtonhoverface
, 0xd0, 0xd0, 0xd7)
677 COLOR(MozButtonhovertext
, 0x00, 0x00, 0x00)
678 COLOR(MozButtonactiveface
, 0xb1, 0xb1, 0xb9)
679 COLOR(MozButtonactivetext
, 0x00, 0x00, 0x00)
680 COLOR(MozMenuhover
, 0x33, 0x99, 0xFF)
681 COLOR(MozMenuhovertext
, 0x00, 0x00, 0x00)
682 COLOR(MozMenubarhovertext
, 0x00, 0x00, 0x00)
683 COLOR(MozMenuhoverdisabled
, 0xF0, 0xF0, 0xF0)
684 COLOR(MozEventreerow
, 0xFF, 0xFF, 0xFF)
685 COLOR(MozOddtreerow
, 0xFF, 0xFF, 0xFF)
686 COLOR(MozMacFocusring
, 0x60, 0x9D, 0xD7)
687 COLOR(MozMacDisabledtoolbartext
, 0x3F, 0x3F, 0x3F)
688 COLOR(MozMacMenupopup
, 0xe6, 0xe6, 0xe6)
689 COLOR(MozMacMenuitem
, 0xe6, 0xe6, 0xe6)
690 COLOR(MozMacActiveMenuitem
, 0x0a, 0x64, 0xdc)
691 COLOR(MozMacSourceList
, 0xf7, 0xf7, 0xf7)
692 COLOR(MozMacSourceListSelection
, 0xc8, 0xc8, 0xc8)
693 COLOR(MozMacActiveSourceListSelection
, 0x0a, 0x64, 0xdc)
694 COLOR(MozMacTooltip
, 0xf7, 0xf7, 0xf7)
695 // Seems to be the default color (hardcoded because of bug 1065998)
696 COLOR(MozNativehyperlinktext
, 0x00, 0x66, 0xCC)
697 COLOR(MozNativevisitedhyperlinktext
, 0x55, 0x1A, 0x8B)
701 return NS_RGB(0xFF, 0xFF, 0xFF);
707 // Taken from in-content/common.inc.css's dark theme.
708 Maybe
<nscolor
> nsXPLookAndFeel::GenericDarkColor(ColorID aID
) {
709 nscolor color
= NS_RGB(0, 0, 0);
710 static constexpr nscolor kWindowBackground
= NS_RGB(28, 27, 34);
711 static constexpr nscolor kWindowText
= NS_RGB(251, 251, 254);
713 case ColorID::Window
: // --in-content-page-background
714 case ColorID::Background
:
715 color
= kWindowBackground
;
719 color
= NS_RGB(0x2b, 0x2a, 0x33);
722 case ColorID::MozMenuhovertext
:
723 case ColorID::MozMenubarhovertext
:
724 case ColorID::Menutext
:
725 color
= NS_RGB(0xfb, 0xfb, 0xfe);
728 case ColorID::MozMenuhover
:
729 color
= NS_RGB(0x52, 0x52, 0x5e);
732 case ColorID::MozMenuhoverdisabled
:
733 color
= NS_RGB(0x3a, 0x39, 0x44);
736 case ColorID::MozOddtreerow
:
737 case ColorID::MozDialog
: // --in-content-box-background
738 color
= NS_RGB(35, 34, 43);
740 case ColorID::Windowtext
: // --in-content-page-color
741 case ColorID::MozDialogtext
:
742 case ColorID::Fieldtext
:
743 case ColorID::Buttontext
: // --in-content-button-text-color (via
744 // --in-content-page-color)
745 case ColorID::MozComboboxtext
:
746 case ColorID::MozButtonhovertext
:
747 case ColorID::MozButtonactivetext
:
748 case ColorID::MozHeaderbartext
:
749 case ColorID::MozHeaderbarinactivetext
:
750 case ColorID::Captiontext
:
751 case ColorID::Inactivecaptiontext
: // TODO(emilio): Maybe make
752 // Inactivecaptiontext Graytext?
755 case ColorID::Buttonshadow
:
756 case ColorID::Threedshadow
:
757 case ColorID::Threedlightshadow
:
758 case ColorID::Buttonborder
: // --in-content-box-border-color computed
759 // with kWindowText above
760 // kWindowBackground.
761 case ColorID::Graytext
: // opacity: 0.4 of kWindowText blended over the
762 // "Window" background color, which happens to be
764 color
= NS_ComposeColors(kWindowBackground
, NS_RGBA(251, 251, 254, 102));
766 case ColorID::MozCellhighlight
:
767 case ColorID::Selecteditem
: // --in-content-primary-button-background /
768 // --in-content-item-selected
769 color
= NS_RGB(0, 221, 255);
772 case ColorID::Buttonface
: // --in-content-button-background
773 case ColorID::Threedface
:
774 case ColorID::MozCombobox
:
775 case ColorID::MozCellhighlighttext
:
776 case ColorID::Selecteditemtext
: // --in-content-primary-button-text-color /
777 // --in-content-item-selected-text
778 color
= NS_RGB(43, 42, 51);
780 case ColorID::Threeddarkshadow
: // Same as Threedlightshadow but with the
782 case ColorID::MozDisabledfield
: // opacity: 0.4 of the face above blended
783 // over the "Window" background color.
784 case ColorID::MozButtondisabledface
:
785 color
= NS_ComposeColors(kWindowBackground
, NS_RGBA(43, 42, 51, 102));
787 case ColorID::MozButtonhoverface
: // --in-content-button-background-hover
788 color
= NS_RGB(82, 82, 94);
790 case ColorID::MozButtonactiveface
: // --in-content-button-background-active
791 color
= NS_RGB(91, 91, 102);
793 case ColorID::Highlight
:
794 color
= NS_RGBA(0, 221, 255, 78);
796 case ColorID::Highlighttext
:
797 color
= NS_SAME_AS_FOREGROUND_COLOR
;
799 case ColorID::MozNativehyperlinktext
:
800 // If you change this color, you probably also want to change the default
801 // value of browser.anchor_color.dark.
802 color
= NS_RGB(0x8c, 0x8c, 0xff);
804 case ColorID::MozNativevisitedhyperlinktext
:
805 // If you change this color, you probably also want to change the default
806 // value of browser.visited_color.dark.
807 color
= NS_RGB(0xff, 0xad, 0xff);
809 case ColorID::SpellCheckerUnderline
:
810 // This is the default for active links in dark mode as well
811 // (browser.active_color.dark). See bug 1755564 for some analysis and
812 // other options too.
813 color
= NS_RGB(0xff, 0x66, 0x66);
815 case ColorID::Activeborder
:
816 case ColorID::Inactiveborder
:
817 color
= NS_RGB(57, 57, 57);
819 case ColorID::MozHeaderbar
:
820 case ColorID::MozHeaderbarinactive
:
821 case ColorID::Activecaption
:
822 case ColorID::Inactivecaption
:
823 color
= NS_RGB(28, 27, 34);
831 // Uncomment the #define below if you want to debug system color use in a skin
832 // that uses them. When set, it will make all system color pairs that are
833 // appropriate for foreground/background pairing the same. This means if the
834 // skin is using system colors correctly you will not be able to see *any* text.
836 // #define DEBUG_SYSTEM_COLOR_USE
838 #ifdef DEBUG_SYSTEM_COLOR_USE
839 static nsresult
SystemColorUseDebuggingColor(LookAndFeel::ColorID aID
,
841 using ColorID
= LookAndFeel::ColorID
;
844 // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
845 case ColorID::Activecaption
:
846 // active window caption background
847 case ColorID::Captiontext
:
848 // text in active window caption
849 aResult
= NS_RGB(0xff, 0x00, 0x00);
852 case ColorID::Highlight
:
853 // background of selected item
854 case ColorID::Highlighttext
:
855 // text of selected item
856 aResult
= NS_RGB(0xff, 0xff, 0x00);
859 case ColorID::Inactivecaption
:
860 // inactive window caption
861 case ColorID::Inactivecaptiontext
:
862 // text in inactive window caption
863 aResult
= NS_RGB(0x66, 0x66, 0x00);
866 case ColorID::Infobackground
:
867 // tooltip background color
868 case ColorID::Infotext
:
869 // tooltip text color
870 aResult
= NS_RGB(0x00, 0xff, 0x00);
875 case ColorID::Menutext
:
877 aResult
= NS_RGB(0x00, 0xff, 0xff);
880 case ColorID::Threedface
:
881 case ColorID::Buttonface
:
883 case ColorID::Buttontext
:
884 // text on push buttons
885 aResult
= NS_RGB(0x00, 0x66, 0x66);
888 case ColorID::Window
:
889 case ColorID::Windowtext
:
890 aResult
= NS_RGB(0x00, 0x00, 0xff);
893 // from the CSS3 working draft (not yet finalized)
894 // http://www.w3.org/tr/2000/wd-css3-userint-20000216.html#color
897 case ColorID::Fieldtext
:
898 aResult
= NS_RGB(0xff, 0x00, 0xff);
901 case ColorID::MozDialog
:
902 case ColorID::MozDialogtext
:
903 aResult
= NS_RGB(0x66, 0x00, 0x66);
907 return NS_ERROR_NOT_AVAILABLE
;
914 static nsresult
GetPrefColor(const char* aPref
, nscolor
& aResult
) {
915 nsAutoCString colorStr
;
916 MOZ_TRY(Preferences::GetCString(aPref
, colorStr
));
917 if (!ServoCSSParser::ComputeColor(nullptr, NS_RGB(0, 0, 0), colorStr
,
919 return NS_ERROR_FAILURE
;
924 static nsresult
GetColorFromPref(LookAndFeel::ColorID aID
, ColorScheme aScheme
,
926 const char* prefName
= sColorPrefs
[size_t(aID
)];
927 if (aScheme
== ColorScheme::Dark
) {
928 nsAutoCString
darkPrefName(prefName
);
929 darkPrefName
.Append(".dark");
930 if (NS_SUCCEEDED(GetPrefColor(darkPrefName
.get(), aResult
))) {
934 return GetPrefColor(prefName
, aResult
);
937 // All these routines will return NS_OK if they have a value,
938 // in which case the nsLookAndFeel should use that value;
939 // otherwise we'll return NS_ERROR_NOT_AVAILABLE, in which case, the
940 // platform-specific nsLookAndFeel should use its own values instead.
941 nsresult
nsXPLookAndFeel::GetColorValue(ColorID aID
, ColorScheme aScheme
,
942 UseStandins aUseStandins
,
948 #ifdef DEBUG_SYSTEM_COLOR_USE
949 if (NS_SUCCEEDED(SystemColorUseDebuggingColor(aID
, aResult
))) {
954 auto& cache
= sColorCaches
.Get(aScheme
, aUseStandins
);
955 if (const auto* cached
= cache
.Get(aID
)) {
956 if (cached
->isNothing()) {
957 return NS_ERROR_FAILURE
;
959 aResult
= cached
->value();
963 // NOTE: Servo holds a lock and the main thread is paused, so writing to the
964 // global cache here is fine.
965 auto result
= GetUncachedColor(aID
, aScheme
, aUseStandins
);
966 cache
.Insert(aID
, result
);
968 return NS_ERROR_FAILURE
;
974 Maybe
<nscolor
> nsXPLookAndFeel::GetUncachedColor(ColorID aID
,
976 UseStandins aUseStandins
) {
977 if (aUseStandins
== UseStandins::Yes
) {
978 return Some(GetStandinForNativeColor(aID
, aScheme
));
981 if (NS_SUCCEEDED(GetColorFromPref(aID
, aScheme
, r
))) {
984 if (NS_SUCCEEDED(NativeGetColor(aID
, aScheme
, r
))) {
985 if (gfxPlatform::GetCMSMode() == CMSMode::All
&& !IsSpecialColor(aID
, r
)) {
986 qcms_transform
* transform
= gfxPlatform::GetCMSInverseRGBTransform();
989 color
[0] = NS_GET_R(r
);
990 color
[1] = NS_GET_G(r
);
991 color
[2] = NS_GET_B(r
);
992 color
[3] = NS_GET_A(r
);
993 qcms_transform_data(transform
, color
, color
, 1);
994 r
= NS_RGBA(color
[0], color
[1], color
[2], color
[3]);
1003 nsresult
nsXPLookAndFeel::GetIntValue(IntID aID
, int32_t& aResult
) {
1004 if (!sInitialized
) {
1008 if (const auto* cached
= sIntCache
.Get(aID
)) {
1009 if (cached
->isNothing()) {
1010 return NS_ERROR_FAILURE
;
1012 aResult
= cached
->value();
1016 if (NS_SUCCEEDED(Preferences::GetInt(sIntPrefs
[size_t(aID
)], &aResult
))) {
1017 sIntCache
.Insert(aID
, Some(aResult
));
1021 if (NS_FAILED(NativeGetInt(aID
, aResult
))) {
1022 sIntCache
.Insert(aID
, Nothing());
1023 return NS_ERROR_FAILURE
;
1026 sIntCache
.Insert(aID
, Some(aResult
));
1030 nsresult
nsXPLookAndFeel::GetFloatValue(FloatID aID
, float& aResult
) {
1031 if (!sInitialized
) {
1035 if (const auto* cached
= sFloatCache
.Get(aID
)) {
1036 if (cached
->isNothing()) {
1037 return NS_ERROR_FAILURE
;
1039 aResult
= cached
->value();
1044 if (NS_SUCCEEDED(Preferences::GetInt(sFloatPrefs
[size_t(aID
)], &pref
))) {
1045 aResult
= float(pref
) / 100.0f
;
1046 sFloatCache
.Insert(aID
, Some(aResult
));
1050 if (NS_FAILED(NativeGetFloat(aID
, aResult
))) {
1051 sFloatCache
.Insert(aID
, Nothing());
1052 return NS_ERROR_FAILURE
;
1055 sFloatCache
.Insert(aID
, Some(aResult
));
1059 bool nsXPLookAndFeel::LookAndFeelFontToStyle(const LookAndFeelFont
& aFont
,
1061 gfxFontStyle
& aStyle
) {
1062 if (!aFont
.haveFont()) {
1065 aName
= aFont
.name();
1066 aStyle
= gfxFontStyle();
1067 aStyle
.size
= aFont
.size();
1068 aStyle
.weight
= FontWeight::FromInt(aFont
.weight());
1070 aFont
.italic() ? FontSlantStyle::ITALIC
: FontSlantStyle::NORMAL
;
1071 aStyle
.systemFont
= true;
1075 widget::LookAndFeelFont
nsXPLookAndFeel::StyleToLookAndFeelFont(
1076 const nsAString
& aName
, const gfxFontStyle
& aStyle
) {
1077 LookAndFeelFont font
;
1078 font
.haveFont() = true;
1079 font
.name() = aName
;
1080 font
.size() = aStyle
.size
;
1081 font
.weight() = aStyle
.weight
.ToFloat();
1082 font
.italic() = aStyle
.style
.IsItalic();
1083 MOZ_ASSERT(aStyle
.style
.IsNormal() || aStyle
.style
.IsItalic(),
1084 "Cannot handle oblique font style");
1087 // Assert that all the remaining font style properties have their
1089 gfxFontStyle candidate
= aStyle
;
1090 gfxFontStyle defaults
{};
1091 candidate
.size
= defaults
.size
;
1092 candidate
.weight
= defaults
.weight
;
1093 candidate
.style
= defaults
.style
;
1094 MOZ_ASSERT(candidate
.Equals(defaults
),
1095 "Some font style properties not supported");
1101 bool nsXPLookAndFeel::GetFontValue(FontID aID
, nsString
& aName
,
1102 gfxFontStyle
& aStyle
) {
1103 if (const LookAndFeelFont
* cached
= sFontCache
.Get(aID
)) {
1104 return LookAndFeelFontToStyle(*cached
, aName
, aStyle
);
1107 LookAndFeelFont font
;
1108 auto GetFontsFromPrefs
= [&]() -> bool {
1109 nsDependentCString
pref(sFontPrefs
[size_t(aID
)]);
1110 if (NS_FAILED(Preferences::GetString(pref
.get(), aName
))) {
1113 font
.haveFont() = true;
1114 font
.name() = aName
;
1115 font
.size() = Preferences::GetFloat(nsAutoCString(pref
+ ".size"_ns
).get());
1116 // This is written this way rather than using the fallback so that an empty
1117 // pref (such like the one about:config creates) doesn't cause system fonts
1118 // to have zero-size.
1119 if (font
.size() < 1.0f
) {
1120 font
.size() = StyleFONT_MEDIUM_PX
;
1122 font
.weight() = Preferences::GetFloat(
1123 nsAutoCString(pref
+ ".weight"_ns
).get(), FontWeight::NORMAL
.ToFloat());
1125 Preferences::GetBool(nsAutoCString(pref
+ ".italic"_ns
).get());
1129 if (GetFontsFromPrefs()) {
1130 LookAndFeelFontToStyle(font
, aName
, aStyle
);
1131 } else if (NativeGetFont(aID
, aName
, aStyle
)) {
1132 font
= StyleToLookAndFeelFont(aName
, aStyle
);
1134 MOZ_ASSERT(!font
.haveFont());
1136 bool success
= font
.haveFont();
1137 sFontCache
.Insert(aID
, std::move(font
));
1141 void nsXPLookAndFeel::RefreshImpl() {
1142 // Wipe out our caches.
1143 sColorCaches
.Clear();
1145 sFloatCache
.Clear();
1148 if (XRE_IsParentProcess()) {
1149 nsLayoutUtils::RecomputeSmoothScrollDefault();
1150 // Clear any cached FullLookAndFeel data, which is now invalid.
1151 widget::RemoteLookAndFeel::ClearCachedData();
1155 static bool sRecordedLookAndFeelTelemetry
= false;
1157 void nsXPLookAndFeel::RecordTelemetry() {
1158 if (!XRE_IsParentProcess()) {
1162 if (sRecordedLookAndFeelTelemetry
) {
1166 sRecordedLookAndFeelTelemetry
= true;
1169 Telemetry::ScalarSet(
1170 Telemetry::ScalarID::WIDGET_DARK_MODE
,
1171 NS_SUCCEEDED(GetIntValue(IntID::SystemUsesDarkTheme
, i
)) && i
!= 0);
1173 RecordLookAndFeelSpecificTelemetry();
1178 bool LookAndFeel::sGlobalThemeChanged
;
1179 static widget::ThemeChangeKind sGlobalThemeChangeKind
{0};
1181 void LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind aKind
) {
1182 sGlobalThemeChanged
= true;
1183 sGlobalThemeChangeKind
|= aKind
;
1185 if (nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService()) {
1186 const char16_t kind
[] = {char16_t(aKind
), 0};
1187 obs
->NotifyObservers(nullptr, "internal-look-and-feel-changed", kind
);
1191 void LookAndFeel::DoHandleGlobalThemeChange() {
1192 MOZ_ASSERT(sGlobalThemeChanged
);
1193 sGlobalThemeChanged
= false;
1194 auto kind
= std::exchange(sGlobalThemeChangeKind
, widget::ThemeChangeKind(0));
1196 // Tell the theme that it changed, so it can flush any handles to stale theme
1199 // We can use the *DoNotUseDirectly functions directly here, because we want
1200 // to notify all possible themes in a given process (but just once).
1201 if (XRE_IsParentProcess() ||
1202 !StaticPrefs::widget_non_native_theme_enabled()) {
1203 if (nsCOMPtr
<nsITheme
> theme
= do_GetNativeThemeDoNotUseDirectly()) {
1204 theme
->ThemeChanged();
1207 if (nsCOMPtr
<nsITheme
> theme
= do_GetBasicNativeThemeDoNotUseDirectly()) {
1208 theme
->ThemeChanged();
1211 // Clear all cached LookAndFeel colors.
1212 LookAndFeel::Refresh();
1214 // Reset default background and foreground colors for the document since they
1215 // may be using system colors, color scheme, etc.
1216 PreferenceSheet::Refresh();
1218 // Vector images (SVG) may be using theme colors so we discard all cached
1219 // surfaces. (We could add a vector image only version of DiscardAll, but
1220 // in bug 940625 we decided theme changes are rare enough not to bother.)
1221 image::SurfaceCacheUtils::DiscardAll();
1223 if (XRE_IsParentProcess()) {
1224 dom::ContentParent::BroadcastThemeUpdate(kind
);
1227 nsContentUtils::AddScriptRunner(
1228 NS_NewRunnableFunction("HandleGlobalThemeChange", [] {
1229 if (nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService()) {
1230 obs
->NotifyObservers(nullptr, "look-and-feel-changed", nullptr);
1235 #define BIT_FOR(_c) (1ull << size_t(ColorID::_c))
1237 // We want to use a non-native color scheme for the non-native theme (except in
1238 // high-contrast mode), so spoof some of the colors with stand-ins to prevent
1239 // lack of contrast.
1240 static constexpr std::bitset
<size_t(ColorID::End
)> sNonNativeThemeStandinColors
{
1241 // Used by default button styles.
1242 BIT_FOR(Buttonface
) | BIT_FOR(Buttontext
) | BIT_FOR(MozButtonhoverface
) |
1243 BIT_FOR(MozButtonhovertext
) | BIT_FOR(MozButtonactiveface
) |
1244 BIT_FOR(MozButtonactivetext
) | BIT_FOR(MozButtondisabledface
) |
1245 BIT_FOR(Buttonborder
) |
1246 // Used by select elements.
1247 BIT_FOR(MozCombobox
) | BIT_FOR(MozComboboxtext
) |
1248 BIT_FOR(Threedlightshadow
) |
1249 // For symmetry with the above.
1250 BIT_FOR(Threeddarkshadow
) |
1251 // Used by fieldset borders.
1252 BIT_FOR(Threedface
) |
1253 // Used by input / textarea.
1254 BIT_FOR(Field
) | BIT_FOR(Fieldtext
) |
1255 // Used by disabled form controls.
1256 BIT_FOR(MozDisabledfield
) | BIT_FOR(Graytext
) |
1257 // Some pages expect these to return windows-like colors, see bug 1773795.
1258 // Also, per spec these should match Canvas/CanvasText, see
1259 // https://drafts.csswg.org/css-color-4/#window
1260 BIT_FOR(Window
) | BIT_FOR(Windowtext
)};
1263 static bool ShouldUseStandinsForNativeColorForNonNativeTheme(
1264 const dom::Document
& aDoc
, LookAndFeel::ColorID aColor
,
1265 const PreferenceSheet::Prefs
& aPrefs
) {
1266 const bool shouldUseStandinsForColor
= [&] {
1267 if (sNonNativeThemeStandinColors
[size_t(aColor
)]) {
1270 // There are platforms where we want the content-exposed accent color to be
1271 // the windows blue rather than the system accent color, for now.
1272 return !StaticPrefs::widget_non_native_theme_use_theme_accent() &&
1273 (aColor
== LookAndFeel::ColorID::Accentcolor
||
1274 aColor
== LookAndFeel::ColorID::Accentcolortext
);
1277 return shouldUseStandinsForColor
&& aDoc
.ShouldAvoidNativeTheme() &&
1278 !aPrefs
.NonNativeThemeShouldBeHighContrast();
1281 bool LookAndFeel::IsDarkColor(nscolor aColor
) {
1282 // Given https://www.w3.org/TR/WCAG20/#contrast-ratiodef, this is the
1283 // threshold that tells us whether contrast is better against white or black.
1285 // Contrast ratio against black is: (L + 0.05) / 0.05
1286 // Contrast ratio against white is: 1.05 / (L + 0.05)
1288 // So the intersection is:
1290 // (L + 0.05) / 0.05 = 1.05 / (L + 0.05)
1292 // And the solution to that equation is:
1294 // sqrt(1.05 * 0.05) - 0.05
1296 // So we consider a color dark if the contrast is below this threshold, and
1297 // it's at least half-opaque.
1298 constexpr float kThreshold
= 0.179129;
1299 return NS_GET_A(aColor
) > 127 &&
1300 RelativeLuminanceUtils::Compute(aColor
) < kThreshold
;
1303 ColorScheme
LookAndFeel::ColorSchemeForStyle(
1304 const dom::Document
& aDoc
, const StyleColorSchemeFlags
& aFlags
,
1305 ColorSchemeMode aMode
) {
1306 const auto& prefs
= PreferenceSheet::PrefsFor(aDoc
);
1307 StyleColorSchemeFlags
style(aFlags
);
1309 style
._0
= aDoc
.GetColorSchemeBits();
1311 const bool supportsDark
= bool(style
& StyleColorSchemeFlags::DARK
);
1312 const bool supportsLight
= bool(style
& StyleColorSchemeFlags::LIGHT
);
1313 if (supportsLight
&& supportsDark
) {
1314 // Both color-schemes are explicitly supported, use the preferred one.
1315 return aDoc
.PreferredColorScheme();
1317 if (supportsDark
|| supportsLight
) {
1318 // One color-scheme is explicitly supported and one isn't, so use the one
1319 // the content supports.
1320 return supportsDark
? ColorScheme::Dark
: ColorScheme::Light
;
1322 // No value specified. Chrome docs, and forced-colors mode always supports
1323 // both, so use the preferred color-scheme.
1324 if (aMode
== ColorSchemeMode::Preferred
|| aDoc
.ChromeRulesEnabled() ||
1325 !prefs
.mUseDocumentColors
) {
1326 return aDoc
.PreferredColorScheme();
1328 // Otherwise default content to light.
1329 return ColorScheme::Light
;
1332 LookAndFeel::ColorScheme
LookAndFeel::ColorSchemeForFrame(
1333 const nsIFrame
* aFrame
, ColorSchemeMode aMode
) {
1334 return ColorSchemeForStyle(*aFrame
->PresContext()->Document(),
1335 aFrame
->StyleUI()->mColorScheme
.bits
, aMode
);
1339 Maybe
<nscolor
> LookAndFeel::GetColor(ColorID aId
, ColorScheme aScheme
,
1340 UseStandins aUseStandins
) {
1342 nsresult rv
= nsLookAndFeel::GetInstance()->GetColorValue(
1343 aId
, aScheme
, aUseStandins
, result
);
1344 if (NS_FAILED(rv
)) {
1347 return Some(result
);
1350 // Returns whether there is a CSS color name for this color.
1351 static bool ColorIsCSSAccessible(LookAndFeel::ColorID aId
) {
1352 using ColorID
= LookAndFeel::ColorID
;
1355 case ColorID::TextSelectDisabledBackground
:
1356 case ColorID::TextSelectAttentionBackground
:
1357 case ColorID::TextSelectAttentionForeground
:
1358 case ColorID::TextHighlightBackground
:
1359 case ColorID::TextHighlightForeground
:
1360 case ColorID::ThemedScrollbar
:
1361 case ColorID::ThemedScrollbarInactive
:
1362 case ColorID::ThemedScrollbarThumb
:
1363 case ColorID::ThemedScrollbarThumbActive
:
1364 case ColorID::ThemedScrollbarThumbInactive
:
1365 case ColorID::ThemedScrollbarThumbHover
:
1366 case ColorID::IMERawInputBackground
:
1367 case ColorID::IMERawInputForeground
:
1368 case ColorID::IMERawInputUnderline
:
1369 case ColorID::IMESelectedRawTextBackground
:
1370 case ColorID::IMESelectedRawTextForeground
:
1371 case ColorID::IMESelectedRawTextUnderline
:
1372 case ColorID::IMEConvertedTextBackground
:
1373 case ColorID::IMEConvertedTextForeground
:
1374 case ColorID::IMEConvertedTextUnderline
:
1375 case ColorID::IMESelectedConvertedTextBackground
:
1376 case ColorID::IMESelectedConvertedTextForeground
:
1377 case ColorID::IMESelectedConvertedTextUnderline
:
1378 case ColorID::SpellCheckerUnderline
:
1387 LookAndFeel::UseStandins
LookAndFeel::ShouldUseStandins(
1388 const dom::Document
& aDoc
, ColorID aId
) {
1389 const auto& prefs
= PreferenceSheet::PrefsFor(aDoc
);
1390 if (ShouldUseStandinsForNativeColorForNonNativeTheme(aDoc
, aId
, prefs
)) {
1391 return UseStandins::Yes
;
1393 if (prefs
.mUseStandins
&& ColorIsCSSAccessible(aId
)) {
1394 return UseStandins::Yes
;
1396 return UseStandins::No
;
1399 Maybe
<nscolor
> LookAndFeel::GetColor(ColorID aId
, const nsIFrame
* aFrame
) {
1400 const auto* doc
= aFrame
->PresContext()->Document();
1401 return GetColor(aId
, ColorSchemeForFrame(aFrame
),
1402 ShouldUseStandins(*doc
, aId
));
1406 nsresult
LookAndFeel::GetInt(IntID aID
, int32_t* aResult
) {
1407 return nsLookAndFeel::GetInstance()->GetIntValue(aID
, *aResult
);
1411 nsresult
LookAndFeel::GetFloat(FloatID aID
, float* aResult
) {
1412 return nsLookAndFeel::GetInstance()->GetFloatValue(aID
, *aResult
);
1416 bool LookAndFeel::GetFont(FontID aID
, nsString
& aName
, gfxFontStyle
& aStyle
) {
1417 return nsLookAndFeel::GetInstance()->GetFontValue(aID
, aName
, aStyle
);
1421 char16_t
LookAndFeel::GetPasswordCharacter() {
1422 return nsLookAndFeel::GetInstance()->GetPasswordCharacterImpl();
1426 bool LookAndFeel::GetEchoPassword() {
1427 if (StaticPrefs::editor_password_mask_delay() >= 0) {
1428 return StaticPrefs::editor_password_mask_delay() > 0;
1430 return nsLookAndFeel::GetInstance()->GetEchoPasswordImpl();
1434 uint32_t LookAndFeel::GetPasswordMaskDelay() {
1435 int32_t delay
= StaticPrefs::editor_password_mask_delay();
1437 return nsLookAndFeel::GetInstance()->GetPasswordMaskDelayImpl();
1442 bool LookAndFeel::DrawInTitlebar() {
1443 switch (StaticPrefs::browser_tabs_inTitlebar()) {
1451 return nsLookAndFeel::GetInstance()->GetDefaultDrawInTitlebar();
1454 void LookAndFeel::GetThemeInfo(nsACString
& aOut
) {
1455 nsLookAndFeel::GetInstance()->GetThemeInfo(aOut
);
1458 uint32_t LookAndFeel::GetMenuAccessKey() {
1459 return StaticPrefs::ui_key_menuAccessKey();
1462 Modifiers
LookAndFeel::GetMenuAccessKeyModifiers() {
1463 switch (GetMenuAccessKey()) {
1464 case dom::KeyboardEvent_Binding::DOM_VK_SHIFT
:
1465 return MODIFIER_SHIFT
;
1466 case dom::KeyboardEvent_Binding::DOM_VK_CONTROL
:
1467 return MODIFIER_CONTROL
;
1468 case dom::KeyboardEvent_Binding::DOM_VK_ALT
:
1469 return MODIFIER_ALT
;
1470 case dom::KeyboardEvent_Binding::DOM_VK_META
:
1471 case dom::KeyboardEvent_Binding::DOM_VK_WIN
:
1472 return MODIFIER_META
;
1479 void LookAndFeel::Refresh() {
1480 nsLookAndFeel::GetInstance()->RefreshImpl();
1481 widget::Theme::LookAndFeelChanged();
1485 void LookAndFeel::NativeInit() { nsLookAndFeel::GetInstance()->NativeInit(); }
1488 void LookAndFeel::SetData(widget::FullLookAndFeel
&& aTables
) {
1489 nsLookAndFeel::GetInstance()->SetDataImpl(std::move(aTables
));
1492 } // namespace mozilla