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",
156 "ui.macGraphiteTheme",
159 "ui.alertNotificationOrigin",
161 "ui.IMERawInputUnderlineStyle",
162 "ui.IMESelectedRawTextUnderlineStyle",
163 "ui.IMEConvertedTextUnderlineStyle",
164 "ui.IMESelectedConvertedTextUnderlineStyle",
165 "ui.SpellCheckerUnderlineStyle",
167 "ui.scrollbarButtonAutoRepeatBehavior",
169 "ui.swipeAnimationEnabled",
170 "ui.scrollbarDisplayOnMouseMove",
171 "ui.scrollbarFadeBeginDelay",
172 "ui.scrollbarFadeDuration",
173 "ui.contextMenuOffsetVertical",
174 "ui.contextMenuOffsetHorizontal",
175 "ui.GtkCSDAvailable",
176 "ui.GtkCSDMinimizeButton",
177 "ui.GtkCSDMaximizeButton",
178 "ui.GtkCSDCloseButton",
179 "ui.GtkCSDMinimizeButtonPosition",
180 "ui.GtkCSDMaximizeButtonPosition",
181 "ui.GtkCSDCloseButtonPosition",
182 "ui.GtkCSDReversedPlacement",
183 "ui.systemUsesDarkTheme",
184 "ui.prefersReducedMotion",
185 "ui.prefersReducedTransparency",
187 "ui.primaryPointerCapabilities",
188 "ui.allPointerCapabilities",
189 "ui.systemScrollbarSize",
190 "ui.touchDeviceSupportPresent",
193 "ui.videoDynamicRange",
194 "ui.panelAnimations",
197 static_assert(ArrayLength(sIntPrefs
) == size_t(LookAndFeel::IntID::End
),
198 "Should have a pref for each int value");
200 // This array MUST be kept in the same order as the float id list in
203 static const char sFloatPrefs
[][37] = {
204 "ui.IMEUnderlineRelativeSize",
205 "ui.SpellCheckerUnderlineRelativeSize",
206 "ui.caretAspectRatio",
207 "ui.textScaleFactor",
212 static_assert(ArrayLength(sFloatPrefs
) == size_t(LookAndFeel::FloatID::End
),
213 "Should have a pref for each float value");
215 // This array MUST be kept in the same order as the color list in
216 // specified/color.rs
217 static const char sColorPrefs
[][41] = {
223 "ui.buttonhighlight",
229 "ui.-moz-disabledfield",
233 "ui.-moz-comboboxtext",
239 "ui.inactivecaption",
240 "ui.inactivecaptiontext",
246 "ui.threeddarkshadow",
248 "ui.threedhighlight",
249 "ui.threedlightshadow",
254 "ui.-moz-buttondefault",
255 "ui.-moz-default-color",
256 "ui.-moz-default-background-color",
258 "ui.-moz-dialogtext",
259 "ui.-moz-dragtargetzone",
260 "ui.-moz-cellhighlight",
261 "ui.-moz_cellhighlighttext",
263 "ui.selecteditemtext",
264 "ui.-moz-buttonhoverface",
265 "ui.-moz_buttonhovertext",
267 "ui.-moz_menuhoverdisabled",
268 "ui.-moz_menuhovertext",
269 "ui.-moz_menubartext",
270 "ui.-moz_menubarhovertext",
271 "ui.-moz_eventreerow",
272 "ui.-moz_oddtreerow",
273 "ui.-moz-buttonactivetext",
274 "ui.-moz-buttonactiveface",
275 "ui.-moz-buttondisabledface",
276 "ui.-moz_mac_chrome_active",
277 "ui.-moz_mac_chrome_inactive",
278 "ui.-moz-mac-defaultbuttontext",
279 "ui.-moz-mac-focusring",
280 "ui.-moz-mac-menuselect",
281 "ui.-moz-mac-menushadow",
282 "ui.-moz-mac-menutextdisable",
283 "ui.-moz-mac-menutextselect",
284 "ui.-moz_mac_disabledtoolbartext",
285 "ui.-moz-mac-secondaryhighlight",
286 "ui.-moz-mac-menupopup",
287 "ui.-moz-mac-menuitem",
288 "ui.-moz-mac-active-menuitem",
289 "ui.-moz-mac-source-list",
290 "ui.-moz-mac-source-list-selection",
291 "ui.-moz-mac-active-source-list-selection",
292 "ui.-moz-mac-tooltip",
294 "ui.accentcolortext",
295 "ui.-moz-autofill-background",
296 "ui.-moz-win-mediatext",
297 "ui.-moz-win-communicationstext",
298 "ui.-moz-nativehyperlinktext",
299 "ui.-moz-nativevisitedhyperlinktext",
300 "ui.-moz-hyperlinktext",
301 "ui.-moz-activehyperlinktext",
302 "ui.-moz-visitedhyperlinktext",
303 "ui.-moz-colheadertext",
304 "ui.-moz-colheaderhovertext",
305 "ui.textSelectDisabledBackground",
306 "ui.textSelectAttentionBackground",
307 "ui.textSelectAttentionForeground",
308 "ui.textHighlightBackground",
309 "ui.textHighlightForeground",
310 "ui.IMERawInputBackground",
311 "ui.IMERawInputForeground",
312 "ui.IMERawInputUnderline",
313 "ui.IMESelectedRawTextBackground",
314 "ui.IMESelectedRawTextForeground",
315 "ui.IMESelectedRawTextUnderline",
316 "ui.IMEConvertedTextBackground",
317 "ui.IMEConvertedTextForeground",
318 "ui.IMEConvertedTextUnderline",
319 "ui.IMESelectedConvertedTextBackground",
320 "ui.IMESelectedConvertedTextForeground",
321 "ui.IMESelectedConvertedTextUnderline",
322 "ui.SpellCheckerUnderline",
323 "ui.themedScrollbar",
324 "ui.themedScrollbarInactive",
325 "ui.themedScrollbarThumb",
326 "ui.themedScrollbarThumbHover",
327 "ui.themedScrollbarThumbActive",
328 "ui.themedScrollbarThumbInactive",
331 static_assert(ArrayLength(sColorPrefs
) == size_t(LookAndFeel::ColorID::End
),
332 "Should have a pref for each color value");
334 // This array MUST be kept in the same order as the SystemFont enum.
335 static const char sFontPrefs
[][41] = {
339 "ui.font.message-box",
340 "ui.font.small-caption",
341 "ui.font.status-bar",
342 "ui.font.-moz-pull-down-menu",
343 "ui.font.-moz-button",
345 "ui.font.-moz-field",
348 static_assert(ArrayLength(sFontPrefs
) == size_t(LookAndFeel::FontID::End
),
349 "Should have a pref for each font value");
351 const char* nsXPLookAndFeel::GetColorPrefName(ColorID aId
) {
352 return sColorPrefs
[size_t(aId
)];
355 bool nsXPLookAndFeel::sInitialized
= false;
357 nsXPLookAndFeel
* nsXPLookAndFeel::sInstance
= nullptr;
358 bool nsXPLookAndFeel::sShutdown
= false;
360 auto LookAndFeel::SystemZoomSettings() -> ZoomSettings
{
361 ZoomSettings settings
;
362 switch (StaticPrefs::browser_display_os_zoom_behavior()) {
367 settings
.mFullZoom
= GetTextScaleFactor();
370 settings
.mTextZoom
= GetTextScaleFactor();
377 nsXPLookAndFeel
* nsXPLookAndFeel::GetInstance() {
382 NS_ENSURE_TRUE(!sShutdown
, nullptr);
384 // If we're in a content process, then the parent process will have supplied
385 // us with an initial FullLookAndFeel object.
386 // We grab this data from the ContentChild,
387 // where it's been temporarily stashed, and initialize our new LookAndFeel
390 FullLookAndFeel
* lnf
= nullptr;
392 if (auto* cc
= mozilla::dom::ContentChild::GetSingleton()) {
393 lnf
= &cc
->BorrowLookAndFeelData();
397 sInstance
= new widget::RemoteLookAndFeel(std::move(*lnf
));
398 } else if (gfxPlatform::IsHeadless()) {
399 sInstance
= new widget::HeadlessLookAndFeel();
401 sInstance
= new nsLookAndFeel();
404 // This is only ever used once during initialization, and can be cleared now.
409 widget::Theme::Init();
414 void nsXPLookAndFeel::Shutdown() {
423 // This keeps strings alive, so need to clear to make leak checking happy.
426 widget::Theme::Shutdown();
429 static void IntPrefChanged(const nsACString
& aPref
) {
430 // Most Int prefs can't change our system colors or fonts, but
431 // ui.systemUsesDarkTheme can, since it affects the effective color-scheme
432 // (affecting system colors).
433 auto changeKind
= aPref
.EqualsLiteral("ui.systemUsesDarkTheme")
434 ? widget::ThemeChangeKind::Style
435 : widget::ThemeChangeKind::MediaQueriesOnly
;
436 LookAndFeel::NotifyChangedAllWindows(changeKind
);
439 static void FloatPrefChanged(const nsACString
& aPref
) {
440 // Most float prefs can't change our system colors or fonts, but
441 // textScaleFactor affects layout.
442 auto changeKind
= aPref
.EqualsLiteral("ui.textScaleFactor")
443 ? widget::ThemeChangeKind::StyleAndLayout
444 : widget::ThemeChangeKind::MediaQueriesOnly
;
445 LookAndFeel::NotifyChangedAllWindows(changeKind
);
448 static void ColorPrefChanged() {
449 // Color prefs affect style, because they by definition change system colors.
450 LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind::Style
);
453 static void FontPrefChanged() {
454 // Color prefs affect style, because they by definition change system fonts.
455 LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind::Style
);
459 void nsXPLookAndFeel::OnPrefChanged(const char* aPref
, void* aClosure
) {
460 nsDependentCString
prefName(aPref
);
461 for (const char* pref
: sIntPrefs
) {
462 if (prefName
.Equals(pref
)) {
463 IntPrefChanged(prefName
);
468 for (const char* pref
: sFloatPrefs
) {
469 if (prefName
.Equals(pref
)) {
470 FloatPrefChanged(prefName
);
475 for (const char* pref
: sColorPrefs
) {
476 // We use StringBeginsWith to handle .dark prefs too.
477 if (StringBeginsWith(prefName
, nsDependentCString(pref
))) {
483 for (const char* pref
: sFontPrefs
) {
484 if (StringBeginsWith(prefName
, nsDependentCString(pref
))) {
491 bool LookAndFeel::WindowsNonNativeMenusEnabled() {
492 switch (StaticPrefs::browser_display_windows_non_native_menus()) {
499 return IsWin10OrLater();
506 static constexpr struct {
507 nsLiteralCString mName
;
508 widget::ThemeChangeKind mChangeKind
=
509 widget::ThemeChangeKind::MediaQueriesOnly
;
510 } kMediaQueryPrefs
[] = {
511 {"browser.display.windows.non_native_menus"_ns
},
512 // Affects whether standins are used for the accent color.
513 {"widget.non-native-theme.use-theme-accent"_ns
,
514 widget::ThemeChangeKind::Style
},
515 // These two affect system colors on Windows.
516 {"widget.windows.uwp-system-colors.enabled"_ns
,
517 widget::ThemeChangeKind::Style
},
518 // These two affect system colors on Windows.
519 {"widget.windows.uwp-system-colors.highlight-accent"_ns
,
520 widget::ThemeChangeKind::Style
},
522 {"layout.css.prefers-color-scheme.content-override"_ns
,
523 widget::ThemeChangeKind::Style
},
524 // Affects media queries and scrollbar sizes, so gotta relayout.
525 {"widget.gtk.overlay-scrollbars.enabled"_ns
,
526 widget::ThemeChangeKind::StyleAndLayout
},
527 // Affects zoom settings which includes text and full zoom.
528 {"browser.display.os-zoom-behavior"_ns
,
529 widget::ThemeChangeKind::StyleAndLayout
},
530 // This affects not only the media query, but also the native theme, so we
531 // need to re-layout.
532 {"browser.theme.toolbar-theme"_ns
, widget::ThemeChangeKind::AllBits
},
533 {"browser.theme.content-theme"_ns
},
534 {"mathml.legacy_maction_and_semantics_implementations.disabled"_ns
},
535 {"mathml.ms_lquote_rquote_attributes.disabled"_ns
},
536 {"dom.element.popover.enabled"_ns
},
539 // Read values from the user's preferences.
540 // This is done once at startup, but since the user's preferences
541 // haven't actually been read yet at that time, we also have to
542 // set a callback to inform us of changes to each pref.
543 void nsXPLookAndFeel::Init() {
544 MOZ_RELEASE_ASSERT(NS_IsMainThread());
546 // Say we're already initialized, and take the chance that it might fail;
547 // protects against some other process writing to our static variables.
550 RecomputeColorSchemes();
552 if (XRE_IsParentProcess()) {
553 nsLayoutUtils::RecomputeSmoothScrollDefault();
556 // XXX If we could reorganize the pref names, we should separate the branch
557 // for each types. Then, we could reduce the unnecessary loop from
558 // nsXPLookAndFeel::OnPrefChanged().
559 Preferences::RegisterPrefixCallback(OnPrefChanged
, "ui.");
560 // We really do just want the accessibility.tabfocus pref, not other prefs
561 // that start with that string.
562 Preferences::RegisterCallback(OnPrefChanged
, "accessibility.tabfocus");
564 for (auto& pref
: kMediaQueryPrefs
) {
565 Preferences::RegisterCallback(
566 [](const char*, void* aChangeKind
) {
568 widget::ThemeChangeKind(reinterpret_cast<uintptr_t>(aChangeKind
));
569 LookAndFeel::NotifyChangedAllWindows(changeKind
);
571 pref
.mName
, reinterpret_cast<void*>(uintptr_t(pref
.mChangeKind
)));
575 nsXPLookAndFeel::~nsXPLookAndFeel() {
576 NS_ASSERTION(sInstance
== this,
577 "This destroying instance isn't the singleton instance");
581 static bool IsSpecialColor(LookAndFeel::ColorID aID
, nscolor aColor
) {
582 using ColorID
= LookAndFeel::ColorID
;
584 if (aColor
== NS_SAME_AS_FOREGROUND_COLOR
) {
589 case ColorID::IMESelectedRawTextBackground
:
590 case ColorID::IMESelectedConvertedTextBackground
:
591 case ColorID::IMERawInputBackground
:
592 case ColorID::IMEConvertedTextBackground
:
593 case ColorID::IMESelectedRawTextForeground
:
594 case ColorID::IMESelectedConvertedTextForeground
:
595 case ColorID::IMERawInputForeground
:
596 case ColorID::IMEConvertedTextForeground
:
597 case ColorID::IMERawInputUnderline
:
598 case ColorID::IMEConvertedTextUnderline
:
599 case ColorID::IMESelectedRawTextUnderline
:
600 case ColorID::IMESelectedConvertedTextUnderline
:
601 case ColorID::SpellCheckerUnderline
:
602 return NS_IS_SELECTION_SPECIAL_COLOR(aColor
);
607 * In GetColor(), every color that is not a special color is color
608 * corrected. Use false to make other colors color corrected.
613 nscolor
nsXPLookAndFeel::GetStandinForNativeColor(ColorID aID
,
614 ColorScheme aScheme
) {
615 if (aScheme
== ColorScheme::Dark
) {
616 if (auto color
= GenericDarkColor(aID
)) {
621 // The stand-in colors are taken from what the non-native theme needs (for
622 // field/button colors), the Windows 7 Aero theme except Mac-specific colors
623 // which are taken from Mac OS 10.7.
625 #define COLOR(name_, r, g, b) \
626 case ColorID::name_: \
627 return NS_RGB(r, g, b);
629 #define COLORA(name_, r, g, b, a) \
630 case ColorID::name_: \
631 return NS_RGBA(r, g, b, a);
634 // These are here for the purposes of headless mode.
635 case ColorID::IMESelectedRawTextBackground
:
636 case ColorID::IMESelectedConvertedTextBackground
:
637 case ColorID::IMERawInputBackground
:
638 case ColorID::IMEConvertedTextBackground
:
639 return NS_TRANSPARENT
;
640 case ColorID::IMESelectedRawTextForeground
:
641 case ColorID::IMESelectedConvertedTextForeground
:
642 case ColorID::IMERawInputForeground
:
643 case ColorID::IMEConvertedTextForeground
:
644 return NS_SAME_AS_FOREGROUND_COLOR
;
645 case ColorID::IMERawInputUnderline
:
646 case ColorID::IMEConvertedTextUnderline
:
647 return NS_40PERCENT_FOREGROUND_COLOR
;
648 case ColorID::Accentcolor
:
649 return widget::sDefaultAccent
.ToABGR();
650 case ColorID::Accentcolortext
:
651 return widget::sDefaultAccentText
.ToABGR();
652 COLOR(SpellCheckerUnderline
, 0xff, 0x00, 0x00)
653 COLOR(TextSelectDisabledBackground
, 0xaa, 0xaa, 0xaa)
656 COLOR(Activeborder
, 0xB4, 0xB4, 0xB4)
657 COLOR(Activecaption
, 0x99, 0xB4, 0xD1)
658 COLOR(Appworkspace
, 0xAB, 0xAB, 0xAB)
659 COLOR(Background
, 0x00, 0x00, 0x00)
660 COLOR(Buttonhighlight
, 0xFF, 0xFF, 0xFF)
661 COLOR(Buttonshadow
, 0xA0, 0xA0, 0xA0)
663 // Buttons and comboboxes should be kept in sync since they are drawn with
664 // the same colors by the non-native theme.
665 COLOR(Buttonface
, 0xe9, 0xe9, 0xed)
666 COLORA(MozButtondisabledface
, 0xe9, 0xe9, 0xed, 128)
668 COLOR(MozCombobox
, 0xe9, 0xe9, 0xed)
670 COLOR(Buttontext
, 0x00, 0x00, 0x00)
671 COLOR(MozComboboxtext
, 0x00, 0x00, 0x00)
673 COLOR(Captiontext
, 0x00, 0x00, 0x00)
674 COLOR(Graytext
, 0x6D, 0x6D, 0x6D)
675 COLOR(Highlight
, 0x33, 0x99, 0xFF)
676 COLOR(Highlighttext
, 0xFF, 0xFF, 0xFF)
677 COLOR(Inactiveborder
, 0xF4, 0xF7, 0xFC)
678 COLOR(Inactivecaption
, 0xBF, 0xCD, 0xDB)
679 COLOR(Inactivecaptiontext
, 0x43, 0x4E, 0x54)
680 COLOR(Infobackground
, 0xFF, 0xFF, 0xE1)
681 COLOR(Infotext
, 0x00, 0x00, 0x00)
682 COLOR(Menu
, 0xF0, 0xF0, 0xF0)
683 COLOR(Menutext
, 0x00, 0x00, 0x00)
684 COLOR(Scrollbar
, 0xC8, 0xC8, 0xC8)
685 COLOR(Threeddarkshadow
, 0x69, 0x69, 0x69)
686 COLOR(Threedface
, 0xF0, 0xF0, 0xF0)
687 COLOR(Threedhighlight
, 0xFF, 0xFF, 0xFF)
688 COLOR(Threedlightshadow
, 0xE3, 0xE3, 0xE3)
689 COLOR(Threedshadow
, 0xA0, 0xA0, 0xA0)
690 COLOR(Buttonborder
, 0xE3, 0xE3, 0xE3)
691 COLOR(Mark
, 0xFF, 0xFF, 0x00)
692 COLOR(Marktext
, 0x00, 0x00, 0x00)
693 COLOR(Window
, 0xFF, 0xFF, 0xFF)
694 COLOR(Windowframe
, 0x64, 0x64, 0x64)
695 COLOR(Windowtext
, 0x00, 0x00, 0x00)
696 COLOR(MozButtondefault
, 0x69, 0x69, 0x69)
697 COLOR(Field
, 0xFF, 0xFF, 0xFF)
698 COLORA(MozDisabledfield
, 0xFF, 0xFF, 0xFF, 128)
699 COLOR(Fieldtext
, 0x00, 0x00, 0x00)
700 COLOR(MozDialog
, 0xF0, 0xF0, 0xF0)
701 COLOR(MozDialogtext
, 0x00, 0x00, 0x00)
702 COLOR(MozColheadertext
, 0x00, 0x00, 0x00)
703 COLOR(MozColheaderhovertext
, 0x00, 0x00, 0x00)
704 COLOR(MozDragtargetzone
, 0xFF, 0xFF, 0xFF)
705 COLOR(MozCellhighlight
, 0xF0, 0xF0, 0xF0)
706 COLOR(MozCellhighlighttext
, 0x00, 0x00, 0x00)
707 COLOR(Selecteditem
, 0x33, 0x99, 0xFF)
708 COLOR(Selecteditemtext
, 0xFF, 0xFF, 0xFF)
709 COLOR(MozButtonhoverface
, 0xd0, 0xd0, 0xd7)
710 COLOR(MozButtonhovertext
, 0x00, 0x00, 0x00)
711 COLOR(MozButtonactiveface
, 0xb1, 0xb1, 0xb9)
712 COLOR(MozButtonactivetext
, 0x00, 0x00, 0x00)
713 COLOR(MozMenuhover
, 0x33, 0x99, 0xFF)
714 COLOR(MozMenuhovertext
, 0x00, 0x00, 0x00)
715 COLOR(MozMenubartext
, 0x00, 0x00, 0x00)
716 COLOR(MozMenubarhovertext
, 0x00, 0x00, 0x00)
717 COLOR(MozMenuhoverdisabled
, 0xF0, 0xF0, 0xF0)
718 COLOR(MozEventreerow
, 0xFF, 0xFF, 0xFF)
719 COLOR(MozOddtreerow
, 0xFF, 0xFF, 0xFF)
720 COLOR(MozMacChromeActive
, 0xB2, 0xB2, 0xB2)
721 COLOR(MozMacChromeInactive
, 0xE1, 0xE1, 0xE1)
722 COLOR(MozMacFocusring
, 0x60, 0x9D, 0xD7)
723 COLOR(MozMacMenuselect
, 0x38, 0x75, 0xD7)
724 COLOR(MozMacMenushadow
, 0xA3, 0xA3, 0xA3)
725 COLOR(MozMacMenutextdisable
, 0x88, 0x88, 0x88)
726 COLOR(MozMacMenutextselect
, 0xFF, 0xFF, 0xFF)
727 COLOR(MozMacDisabledtoolbartext
, 0x3F, 0x3F, 0x3F)
728 COLOR(MozMacSecondaryhighlight
, 0xD4, 0xD4, 0xD4)
729 COLOR(MozMacMenupopup
, 0xe6, 0xe6, 0xe6)
730 COLOR(MozMacMenuitem
, 0xe6, 0xe6, 0xe6)
731 COLOR(MozMacActiveMenuitem
, 0x0a, 0x64, 0xdc)
732 COLOR(MozMacSourceList
, 0xf7, 0xf7, 0xf7)
733 COLOR(MozMacSourceListSelection
, 0xc8, 0xc8, 0xc8)
734 COLOR(MozMacActiveSourceListSelection
, 0x0a, 0x64, 0xdc)
735 COLOR(MozMacTooltip
, 0xf7, 0xf7, 0xf7)
736 // Seems to be the default color (hardcoded because of bug 1065998)
737 COLOR(MozWinMediatext
, 0xFF, 0xFF, 0xFF)
738 COLOR(MozWinCommunicationstext
, 0xFF, 0xFF, 0xFF)
739 COLOR(MozNativehyperlinktext
, 0x00, 0x66, 0xCC)
740 COLOR(MozNativevisitedhyperlinktext
, 0x55, 0x1A, 0x8B)
744 return NS_RGB(0xFF, 0xFF, 0xFF);
750 // Taken from in-content/common.inc.css's dark theme.
751 Maybe
<nscolor
> nsXPLookAndFeel::GenericDarkColor(ColorID aID
) {
752 nscolor color
= NS_RGB(0, 0, 0);
753 static constexpr nscolor kWindowBackground
= NS_RGB(28, 27, 34);
754 static constexpr nscolor kWindowText
= NS_RGB(251, 251, 254);
756 case ColorID::Window
: // --in-content-page-background
757 case ColorID::Background
:
758 color
= kWindowBackground
;
762 color
= NS_RGB(0x2b, 0x2a, 0x33);
765 case ColorID::MozMenuhovertext
:
766 case ColorID::MozMenubarhovertext
:
767 case ColorID::Menutext
:
768 color
= NS_RGB(0xfb, 0xfb, 0xfe);
771 case ColorID::MozMenuhover
:
772 color
= NS_RGB(0x52, 0x52, 0x5e);
775 case ColorID::MozMenuhoverdisabled
:
776 color
= NS_RGB(0x3a, 0x39, 0x44);
779 case ColorID::MozOddtreerow
:
780 case ColorID::MozDialog
: // --in-content-box-background
781 color
= NS_RGB(35, 34, 43);
783 case ColorID::Windowtext
: // --in-content-page-color
784 case ColorID::MozDialogtext
:
785 case ColorID::Fieldtext
:
786 case ColorID::Buttontext
: // --in-content-button-text-color (via
787 // --in-content-page-color)
788 case ColorID::MozComboboxtext
:
789 case ColorID::MozButtonhovertext
:
790 case ColorID::MozButtonactivetext
:
793 case ColorID::Buttonshadow
:
794 case ColorID::Threedshadow
:
795 case ColorID::Threedlightshadow
:
796 case ColorID::Buttonborder
: // --in-content-box-border-color computed
797 // with kWindowText above
798 // kWindowBackground.
799 case ColorID::Graytext
: // opacity: 0.4 of kWindowText blended over the
800 // "Window" background color, which happens to be
802 color
= NS_ComposeColors(kWindowBackground
, NS_RGBA(251, 251, 254, 102));
804 case ColorID::MozCellhighlight
:
805 case ColorID::Selecteditem
: // --in-content-primary-button-background /
806 // --in-content-item-selected
807 color
= NS_RGB(0, 221, 255);
810 case ColorID::Buttonface
: // --in-content-button-background
811 case ColorID::Threedface
:
812 case ColorID::MozCombobox
:
813 case ColorID::MozCellhighlighttext
:
814 case ColorID::Selecteditemtext
: // --in-content-primary-button-text-color /
815 // --in-content-item-selected-text
816 color
= NS_RGB(43, 42, 51);
818 case ColorID::Threeddarkshadow
: // Same as Threedlightshadow but with the
820 case ColorID::MozDisabledfield
: // opacity: 0.4 of the face above blended
821 // over the "Window" background color.
822 case ColorID::MozButtondisabledface
:
823 color
= NS_ComposeColors(kWindowBackground
, NS_RGBA(43, 42, 51, 102));
825 case ColorID::MozButtonhoverface
: // --in-content-button-background-hover
826 color
= NS_RGB(82, 82, 94);
828 case ColorID::MozButtonactiveface
: // --in-content-button-background-active
829 color
= NS_RGB(91, 91, 102);
831 case ColorID::Highlight
:
832 color
= NS_RGBA(0, 221, 255, 78);
834 case ColorID::Highlighttext
:
835 color
= NS_SAME_AS_FOREGROUND_COLOR
;
837 case ColorID::MozNativehyperlinktext
:
838 // If you change this color, you probably also want to change the default
839 // value of browser.anchor_color.dark.
840 color
= NS_RGB(0x8c, 0x8c, 0xff);
842 case ColorID::MozNativevisitedhyperlinktext
:
843 // If you change this color, you probably also want to change the default
844 // value of browser.visited_color.dark.
845 color
= NS_RGB(0xff, 0xad, 0xff);
847 case ColorID::SpellCheckerUnderline
:
848 // This is the default for active links in dark mode as well
849 // (browser.active_color.dark). See bug 1755564 for some analysis and
850 // other options too.
851 color
= NS_RGB(0xff, 0x66, 0x66);
859 // Uncomment the #define below if you want to debug system color use in a skin
860 // that uses them. When set, it will make all system color pairs that are
861 // appropriate for foreground/background pairing the same. This means if the
862 // skin is using system colors correctly you will not be able to see *any* text.
864 // #define DEBUG_SYSTEM_COLOR_USE
866 #ifdef DEBUG_SYSTEM_COLOR_USE
867 static nsresult
SystemColorUseDebuggingColor(LookAndFeel::ColorID aID
,
869 using ColorID
= LookAndFeel::ColorID
;
872 // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
873 case ColorID::Activecaption
:
874 // active window caption background
875 case ColorID::Captiontext
:
876 // text in active window caption
877 aResult
= NS_RGB(0xff, 0x00, 0x00);
880 case ColorID::Highlight
:
881 // background of selected item
882 case ColorID::Highlighttext
:
883 // text of selected item
884 aResult
= NS_RGB(0xff, 0xff, 0x00);
887 case ColorID::Inactivecaption
:
888 // inactive window caption
889 case ColorID::Inactivecaptiontext
:
890 // text in inactive window caption
891 aResult
= NS_RGB(0x66, 0x66, 0x00);
894 case ColorID::Infobackground
:
895 // tooltip background color
896 case ColorID::Infotext
:
897 // tooltip text color
898 aResult
= NS_RGB(0x00, 0xff, 0x00);
903 case ColorID::Menutext
:
905 aResult
= NS_RGB(0x00, 0xff, 0xff);
908 case ColorID::Threedface
:
909 case ColorID::Buttonface
:
911 case ColorID::Buttontext
:
912 // text on push buttons
913 aResult
= NS_RGB(0x00, 0x66, 0x66);
916 case ColorID::Window
:
917 case ColorID::Windowtext
:
918 aResult
= NS_RGB(0x00, 0x00, 0xff);
921 // from the CSS3 working draft (not yet finalized)
922 // http://www.w3.org/tr/2000/wd-css3-userint-20000216.html#color
925 case ColorID::Fieldtext
:
926 aResult
= NS_RGB(0xff, 0x00, 0xff);
929 case ColorID::MozDialog
:
930 case ColorID::MozDialogtext
:
931 aResult
= NS_RGB(0x66, 0x00, 0x66);
935 return NS_ERROR_NOT_AVAILABLE
;
942 static nsresult
GetPrefColor(const char* aPref
, nscolor
& aResult
) {
943 nsAutoCString colorStr
;
944 MOZ_TRY(Preferences::GetCString(aPref
, colorStr
));
945 if (!ServoCSSParser::ComputeColor(nullptr, NS_RGB(0, 0, 0), colorStr
,
947 return NS_ERROR_FAILURE
;
952 static nsresult
GetColorFromPref(LookAndFeel::ColorID aID
, ColorScheme aScheme
,
954 const char* prefName
= sColorPrefs
[size_t(aID
)];
955 if (aScheme
== ColorScheme::Dark
) {
956 nsAutoCString
darkPrefName(prefName
);
957 darkPrefName
.Append(".dark");
958 if (NS_SUCCEEDED(GetPrefColor(darkPrefName
.get(), aResult
))) {
962 return GetPrefColor(prefName
, aResult
);
965 // All these routines will return NS_OK if they have a value,
966 // in which case the nsLookAndFeel should use that value;
967 // otherwise we'll return NS_ERROR_NOT_AVAILABLE, in which case, the
968 // platform-specific nsLookAndFeel should use its own values instead.
969 nsresult
nsXPLookAndFeel::GetColorValue(ColorID aID
, ColorScheme aScheme
,
970 UseStandins aUseStandins
,
976 #ifdef DEBUG_SYSTEM_COLOR_USE
977 if (NS_SUCCEEDED(SystemColorUseDebuggingColor(aID
, aResult
))) {
982 auto& cache
= sColorCaches
.Get(aScheme
, aUseStandins
);
983 if (const auto* cached
= cache
.Get(aID
)) {
984 if (cached
->isNothing()) {
985 return NS_ERROR_FAILURE
;
987 aResult
= cached
->value();
991 // NOTE: Servo holds a lock and the main thread is paused, so writing to the
992 // global cache here is fine.
993 auto result
= GetUncachedColor(aID
, aScheme
, aUseStandins
);
994 cache
.Insert(aID
, result
);
996 return NS_ERROR_FAILURE
;
1002 Maybe
<nscolor
> nsXPLookAndFeel::GetUncachedColor(ColorID aID
,
1003 ColorScheme aScheme
,
1004 UseStandins aUseStandins
) {
1005 if (aUseStandins
== UseStandins::Yes
) {
1006 return Some(GetStandinForNativeColor(aID
, aScheme
));
1009 if (NS_SUCCEEDED(GetColorFromPref(aID
, aScheme
, r
))) {
1012 if (NS_SUCCEEDED(NativeGetColor(aID
, aScheme
, r
))) {
1013 if (gfxPlatform::GetCMSMode() == CMSMode::All
&& !IsSpecialColor(aID
, r
)) {
1014 qcms_transform
* transform
= gfxPlatform::GetCMSInverseRGBTransform();
1017 color
[0] = NS_GET_R(r
);
1018 color
[1] = NS_GET_G(r
);
1019 color
[2] = NS_GET_B(r
);
1020 color
[3] = NS_GET_A(r
);
1021 qcms_transform_data(transform
, color
, color
, 1);
1022 r
= NS_RGBA(color
[0], color
[1], color
[2], color
[3]);
1031 nsresult
nsXPLookAndFeel::GetIntValue(IntID aID
, int32_t& aResult
) {
1032 if (!sInitialized
) {
1036 if (const auto* cached
= sIntCache
.Get(aID
)) {
1037 if (cached
->isNothing()) {
1038 return NS_ERROR_FAILURE
;
1040 aResult
= cached
->value();
1044 if (NS_SUCCEEDED(Preferences::GetInt(sIntPrefs
[size_t(aID
)], &aResult
))) {
1045 sIntCache
.Insert(aID
, Some(aResult
));
1049 if (NS_FAILED(NativeGetInt(aID
, aResult
))) {
1050 sIntCache
.Insert(aID
, Nothing());
1051 return NS_ERROR_FAILURE
;
1054 sIntCache
.Insert(aID
, Some(aResult
));
1058 nsresult
nsXPLookAndFeel::GetFloatValue(FloatID aID
, float& aResult
) {
1059 if (!sInitialized
) {
1063 if (const auto* cached
= sFloatCache
.Get(aID
)) {
1064 if (cached
->isNothing()) {
1065 return NS_ERROR_FAILURE
;
1067 aResult
= cached
->value();
1072 if (NS_SUCCEEDED(Preferences::GetInt(sFloatPrefs
[size_t(aID
)], &pref
))) {
1073 aResult
= float(pref
) / 100.0f
;
1074 sFloatCache
.Insert(aID
, Some(aResult
));
1078 if (NS_FAILED(NativeGetFloat(aID
, aResult
))) {
1079 sFloatCache
.Insert(aID
, Nothing());
1080 return NS_ERROR_FAILURE
;
1083 sFloatCache
.Insert(aID
, Some(aResult
));
1087 bool nsXPLookAndFeel::LookAndFeelFontToStyle(const LookAndFeelFont
& aFont
,
1089 gfxFontStyle
& aStyle
) {
1090 if (!aFont
.haveFont()) {
1093 aName
= aFont
.name();
1094 aStyle
= gfxFontStyle();
1095 aStyle
.size
= aFont
.size();
1096 aStyle
.weight
= FontWeight::FromInt(aFont
.weight());
1098 aFont
.italic() ? FontSlantStyle::ITALIC
: FontSlantStyle::NORMAL
;
1099 aStyle
.systemFont
= true;
1103 widget::LookAndFeelFont
nsXPLookAndFeel::StyleToLookAndFeelFont(
1104 const nsAString
& aName
, const gfxFontStyle
& aStyle
) {
1105 LookAndFeelFont font
;
1106 font
.haveFont() = true;
1107 font
.name() = aName
;
1108 font
.size() = aStyle
.size
;
1109 font
.weight() = aStyle
.weight
.ToFloat();
1110 font
.italic() = aStyle
.style
.IsItalic();
1111 MOZ_ASSERT(aStyle
.style
.IsNormal() || aStyle
.style
.IsItalic(),
1112 "Cannot handle oblique font style");
1115 // Assert that all the remaining font style properties have their
1117 gfxFontStyle candidate
= aStyle
;
1118 gfxFontStyle defaults
{};
1119 candidate
.size
= defaults
.size
;
1120 candidate
.weight
= defaults
.weight
;
1121 candidate
.style
= defaults
.style
;
1122 MOZ_ASSERT(candidate
.Equals(defaults
),
1123 "Some font style properties not supported");
1129 bool nsXPLookAndFeel::GetFontValue(FontID aID
, nsString
& aName
,
1130 gfxFontStyle
& aStyle
) {
1131 if (const LookAndFeelFont
* cached
= sFontCache
.Get(aID
)) {
1132 return LookAndFeelFontToStyle(*cached
, aName
, aStyle
);
1135 LookAndFeelFont font
;
1136 auto GetFontsFromPrefs
= [&]() -> bool {
1137 nsDependentCString
pref(sFontPrefs
[size_t(aID
)]);
1138 if (NS_FAILED(Preferences::GetString(pref
.get(), aName
))) {
1141 font
.haveFont() = true;
1142 font
.name() = aName
;
1143 font
.size() = Preferences::GetFloat(nsAutoCString(pref
+ ".size"_ns
).get());
1144 // This is written this way rather than using the fallback so that an empty
1145 // pref (such like the one about:config creates) doesn't cause system fonts
1146 // to have zero-size.
1147 if (font
.size() < 1.0f
) {
1148 font
.size() = StyleFONT_MEDIUM_PX
;
1150 font
.weight() = Preferences::GetFloat(
1151 nsAutoCString(pref
+ ".weight"_ns
).get(), FontWeight::NORMAL
.ToFloat());
1153 Preferences::GetBool(nsAutoCString(pref
+ ".italic"_ns
).get());
1157 if (GetFontsFromPrefs()) {
1158 LookAndFeelFontToStyle(font
, aName
, aStyle
);
1159 } else if (NativeGetFont(aID
, aName
, aStyle
)) {
1160 font
= StyleToLookAndFeelFont(aName
, aStyle
);
1162 MOZ_ASSERT(!font
.haveFont());
1164 bool success
= font
.haveFont();
1165 sFontCache
.Insert(aID
, std::move(font
));
1169 void nsXPLookAndFeel::RefreshImpl() {
1170 // Wipe out our caches.
1171 sColorCaches
.Clear();
1173 sFloatCache
.Clear();
1175 RecomputeColorSchemes();
1177 if (XRE_IsParentProcess()) {
1178 nsLayoutUtils::RecomputeSmoothScrollDefault();
1179 // Clear any cached FullLookAndFeel data, which is now invalid.
1180 widget::RemoteLookAndFeel::ClearCachedData();
1184 static bool sRecordedLookAndFeelTelemetry
= false;
1186 void nsXPLookAndFeel::RecordTelemetry() {
1187 if (!XRE_IsParentProcess()) {
1191 if (sRecordedLookAndFeelTelemetry
) {
1195 sRecordedLookAndFeelTelemetry
= true;
1198 Telemetry::ScalarSet(
1199 Telemetry::ScalarID::WIDGET_DARK_MODE
,
1200 NS_SUCCEEDED(GetIntValue(IntID::SystemUsesDarkTheme
, i
)) && i
!= 0);
1202 RecordLookAndFeelSpecificTelemetry();
1207 static widget::ThemeChangeKind sGlobalThemeChangeKind
{0};
1209 void LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind aKind
) {
1210 sGlobalThemeChanged
= true;
1211 sGlobalThemeChangeKind
|= aKind
;
1213 if (nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService()) {
1214 const char16_t kind
[] = {char16_t(aKind
), 0};
1215 obs
->NotifyObservers(nullptr, "internal-look-and-feel-changed", kind
);
1219 void LookAndFeel::DoHandleGlobalThemeChange() {
1220 MOZ_ASSERT(sGlobalThemeChanged
);
1221 sGlobalThemeChanged
= false;
1222 auto kind
= std::exchange(sGlobalThemeChangeKind
, widget::ThemeChangeKind(0));
1224 // Tell the theme that it changed, so it can flush any handles to stale theme
1227 // We can use the *DoNotUseDirectly functions directly here, because we want
1228 // to notify all possible themes in a given process (but just once).
1229 if (XRE_IsParentProcess() ||
1230 !StaticPrefs::widget_non_native_theme_enabled()) {
1231 if (nsCOMPtr
<nsITheme
> theme
= do_GetNativeThemeDoNotUseDirectly()) {
1232 theme
->ThemeChanged();
1235 if (nsCOMPtr
<nsITheme
> theme
= do_GetBasicNativeThemeDoNotUseDirectly()) {
1236 theme
->ThemeChanged();
1239 // Clear all cached LookAndFeel colors.
1240 LookAndFeel::Refresh();
1242 // Reset default background and foreground colors for the document since they
1243 // may be using system colors.
1244 PreferenceSheet::Refresh();
1246 // Vector images (SVG) may be using theme colors so we discard all cached
1247 // surfaces. (We could add a vector image only version of DiscardAll, but
1248 // in bug 940625 we decided theme changes are rare enough not to bother.)
1249 image::SurfaceCacheUtils::DiscardAll();
1251 if (XRE_IsParentProcess()) {
1252 dom::ContentParent::BroadcastThemeUpdate(kind
);
1255 nsContentUtils::AddScriptRunner(
1256 NS_NewRunnableFunction("HandleGlobalThemeChange", [] {
1257 if (nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService()) {
1258 obs
->NotifyObservers(nullptr, "look-and-feel-changed", nullptr);
1263 #define BIT_FOR(_c) (1ull << size_t(ColorID::_c))
1265 // We want to use a non-native color scheme for the non-native theme (except in
1266 // high-contrast mode), so spoof some of the colors with stand-ins to prevent
1267 // lack of contrast.
1268 static constexpr std::bitset
<size_t(ColorID::End
)> sNonNativeThemeStandinColors
{
1269 // Used by default button styles.
1270 BIT_FOR(Buttonface
) | BIT_FOR(Buttontext
) | BIT_FOR(MozButtonhoverface
) |
1271 BIT_FOR(MozButtonhovertext
) | BIT_FOR(MozButtonactiveface
) |
1272 BIT_FOR(MozButtonactivetext
) | BIT_FOR(MozButtondisabledface
) |
1273 BIT_FOR(Buttonborder
) |
1274 // Used by select elements.
1275 BIT_FOR(MozCombobox
) | BIT_FOR(MozComboboxtext
) |
1276 BIT_FOR(Threedlightshadow
) |
1277 // For symmetry with the above.
1278 BIT_FOR(Threeddarkshadow
) |
1279 // Used by fieldset borders.
1280 BIT_FOR(Threedface
) |
1281 // Used by input / textarea.
1282 BIT_FOR(Field
) | BIT_FOR(Fieldtext
) |
1283 // Used by disabled form controls.
1284 BIT_FOR(MozDisabledfield
) | BIT_FOR(Graytext
) |
1285 // Some pages expect these to return windows-like colors, see bug 1773795.
1286 // Also, per spec these should match Canvas/CanvasText, see
1287 // https://drafts.csswg.org/css-color-4/#window
1288 BIT_FOR(Window
) | BIT_FOR(Windowtext
)};
1291 static bool ShouldUseStandinsForNativeColorForNonNativeTheme(
1292 const dom::Document
& aDoc
, LookAndFeel::ColorID aColor
,
1293 const PreferenceSheet::Prefs
& aPrefs
) {
1294 const bool shouldUseStandinsForColor
= [&] {
1295 if (sNonNativeThemeStandinColors
[size_t(aColor
)]) {
1298 // There are platforms where we want the content-exposed accent color to be
1299 // the windows blue rather than the system accent color, for now.
1300 return !StaticPrefs::widget_non_native_theme_use_theme_accent() &&
1301 (aColor
== LookAndFeel::ColorID::Accentcolor
||
1302 aColor
== LookAndFeel::ColorID::Accentcolortext
);
1305 return shouldUseStandinsForColor
&& aDoc
.ShouldAvoidNativeTheme() &&
1306 !aPrefs
.NonNativeThemeShouldBeHighContrast();
1309 ColorScheme
LookAndFeel::sChromeColorScheme
;
1310 ColorScheme
LookAndFeel::sContentColorScheme
;
1311 bool LookAndFeel::sColorSchemeInitialized
;
1312 bool LookAndFeel::sGlobalThemeChanged
;
1314 bool LookAndFeel::IsDarkColor(nscolor aColor
) {
1315 // Given https://www.w3.org/TR/WCAG20/#contrast-ratiodef, this is the
1316 // threshold that tells us whether contrast is better against white or black.
1318 // Contrast ratio against black is: (L + 0.05) / 0.05
1319 // Contrast ratio against white is: 1.05 / (L + 0.05)
1321 // So the intersection is:
1323 // (L + 0.05) / 0.05 = 1.05 / (L + 0.05)
1325 // And the solution to that equation is:
1327 // sqrt(1.05 * 0.05) - 0.05
1329 // So we consider a color dark if the contrast is below this threshold, and
1330 // it's at least half-opaque.
1331 constexpr float kThreshold
= 0.179129;
1332 return NS_GET_A(aColor
) > 127 &&
1333 RelativeLuminanceUtils::Compute(aColor
) < kThreshold
;
1336 auto LookAndFeel::ColorSchemeSettingForChrome() -> ChromeColorSchemeSetting
{
1337 switch (StaticPrefs::browser_theme_toolbar_theme()) {
1339 return ChromeColorSchemeSetting::Dark
;
1341 return ChromeColorSchemeSetting::Light
;
1343 return ChromeColorSchemeSetting::System
;
1347 ColorScheme
LookAndFeel::ThemeDerivedColorSchemeForContent() {
1348 switch (StaticPrefs::browser_theme_content_theme()) {
1350 return ColorScheme::Dark
;
1352 return ColorScheme::Light
;
1354 return SystemColorScheme();
1358 void LookAndFeel::RecomputeColorSchemes() {
1359 sColorSchemeInitialized
= true;
1361 sChromeColorScheme
= [] {
1362 switch (ColorSchemeSettingForChrome()) {
1363 case ChromeColorSchemeSetting::Light
:
1364 return ColorScheme::Light
;
1365 case ChromeColorSchemeSetting::Dark
:
1366 return ColorScheme::Dark
;
1367 case ChromeColorSchemeSetting::System
:
1370 return SystemColorScheme();
1373 sContentColorScheme
= [] {
1374 switch (StaticPrefs::layout_css_prefers_color_scheme_content_override()) {
1376 return ColorScheme::Dark
;
1378 return ColorScheme::Light
;
1380 return ThemeDerivedColorSchemeForContent();
1385 ColorScheme
LookAndFeel::ColorSchemeForStyle(
1386 const dom::Document
& aDoc
, const StyleColorSchemeFlags
& aFlags
,
1387 ColorSchemeMode aMode
) {
1388 using Choice
= PreferenceSheet::Prefs::ColorSchemeChoice
;
1390 const auto& prefs
= PreferenceSheet::PrefsFor(aDoc
);
1391 switch (prefs
.mColorSchemeChoice
) {
1392 case Choice::Standard
:
1394 case Choice::UserPreferred
:
1395 return aDoc
.PreferredColorScheme();
1397 return ColorScheme::Light
;
1399 return ColorScheme::Dark
;
1402 StyleColorSchemeFlags
style(aFlags
);
1404 style
.bits
= aDoc
.GetColorSchemeBits();
1406 const bool supportsDark
= bool(style
& StyleColorSchemeFlags::DARK
);
1407 const bool supportsLight
= bool(style
& StyleColorSchemeFlags::LIGHT
);
1408 if (supportsLight
&& supportsDark
) {
1409 // Both color-schemes are explicitly supported, use the preferred one.
1410 return aDoc
.PreferredColorScheme();
1412 if (supportsDark
|| supportsLight
) {
1413 // One color-scheme is explicitly supported and one isn't, so use the one
1414 // the content supports.
1415 return supportsDark
? ColorScheme::Dark
: ColorScheme::Light
;
1417 // No value specified. Chrome docs always supports both, so use the preferred
1419 if (aMode
== ColorSchemeMode::Preferred
||
1420 nsContentUtils::IsChromeDoc(&aDoc
)) {
1421 return aDoc
.PreferredColorScheme();
1423 // Default content to light.
1424 return ColorScheme::Light
;
1427 LookAndFeel::ColorScheme
LookAndFeel::ColorSchemeForFrame(
1428 const nsIFrame
* aFrame
, ColorSchemeMode aMode
) {
1429 return ColorSchemeForStyle(*aFrame
->PresContext()->Document(),
1430 aFrame
->StyleUI()->mColorScheme
.bits
, aMode
);
1434 Maybe
<nscolor
> LookAndFeel::GetColor(ColorID aId
, ColorScheme aScheme
,
1435 UseStandins aUseStandins
) {
1437 nsresult rv
= nsLookAndFeel::GetInstance()->GetColorValue(
1438 aId
, aScheme
, aUseStandins
, result
);
1439 if (NS_FAILED(rv
)) {
1442 return Some(result
);
1445 // Returns whether there is a CSS color name for this color.
1446 static bool ColorIsCSSAccessible(LookAndFeel::ColorID aId
) {
1447 using ColorID
= LookAndFeel::ColorID
;
1450 case ColorID::TextSelectDisabledBackground
:
1451 case ColorID::TextSelectAttentionBackground
:
1452 case ColorID::TextSelectAttentionForeground
:
1453 case ColorID::TextHighlightBackground
:
1454 case ColorID::TextHighlightForeground
:
1455 case ColorID::ThemedScrollbar
:
1456 case ColorID::ThemedScrollbarInactive
:
1457 case ColorID::ThemedScrollbarThumb
:
1458 case ColorID::ThemedScrollbarThumbActive
:
1459 case ColorID::ThemedScrollbarThumbInactive
:
1460 case ColorID::ThemedScrollbarThumbHover
:
1461 case ColorID::IMERawInputBackground
:
1462 case ColorID::IMERawInputForeground
:
1463 case ColorID::IMERawInputUnderline
:
1464 case ColorID::IMESelectedRawTextBackground
:
1465 case ColorID::IMESelectedRawTextForeground
:
1466 case ColorID::IMESelectedRawTextUnderline
:
1467 case ColorID::IMEConvertedTextBackground
:
1468 case ColorID::IMEConvertedTextForeground
:
1469 case ColorID::IMEConvertedTextUnderline
:
1470 case ColorID::IMESelectedConvertedTextBackground
:
1471 case ColorID::IMESelectedConvertedTextForeground
:
1472 case ColorID::IMESelectedConvertedTextUnderline
:
1473 case ColorID::SpellCheckerUnderline
:
1482 LookAndFeel::UseStandins
LookAndFeel::ShouldUseStandins(
1483 const dom::Document
& aDoc
, ColorID aId
) {
1484 const auto& prefs
= PreferenceSheet::PrefsFor(aDoc
);
1485 if (ShouldUseStandinsForNativeColorForNonNativeTheme(aDoc
, aId
, prefs
)) {
1486 return UseStandins::Yes
;
1488 if (prefs
.mUseStandins
&& ColorIsCSSAccessible(aId
)) {
1489 return UseStandins::Yes
;
1491 return UseStandins::No
;
1494 Maybe
<nscolor
> LookAndFeel::GetColor(ColorID aId
, const nsIFrame
* aFrame
) {
1495 const auto* doc
= aFrame
->PresContext()->Document();
1496 return GetColor(aId
, ColorSchemeForFrame(aFrame
),
1497 ShouldUseStandins(*doc
, aId
));
1501 nsresult
LookAndFeel::GetInt(IntID aID
, int32_t* aResult
) {
1502 return nsLookAndFeel::GetInstance()->GetIntValue(aID
, *aResult
);
1506 nsresult
LookAndFeel::GetFloat(FloatID aID
, float* aResult
) {
1507 return nsLookAndFeel::GetInstance()->GetFloatValue(aID
, *aResult
);
1511 bool LookAndFeel::GetFont(FontID aID
, nsString
& aName
, gfxFontStyle
& aStyle
) {
1512 return nsLookAndFeel::GetInstance()->GetFontValue(aID
, aName
, aStyle
);
1516 char16_t
LookAndFeel::GetPasswordCharacter() {
1517 return nsLookAndFeel::GetInstance()->GetPasswordCharacterImpl();
1521 bool LookAndFeel::GetEchoPassword() {
1522 if (StaticPrefs::editor_password_mask_delay() >= 0) {
1523 return StaticPrefs::editor_password_mask_delay() > 0;
1525 return nsLookAndFeel::GetInstance()->GetEchoPasswordImpl();
1529 uint32_t LookAndFeel::GetPasswordMaskDelay() {
1530 int32_t delay
= StaticPrefs::editor_password_mask_delay();
1532 return nsLookAndFeel::GetInstance()->GetPasswordMaskDelayImpl();
1537 bool LookAndFeel::DrawInTitlebar() {
1538 switch (StaticPrefs::browser_tabs_inTitlebar()) {
1546 return nsLookAndFeel::GetInstance()->GetDefaultDrawInTitlebar();
1549 void LookAndFeel::GetThemeInfo(nsACString
& aOut
) {
1550 nsLookAndFeel::GetInstance()->GetThemeInfo(aOut
);
1553 uint32_t LookAndFeel::GetMenuAccessKey() {
1554 return StaticPrefs::ui_key_menuAccessKey();
1557 Modifiers
LookAndFeel::GetMenuAccessKeyModifiers() {
1558 switch (GetMenuAccessKey()) {
1559 case dom::KeyboardEvent_Binding::DOM_VK_SHIFT
:
1560 return MODIFIER_SHIFT
;
1561 case dom::KeyboardEvent_Binding::DOM_VK_CONTROL
:
1562 return MODIFIER_CONTROL
;
1563 case dom::KeyboardEvent_Binding::DOM_VK_ALT
:
1564 return MODIFIER_ALT
;
1565 case dom::KeyboardEvent_Binding::DOM_VK_META
:
1566 return MODIFIER_META
;
1567 case dom::KeyboardEvent_Binding::DOM_VK_WIN
:
1575 void LookAndFeel::Refresh() {
1576 nsLookAndFeel::GetInstance()->RefreshImpl();
1577 widget::Theme::LookAndFeelChanged();
1581 void LookAndFeel::NativeInit() { nsLookAndFeel::GetInstance()->NativeInit(); }
1584 void LookAndFeel::SetData(widget::FullLookAndFeel
&& aTables
) {
1585 nsLookAndFeel::GetInstance()->SetDataImpl(std::move(aTables
));
1588 } // namespace mozilla