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
, Value
, size_t(kEnd
)> 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.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 "ui.chosenMenuItemsShouldBlink",
150 "ui.windowsAccentColorInTitlebar",
153 "ui.macTitlebarHeight",
154 "ui.alertNotificationOrigin",
156 "ui.IMERawInputUnderlineStyle",
157 "ui.IMESelectedRawTextUnderlineStyle",
158 "ui.IMEConvertedTextUnderlineStyle",
159 "ui.IMESelectedConvertedTextUnderlineStyle",
160 "ui.SpellCheckerUnderlineStyle",
162 "ui.scrollbarButtonAutoRepeatBehavior",
163 "ui.swipeAnimationEnabled",
164 "ui.scrollbarDisplayOnMouseMove",
165 "ui.scrollbarFadeBeginDelay",
166 "ui.scrollbarFadeDuration",
167 "ui.contextMenuOffsetVertical",
168 "ui.contextMenuOffsetHorizontal",
169 "ui.tooltipOffsetVertical",
170 "ui.GtkCSDAvailable",
171 "ui.GtkCSDMinimizeButton",
172 "ui.GtkCSDMaximizeButton",
173 "ui.GtkCSDCloseButton",
174 "ui.GtkCSDMinimizeButtonPosition",
175 "ui.GtkCSDMaximizeButtonPosition",
176 "ui.GtkCSDCloseButtonPosition",
177 "ui.GtkCSDReversedPlacement",
178 "ui.systemUsesDarkTheme",
179 "ui.prefersReducedMotion",
180 "ui.prefersReducedTransparency",
182 "ui.primaryPointerCapabilities",
183 "ui.allPointerCapabilities",
184 "ui.systemScrollbarSize",
185 "ui.touchDeviceSupportPresent",
187 "ui.titlebarButtonSpacing",
189 "ui.panelAnimations",
190 "ui.hideCursorWhileTyping",
192 "ui.fullKeyboardAccess",
195 static_assert(ArrayLength(sIntPrefs
) == size_t(LookAndFeel::IntID::End
),
196 "Should have a pref for each int value");
198 // This array MUST be kept in the same order as the float id list in
201 static const char sFloatPrefs
[][37] = {
202 "ui.IMEUnderlineRelativeSize",
203 "ui.SpellCheckerUnderlineRelativeSize",
204 "ui.caretAspectRatio",
205 "ui.textScaleFactor",
210 static_assert(ArrayLength(sFloatPrefs
) == size_t(LookAndFeel::FloatID::End
),
211 "Should have a pref for each float value");
213 // This array MUST be kept in the same order as the color list in
214 // specified/color.rs
215 static const char sColorPrefs
[][41] = {
221 "ui.buttonhighlight",
227 "ui.-moz-disabledfield",
231 "ui.-moz-comboboxtext",
237 "ui.inactivecaption",
238 "ui.inactivecaptiontext",
244 "ui.threeddarkshadow",
246 "ui.threedhighlight",
247 "ui.threedlightshadow",
252 "ui.-moz-default-color",
253 "ui.-moz-default-background-color",
255 "ui.-moz-dialogtext",
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",
266 "ui.-moz_eventreerow",
267 "ui.-moz_oddtreerow",
268 "ui.-moz-buttonactivetext",
269 "ui.-moz-buttonactiveface",
270 "ui.-moz-buttondisabledface",
272 "ui.-moz-headerbartext",
273 "ui.-moz-headerbarinactive",
274 "ui.-moz-headerbarinactivetext",
275 "ui.-moz-mac-defaultbuttontext",
276 "ui.-moz-mac-focusring",
277 "ui.-moz_mac_disabledtoolbartext",
279 "ui.-moz-sidebartext",
280 "ui.-moz-sidebarborder",
282 "ui.accentcolortext",
283 "ui.-moz-autofill-background",
284 "ui.-moz-nativehyperlinktext",
285 "ui.-moz-nativevisitedhyperlinktext",
286 "ui.-moz-hyperlinktext",
287 "ui.-moz-activehyperlinktext",
288 "ui.-moz-visitedhyperlinktext",
290 "ui.-moz-colheadertext",
291 "ui.-moz-colheaderhover",
292 "ui.-moz-colheaderhovertext",
293 "ui.-moz-colheaderactive",
294 "ui.-moz-colheaderactivetext",
295 "ui.textSelectDisabledBackground",
296 "ui.textSelectAttentionBackground",
297 "ui.textSelectAttentionForeground",
298 "ui.textHighlightBackground",
299 "ui.textHighlightForeground",
300 "ui.targetTextBackground",
301 "ui.targetTextForeground",
302 "ui.IMERawInputBackground",
303 "ui.IMERawInputForeground",
304 "ui.IMERawInputUnderline",
305 "ui.IMESelectedRawTextBackground",
306 "ui.IMESelectedRawTextForeground",
307 "ui.IMESelectedRawTextUnderline",
308 "ui.IMEConvertedTextBackground",
309 "ui.IMEConvertedTextForeground",
310 "ui.IMEConvertedTextUnderline",
311 "ui.IMESelectedConvertedTextBackground",
312 "ui.IMESelectedConvertedTextForeground",
313 "ui.IMESelectedConvertedTextUnderline",
314 "ui.SpellCheckerUnderline",
315 "ui.themedScrollbar",
316 "ui.themedScrollbarInactive",
317 "ui.themedScrollbarThumb",
318 "ui.themedScrollbarThumbHover",
319 "ui.themedScrollbarThumbActive",
320 "ui.themedScrollbarThumbInactive",
323 static_assert(ArrayLength(sColorPrefs
) == size_t(LookAndFeel::ColorID::End
),
324 "Should have a pref for each color value");
326 // This array MUST be kept in the same order as the SystemFont enum.
327 static const char sFontPrefs
[][41] = {
331 "ui.font.message-box",
332 "ui.font.small-caption",
333 "ui.font.status-bar",
334 "ui.font.-moz-pull-down-menu",
335 "ui.font.-moz-button",
337 "ui.font.-moz-field",
340 static_assert(ArrayLength(sFontPrefs
) == size_t(LookAndFeel::FontID::End
),
341 "Should have a pref for each font value");
343 const char* nsXPLookAndFeel::GetColorPrefName(ColorID aId
) {
344 return sColorPrefs
[size_t(aId
)];
347 bool nsXPLookAndFeel::sInitialized
= false;
349 nsXPLookAndFeel
* nsXPLookAndFeel::sInstance
= nullptr;
350 bool nsXPLookAndFeel::sShutdown
= false;
352 auto LookAndFeel::SystemZoomSettings() -> ZoomSettings
{
353 ZoomSettings settings
;
354 switch (StaticPrefs::browser_display_os_zoom_behavior()) {
359 settings
.mFullZoom
= GetTextScaleFactor();
362 settings
.mTextZoom
= GetTextScaleFactor();
369 nsXPLookAndFeel
* nsXPLookAndFeel::GetInstance() {
374 NS_ENSURE_TRUE(!sShutdown
, nullptr);
376 // If we're in a content process, then the parent process will have supplied
377 // us with an initial FullLookAndFeel object.
378 // We grab this data from the ContentChild,
379 // where it's been temporarily stashed, and initialize our new LookAndFeel
382 FullLookAndFeel
* lnf
= nullptr;
384 if (auto* cc
= mozilla::dom::ContentChild::GetSingleton()) {
385 lnf
= &cc
->BorrowLookAndFeelData();
389 sInstance
= new widget::RemoteLookAndFeel(std::move(*lnf
));
390 } else if (gfxPlatform::IsHeadless()) {
391 sInstance
= new widget::HeadlessLookAndFeel();
393 sInstance
= new nsLookAndFeel();
396 // This is only ever used once during initialization, and can be cleared now.
401 widget::Theme::Init();
406 void nsXPLookAndFeel::Shutdown() {
415 // This keeps strings alive, so need to clear to make leak checking happy.
418 widget::Theme::Shutdown();
421 static void IntPrefChanged(const nsACString
& aPref
) {
422 // Most Int prefs can't change our system colors or fonts, but
423 // ui.systemUsesDarkTheme can, since it affects the effective color-scheme
424 // (affecting system colors).
425 auto changeKind
= aPref
.EqualsLiteral("ui.systemUsesDarkTheme")
426 ? widget::ThemeChangeKind::Style
427 : widget::ThemeChangeKind::MediaQueriesOnly
;
428 LookAndFeel::NotifyChangedAllWindows(changeKind
);
431 static void FloatPrefChanged(const nsACString
& aPref
) {
432 // Most float prefs can't change our system colors or fonts, but
433 // textScaleFactor affects layout.
434 auto changeKind
= aPref
.EqualsLiteral("ui.textScaleFactor")
435 ? widget::ThemeChangeKind::StyleAndLayout
436 : widget::ThemeChangeKind::MediaQueriesOnly
;
437 LookAndFeel::NotifyChangedAllWindows(changeKind
);
440 static void ColorPrefChanged() {
441 // Color prefs affect style, because they by definition change system colors.
442 LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind::Style
);
445 static void FontPrefChanged() {
446 // Color prefs affect style, because they by definition change system fonts.
447 LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind::Style
);
451 void nsXPLookAndFeel::OnPrefChanged(const char* aPref
, void* aClosure
) {
452 nsDependentCString
prefName(aPref
);
453 for (const char* pref
: sIntPrefs
) {
454 if (prefName
.Equals(pref
)) {
455 IntPrefChanged(prefName
);
460 for (const char* pref
: sFloatPrefs
) {
461 if (prefName
.Equals(pref
)) {
462 FloatPrefChanged(prefName
);
467 for (const char* pref
: sColorPrefs
) {
468 // We use StringBeginsWith to handle .dark prefs too.
469 if (StringBeginsWith(prefName
, nsDependentCString(pref
))) {
475 for (const char* pref
: sFontPrefs
) {
476 if (StringBeginsWith(prefName
, nsDependentCString(pref
))) {
483 static constexpr struct {
484 nsLiteralCString mName
;
485 widget::ThemeChangeKind mChangeKind
=
486 widget::ThemeChangeKind::MediaQueriesOnly
;
487 } kMediaQueryPrefs
[] = {
488 // Affects whether standins are used for the accent color.
489 {"widget.non-native-theme.use-theme-accent"_ns
,
490 widget::ThemeChangeKind::Style
},
491 // These three affect system colors on Windows.
492 {"widget.windows.uwp-system-colors.enabled"_ns
,
493 widget::ThemeChangeKind::Style
},
494 {"widget.windows.uwp-system-colors.highlight-accent"_ns
,
495 widget::ThemeChangeKind::Style
},
497 {"layout.css.prefers-color-scheme.content-override"_ns
,
498 widget::ThemeChangeKind::Style
},
499 // Affects media queries and scrollbar sizes, so gotta relayout.
500 {"widget.gtk.overlay-scrollbars.enabled"_ns
,
501 widget::ThemeChangeKind::StyleAndLayout
},
502 // Affects zoom settings which includes text and full zoom.
503 {"browser.display.os-zoom-behavior"_ns
,
504 widget::ThemeChangeKind::StyleAndLayout
},
505 // This affects system colors on Linux.
506 {"widget.gtk.libadwaita-colors.enabled"_ns
, widget::ThemeChangeKind::Style
},
507 // This affects not only the media query, but also the native theme, so we
508 // need to re-layout.
509 {"browser.theme.toolbar-theme"_ns
, widget::ThemeChangeKind::AllBits
},
510 {"browser.theme.content-theme"_ns
},
513 // Read values from the user's preferences.
514 // This is done once at startup, but since the user's preferences
515 // haven't actually been read yet at that time, we also have to
516 // set a callback to inform us of changes to each pref.
517 void nsXPLookAndFeel::Init() {
518 MOZ_RELEASE_ASSERT(NS_IsMainThread());
520 // Say we're already initialized, and take the chance that it might fail;
521 // protects against some other process writing to our static variables.
524 if (XRE_IsParentProcess()) {
525 nsLayoutUtils::RecomputeSmoothScrollDefault();
528 // XXX If we could reorganize the pref names, we should separate the branch
529 // for each types. Then, we could reduce the unnecessary loop from
530 // nsXPLookAndFeel::OnPrefChanged().
531 Preferences::RegisterPrefixCallback(OnPrefChanged
, "ui.");
533 for (const auto& pref
: kMediaQueryPrefs
) {
534 Preferences::RegisterCallback(
535 [](const char*, void* aChangeKind
) {
537 widget::ThemeChangeKind(reinterpret_cast<uintptr_t>(aChangeKind
));
538 LookAndFeel::NotifyChangedAllWindows(changeKind
);
540 pref
.mName
, reinterpret_cast<void*>(uintptr_t(pref
.mChangeKind
)));
544 nsXPLookAndFeel::~nsXPLookAndFeel() {
545 NS_ASSERTION(sInstance
== this,
546 "This destroying instance isn't the singleton instance");
550 static bool IsSpecialColor(LookAndFeel::ColorID aID
, nscolor aColor
) {
551 using ColorID
= LookAndFeel::ColorID
;
553 if (aColor
== NS_SAME_AS_FOREGROUND_COLOR
) {
558 case ColorID::IMESelectedRawTextBackground
:
559 case ColorID::IMESelectedConvertedTextBackground
:
560 case ColorID::IMERawInputBackground
:
561 case ColorID::IMEConvertedTextBackground
:
562 case ColorID::IMESelectedRawTextForeground
:
563 case ColorID::IMESelectedConvertedTextForeground
:
564 case ColorID::IMERawInputForeground
:
565 case ColorID::IMEConvertedTextForeground
:
566 case ColorID::IMERawInputUnderline
:
567 case ColorID::IMEConvertedTextUnderline
:
568 case ColorID::IMESelectedRawTextUnderline
:
569 case ColorID::IMESelectedConvertedTextUnderline
:
570 case ColorID::SpellCheckerUnderline
:
571 return NS_IS_SELECTION_SPECIAL_COLOR(aColor
);
576 * In GetColor(), every color that is not a special color is color
577 * corrected. Use false to make other colors color corrected.
582 nscolor
nsXPLookAndFeel::GetStandinForNativeColor(ColorID aID
,
583 ColorScheme aScheme
) {
584 if (aScheme
== ColorScheme::Dark
) {
585 if (auto color
= GenericDarkColor(aID
)) {
590 // The stand-in colors are taken from what the non-native theme needs (for
591 // field/button colors), the Windows 7 Aero theme except Mac-specific colors
592 // which are taken from Mac OS 10.7.
594 #define COLOR(name_, r, g, b) \
595 case ColorID::name_: \
596 return NS_RGB(r, g, b);
598 #define COLORA(name_, r, g, b, a) \
599 case ColorID::name_: \
600 return NS_RGBA(r, g, b, a);
603 // These are here for the purposes of headless mode.
604 case ColorID::IMESelectedRawTextBackground
:
605 case ColorID::IMESelectedConvertedTextBackground
:
606 case ColorID::IMERawInputBackground
:
607 case ColorID::IMEConvertedTextBackground
:
608 return NS_TRANSPARENT
;
609 case ColorID::IMESelectedRawTextForeground
:
610 case ColorID::IMESelectedConvertedTextForeground
:
611 case ColorID::IMERawInputForeground
:
612 case ColorID::IMEConvertedTextForeground
:
613 return NS_SAME_AS_FOREGROUND_COLOR
;
614 case ColorID::IMERawInputUnderline
:
615 case ColorID::IMEConvertedTextUnderline
:
616 return NS_40PERCENT_FOREGROUND_COLOR
;
617 case ColorID::Accentcolor
:
618 return widget::sDefaultAccent
.ToABGR();
619 case ColorID::Accentcolortext
:
620 return widget::sDefaultAccentText
.ToABGR();
621 COLOR(SpellCheckerUnderline
, 0xff, 0x00, 0x00)
622 COLOR(TextSelectDisabledBackground
, 0xAA, 0xAA, 0xAA)
625 // deprecated in CSS Color Level 4, same as Buttonborder:
626 COLOR(Activeborder
, 0xE3, 0xE3, 0xE3)
627 // deprecated in CSS Color Level 4, same as Buttonborder:
628 COLOR(Inactiveborder
, 0xE3, 0xE3, 0xE3)
629 // deprecated in CSS Color Level 4, same as Canvas/Window:
630 COLOR(Activecaption
, 0xFF, 0xFF, 0xFF)
631 // deprecated in CSS Color Level 4, same as Canvas/Window:
632 COLOR(Inactivecaption
, 0xFF, 0xFF, 0xFF)
633 // deprecated in CSS Color Level 4, same as Canvastext/Windowtext:
634 COLOR(Captiontext
, 0x00, 0x00, 0x00)
635 // deprecated in CSS Color Level 4, same as Graytext:
636 COLOR(Inactivecaptiontext
, 0x6D, 0x6D, 0x6D)
639 // deprecated in CSS Color Level 4, same as Canvas/Window:
640 COLOR(Appworkspace
, 0xFF, 0xFF, 0xFF)
641 // deprecated in CSS Color Level 4, same as Canvas/Window:
642 COLOR(Background
, 0xFF, 0xFF, 0xFF)
643 // deprecated in CSS Color Level 4, same as Buttonface:
644 COLOR(Buttonhighlight
, 0xE9, 0xE9, 0xED)
645 // deprecated in CSS Color Level 4, same as Buttonface:
646 COLOR(Buttonshadow
, 0xE9, 0xE9, 0xED)
648 // Buttons and comboboxes should be kept in sync since they are drawn with
649 // the same colors by the non-native theme.
650 COLOR(Buttonface
, 0xE9, 0xE9, 0xED)
651 COLORA(MozButtondisabledface
, 0xE9, 0xE9, 0xED, 128)
653 COLOR(MozCombobox
, 0xE9, 0xE9, 0xED)
655 COLOR(Buttontext
, 0x00, 0x00, 0x00)
656 COLOR(MozComboboxtext
, 0x00, 0x00, 0x00)
658 COLOR(Graytext
, 0x6D, 0x6D, 0x6D)
659 COLOR(Highlight
, 0x33, 0x99, 0xFF)
660 COLOR(Highlighttext
, 0xFF, 0xFF, 0xFF)
661 // deprecated in CSS Color Level 4, same as Canvas/Window:
662 COLOR(Infobackground
, 0xFF, 0xFF, 0xFF)
663 // deprecated in CSS Color Level 4, same as Canvastext/Windowtext:
664 COLOR(Infotext
, 0x00, 0x00, 0x00)
665 // deprecated in CSS Color Level 4, same as Canvas/Window:
666 COLOR(Menu
, 0xFF, 0xFF, 0xFF)
667 // deprecated in CSS Color Level 4, same as Canvastext/Windowtext:
668 COLOR(Menutext
, 0x00, 0x00, 0x00)
669 // deprecated in CSS Color Level 4, same as Canvas/Window:
670 COLOR(Scrollbar
, 0xFF, 0xFF, 0xFF)
671 // deprecated in CSS Color Level 4, same as Buttonborder:
672 COLOR(Threeddarkshadow
, 0xE3, 0xE3, 0xE3)
673 // deprecated in CSS Color Level 4, same as Buttonface:
674 COLOR(Threedface
, 0xE9, 0xE9, 0xED)
675 // deprecated in CSS Color Level 4, same as Buttonborder:
676 COLOR(Threedhighlight
, 0xE3, 0xE3, 0xE3)
677 COLOR(Threedlightshadow
, 0xE3, 0xE3, 0xE3)
678 // deprecated in CSS Color Level 4, same as Buttonborder:
679 COLOR(Threedshadow
, 0xE3, 0xE3, 0xE3)
680 COLOR(Buttonborder
, 0xE3, 0xE3, 0xE3)
681 COLOR(Mark
, 0xFF, 0xFF, 0x00)
682 COLOR(Marktext
, 0x00, 0x00, 0x00)
683 COLOR(Window
, 0xFF, 0xFF, 0xFF)
684 // deprecated in CSS Color Level 4, same as Buttonborder:
685 COLOR(Windowframe
, 0xE3, 0xE3, 0xE3)
686 COLOR(Windowtext
, 0x00, 0x00, 0x00)
687 COLOR(Field
, 0xFF, 0xFF, 0xFF)
688 COLORA(MozDisabledfield
, 0xFF, 0xFF, 0xFF, 128)
689 COLOR(Fieldtext
, 0x00, 0x00, 0x00)
690 COLOR(MozDialog
, 0xF0, 0xF0, 0xF0)
691 COLOR(MozDialogtext
, 0x00, 0x00, 0x00)
692 COLOR(MozColheadertext
, 0x00, 0x00, 0x00)
693 COLOR(MozColheaderhovertext
, 0x00, 0x00, 0x00)
694 COLOR(MozCellhighlight
, 0xF0, 0xF0, 0xF0)
695 COLOR(MozCellhighlighttext
, 0x00, 0x00, 0x00)
696 COLOR(Selecteditem
, 0x33, 0x99, 0xFF)
697 COLOR(Selecteditemtext
, 0xFF, 0xFF, 0xFF)
698 COLOR(MozButtonhoverface
, 0xd0, 0xd0, 0xd7)
699 COLOR(MozButtonhovertext
, 0x00, 0x00, 0x00)
700 COLOR(MozButtonactiveface
, 0xb1, 0xb1, 0xb9)
701 COLOR(MozButtonactivetext
, 0x00, 0x00, 0x00)
702 COLOR(MozMenuhover
, 0x33, 0x99, 0xFF)
703 COLOR(MozMenuhovertext
, 0x00, 0x00, 0x00)
704 COLOR(MozMenubarhovertext
, 0x00, 0x00, 0x00)
705 COLOR(MozMenuhoverdisabled
, 0xF0, 0xF0, 0xF0)
706 COLOR(MozEventreerow
, 0xFF, 0xFF, 0xFF)
707 COLOR(MozOddtreerow
, 0xFF, 0xFF, 0xFF)
708 COLOR(MozMacFocusring
, 0x60, 0x9D, 0xD7)
709 COLOR(MozMacDisabledtoolbartext
, 0x3F, 0x3F, 0x3F)
710 // Seems to be the default color (hardcoded because of bug 1065998)
711 COLOR(MozNativehyperlinktext
, 0x00, 0x66, 0xCC)
712 COLOR(MozNativevisitedhyperlinktext
, 0x55, 0x1A, 0x8B)
713 COLOR(MozAutofillBackground
, 0xff, 0xfc, 0xc8)
714 COLOR(TargetTextBackground
, 0xff, 0xeb, 0xcd)
715 COLOR(TargetTextForeground
, 0x00, 0x00, 0x00)
719 return NS_RGB(0xFF, 0xFF, 0xFF);
725 // Taken from in-content/common.inc.css's dark theme.
726 Maybe
<nscolor
> nsXPLookAndFeel::GenericDarkColor(ColorID aID
) {
727 nscolor color
= NS_RGB(0, 0, 0);
728 static constexpr nscolor kWindowBackground
= NS_RGB(28, 27, 34);
729 static constexpr nscolor kWindowText
= NS_RGB(251, 251, 254);
731 case ColorID::Window
: // --in-content-page-background
732 case ColorID::Background
:
733 case ColorID::Appworkspace
:
734 case ColorID::Scrollbar
:
735 case ColorID::Infobackground
:
736 color
= kWindowBackground
;
740 color
= NS_RGB(0x2b, 0x2a, 0x33);
743 case ColorID::MozMenuhovertext
:
744 case ColorID::MozMenubarhovertext
:
745 case ColorID::Menutext
:
746 color
= NS_RGB(0xfb, 0xfb, 0xfe);
749 case ColorID::MozMenuhover
:
750 color
= NS_RGB(0x52, 0x52, 0x5e);
753 case ColorID::MozMenuhoverdisabled
:
754 color
= NS_RGB(0x3a, 0x39, 0x44);
757 case ColorID::MozEventreerow
:
758 case ColorID::MozOddtreerow
:
759 case ColorID::MozDialog
: // --in-content-box-background
760 color
= NS_RGB(35, 34, 43);
762 case ColorID::Windowtext
: // --in-content-page-color
763 case ColorID::MozDialogtext
:
764 case ColorID::MozSidebartext
:
765 case ColorID::Fieldtext
:
766 case ColorID::Infotext
:
767 case ColorID::Buttontext
: // --in-content-button-text-color (via
768 // --in-content-page-color)
769 case ColorID::MozComboboxtext
:
770 case ColorID::MozButtonhovertext
:
771 case ColorID::MozButtonactivetext
:
772 case ColorID::MozHeaderbartext
:
773 case ColorID::MozHeaderbarinactivetext
:
774 case ColorID::Captiontext
:
775 case ColorID::Inactivecaptiontext
: // TODO(emilio): Maybe make
776 // Inactivecaptiontext Graytext?
777 case ColorID::MozColheadertext
:
778 case ColorID::MozColheaderhovertext
:
779 case ColorID::MozColheaderactivetext
:
782 case ColorID::Buttonshadow
:
783 case ColorID::Threedshadow
:
784 case ColorID::MozSidebarborder
:
785 case ColorID::Threedlightshadow
:
786 case ColorID::Threedhighlight
:
787 case ColorID::Windowframe
:
788 case ColorID::Buttonborder
: // --in-content-box-border-color computed
789 // with kWindowText above
790 // kWindowBackground.
791 case ColorID::Graytext
: // opacity: 0.4 of kWindowText blended over the
792 // "Window" background color, which happens to be
794 color
= NS_ComposeColors(kWindowBackground
, NS_RGBA(251, 251, 254, 102));
796 case ColorID::MozCellhighlight
:
797 case ColorID::Selecteditem
: // --in-content-primary-button-background /
798 // --in-content-item-selected
799 color
= NS_RGB(0, 221, 255);
801 case ColorID::MozSidebar
:
803 case ColorID::Buttonface
: // --in-content-button-background
804 case ColorID::Buttonhighlight
:
805 case ColorID::MozColheader
:
806 case ColorID::Threedface
:
807 case ColorID::MozCombobox
:
808 case ColorID::MozCellhighlighttext
:
809 case ColorID::Selecteditemtext
: // --in-content-primary-button-text-color /
810 // --in-content-item-selected-text
811 color
= NS_RGB(43, 42, 51);
813 case ColorID::Threeddarkshadow
: // Same as Threedlightshadow but with the
815 case ColorID::MozDisabledfield
: // opacity: 0.4 of the face above blended
816 // over the "Window" background color.
817 case ColorID::MozButtondisabledface
:
818 color
= NS_ComposeColors(kWindowBackground
, NS_RGBA(43, 42, 51, 102));
820 case ColorID::MozButtonhoverface
: // --in-content-button-background-hover
821 case ColorID::MozColheaderhover
:
822 color
= NS_RGB(82, 82, 94);
824 case ColorID::MozButtonactiveface
: // --in-content-button-background-active
825 case ColorID::MozColheaderactive
:
826 color
= NS_RGB(91, 91, 102);
828 case ColorID::Highlight
:
829 color
= NS_RGBA(0, 221, 255, 78);
831 case ColorID::Highlighttext
:
832 color
= NS_SAME_AS_FOREGROUND_COLOR
;
834 case ColorID::MozNativehyperlinktext
:
835 // If you change this color, you probably also want to change the default
836 // value of browser.anchor_color.dark.
837 color
= NS_RGB(0x8c, 0x8c, 0xff);
839 case ColorID::MozNativevisitedhyperlinktext
:
840 // If you change this color, you probably also want to change the default
841 // value of browser.visited_color.dark.
842 color
= NS_RGB(0xff, 0xad, 0xff);
844 case ColorID::SpellCheckerUnderline
:
845 // This is the default for active links in dark mode as well
846 // (browser.active_color.dark). See bug 1755564 for some analysis and
847 // other options too.
848 color
= NS_RGB(0xff, 0x66, 0x66);
850 case ColorID::Activeborder
:
851 case ColorID::Inactiveborder
:
852 color
= NS_RGB(57, 57, 57);
854 case ColorID::MozHeaderbar
:
855 case ColorID::MozHeaderbarinactive
:
856 case ColorID::Activecaption
:
857 case ColorID::Inactivecaption
:
858 color
= NS_RGB(28, 27, 34);
860 case ColorID::MozAutofillBackground
:
861 // This is the light version of this color, but darkened to have good
862 // contrast with our white-ish FieldText.
863 color
= NS_RGB(0x72, 0x6c, 0x00);
871 // Uncomment the #define below if you want to debug system color use in a skin
872 // that uses them. When set, it will make all system color pairs that are
873 // appropriate for foreground/background pairing the same. This means if the
874 // skin is using system colors correctly you will not be able to see *any* text.
876 // #define DEBUG_SYSTEM_COLOR_USE
878 #ifdef DEBUG_SYSTEM_COLOR_USE
879 static nsresult
SystemColorUseDebuggingColor(LookAndFeel::ColorID aID
,
881 using ColorID
= LookAndFeel::ColorID
;
884 // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
885 case ColorID::Activecaption
:
886 // active window caption background
887 case ColorID::Captiontext
:
888 // text in active window caption
889 aResult
= NS_RGB(0xff, 0x00, 0x00);
892 case ColorID::Highlight
:
893 // background of selected item
894 case ColorID::Highlighttext
:
895 // text of selected item
896 aResult
= NS_RGB(0xff, 0xff, 0x00);
899 case ColorID::Inactivecaption
:
900 // inactive window caption
901 case ColorID::Inactivecaptiontext
:
902 // text in inactive window caption
903 aResult
= NS_RGB(0x66, 0x66, 0x00);
906 case ColorID::Infobackground
:
907 // tooltip background color
908 case ColorID::Infotext
:
909 // tooltip text color
910 aResult
= NS_RGB(0x00, 0xff, 0x00);
915 case ColorID::Menutext
:
917 aResult
= NS_RGB(0x00, 0xff, 0xff);
920 case ColorID::Threedface
:
921 case ColorID::Buttonface
:
923 case ColorID::Buttontext
:
924 // text on push buttons
925 aResult
= NS_RGB(0x00, 0x66, 0x66);
928 case ColorID::Window
:
929 case ColorID::Windowtext
:
930 aResult
= NS_RGB(0x00, 0x00, 0xff);
933 // from the CSS3 working draft (not yet finalized)
934 // http://www.w3.org/tr/2000/wd-css3-userint-20000216.html#color
937 case ColorID::Fieldtext
:
938 aResult
= NS_RGB(0xff, 0x00, 0xff);
941 case ColorID::MozDialog
:
942 case ColorID::MozDialogtext
:
943 aResult
= NS_RGB(0x66, 0x00, 0x66);
947 return NS_ERROR_NOT_AVAILABLE
;
954 static nsresult
GetPrefColor(const char* aPref
, nscolor
& aResult
) {
955 nsAutoCString colorStr
;
956 MOZ_TRY(Preferences::GetCString(aPref
, colorStr
));
957 if (!ServoCSSParser::ComputeColor(nullptr, NS_RGB(0, 0, 0), colorStr
,
959 return NS_ERROR_FAILURE
;
964 static nsresult
GetColorFromPref(LookAndFeel::ColorID aID
, ColorScheme aScheme
,
966 const char* prefName
= sColorPrefs
[size_t(aID
)];
967 if (aScheme
== ColorScheme::Dark
) {
968 nsAutoCString
darkPrefName(prefName
);
969 darkPrefName
.Append(".dark");
970 if (NS_SUCCEEDED(GetPrefColor(darkPrefName
.get(), aResult
))) {
974 return GetPrefColor(prefName
, aResult
);
977 // All these routines will return NS_OK if they have a value,
978 // in which case the nsLookAndFeel should use that value;
979 // otherwise we'll return NS_ERROR_NOT_AVAILABLE, in which case, the
980 // platform-specific nsLookAndFeel should use its own values instead.
981 nsresult
nsXPLookAndFeel::GetColorValue(ColorID aID
, ColorScheme aScheme
,
982 UseStandins aUseStandins
,
988 #ifdef DEBUG_SYSTEM_COLOR_USE
989 if (NS_SUCCEEDED(SystemColorUseDebuggingColor(aID
, aResult
))) {
994 auto& cache
= sColorCaches
.Get(aScheme
, aUseStandins
);
995 if (const auto* cached
= cache
.Get(aID
)) {
996 if (cached
->isNothing()) {
997 return NS_ERROR_FAILURE
;
999 aResult
= cached
->value();
1003 // NOTE: Servo holds a lock and the main thread is paused, so writing to the
1004 // global cache here is fine.
1005 auto result
= GetUncachedColor(aID
, aScheme
, aUseStandins
);
1006 cache
.Insert(aID
, result
);
1008 return NS_ERROR_FAILURE
;
1014 Maybe
<nscolor
> nsXPLookAndFeel::GetUncachedColor(ColorID aID
,
1015 ColorScheme aScheme
,
1016 UseStandins aUseStandins
) {
1017 if (aUseStandins
== UseStandins::Yes
) {
1018 return Some(GetStandinForNativeColor(aID
, aScheme
));
1021 if (NS_SUCCEEDED(GetColorFromPref(aID
, aScheme
, r
))) {
1024 if (NS_SUCCEEDED(NativeGetColor(aID
, aScheme
, r
))) {
1025 if (gfxPlatform::GetCMSMode() == CMSMode::All
&& !IsSpecialColor(aID
, r
)) {
1026 qcms_transform
* transform
= gfxPlatform::GetCMSInverseRGBTransform();
1029 color
[0] = NS_GET_R(r
);
1030 color
[1] = NS_GET_G(r
);
1031 color
[2] = NS_GET_B(r
);
1032 color
[3] = NS_GET_A(r
);
1033 qcms_transform_data(transform
, color
, color
, 1);
1034 r
= NS_RGBA(color
[0], color
[1], color
[2], color
[3]);
1043 nsresult
nsXPLookAndFeel::GetIntValue(IntID aID
, int32_t& aResult
) {
1044 if (!sInitialized
) {
1048 if (const auto* cached
= sIntCache
.Get(aID
)) {
1049 if (cached
->isNothing()) {
1050 return NS_ERROR_FAILURE
;
1052 aResult
= cached
->value();
1056 if (NS_SUCCEEDED(Preferences::GetInt(sIntPrefs
[size_t(aID
)], &aResult
))) {
1057 sIntCache
.Insert(aID
, Some(aResult
));
1061 if (NS_FAILED(NativeGetInt(aID
, aResult
))) {
1062 sIntCache
.Insert(aID
, Nothing());
1063 return NS_ERROR_FAILURE
;
1066 sIntCache
.Insert(aID
, Some(aResult
));
1070 nsresult
nsXPLookAndFeel::GetFloatValue(FloatID aID
, float& aResult
) {
1071 if (!sInitialized
) {
1075 if (const auto* cached
= sFloatCache
.Get(aID
)) {
1076 if (cached
->isNothing()) {
1077 return NS_ERROR_FAILURE
;
1079 aResult
= cached
->value();
1084 if (NS_SUCCEEDED(Preferences::GetInt(sFloatPrefs
[size_t(aID
)], &pref
))) {
1085 aResult
= float(pref
) / 100.0f
;
1086 sFloatCache
.Insert(aID
, Some(aResult
));
1090 if (NS_FAILED(NativeGetFloat(aID
, aResult
))) {
1091 sFloatCache
.Insert(aID
, Nothing());
1092 return NS_ERROR_FAILURE
;
1095 sFloatCache
.Insert(aID
, Some(aResult
));
1099 bool nsXPLookAndFeel::LookAndFeelFontToStyle(const LookAndFeelFont
& aFont
,
1101 gfxFontStyle
& aStyle
) {
1102 if (!aFont
.haveFont()) {
1105 aName
= aFont
.name();
1106 aStyle
= gfxFontStyle();
1107 aStyle
.size
= aFont
.size();
1108 aStyle
.weight
= FontWeight::FromInt(aFont
.weight());
1110 aFont
.italic() ? FontSlantStyle::ITALIC
: FontSlantStyle::NORMAL
;
1111 aStyle
.systemFont
= true;
1115 widget::LookAndFeelFont
nsXPLookAndFeel::StyleToLookAndFeelFont(
1116 const nsAString
& aName
, const gfxFontStyle
& aStyle
) {
1117 LookAndFeelFont font
;
1118 font
.haveFont() = true;
1119 font
.name() = aName
;
1120 font
.size() = aStyle
.size
;
1121 font
.weight() = aStyle
.weight
.ToFloat();
1122 font
.italic() = aStyle
.style
.IsItalic();
1123 MOZ_ASSERT(aStyle
.style
.IsNormal() || aStyle
.style
.IsItalic(),
1124 "Cannot handle oblique font style");
1127 // Assert that all the remaining font style properties have their
1129 gfxFontStyle candidate
= aStyle
;
1130 gfxFontStyle defaults
{};
1131 candidate
.size
= defaults
.size
;
1132 candidate
.weight
= defaults
.weight
;
1133 candidate
.style
= defaults
.style
;
1134 MOZ_ASSERT(candidate
.Equals(defaults
),
1135 "Some font style properties not supported");
1141 bool nsXPLookAndFeel::GetFontValue(FontID aID
, nsString
& aName
,
1142 gfxFontStyle
& aStyle
) {
1143 if (const LookAndFeelFont
* cached
= sFontCache
.Get(aID
)) {
1144 return LookAndFeelFontToStyle(*cached
, aName
, aStyle
);
1147 LookAndFeelFont font
;
1148 auto GetFontsFromPrefs
= [&]() -> bool {
1149 nsDependentCString
pref(sFontPrefs
[size_t(aID
)]);
1150 if (NS_FAILED(Preferences::GetString(pref
.get(), aName
))) {
1153 font
.haveFont() = true;
1154 font
.name() = aName
;
1155 font
.size() = Preferences::GetFloat(nsAutoCString(pref
+ ".size"_ns
).get());
1156 // This is written this way rather than using the fallback so that an empty
1157 // pref (such like the one about:config creates) doesn't cause system fonts
1158 // to have zero-size.
1159 if (font
.size() < 1.0f
) {
1160 font
.size() = StyleFONT_MEDIUM_PX
;
1162 font
.weight() = Preferences::GetFloat(
1163 nsAutoCString(pref
+ ".weight"_ns
).get(), FontWeight::NORMAL
.ToFloat());
1165 Preferences::GetBool(nsAutoCString(pref
+ ".italic"_ns
).get());
1169 if (GetFontsFromPrefs()) {
1170 LookAndFeelFontToStyle(font
, aName
, aStyle
);
1171 } else if (NativeGetFont(aID
, aName
, aStyle
)) {
1172 font
= StyleToLookAndFeelFont(aName
, aStyle
);
1174 MOZ_ASSERT(!font
.haveFont());
1176 bool success
= font
.haveFont();
1177 sFontCache
.Insert(aID
, std::move(font
));
1181 void nsXPLookAndFeel::RefreshImpl() {
1182 // Wipe out our caches.
1183 sColorCaches
.Clear();
1185 sFloatCache
.Clear();
1188 if (XRE_IsParentProcess()) {
1189 nsLayoutUtils::RecomputeSmoothScrollDefault();
1190 // Clear any cached FullLookAndFeel data, which is now invalid.
1191 widget::RemoteLookAndFeel::ClearCachedData();
1195 static bool sRecordedLookAndFeelTelemetry
= false;
1197 void nsXPLookAndFeel::RecordTelemetry() {
1198 if (!XRE_IsParentProcess()) {
1202 if (sRecordedLookAndFeelTelemetry
) {
1206 sRecordedLookAndFeelTelemetry
= true;
1209 Telemetry::ScalarSet(
1210 Telemetry::ScalarID::WIDGET_DARK_MODE
,
1211 NS_SUCCEEDED(GetIntValue(IntID::SystemUsesDarkTheme
, i
)) && i
!= 0);
1213 RecordLookAndFeelSpecificTelemetry();
1218 bool LookAndFeel::sGlobalThemeChanged
;
1219 static widget::ThemeChangeKind sGlobalThemeChangeKind
{0};
1221 void LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind aKind
) {
1222 sGlobalThemeChanged
= true;
1223 sGlobalThemeChangeKind
|= aKind
;
1225 if (nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService()) {
1226 const char16_t kind
[] = {char16_t(aKind
), 0};
1227 obs
->NotifyObservers(nullptr, "internal-look-and-feel-changed", kind
);
1231 void LookAndFeel::DoHandleGlobalThemeChange() {
1232 MOZ_ASSERT(sGlobalThemeChanged
);
1233 sGlobalThemeChanged
= false;
1234 auto kind
= std::exchange(sGlobalThemeChangeKind
, widget::ThemeChangeKind(0));
1236 // Tell the theme that it changed, so it can flush any handles to stale theme
1239 // We can use the *DoNotUseDirectly functions directly here, because we want
1240 // to notify all possible themes in a given process (but just once).
1241 if (XRE_IsParentProcess()) {
1242 if (nsCOMPtr
<nsITheme
> theme
= do_GetNativeThemeDoNotUseDirectly()) {
1243 theme
->ThemeChanged();
1246 if (nsCOMPtr
<nsITheme
> theme
= do_GetBasicNativeThemeDoNotUseDirectly()) {
1247 theme
->ThemeChanged();
1250 // Clear all cached LookAndFeel colors.
1251 LookAndFeel::Refresh();
1253 // Reset default background and foreground colors for the document since they
1254 // may be using system colors, color scheme, etc.
1255 PreferenceSheet::Refresh();
1257 // Vector images (SVG) may be using theme colors so we discard all cached
1258 // surfaces. (We could add a vector image only version of DiscardAll, but
1259 // in bug 940625 we decided theme changes are rare enough not to bother.)
1260 image::SurfaceCacheUtils::DiscardAll();
1262 if (XRE_IsParentProcess()) {
1263 dom::ContentParent::BroadcastThemeUpdate(kind
);
1266 nsContentUtils::AddScriptRunner(
1267 NS_NewRunnableFunction("HandleGlobalThemeChange", [] {
1268 if (nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService()) {
1269 obs
->NotifyObservers(nullptr, "look-and-feel-changed", nullptr);
1274 #define BIT_FOR(_c) (1ull << size_t(ColorID::_c))
1276 // We want to use a non-native color scheme for the non-native theme (except in
1277 // high-contrast mode), so spoof some of the colors with stand-ins to prevent
1278 // lack of contrast.
1279 static constexpr std::bitset
<size_t(ColorID::End
)> sNonNativeThemeStandinColors
{
1280 // Used by default button styles.
1281 BIT_FOR(Buttonface
) | BIT_FOR(Buttontext
) | BIT_FOR(MozButtonhoverface
) |
1282 BIT_FOR(MozButtonhovertext
) | BIT_FOR(MozButtonactiveface
) |
1283 BIT_FOR(MozButtonactivetext
) | BIT_FOR(MozButtondisabledface
) |
1284 BIT_FOR(Buttonborder
) |
1285 // Used by select elements.
1286 BIT_FOR(MozCombobox
) | BIT_FOR(MozComboboxtext
) |
1287 BIT_FOR(Threedlightshadow
) |
1288 // For symmetry with the above.
1289 BIT_FOR(Threeddarkshadow
) |
1290 // Used by fieldset borders.
1291 BIT_FOR(Threedface
) |
1292 // Used by input / textarea.
1293 BIT_FOR(Field
) | BIT_FOR(Fieldtext
) |
1294 // Used by disabled form controls.
1295 BIT_FOR(MozDisabledfield
) | BIT_FOR(Graytext
) |
1296 // Per spec, the following colors are deprecated, see
1297 // https://drafts.csswg.org/css-color-4/#deprecated-system-colors
1298 // should match ButtonFace:
1299 BIT_FOR(Buttonhighlight
) | BIT_FOR(Buttonshadow
) | BIT_FOR(Threedface
) |
1300 // should match ButtonBorder:
1301 BIT_FOR(Activeborder
) | BIT_FOR(Inactiveborder
) |
1302 BIT_FOR(Threeddarkshadow
) | BIT_FOR(Threedhighlight
) |
1303 BIT_FOR(Threedshadow
) | BIT_FOR(Windowframe
) |
1304 // should match GrayText:
1305 BIT_FOR(Inactivecaptiontext
) |
1306 // should match Canvas/Window:
1307 BIT_FOR(Appworkspace
) | BIT_FOR(Background
) | BIT_FOR(Inactivecaption
) |
1308 BIT_FOR(Infobackground
) | BIT_FOR(Menu
) | BIT_FOR(Scrollbar
) |
1309 // should match CanvasText/WindowText:
1310 BIT_FOR(Activecaption
) | BIT_FOR(Captiontext
) | BIT_FOR(Infotext
) |
1312 // Some pages expect these to return windows-like colors, see bug 1773795.
1313 // Also, per spec, these should match Canvas/CanvasText, see
1314 // https://drafts.csswg.org/css-color-4/#valdef-color-window and
1315 // https://drafts.csswg.org/css-color-4/#valdef-color-windowtext
1316 BIT_FOR(Window
) | BIT_FOR(Windowtext
)};
1319 static bool ShouldUseStandinsForNativeColorForNonNativeTheme(
1320 const dom::Document
& aDoc
, LookAndFeel::ColorID aColor
,
1321 const PreferenceSheet::Prefs
& aPrefs
) {
1322 const bool shouldUseStandinsForColor
= [&] {
1323 if (sNonNativeThemeStandinColors
[size_t(aColor
)]) {
1326 // There are platforms where we want the content-exposed accent color to be
1327 // the windows blue rather than the system accent color, for now.
1328 return !StaticPrefs::widget_non_native_theme_use_theme_accent() &&
1329 (aColor
== LookAndFeel::ColorID::Accentcolor
||
1330 aColor
== LookAndFeel::ColorID::Accentcolortext
);
1333 return shouldUseStandinsForColor
&& aDoc
.ShouldAvoidNativeTheme() &&
1334 !aPrefs
.NonNativeThemeShouldBeHighContrast();
1337 bool LookAndFeel::IsDarkColor(nscolor aColor
) {
1338 // Given https://www.w3.org/TR/WCAG20/#contrast-ratiodef, this is the
1339 // threshold that tells us whether contrast is better against white or black.
1341 // Contrast ratio against black is: (L + 0.05) / 0.05
1342 // Contrast ratio against white is: 1.05 / (L + 0.05)
1344 // So the intersection is:
1346 // (L + 0.05) / 0.05 = 1.05 / (L + 0.05)
1348 // And the solution to that equation is:
1350 // sqrt(1.05 * 0.05) - 0.05
1352 // So we consider a color dark if the contrast is below this threshold, and
1353 // it's at least half-opaque.
1354 constexpr float kThreshold
= 0.179129;
1355 return NS_GET_A(aColor
) > 127 &&
1356 RelativeLuminanceUtils::Compute(aColor
) < kThreshold
;
1359 ColorScheme
LookAndFeel::ColorSchemeForStyle(
1360 const dom::Document
& aDoc
, const StyleColorSchemeFlags
& aFlags
,
1361 ColorSchemeMode aMode
) {
1362 const auto& prefs
= PreferenceSheet::PrefsFor(aDoc
);
1363 StyleColorSchemeFlags
style(aFlags
);
1365 style
._0
= aDoc
.GetColorSchemeBits();
1367 const bool supportsDark
= bool(style
& StyleColorSchemeFlags::DARK
);
1368 const bool supportsLight
= bool(style
& StyleColorSchemeFlags::LIGHT
);
1369 if (supportsLight
&& supportsDark
) {
1370 // Both color-schemes are explicitly supported, use the preferred one.
1371 return aDoc
.PreferredColorScheme();
1373 if (supportsDark
|| supportsLight
) {
1374 // One color-scheme is explicitly supported and one isn't, so use the one
1375 // the content supports.
1376 return supportsDark
? ColorScheme::Dark
: ColorScheme::Light
;
1378 // No value specified. Chrome docs, and forced-colors mode always supports
1379 // both, so use the preferred color-scheme.
1380 if (aMode
== ColorSchemeMode::Preferred
|| aDoc
.ChromeRulesEnabled() ||
1381 !prefs
.mUseDocumentColors
) {
1382 return aDoc
.PreferredColorScheme();
1384 // Otherwise default content to light.
1385 return ColorScheme::Light
;
1388 LookAndFeel::ColorScheme
LookAndFeel::ColorSchemeForFrame(
1389 const nsIFrame
* aFrame
, ColorSchemeMode aMode
) {
1390 return ColorSchemeForStyle(*aFrame
->PresContext()->Document(),
1391 aFrame
->StyleUI()->mColorScheme
.bits
, aMode
);
1395 Maybe
<nscolor
> LookAndFeel::GetColor(ColorID aId
, ColorScheme aScheme
,
1396 UseStandins aUseStandins
) {
1398 nsresult rv
= nsLookAndFeel::GetInstance()->GetColorValue(
1399 aId
, aScheme
, aUseStandins
, result
);
1400 if (NS_FAILED(rv
)) {
1403 return Some(result
);
1406 // Returns whether there is a CSS color name for this color.
1407 static bool ColorIsCSSAccessible(LookAndFeel::ColorID aId
) {
1408 using ColorID
= LookAndFeel::ColorID
;
1411 case ColorID::TextSelectDisabledBackground
:
1412 case ColorID::TextSelectAttentionBackground
:
1413 case ColorID::TextSelectAttentionForeground
:
1414 case ColorID::TextHighlightBackground
:
1415 case ColorID::TextHighlightForeground
:
1416 case ColorID::ThemedScrollbar
:
1417 case ColorID::ThemedScrollbarInactive
:
1418 case ColorID::ThemedScrollbarThumb
:
1419 case ColorID::ThemedScrollbarThumbActive
:
1420 case ColorID::ThemedScrollbarThumbInactive
:
1421 case ColorID::ThemedScrollbarThumbHover
:
1422 case ColorID::IMERawInputBackground
:
1423 case ColorID::IMERawInputForeground
:
1424 case ColorID::IMERawInputUnderline
:
1425 case ColorID::IMESelectedRawTextBackground
:
1426 case ColorID::IMESelectedRawTextForeground
:
1427 case ColorID::IMESelectedRawTextUnderline
:
1428 case ColorID::IMEConvertedTextBackground
:
1429 case ColorID::IMEConvertedTextForeground
:
1430 case ColorID::IMEConvertedTextUnderline
:
1431 case ColorID::IMESelectedConvertedTextBackground
:
1432 case ColorID::IMESelectedConvertedTextForeground
:
1433 case ColorID::IMESelectedConvertedTextUnderline
:
1434 case ColorID::SpellCheckerUnderline
:
1443 LookAndFeel::UseStandins
LookAndFeel::ShouldUseStandins(
1444 const dom::Document
& aDoc
, ColorID aId
) {
1445 const auto& prefs
= PreferenceSheet::PrefsFor(aDoc
);
1446 if (ShouldUseStandinsForNativeColorForNonNativeTheme(aDoc
, aId
, prefs
)) {
1447 return UseStandins::Yes
;
1449 if (prefs
.mUseStandins
&& ColorIsCSSAccessible(aId
)) {
1450 return UseStandins::Yes
;
1452 return UseStandins::No
;
1455 Maybe
<nscolor
> LookAndFeel::GetColor(ColorID aId
, const nsIFrame
* aFrame
) {
1456 const auto* doc
= aFrame
->PresContext()->Document();
1457 return GetColor(aId
, ColorSchemeForFrame(aFrame
),
1458 ShouldUseStandins(*doc
, aId
));
1462 nsresult
LookAndFeel::GetInt(IntID aID
, int32_t* aResult
) {
1463 return nsLookAndFeel::GetInstance()->GetIntValue(aID
, *aResult
);
1467 nsresult
LookAndFeel::GetFloat(FloatID aID
, float* aResult
) {
1468 return nsLookAndFeel::GetInstance()->GetFloatValue(aID
, *aResult
);
1472 bool LookAndFeel::GetFont(FontID aID
, nsString
& aName
, gfxFontStyle
& aStyle
) {
1473 return nsLookAndFeel::GetInstance()->GetFontValue(aID
, aName
, aStyle
);
1477 char16_t
LookAndFeel::GetPasswordCharacter() {
1478 return nsLookAndFeel::GetInstance()->GetPasswordCharacterImpl();
1482 bool LookAndFeel::GetEchoPassword() {
1483 if (StaticPrefs::editor_password_mask_delay() >= 0) {
1484 return StaticPrefs::editor_password_mask_delay() > 0;
1486 return nsLookAndFeel::GetInstance()->GetEchoPasswordImpl();
1490 uint32_t LookAndFeel::GetPasswordMaskDelay() {
1491 int32_t delay
= StaticPrefs::editor_password_mask_delay();
1493 return nsLookAndFeel::GetInstance()->GetPasswordMaskDelayImpl();
1498 bool LookAndFeel::DrawInTitlebar() {
1499 switch (StaticPrefs::browser_tabs_inTitlebar()) {
1507 return nsLookAndFeel::GetInstance()->GetDefaultDrawInTitlebar();
1510 LookAndFeel::TitlebarAction
LookAndFeel::GetTitlebarAction(
1511 TitlebarEvent aEvent
) {
1512 return nsLookAndFeel::GetInstance()->GetTitlebarAction(aEvent
);
1515 void LookAndFeel::GetThemeInfo(nsACString
& aOut
) {
1516 nsLookAndFeel::GetInstance()->GetThemeInfo(aOut
);
1519 uint32_t LookAndFeel::GetMenuAccessKey() {
1520 return StaticPrefs::ui_key_menuAccessKey();
1523 Modifiers
LookAndFeel::GetMenuAccessKeyModifiers() {
1524 switch (GetMenuAccessKey()) {
1525 case dom::KeyboardEvent_Binding::DOM_VK_SHIFT
:
1526 return MODIFIER_SHIFT
;
1527 case dom::KeyboardEvent_Binding::DOM_VK_CONTROL
:
1528 return MODIFIER_CONTROL
;
1529 case dom::KeyboardEvent_Binding::DOM_VK_ALT
:
1530 return MODIFIER_ALT
;
1531 case dom::KeyboardEvent_Binding::DOM_VK_META
:
1532 case dom::KeyboardEvent_Binding::DOM_VK_WIN
:
1533 return MODIFIER_META
;
1540 void LookAndFeel::Refresh() {
1541 nsLookAndFeel::GetInstance()->RefreshImpl();
1542 widget::Theme::LookAndFeelChanged();
1546 void LookAndFeel::NativeInit() { nsLookAndFeel::GetInstance()->NativeInit(); }
1549 void LookAndFeel::SetData(widget::FullLookAndFeel
&& aTables
) {
1550 nsLookAndFeel::GetInstance()->SetDataImpl(std::move(aTables
));
1553 } // namespace mozilla