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.caretVisibleWithSelection",
132 "ui.selectTextfieldsOnKeyFocus",
134 "ui.menusCanOverlapOSBar",
135 "ui.useOverlayScrollbars",
136 "ui.allowOverlayScrollbarsOverlap",
137 "ui.skipNavigatingDisabledMenuItem",
140 "ui.useAccessibilityTheme",
141 "ui.scrollArrowStyle",
142 "ui.scrollButtonLeftMouseButtonAction",
143 "ui.scrollButtonMiddleMouseButtonAction",
144 "ui.scrollButtonRightMouseButtonAction",
147 "ui.treeLazyScrollDelay",
148 "ui.treeScrollDelay",
149 "ui.treeScrollLinesMax",
150 "accessibility.tabfocus", // Weird one...
151 "ui.chosenMenuItemsShouldBlink",
152 "ui.windowsAccentColorInTitlebar",
155 "ui.alertNotificationOrigin",
157 "ui.IMERawInputUnderlineStyle",
158 "ui.IMESelectedRawTextUnderlineStyle",
159 "ui.IMEConvertedTextUnderlineStyle",
160 "ui.IMESelectedConvertedTextUnderlineStyle",
161 "ui.SpellCheckerUnderlineStyle",
163 "ui.scrollbarButtonAutoRepeatBehavior",
164 "ui.swipeAnimationEnabled",
165 "ui.scrollbarDisplayOnMouseMove",
166 "ui.scrollbarFadeBeginDelay",
167 "ui.scrollbarFadeDuration",
168 "ui.contextMenuOffsetVertical",
169 "ui.contextMenuOffsetHorizontal",
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.videoDynamicRange",
190 "ui.panelAnimations",
191 "ui.hideCursorWhileTyping",
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.IMERawInputBackground",
301 "ui.IMERawInputForeground",
302 "ui.IMERawInputUnderline",
303 "ui.IMESelectedRawTextBackground",
304 "ui.IMESelectedRawTextForeground",
305 "ui.IMESelectedRawTextUnderline",
306 "ui.IMEConvertedTextBackground",
307 "ui.IMEConvertedTextForeground",
308 "ui.IMEConvertedTextUnderline",
309 "ui.IMESelectedConvertedTextBackground",
310 "ui.IMESelectedConvertedTextForeground",
311 "ui.IMESelectedConvertedTextUnderline",
312 "ui.SpellCheckerUnderline",
313 "ui.themedScrollbar",
314 "ui.themedScrollbarInactive",
315 "ui.themedScrollbarThumb",
316 "ui.themedScrollbarThumbHover",
317 "ui.themedScrollbarThumbActive",
318 "ui.themedScrollbarThumbInactive",
321 static_assert(ArrayLength(sColorPrefs
) == size_t(LookAndFeel::ColorID::End
),
322 "Should have a pref for each color value");
324 // This array MUST be kept in the same order as the SystemFont enum.
325 static const char sFontPrefs
[][41] = {
329 "ui.font.message-box",
330 "ui.font.small-caption",
331 "ui.font.status-bar",
332 "ui.font.-moz-pull-down-menu",
333 "ui.font.-moz-button",
335 "ui.font.-moz-field",
338 static_assert(ArrayLength(sFontPrefs
) == size_t(LookAndFeel::FontID::End
),
339 "Should have a pref for each font value");
341 const char* nsXPLookAndFeel::GetColorPrefName(ColorID aId
) {
342 return sColorPrefs
[size_t(aId
)];
345 bool nsXPLookAndFeel::sInitialized
= false;
347 nsXPLookAndFeel
* nsXPLookAndFeel::sInstance
= nullptr;
348 bool nsXPLookAndFeel::sShutdown
= false;
350 auto LookAndFeel::SystemZoomSettings() -> ZoomSettings
{
351 ZoomSettings settings
;
352 switch (StaticPrefs::browser_display_os_zoom_behavior()) {
357 settings
.mFullZoom
= GetTextScaleFactor();
360 settings
.mTextZoom
= GetTextScaleFactor();
367 nsXPLookAndFeel
* nsXPLookAndFeel::GetInstance() {
372 NS_ENSURE_TRUE(!sShutdown
, nullptr);
374 // If we're in a content process, then the parent process will have supplied
375 // us with an initial FullLookAndFeel object.
376 // We grab this data from the ContentChild,
377 // where it's been temporarily stashed, and initialize our new LookAndFeel
380 FullLookAndFeel
* lnf
= nullptr;
382 if (auto* cc
= mozilla::dom::ContentChild::GetSingleton()) {
383 lnf
= &cc
->BorrowLookAndFeelData();
387 sInstance
= new widget::RemoteLookAndFeel(std::move(*lnf
));
388 } else if (gfxPlatform::IsHeadless()) {
389 sInstance
= new widget::HeadlessLookAndFeel();
391 sInstance
= new nsLookAndFeel();
394 // This is only ever used once during initialization, and can be cleared now.
399 widget::Theme::Init();
404 void nsXPLookAndFeel::Shutdown() {
413 // This keeps strings alive, so need to clear to make leak checking happy.
416 widget::Theme::Shutdown();
419 static void IntPrefChanged(const nsACString
& aPref
) {
420 // Most Int prefs can't change our system colors or fonts, but
421 // ui.systemUsesDarkTheme can, since it affects the effective color-scheme
422 // (affecting system colors).
423 auto changeKind
= aPref
.EqualsLiteral("ui.systemUsesDarkTheme")
424 ? widget::ThemeChangeKind::Style
425 : widget::ThemeChangeKind::MediaQueriesOnly
;
426 LookAndFeel::NotifyChangedAllWindows(changeKind
);
429 static void FloatPrefChanged(const nsACString
& aPref
) {
430 // Most float prefs can't change our system colors or fonts, but
431 // textScaleFactor affects layout.
432 auto changeKind
= aPref
.EqualsLiteral("ui.textScaleFactor")
433 ? widget::ThemeChangeKind::StyleAndLayout
434 : widget::ThemeChangeKind::MediaQueriesOnly
;
435 LookAndFeel::NotifyChangedAllWindows(changeKind
);
438 static void ColorPrefChanged() {
439 // Color prefs affect style, because they by definition change system colors.
440 LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind::Style
);
443 static void FontPrefChanged() {
444 // Color prefs affect style, because they by definition change system fonts.
445 LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind::Style
);
449 void nsXPLookAndFeel::OnPrefChanged(const char* aPref
, void* aClosure
) {
450 nsDependentCString
prefName(aPref
);
451 for (const char* pref
: sIntPrefs
) {
452 if (prefName
.Equals(pref
)) {
453 IntPrefChanged(prefName
);
458 for (const char* pref
: sFloatPrefs
) {
459 if (prefName
.Equals(pref
)) {
460 FloatPrefChanged(prefName
);
465 for (const char* pref
: sColorPrefs
) {
466 // We use StringBeginsWith to handle .dark prefs too.
467 if (StringBeginsWith(prefName
, nsDependentCString(pref
))) {
473 for (const char* pref
: sFontPrefs
) {
474 if (StringBeginsWith(prefName
, nsDependentCString(pref
))) {
481 static constexpr struct {
482 nsLiteralCString mName
;
483 widget::ThemeChangeKind mChangeKind
=
484 widget::ThemeChangeKind::MediaQueriesOnly
;
485 } kMediaQueryPrefs
[] = {
486 // Affects whether standins are used for the accent color.
487 {"widget.non-native-theme.use-theme-accent"_ns
,
488 widget::ThemeChangeKind::Style
},
489 // These three affect system colors on Windows.
490 {"widget.windows.uwp-system-colors.enabled"_ns
,
491 widget::ThemeChangeKind::Style
},
492 {"widget.windows.uwp-system-colors.highlight-accent"_ns
,
493 widget::ThemeChangeKind::Style
},
495 {"layout.css.prefers-color-scheme.content-override"_ns
,
496 widget::ThemeChangeKind::Style
},
497 // Affects media queries and scrollbar sizes, so gotta relayout.
498 {"widget.gtk.overlay-scrollbars.enabled"_ns
,
499 widget::ThemeChangeKind::StyleAndLayout
},
500 // Affects zoom settings which includes text and full zoom.
501 {"browser.display.os-zoom-behavior"_ns
,
502 widget::ThemeChangeKind::StyleAndLayout
},
503 // This affects system colors on Linux.
504 {"widget.gtk.libadwaita-colors.enabled"_ns
, widget::ThemeChangeKind::Style
},
505 // This affects not only the media query, but also the native theme, so we
506 // need to re-layout.
507 {"browser.theme.toolbar-theme"_ns
, widget::ThemeChangeKind::AllBits
},
508 {"browser.theme.content-theme"_ns
},
511 // Read values from the user's preferences.
512 // This is done once at startup, but since the user's preferences
513 // haven't actually been read yet at that time, we also have to
514 // set a callback to inform us of changes to each pref.
515 void nsXPLookAndFeel::Init() {
516 MOZ_RELEASE_ASSERT(NS_IsMainThread());
518 // Say we're already initialized, and take the chance that it might fail;
519 // protects against some other process writing to our static variables.
522 if (XRE_IsParentProcess()) {
523 nsLayoutUtils::RecomputeSmoothScrollDefault();
526 // XXX If we could reorganize the pref names, we should separate the branch
527 // for each types. Then, we could reduce the unnecessary loop from
528 // nsXPLookAndFeel::OnPrefChanged().
529 Preferences::RegisterPrefixCallback(OnPrefChanged
, "ui.");
530 // We really do just want the accessibility.tabfocus pref, not other prefs
531 // that start with that string.
532 Preferences::RegisterCallback(OnPrefChanged
, "accessibility.tabfocus");
534 for (const auto& pref
: kMediaQueryPrefs
) {
535 Preferences::RegisterCallback(
536 [](const char*, void* aChangeKind
) {
538 widget::ThemeChangeKind(reinterpret_cast<uintptr_t>(aChangeKind
));
539 LookAndFeel::NotifyChangedAllWindows(changeKind
);
541 pref
.mName
, reinterpret_cast<void*>(uintptr_t(pref
.mChangeKind
)));
545 nsXPLookAndFeel::~nsXPLookAndFeel() {
546 NS_ASSERTION(sInstance
== this,
547 "This destroying instance isn't the singleton instance");
551 static bool IsSpecialColor(LookAndFeel::ColorID aID
, nscolor aColor
) {
552 using ColorID
= LookAndFeel::ColorID
;
554 if (aColor
== NS_SAME_AS_FOREGROUND_COLOR
) {
559 case ColorID::IMESelectedRawTextBackground
:
560 case ColorID::IMESelectedConvertedTextBackground
:
561 case ColorID::IMERawInputBackground
:
562 case ColorID::IMEConvertedTextBackground
:
563 case ColorID::IMESelectedRawTextForeground
:
564 case ColorID::IMESelectedConvertedTextForeground
:
565 case ColorID::IMERawInputForeground
:
566 case ColorID::IMEConvertedTextForeground
:
567 case ColorID::IMERawInputUnderline
:
568 case ColorID::IMEConvertedTextUnderline
:
569 case ColorID::IMESelectedRawTextUnderline
:
570 case ColorID::IMESelectedConvertedTextUnderline
:
571 case ColorID::SpellCheckerUnderline
:
572 return NS_IS_SELECTION_SPECIAL_COLOR(aColor
);
577 * In GetColor(), every color that is not a special color is color
578 * corrected. Use false to make other colors color corrected.
583 nscolor
nsXPLookAndFeel::GetStandinForNativeColor(ColorID aID
,
584 ColorScheme aScheme
) {
585 if (aScheme
== ColorScheme::Dark
) {
586 if (auto color
= GenericDarkColor(aID
)) {
591 // The stand-in colors are taken from what the non-native theme needs (for
592 // field/button colors), the Windows 7 Aero theme except Mac-specific colors
593 // which are taken from Mac OS 10.7.
595 #define COLOR(name_, r, g, b) \
596 case ColorID::name_: \
597 return NS_RGB(r, g, b);
599 #define COLORA(name_, r, g, b, a) \
600 case ColorID::name_: \
601 return NS_RGBA(r, g, b, a);
604 // These are here for the purposes of headless mode.
605 case ColorID::IMESelectedRawTextBackground
:
606 case ColorID::IMESelectedConvertedTextBackground
:
607 case ColorID::IMERawInputBackground
:
608 case ColorID::IMEConvertedTextBackground
:
609 return NS_TRANSPARENT
;
610 case ColorID::IMESelectedRawTextForeground
:
611 case ColorID::IMESelectedConvertedTextForeground
:
612 case ColorID::IMERawInputForeground
:
613 case ColorID::IMEConvertedTextForeground
:
614 return NS_SAME_AS_FOREGROUND_COLOR
;
615 case ColorID::IMERawInputUnderline
:
616 case ColorID::IMEConvertedTextUnderline
:
617 return NS_40PERCENT_FOREGROUND_COLOR
;
618 case ColorID::Accentcolor
:
619 return widget::sDefaultAccent
.ToABGR();
620 case ColorID::Accentcolortext
:
621 return widget::sDefaultAccentText
.ToABGR();
622 COLOR(SpellCheckerUnderline
, 0xff, 0x00, 0x00)
623 COLOR(TextSelectDisabledBackground
, 0xAA, 0xAA, 0xAA)
626 // deprecated in CSS Color Level 4, same as Buttonborder:
627 COLOR(Activeborder
, 0xE3, 0xE3, 0xE3)
628 // deprecated in CSS Color Level 4, same as Buttonborder:
629 COLOR(Inactiveborder
, 0xE3, 0xE3, 0xE3)
630 // deprecated in CSS Color Level 4, same as Canvas/Window:
631 COLOR(Activecaption
, 0xFF, 0xFF, 0xFF)
632 // deprecated in CSS Color Level 4, same as Canvas/Window:
633 COLOR(Inactivecaption
, 0xFF, 0xFF, 0xFF)
634 // deprecated in CSS Color Level 4, same as Canvastext/Windowtext:
635 COLOR(Captiontext
, 0x00, 0x00, 0x00)
636 // deprecated in CSS Color Level 4, same as Graytext:
637 COLOR(Inactivecaptiontext
, 0x6D, 0x6D, 0x6D)
640 // deprecated in CSS Color Level 4, same as Canvas/Window:
641 COLOR(Appworkspace
, 0xFF, 0xFF, 0xFF)
642 // deprecated in CSS Color Level 4, same as Canvas/Window:
643 COLOR(Background
, 0xFF, 0xFF, 0xFF)
644 // deprecated in CSS Color Level 4, same as Buttonface:
645 COLOR(Buttonhighlight
, 0xE9, 0xE9, 0xED)
646 // deprecated in CSS Color Level 4, same as Buttonface:
647 COLOR(Buttonshadow
, 0xE9, 0xE9, 0xED)
649 // Buttons and comboboxes should be kept in sync since they are drawn with
650 // the same colors by the non-native theme.
651 COLOR(Buttonface
, 0xE9, 0xE9, 0xED)
652 COLORA(MozButtondisabledface
, 0xE9, 0xE9, 0xED, 128)
654 COLOR(MozCombobox
, 0xE9, 0xE9, 0xED)
656 COLOR(Buttontext
, 0x00, 0x00, 0x00)
657 COLOR(MozComboboxtext
, 0x00, 0x00, 0x00)
659 COLOR(Graytext
, 0x6D, 0x6D, 0x6D)
660 COLOR(Highlight
, 0x33, 0x99, 0xFF)
661 COLOR(Highlighttext
, 0xFF, 0xFF, 0xFF)
662 // deprecated in CSS Color Level 4, same as Canvas/Window:
663 COLOR(Infobackground
, 0xFF, 0xFF, 0xFF)
664 // deprecated in CSS Color Level 4, same as Canvastext/Windowtext:
665 COLOR(Infotext
, 0x00, 0x00, 0x00)
666 // deprecated in CSS Color Level 4, same as Canvas/Window:
667 COLOR(Menu
, 0xFF, 0xFF, 0xFF)
668 // deprecated in CSS Color Level 4, same as Canvastext/Windowtext:
669 COLOR(Menutext
, 0x00, 0x00, 0x00)
670 // deprecated in CSS Color Level 4, same as Canvas/Window:
671 COLOR(Scrollbar
, 0xFF, 0xFF, 0xFF)
672 // deprecated in CSS Color Level 4, same as Buttonborder:
673 COLOR(Threeddarkshadow
, 0xE3, 0xE3, 0xE3)
674 // deprecated in CSS Color Level 4, same as Buttonface:
675 COLOR(Threedface
, 0xE9, 0xE9, 0xED)
676 // deprecated in CSS Color Level 4, same as Buttonborder:
677 COLOR(Threedhighlight
, 0xE3, 0xE3, 0xE3)
678 COLOR(Threedlightshadow
, 0xE3, 0xE3, 0xE3)
679 // deprecated in CSS Color Level 4, same as Buttonborder:
680 COLOR(Threedshadow
, 0xE3, 0xE3, 0xE3)
681 COLOR(Buttonborder
, 0xE3, 0xE3, 0xE3)
682 COLOR(Mark
, 0xFF, 0xFF, 0x00)
683 COLOR(Marktext
, 0x00, 0x00, 0x00)
684 COLOR(Window
, 0xFF, 0xFF, 0xFF)
685 // deprecated in CSS Color Level 4, same as Buttonborder:
686 COLOR(Windowframe
, 0xE3, 0xE3, 0xE3)
687 COLOR(Windowtext
, 0x00, 0x00, 0x00)
688 COLOR(Field
, 0xFF, 0xFF, 0xFF)
689 COLORA(MozDisabledfield
, 0xFF, 0xFF, 0xFF, 128)
690 COLOR(Fieldtext
, 0x00, 0x00, 0x00)
691 COLOR(MozDialog
, 0xF0, 0xF0, 0xF0)
692 COLOR(MozDialogtext
, 0x00, 0x00, 0x00)
693 COLOR(MozColheadertext
, 0x00, 0x00, 0x00)
694 COLOR(MozColheaderhovertext
, 0x00, 0x00, 0x00)
695 COLOR(MozCellhighlight
, 0xF0, 0xF0, 0xF0)
696 COLOR(MozCellhighlighttext
, 0x00, 0x00, 0x00)
697 COLOR(Selecteditem
, 0x33, 0x99, 0xFF)
698 COLOR(Selecteditemtext
, 0xFF, 0xFF, 0xFF)
699 COLOR(MozButtonhoverface
, 0xd0, 0xd0, 0xd7)
700 COLOR(MozButtonhovertext
, 0x00, 0x00, 0x00)
701 COLOR(MozButtonactiveface
, 0xb1, 0xb1, 0xb9)
702 COLOR(MozButtonactivetext
, 0x00, 0x00, 0x00)
703 COLOR(MozMenuhover
, 0x33, 0x99, 0xFF)
704 COLOR(MozMenuhovertext
, 0x00, 0x00, 0x00)
705 COLOR(MozMenubarhovertext
, 0x00, 0x00, 0x00)
706 COLOR(MozMenuhoverdisabled
, 0xF0, 0xF0, 0xF0)
707 COLOR(MozEventreerow
, 0xFF, 0xFF, 0xFF)
708 COLOR(MozOddtreerow
, 0xFF, 0xFF, 0xFF)
709 COLOR(MozMacFocusring
, 0x60, 0x9D, 0xD7)
710 COLOR(MozMacDisabledtoolbartext
, 0x3F, 0x3F, 0x3F)
711 // Seems to be the default color (hardcoded because of bug 1065998)
712 COLOR(MozNativehyperlinktext
, 0x00, 0x66, 0xCC)
713 COLOR(MozNativevisitedhyperlinktext
, 0x55, 0x1A, 0x8B)
717 return NS_RGB(0xFF, 0xFF, 0xFF);
723 // Taken from in-content/common.inc.css's dark theme.
724 Maybe
<nscolor
> nsXPLookAndFeel::GenericDarkColor(ColorID aID
) {
725 nscolor color
= NS_RGB(0, 0, 0);
726 static constexpr nscolor kWindowBackground
= NS_RGB(28, 27, 34);
727 static constexpr nscolor kWindowText
= NS_RGB(251, 251, 254);
729 case ColorID::Window
: // --in-content-page-background
730 case ColorID::Background
:
731 case ColorID::Appworkspace
:
732 case ColorID::Scrollbar
:
733 case ColorID::Infobackground
:
734 color
= kWindowBackground
;
738 color
= NS_RGB(0x2b, 0x2a, 0x33);
741 case ColorID::MozMenuhovertext
:
742 case ColorID::MozMenubarhovertext
:
743 case ColorID::Menutext
:
744 color
= NS_RGB(0xfb, 0xfb, 0xfe);
747 case ColorID::MozMenuhover
:
748 color
= NS_RGB(0x52, 0x52, 0x5e);
751 case ColorID::MozMenuhoverdisabled
:
752 color
= NS_RGB(0x3a, 0x39, 0x44);
755 case ColorID::MozEventreerow
:
756 case ColorID::MozOddtreerow
:
757 case ColorID::MozDialog
: // --in-content-box-background
758 color
= NS_RGB(35, 34, 43);
760 case ColorID::Windowtext
: // --in-content-page-color
761 case ColorID::MozDialogtext
:
762 case ColorID::MozSidebartext
:
763 case ColorID::Fieldtext
:
764 case ColorID::Infotext
:
765 case ColorID::Buttontext
: // --in-content-button-text-color (via
766 // --in-content-page-color)
767 case ColorID::MozComboboxtext
:
768 case ColorID::MozButtonhovertext
:
769 case ColorID::MozButtonactivetext
:
770 case ColorID::MozHeaderbartext
:
771 case ColorID::MozHeaderbarinactivetext
:
772 case ColorID::Captiontext
:
773 case ColorID::Inactivecaptiontext
: // TODO(emilio): Maybe make
774 // Inactivecaptiontext Graytext?
775 case ColorID::MozColheadertext
:
776 case ColorID::MozColheaderhovertext
:
777 case ColorID::MozColheaderactivetext
:
780 case ColorID::Buttonshadow
:
781 case ColorID::Threedshadow
:
782 case ColorID::MozSidebarborder
:
783 case ColorID::Threedlightshadow
:
784 case ColorID::Threedhighlight
:
785 case ColorID::Windowframe
:
786 case ColorID::Buttonborder
: // --in-content-box-border-color computed
787 // with kWindowText above
788 // kWindowBackground.
789 case ColorID::Graytext
: // opacity: 0.4 of kWindowText blended over the
790 // "Window" background color, which happens to be
792 color
= NS_ComposeColors(kWindowBackground
, NS_RGBA(251, 251, 254, 102));
794 case ColorID::MozCellhighlight
:
795 case ColorID::Selecteditem
: // --in-content-primary-button-background /
796 // --in-content-item-selected
797 color
= NS_RGB(0, 221, 255);
799 case ColorID::MozSidebar
:
801 case ColorID::Buttonface
: // --in-content-button-background
802 case ColorID::Buttonhighlight
:
803 case ColorID::MozColheader
:
804 case ColorID::Threedface
:
805 case ColorID::MozCombobox
:
806 case ColorID::MozCellhighlighttext
:
807 case ColorID::Selecteditemtext
: // --in-content-primary-button-text-color /
808 // --in-content-item-selected-text
809 color
= NS_RGB(43, 42, 51);
811 case ColorID::Threeddarkshadow
: // Same as Threedlightshadow but with the
813 case ColorID::MozDisabledfield
: // opacity: 0.4 of the face above blended
814 // over the "Window" background color.
815 case ColorID::MozButtondisabledface
:
816 color
= NS_ComposeColors(kWindowBackground
, NS_RGBA(43, 42, 51, 102));
818 case ColorID::MozButtonhoverface
: // --in-content-button-background-hover
819 case ColorID::MozColheaderhover
:
820 color
= NS_RGB(82, 82, 94);
822 case ColorID::MozButtonactiveface
: // --in-content-button-background-active
823 case ColorID::MozColheaderactive
:
824 color
= NS_RGB(91, 91, 102);
826 case ColorID::Highlight
:
827 color
= NS_RGBA(0, 221, 255, 78);
829 case ColorID::Highlighttext
:
830 color
= NS_SAME_AS_FOREGROUND_COLOR
;
832 case ColorID::MozNativehyperlinktext
:
833 // If you change this color, you probably also want to change the default
834 // value of browser.anchor_color.dark.
835 color
= NS_RGB(0x8c, 0x8c, 0xff);
837 case ColorID::MozNativevisitedhyperlinktext
:
838 // If you change this color, you probably also want to change the default
839 // value of browser.visited_color.dark.
840 color
= NS_RGB(0xff, 0xad, 0xff);
842 case ColorID::SpellCheckerUnderline
:
843 // This is the default for active links in dark mode as well
844 // (browser.active_color.dark). See bug 1755564 for some analysis and
845 // other options too.
846 color
= NS_RGB(0xff, 0x66, 0x66);
848 case ColorID::Activeborder
:
849 case ColorID::Inactiveborder
:
850 color
= NS_RGB(57, 57, 57);
852 case ColorID::MozHeaderbar
:
853 case ColorID::MozHeaderbarinactive
:
854 case ColorID::Activecaption
:
855 case ColorID::Inactivecaption
:
856 color
= NS_RGB(28, 27, 34);
864 // Uncomment the #define below if you want to debug system color use in a skin
865 // that uses them. When set, it will make all system color pairs that are
866 // appropriate for foreground/background pairing the same. This means if the
867 // skin is using system colors correctly you will not be able to see *any* text.
869 // #define DEBUG_SYSTEM_COLOR_USE
871 #ifdef DEBUG_SYSTEM_COLOR_USE
872 static nsresult
SystemColorUseDebuggingColor(LookAndFeel::ColorID aID
,
874 using ColorID
= LookAndFeel::ColorID
;
877 // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
878 case ColorID::Activecaption
:
879 // active window caption background
880 case ColorID::Captiontext
:
881 // text in active window caption
882 aResult
= NS_RGB(0xff, 0x00, 0x00);
885 case ColorID::Highlight
:
886 // background of selected item
887 case ColorID::Highlighttext
:
888 // text of selected item
889 aResult
= NS_RGB(0xff, 0xff, 0x00);
892 case ColorID::Inactivecaption
:
893 // inactive window caption
894 case ColorID::Inactivecaptiontext
:
895 // text in inactive window caption
896 aResult
= NS_RGB(0x66, 0x66, 0x00);
899 case ColorID::Infobackground
:
900 // tooltip background color
901 case ColorID::Infotext
:
902 // tooltip text color
903 aResult
= NS_RGB(0x00, 0xff, 0x00);
908 case ColorID::Menutext
:
910 aResult
= NS_RGB(0x00, 0xff, 0xff);
913 case ColorID::Threedface
:
914 case ColorID::Buttonface
:
916 case ColorID::Buttontext
:
917 // text on push buttons
918 aResult
= NS_RGB(0x00, 0x66, 0x66);
921 case ColorID::Window
:
922 case ColorID::Windowtext
:
923 aResult
= NS_RGB(0x00, 0x00, 0xff);
926 // from the CSS3 working draft (not yet finalized)
927 // http://www.w3.org/tr/2000/wd-css3-userint-20000216.html#color
930 case ColorID::Fieldtext
:
931 aResult
= NS_RGB(0xff, 0x00, 0xff);
934 case ColorID::MozDialog
:
935 case ColorID::MozDialogtext
:
936 aResult
= NS_RGB(0x66, 0x00, 0x66);
940 return NS_ERROR_NOT_AVAILABLE
;
947 static nsresult
GetPrefColor(const char* aPref
, nscolor
& aResult
) {
948 nsAutoCString colorStr
;
949 MOZ_TRY(Preferences::GetCString(aPref
, colorStr
));
950 if (!ServoCSSParser::ComputeColor(nullptr, NS_RGB(0, 0, 0), colorStr
,
952 return NS_ERROR_FAILURE
;
957 static nsresult
GetColorFromPref(LookAndFeel::ColorID aID
, ColorScheme aScheme
,
959 const char* prefName
= sColorPrefs
[size_t(aID
)];
960 if (aScheme
== ColorScheme::Dark
) {
961 nsAutoCString
darkPrefName(prefName
);
962 darkPrefName
.Append(".dark");
963 if (NS_SUCCEEDED(GetPrefColor(darkPrefName
.get(), aResult
))) {
967 return GetPrefColor(prefName
, aResult
);
970 // All these routines will return NS_OK if they have a value,
971 // in which case the nsLookAndFeel should use that value;
972 // otherwise we'll return NS_ERROR_NOT_AVAILABLE, in which case, the
973 // platform-specific nsLookAndFeel should use its own values instead.
974 nsresult
nsXPLookAndFeel::GetColorValue(ColorID aID
, ColorScheme aScheme
,
975 UseStandins aUseStandins
,
981 #ifdef DEBUG_SYSTEM_COLOR_USE
982 if (NS_SUCCEEDED(SystemColorUseDebuggingColor(aID
, aResult
))) {
987 auto& cache
= sColorCaches
.Get(aScheme
, aUseStandins
);
988 if (const auto* cached
= cache
.Get(aID
)) {
989 if (cached
->isNothing()) {
990 return NS_ERROR_FAILURE
;
992 aResult
= cached
->value();
996 // NOTE: Servo holds a lock and the main thread is paused, so writing to the
997 // global cache here is fine.
998 auto result
= GetUncachedColor(aID
, aScheme
, aUseStandins
);
999 cache
.Insert(aID
, result
);
1001 return NS_ERROR_FAILURE
;
1007 Maybe
<nscolor
> nsXPLookAndFeel::GetUncachedColor(ColorID aID
,
1008 ColorScheme aScheme
,
1009 UseStandins aUseStandins
) {
1010 if (aUseStandins
== UseStandins::Yes
) {
1011 return Some(GetStandinForNativeColor(aID
, aScheme
));
1014 if (NS_SUCCEEDED(GetColorFromPref(aID
, aScheme
, r
))) {
1017 if (NS_SUCCEEDED(NativeGetColor(aID
, aScheme
, r
))) {
1018 if (gfxPlatform::GetCMSMode() == CMSMode::All
&& !IsSpecialColor(aID
, r
)) {
1019 qcms_transform
* transform
= gfxPlatform::GetCMSInverseRGBTransform();
1022 color
[0] = NS_GET_R(r
);
1023 color
[1] = NS_GET_G(r
);
1024 color
[2] = NS_GET_B(r
);
1025 color
[3] = NS_GET_A(r
);
1026 qcms_transform_data(transform
, color
, color
, 1);
1027 r
= NS_RGBA(color
[0], color
[1], color
[2], color
[3]);
1036 nsresult
nsXPLookAndFeel::GetIntValue(IntID aID
, int32_t& aResult
) {
1037 if (!sInitialized
) {
1041 if (const auto* cached
= sIntCache
.Get(aID
)) {
1042 if (cached
->isNothing()) {
1043 return NS_ERROR_FAILURE
;
1045 aResult
= cached
->value();
1049 if (NS_SUCCEEDED(Preferences::GetInt(sIntPrefs
[size_t(aID
)], &aResult
))) {
1050 sIntCache
.Insert(aID
, Some(aResult
));
1054 if (NS_FAILED(NativeGetInt(aID
, aResult
))) {
1055 sIntCache
.Insert(aID
, Nothing());
1056 return NS_ERROR_FAILURE
;
1059 sIntCache
.Insert(aID
, Some(aResult
));
1063 nsresult
nsXPLookAndFeel::GetFloatValue(FloatID aID
, float& aResult
) {
1064 if (!sInitialized
) {
1068 if (const auto* cached
= sFloatCache
.Get(aID
)) {
1069 if (cached
->isNothing()) {
1070 return NS_ERROR_FAILURE
;
1072 aResult
= cached
->value();
1077 if (NS_SUCCEEDED(Preferences::GetInt(sFloatPrefs
[size_t(aID
)], &pref
))) {
1078 aResult
= float(pref
) / 100.0f
;
1079 sFloatCache
.Insert(aID
, Some(aResult
));
1083 if (NS_FAILED(NativeGetFloat(aID
, aResult
))) {
1084 sFloatCache
.Insert(aID
, Nothing());
1085 return NS_ERROR_FAILURE
;
1088 sFloatCache
.Insert(aID
, Some(aResult
));
1092 bool nsXPLookAndFeel::LookAndFeelFontToStyle(const LookAndFeelFont
& aFont
,
1094 gfxFontStyle
& aStyle
) {
1095 if (!aFont
.haveFont()) {
1098 aName
= aFont
.name();
1099 aStyle
= gfxFontStyle();
1100 aStyle
.size
= aFont
.size();
1101 aStyle
.weight
= FontWeight::FromInt(aFont
.weight());
1103 aFont
.italic() ? FontSlantStyle::ITALIC
: FontSlantStyle::NORMAL
;
1104 aStyle
.systemFont
= true;
1108 widget::LookAndFeelFont
nsXPLookAndFeel::StyleToLookAndFeelFont(
1109 const nsAString
& aName
, const gfxFontStyle
& aStyle
) {
1110 LookAndFeelFont font
;
1111 font
.haveFont() = true;
1112 font
.name() = aName
;
1113 font
.size() = aStyle
.size
;
1114 font
.weight() = aStyle
.weight
.ToFloat();
1115 font
.italic() = aStyle
.style
.IsItalic();
1116 MOZ_ASSERT(aStyle
.style
.IsNormal() || aStyle
.style
.IsItalic(),
1117 "Cannot handle oblique font style");
1120 // Assert that all the remaining font style properties have their
1122 gfxFontStyle candidate
= aStyle
;
1123 gfxFontStyle defaults
{};
1124 candidate
.size
= defaults
.size
;
1125 candidate
.weight
= defaults
.weight
;
1126 candidate
.style
= defaults
.style
;
1127 MOZ_ASSERT(candidate
.Equals(defaults
),
1128 "Some font style properties not supported");
1134 bool nsXPLookAndFeel::GetFontValue(FontID aID
, nsString
& aName
,
1135 gfxFontStyle
& aStyle
) {
1136 if (const LookAndFeelFont
* cached
= sFontCache
.Get(aID
)) {
1137 return LookAndFeelFontToStyle(*cached
, aName
, aStyle
);
1140 LookAndFeelFont font
;
1141 auto GetFontsFromPrefs
= [&]() -> bool {
1142 nsDependentCString
pref(sFontPrefs
[size_t(aID
)]);
1143 if (NS_FAILED(Preferences::GetString(pref
.get(), aName
))) {
1146 font
.haveFont() = true;
1147 font
.name() = aName
;
1148 font
.size() = Preferences::GetFloat(nsAutoCString(pref
+ ".size"_ns
).get());
1149 // This is written this way rather than using the fallback so that an empty
1150 // pref (such like the one about:config creates) doesn't cause system fonts
1151 // to have zero-size.
1152 if (font
.size() < 1.0f
) {
1153 font
.size() = StyleFONT_MEDIUM_PX
;
1155 font
.weight() = Preferences::GetFloat(
1156 nsAutoCString(pref
+ ".weight"_ns
).get(), FontWeight::NORMAL
.ToFloat());
1158 Preferences::GetBool(nsAutoCString(pref
+ ".italic"_ns
).get());
1162 if (GetFontsFromPrefs()) {
1163 LookAndFeelFontToStyle(font
, aName
, aStyle
);
1164 } else if (NativeGetFont(aID
, aName
, aStyle
)) {
1165 font
= StyleToLookAndFeelFont(aName
, aStyle
);
1167 MOZ_ASSERT(!font
.haveFont());
1169 bool success
= font
.haveFont();
1170 sFontCache
.Insert(aID
, std::move(font
));
1174 void nsXPLookAndFeel::RefreshImpl() {
1175 // Wipe out our caches.
1176 sColorCaches
.Clear();
1178 sFloatCache
.Clear();
1181 if (XRE_IsParentProcess()) {
1182 nsLayoutUtils::RecomputeSmoothScrollDefault();
1183 // Clear any cached FullLookAndFeel data, which is now invalid.
1184 widget::RemoteLookAndFeel::ClearCachedData();
1188 static bool sRecordedLookAndFeelTelemetry
= false;
1190 void nsXPLookAndFeel::RecordTelemetry() {
1191 if (!XRE_IsParentProcess()) {
1195 if (sRecordedLookAndFeelTelemetry
) {
1199 sRecordedLookAndFeelTelemetry
= true;
1202 Telemetry::ScalarSet(
1203 Telemetry::ScalarID::WIDGET_DARK_MODE
,
1204 NS_SUCCEEDED(GetIntValue(IntID::SystemUsesDarkTheme
, i
)) && i
!= 0);
1206 RecordLookAndFeelSpecificTelemetry();
1211 bool LookAndFeel::sGlobalThemeChanged
;
1212 static widget::ThemeChangeKind sGlobalThemeChangeKind
{0};
1214 void LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind aKind
) {
1215 sGlobalThemeChanged
= true;
1216 sGlobalThemeChangeKind
|= aKind
;
1218 if (nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService()) {
1219 const char16_t kind
[] = {char16_t(aKind
), 0};
1220 obs
->NotifyObservers(nullptr, "internal-look-and-feel-changed", kind
);
1224 void LookAndFeel::DoHandleGlobalThemeChange() {
1225 MOZ_ASSERT(sGlobalThemeChanged
);
1226 sGlobalThemeChanged
= false;
1227 auto kind
= std::exchange(sGlobalThemeChangeKind
, widget::ThemeChangeKind(0));
1229 // Tell the theme that it changed, so it can flush any handles to stale theme
1232 // We can use the *DoNotUseDirectly functions directly here, because we want
1233 // to notify all possible themes in a given process (but just once).
1234 if (XRE_IsParentProcess() ||
1235 !StaticPrefs::widget_non_native_theme_enabled()) {
1236 if (nsCOMPtr
<nsITheme
> theme
= do_GetNativeThemeDoNotUseDirectly()) {
1237 theme
->ThemeChanged();
1240 if (nsCOMPtr
<nsITheme
> theme
= do_GetBasicNativeThemeDoNotUseDirectly()) {
1241 theme
->ThemeChanged();
1244 // Clear all cached LookAndFeel colors.
1245 LookAndFeel::Refresh();
1247 // Reset default background and foreground colors for the document since they
1248 // may be using system colors, color scheme, etc.
1249 PreferenceSheet::Refresh();
1251 // Vector images (SVG) may be using theme colors so we discard all cached
1252 // surfaces. (We could add a vector image only version of DiscardAll, but
1253 // in bug 940625 we decided theme changes are rare enough not to bother.)
1254 image::SurfaceCacheUtils::DiscardAll();
1256 if (XRE_IsParentProcess()) {
1257 dom::ContentParent::BroadcastThemeUpdate(kind
);
1260 nsContentUtils::AddScriptRunner(
1261 NS_NewRunnableFunction("HandleGlobalThemeChange", [] {
1262 if (nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService()) {
1263 obs
->NotifyObservers(nullptr, "look-and-feel-changed", nullptr);
1268 #define BIT_FOR(_c) (1ull << size_t(ColorID::_c))
1270 // We want to use a non-native color scheme for the non-native theme (except in
1271 // high-contrast mode), so spoof some of the colors with stand-ins to prevent
1272 // lack of contrast.
1273 static constexpr std::bitset
<size_t(ColorID::End
)> sNonNativeThemeStandinColors
{
1274 // Used by default button styles.
1275 BIT_FOR(Buttonface
) | BIT_FOR(Buttontext
) | BIT_FOR(MozButtonhoverface
) |
1276 BIT_FOR(MozButtonhovertext
) | BIT_FOR(MozButtonactiveface
) |
1277 BIT_FOR(MozButtonactivetext
) | BIT_FOR(MozButtondisabledface
) |
1278 BIT_FOR(Buttonborder
) |
1279 // Used by select elements.
1280 BIT_FOR(MozCombobox
) | BIT_FOR(MozComboboxtext
) |
1281 BIT_FOR(Threedlightshadow
) |
1282 // For symmetry with the above.
1283 BIT_FOR(Threeddarkshadow
) |
1284 // Used by fieldset borders.
1285 BIT_FOR(Threedface
) |
1286 // Used by input / textarea.
1287 BIT_FOR(Field
) | BIT_FOR(Fieldtext
) |
1288 // Used by disabled form controls.
1289 BIT_FOR(MozDisabledfield
) | BIT_FOR(Graytext
) |
1290 // Per spec, the following colors are deprecated, see
1291 // https://drafts.csswg.org/css-color-4/#deprecated-system-colors
1292 // should match ButtonFace:
1293 BIT_FOR(Buttonhighlight
) | BIT_FOR(Buttonshadow
) | BIT_FOR(Threedface
) |
1294 // should match ButtonBorder:
1295 BIT_FOR(Activeborder
) | BIT_FOR(Inactiveborder
) |
1296 BIT_FOR(Threeddarkshadow
) | BIT_FOR(Threedhighlight
) |
1297 BIT_FOR(Threedshadow
) | BIT_FOR(Windowframe
) |
1298 // should match GrayText:
1299 BIT_FOR(Inactivecaptiontext
) |
1300 // should match Canvas/Window:
1301 BIT_FOR(Appworkspace
) | BIT_FOR(Background
) | BIT_FOR(Inactivecaption
) |
1302 BIT_FOR(Infobackground
) | BIT_FOR(Menu
) | BIT_FOR(Scrollbar
) |
1303 // should match CanvasText/WindowText:
1304 BIT_FOR(Activecaption
) | BIT_FOR(Captiontext
) | BIT_FOR(Infotext
) |
1306 // Some pages expect these to return windows-like colors, see bug 1773795.
1307 // Also, per spec, these should match Canvas/CanvasText, see
1308 // https://drafts.csswg.org/css-color-4/#valdef-color-window and
1309 // https://drafts.csswg.org/css-color-4/#valdef-color-windowtext
1310 BIT_FOR(Window
) | BIT_FOR(Windowtext
)};
1313 static bool ShouldUseStandinsForNativeColorForNonNativeTheme(
1314 const dom::Document
& aDoc
, LookAndFeel::ColorID aColor
,
1315 const PreferenceSheet::Prefs
& aPrefs
) {
1316 const bool shouldUseStandinsForColor
= [&] {
1317 if (sNonNativeThemeStandinColors
[size_t(aColor
)]) {
1320 // There are platforms where we want the content-exposed accent color to be
1321 // the windows blue rather than the system accent color, for now.
1322 return !StaticPrefs::widget_non_native_theme_use_theme_accent() &&
1323 (aColor
== LookAndFeel::ColorID::Accentcolor
||
1324 aColor
== LookAndFeel::ColorID::Accentcolortext
);
1327 return shouldUseStandinsForColor
&& aDoc
.ShouldAvoidNativeTheme() &&
1328 !aPrefs
.NonNativeThemeShouldBeHighContrast();
1331 bool LookAndFeel::IsDarkColor(nscolor aColor
) {
1332 // Given https://www.w3.org/TR/WCAG20/#contrast-ratiodef, this is the
1333 // threshold that tells us whether contrast is better against white or black.
1335 // Contrast ratio against black is: (L + 0.05) / 0.05
1336 // Contrast ratio against white is: 1.05 / (L + 0.05)
1338 // So the intersection is:
1340 // (L + 0.05) / 0.05 = 1.05 / (L + 0.05)
1342 // And the solution to that equation is:
1344 // sqrt(1.05 * 0.05) - 0.05
1346 // So we consider a color dark if the contrast is below this threshold, and
1347 // it's at least half-opaque.
1348 constexpr float kThreshold
= 0.179129;
1349 return NS_GET_A(aColor
) > 127 &&
1350 RelativeLuminanceUtils::Compute(aColor
) < kThreshold
;
1353 ColorScheme
LookAndFeel::ColorSchemeForStyle(
1354 const dom::Document
& aDoc
, const StyleColorSchemeFlags
& aFlags
,
1355 ColorSchemeMode aMode
) {
1356 const auto& prefs
= PreferenceSheet::PrefsFor(aDoc
);
1357 StyleColorSchemeFlags
style(aFlags
);
1359 style
._0
= aDoc
.GetColorSchemeBits();
1361 const bool supportsDark
= bool(style
& StyleColorSchemeFlags::DARK
);
1362 const bool supportsLight
= bool(style
& StyleColorSchemeFlags::LIGHT
);
1363 if (supportsLight
&& supportsDark
) {
1364 // Both color-schemes are explicitly supported, use the preferred one.
1365 return aDoc
.PreferredColorScheme();
1367 if (supportsDark
|| supportsLight
) {
1368 // One color-scheme is explicitly supported and one isn't, so use the one
1369 // the content supports.
1370 return supportsDark
? ColorScheme::Dark
: ColorScheme::Light
;
1372 // No value specified. Chrome docs, and forced-colors mode always supports
1373 // both, so use the preferred color-scheme.
1374 if (aMode
== ColorSchemeMode::Preferred
|| aDoc
.ChromeRulesEnabled() ||
1375 !prefs
.mUseDocumentColors
) {
1376 return aDoc
.PreferredColorScheme();
1378 // Otherwise default content to light.
1379 return ColorScheme::Light
;
1382 LookAndFeel::ColorScheme
LookAndFeel::ColorSchemeForFrame(
1383 const nsIFrame
* aFrame
, ColorSchemeMode aMode
) {
1384 return ColorSchemeForStyle(*aFrame
->PresContext()->Document(),
1385 aFrame
->StyleUI()->mColorScheme
.bits
, aMode
);
1389 Maybe
<nscolor
> LookAndFeel::GetColor(ColorID aId
, ColorScheme aScheme
,
1390 UseStandins aUseStandins
) {
1392 nsresult rv
= nsLookAndFeel::GetInstance()->GetColorValue(
1393 aId
, aScheme
, aUseStandins
, result
);
1394 if (NS_FAILED(rv
)) {
1397 return Some(result
);
1400 // Returns whether there is a CSS color name for this color.
1401 static bool ColorIsCSSAccessible(LookAndFeel::ColorID aId
) {
1402 using ColorID
= LookAndFeel::ColorID
;
1405 case ColorID::TextSelectDisabledBackground
:
1406 case ColorID::TextSelectAttentionBackground
:
1407 case ColorID::TextSelectAttentionForeground
:
1408 case ColorID::TextHighlightBackground
:
1409 case ColorID::TextHighlightForeground
:
1410 case ColorID::ThemedScrollbar
:
1411 case ColorID::ThemedScrollbarInactive
:
1412 case ColorID::ThemedScrollbarThumb
:
1413 case ColorID::ThemedScrollbarThumbActive
:
1414 case ColorID::ThemedScrollbarThumbInactive
:
1415 case ColorID::ThemedScrollbarThumbHover
:
1416 case ColorID::IMERawInputBackground
:
1417 case ColorID::IMERawInputForeground
:
1418 case ColorID::IMERawInputUnderline
:
1419 case ColorID::IMESelectedRawTextBackground
:
1420 case ColorID::IMESelectedRawTextForeground
:
1421 case ColorID::IMESelectedRawTextUnderline
:
1422 case ColorID::IMEConvertedTextBackground
:
1423 case ColorID::IMEConvertedTextForeground
:
1424 case ColorID::IMEConvertedTextUnderline
:
1425 case ColorID::IMESelectedConvertedTextBackground
:
1426 case ColorID::IMESelectedConvertedTextForeground
:
1427 case ColorID::IMESelectedConvertedTextUnderline
:
1428 case ColorID::SpellCheckerUnderline
:
1437 LookAndFeel::UseStandins
LookAndFeel::ShouldUseStandins(
1438 const dom::Document
& aDoc
, ColorID aId
) {
1439 const auto& prefs
= PreferenceSheet::PrefsFor(aDoc
);
1440 if (ShouldUseStandinsForNativeColorForNonNativeTheme(aDoc
, aId
, prefs
)) {
1441 return UseStandins::Yes
;
1443 if (prefs
.mUseStandins
&& ColorIsCSSAccessible(aId
)) {
1444 return UseStandins::Yes
;
1446 return UseStandins::No
;
1449 Maybe
<nscolor
> LookAndFeel::GetColor(ColorID aId
, const nsIFrame
* aFrame
) {
1450 const auto* doc
= aFrame
->PresContext()->Document();
1451 return GetColor(aId
, ColorSchemeForFrame(aFrame
),
1452 ShouldUseStandins(*doc
, aId
));
1456 nsresult
LookAndFeel::GetInt(IntID aID
, int32_t* aResult
) {
1457 return nsLookAndFeel::GetInstance()->GetIntValue(aID
, *aResult
);
1461 nsresult
LookAndFeel::GetFloat(FloatID aID
, float* aResult
) {
1462 return nsLookAndFeel::GetInstance()->GetFloatValue(aID
, *aResult
);
1466 bool LookAndFeel::GetFont(FontID aID
, nsString
& aName
, gfxFontStyle
& aStyle
) {
1467 return nsLookAndFeel::GetInstance()->GetFontValue(aID
, aName
, aStyle
);
1471 char16_t
LookAndFeel::GetPasswordCharacter() {
1472 return nsLookAndFeel::GetInstance()->GetPasswordCharacterImpl();
1476 bool LookAndFeel::GetEchoPassword() {
1477 if (StaticPrefs::editor_password_mask_delay() >= 0) {
1478 return StaticPrefs::editor_password_mask_delay() > 0;
1480 return nsLookAndFeel::GetInstance()->GetEchoPasswordImpl();
1484 uint32_t LookAndFeel::GetPasswordMaskDelay() {
1485 int32_t delay
= StaticPrefs::editor_password_mask_delay();
1487 return nsLookAndFeel::GetInstance()->GetPasswordMaskDelayImpl();
1492 bool LookAndFeel::DrawInTitlebar() {
1493 switch (StaticPrefs::browser_tabs_inTitlebar()) {
1501 return nsLookAndFeel::GetInstance()->GetDefaultDrawInTitlebar();
1504 LookAndFeel::TitlebarAction
LookAndFeel::GetTitlebarAction(
1505 TitlebarEvent aEvent
) {
1506 return nsLookAndFeel::GetInstance()->GetTitlebarAction(aEvent
);
1509 void LookAndFeel::GetThemeInfo(nsACString
& aOut
) {
1510 nsLookAndFeel::GetInstance()->GetThemeInfo(aOut
);
1513 uint32_t LookAndFeel::GetMenuAccessKey() {
1514 return StaticPrefs::ui_key_menuAccessKey();
1517 Modifiers
LookAndFeel::GetMenuAccessKeyModifiers() {
1518 switch (GetMenuAccessKey()) {
1519 case dom::KeyboardEvent_Binding::DOM_VK_SHIFT
:
1520 return MODIFIER_SHIFT
;
1521 case dom::KeyboardEvent_Binding::DOM_VK_CONTROL
:
1522 return MODIFIER_CONTROL
;
1523 case dom::KeyboardEvent_Binding::DOM_VK_ALT
:
1524 return MODIFIER_ALT
;
1525 case dom::KeyboardEvent_Binding::DOM_VK_META
:
1526 case dom::KeyboardEvent_Binding::DOM_VK_WIN
:
1527 return MODIFIER_META
;
1534 void LookAndFeel::Refresh() {
1535 nsLookAndFeel::GetInstance()->RefreshImpl();
1536 widget::Theme::LookAndFeelChanged();
1540 void LookAndFeel::NativeInit() { nsLookAndFeel::GetInstance()->NativeInit(); }
1543 void LookAndFeel::SetData(widget::FullLookAndFeel
&& aTables
) {
1544 nsLookAndFeel::GetInstance()->SetDataImpl(std::move(aTables
));
1547 } // namespace mozilla