Bug 1758698 [wpt PR 33120] - Add more referrer policy WPTs for Early Hints, a=testonly
[gecko.git] / widget / nsXPLookAndFeel.cpp
blobea7af265522d4f7b678f228e52fa4c36838cfe36
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 "nscore.h"
10 #include "nsXPLookAndFeel.h"
11 #include "nsLookAndFeel.h"
12 #include "HeadlessLookAndFeel.h"
13 #include "RemoteLookAndFeel.h"
14 #include "nsContentUtils.h"
15 #include "nsCRT.h"
16 #include "nsFont.h"
17 #include "nsIFrame.h"
18 #include "nsIXULRuntime.h"
19 #include "Theme.h"
20 #include "SurfaceCacheUtils.h"
21 #include "mozilla/dom/ContentParent.h"
22 #include "mozilla/dom/ContentChild.h"
23 #include "mozilla/Preferences.h"
24 #include "mozilla/Services.h"
25 #include "mozilla/ServoStyleSet.h"
26 #include "mozilla/ServoCSSParser.h"
27 #include "mozilla/StaticPrefs_browser.h"
28 #include "mozilla/StaticPrefs_editor.h"
29 #include "mozilla/StaticPrefs_ui.h"
30 #include "mozilla/StaticPrefs_widget.h"
31 #include "mozilla/dom/Document.h"
32 #include "mozilla/PreferenceSheet.h"
33 #include "mozilla/gfx/2D.h"
34 #include "mozilla/widget/WidgetMessageUtils.h"
35 #include "mozilla/Telemetry.h"
36 #include "mozilla/TelemetryScalarEnums.h"
38 #include "gfxPlatform.h"
39 #include "gfxFont.h"
41 #include "qcms.h"
43 #ifdef DEBUG
44 # include "nsSize.h"
45 #endif
47 using namespace mozilla;
49 using IntID = mozilla::LookAndFeel::IntID;
50 using FloatID = mozilla::LookAndFeel::FloatID;
51 using ColorID = mozilla::LookAndFeel::ColorID;
52 using FontID = mozilla::LookAndFeel::FontID;
54 template <typename Index, typename Value, Index kEnd>
55 class EnumeratedCache {
56 static constexpr uint32_t ChunkFor(Index aIndex) {
57 return uint32_t(aIndex) >> 5; // >> 5 is the same as / 32.
59 static constexpr uint32_t BitFor(Index aIndex) {
60 return 1u << (uint32_t(aIndex) & 31);
62 static constexpr uint32_t kChunks = ChunkFor(kEnd) + 1;
64 mozilla::EnumeratedArray<Index, kEnd, Value> mEntries;
65 uint32_t mValidity[kChunks] = {0};
67 public:
68 constexpr EnumeratedCache() = default;
70 bool IsValid(Index aIndex) const {
71 return mValidity[ChunkFor(aIndex)] & BitFor(aIndex);
74 const Value* Get(Index aIndex) const {
75 return IsValid(aIndex) ? &mEntries[aIndex] : nullptr;
78 void Insert(Index aIndex, Value aValue) {
79 mValidity[ChunkFor(aIndex)] |= BitFor(aIndex);
80 mEntries[aIndex] = aValue;
83 void Remove(Index aIndex) {
84 mValidity[ChunkFor(aIndex)] &= ~BitFor(aIndex);
85 mEntries[aIndex] = Value();
88 void Clear() {
89 for (auto& chunk : mValidity) {
90 chunk = 0;
92 for (auto& entry : mEntries) {
93 entry = Value();
98 static EnumeratedCache<ColorID, Maybe<nscolor>, ColorID::End> sLightColorCache;
99 static EnumeratedCache<ColorID, Maybe<nscolor>, ColorID::End> sDarkColorCache;
100 static EnumeratedCache<FloatID, Maybe<float>, FloatID::End> sFloatCache;
101 static EnumeratedCache<IntID, Maybe<int32_t>, IntID::End> sIntCache;
102 static EnumeratedCache<FontID, widget::LookAndFeelFont, FontID::End> sFontCache;
104 // To make one of these prefs toggleable from a reftest add a user
105 // pref in testing/profiles/reftest/user.js. For example, to make
106 // ui.useAccessibilityTheme toggleable, add:
108 // user_pref("ui.useAccessibilityTheme", 0);
110 // This needs to be of the same length and in the same order as
111 // LookAndFeel::IntID values.
112 static const char sIntPrefs[][45] = {
113 "ui.caretBlinkTime",
114 "ui.caretBlinkCount",
115 "ui.caretWidth",
116 "ui.caretVisibleWithSelection",
117 "ui.selectTextfieldsOnKeyFocus",
118 "ui.submenuDelay",
119 "ui.menusCanOverlapOSBar",
120 "ui.useOverlayScrollbars",
121 "ui.allowOverlayScrollbarsOverlap",
122 "ui.skipNavigatingDisabledMenuItem",
123 "ui.dragThresholdX",
124 "ui.dragThresholdY",
125 "ui.useAccessibilityTheme",
126 "ui.scrollArrowStyle",
127 "ui.scrollSliderStyle",
128 "ui.scrollButtonLeftMouseButtonAction",
129 "ui.scrollButtonMiddleMouseButtonAction",
130 "ui.scrollButtonRightMouseButtonAction",
131 "ui.treeOpenDelay",
132 "ui.treeCloseDelay",
133 "ui.treeLazyScrollDelay",
134 "ui.treeScrollDelay",
135 "ui.treeScrollLinesMax",
136 "accessibility.tabfocus", // Weird one...
137 "ui.chosenMenuItemsShouldBlink",
138 "ui.windowsAccentColorInTitlebar",
139 "ui.windowsDefaultTheme",
140 "ui.dwmCompositor",
141 "ui.windowsClassic",
142 "ui.windowsGlass",
143 "ui.macGraphiteTheme",
144 "ui.macBigSurTheme",
145 "ui.macRTL",
146 "ui.alertNotificationOrigin",
147 "ui.scrollToClick",
148 "ui.IMERawInputUnderlineStyle",
149 "ui.IMESelectedRawTextUnderlineStyle",
150 "ui.IMEConvertedTextUnderlineStyle",
151 "ui.IMESelectedConvertedTextUnderlineStyle",
152 "ui.SpellCheckerUnderlineStyle",
153 "ui.menuBarDrag",
154 "ui.scrollbarButtonAutoRepeatBehavior",
155 "ui.tooltipDelay",
156 "ui.swipeAnimationEnabled",
157 "ui.scrollbarDisplayOnMouseMove",
158 "ui.scrollbarFadeBeginDelay",
159 "ui.scrollbarFadeDuration",
160 "ui.contextMenuOffsetVertical",
161 "ui.contextMenuOffsetHorizontal",
162 "ui.GtkCSDAvailable",
163 "ui.GtkCSDMinimizeButton",
164 "ui.GtkCSDMaximizeButton",
165 "ui.GtkCSDCloseButton",
166 "ui.GtkCSDMinimizeButtonPosition",
167 "ui.GtkCSDMaximizeButtonPosition",
168 "ui.GtkCSDCloseButtonPosition",
169 "ui.GtkCSDReversedPlacement",
170 "ui.systemUsesDarkTheme",
171 "ui.prefersReducedMotion",
172 "ui.primaryPointerCapabilities",
173 "ui.allPointerCapabilities",
174 "ui.systemVerticalScrollbarWidth",
175 "ui.systemHorizontalScrollbarHeight",
176 "ui.touchDeviceSupportPresent",
177 "ui.titlebarRadius",
178 "ui.GtkMenuRadius",
179 "ui.dynamicRange",
180 "ui.videoDynamicRange",
183 static_assert(ArrayLength(sIntPrefs) == size_t(LookAndFeel::IntID::End),
184 "Should have a pref for each int value");
186 // This array MUST be kept in the same order as the float id list in
187 // LookAndFeel.h
188 // clang-format off
189 static const char sFloatPrefs[][37] = {
190 "ui.IMEUnderlineRelativeSize",
191 "ui.SpellCheckerUnderlineRelativeSize",
192 "ui.caretAspectRatio",
193 "ui.textScaleFactor",
194 "ui.cursorScale",
196 // clang-format on
198 static_assert(ArrayLength(sFloatPrefs) == size_t(LookAndFeel::FloatID::End),
199 "Should have a pref for each float value");
201 // This array MUST be kept in the same order as the color list in
202 // specified/color.rs
203 static const char sColorPrefs[][41] = {
204 "ui.textSelectDisabledBackground",
205 "ui.textSelectAttentionBackground",
206 "ui.textSelectAttentionForeground",
207 "ui.textHighlightBackground",
208 "ui.textHighlightForeground",
209 "ui.IMERawInputBackground",
210 "ui.IMERawInputForeground",
211 "ui.IMERawInputUnderline",
212 "ui.IMESelectedRawTextBackground",
213 "ui.IMESelectedRawTextForeground",
214 "ui.IMESelectedRawTextUnderline",
215 "ui.IMEConvertedTextBackground",
216 "ui.IMEConvertedTextForeground",
217 "ui.IMEConvertedTextUnderline",
218 "ui.IMESelectedConvertedTextBackground",
219 "ui.IMESelectedConvertedTextForeground",
220 "ui.IMESelectedConvertedTextUnderline",
221 "ui.SpellCheckerUnderline",
222 "ui.themedScrollbar",
223 "ui.themedScrollbarInactive",
224 "ui.themedScrollbarThumb",
225 "ui.themedScrollbarThumbHover",
226 "ui.themedScrollbarThumbActive",
227 "ui.themedScrollbarThumbInactive",
228 "ui.activeborder",
229 "ui.activecaption",
230 "ui.appworkspace",
231 "ui.background",
232 "ui.buttonface",
233 "ui.buttonhighlight",
234 "ui.buttonshadow",
235 "ui.buttontext",
236 "ui.captiontext",
237 "ui.-moz-field",
238 "ui.-moz-disabledfield",
239 "ui.-moz-fieldtext",
240 "ui.graytext",
241 "ui.highlight",
242 "ui.highlighttext",
243 "ui.inactiveborder",
244 "ui.inactivecaption",
245 "ui.inactivecaptiontext",
246 "ui.infobackground",
247 "ui.infotext",
248 "ui.menu",
249 "ui.menutext",
250 "ui.scrollbar",
251 "ui.threeddarkshadow",
252 "ui.threedface",
253 "ui.threedhighlight",
254 "ui.threedlightshadow",
255 "ui.threedshadow",
256 "ui.window",
257 "ui.windowframe",
258 "ui.windowtext",
259 "ui.-moz-buttondefault",
260 "ui.-moz-default-color",
261 "ui.-moz-default-background-color",
262 "ui.-moz-dialog",
263 "ui.-moz-dialogtext",
264 "ui.-moz-dragtargetzone",
265 "ui.-moz-cellhighlight",
266 "ui.-moz_cellhighlighttext",
267 "ui.selecteditem",
268 "ui.selecteditemtext",
269 "ui.-moz-buttonhoverface",
270 "ui.-moz_buttonhovertext",
271 "ui.-moz_menuhover",
272 "ui.-moz_menuhovertext",
273 "ui.-moz_menubartext",
274 "ui.-moz_menubarhovertext",
275 "ui.-moz_eventreerow",
276 "ui.-moz_oddtreerow",
277 "ui.-moz-buttonactivetext",
278 "ui.-moz-buttonactiveface",
279 "ui.-moz-buttondisabledface",
280 "ui.-moz_mac_chrome_active",
281 "ui.-moz_mac_chrome_inactive",
282 "ui.-moz-mac-defaultbuttontext",
283 "ui.-moz-mac-focusring",
284 "ui.-moz-mac-menuselect",
285 "ui.-moz-mac-menushadow",
286 "ui.-moz-mac-menutextdisable",
287 "ui.-moz-mac-menutextselect",
288 "ui.-moz_mac_disabledtoolbartext",
289 "ui.-moz-mac-secondaryhighlight",
290 "ui.-moz-mac-vibrant-titlebar-light",
291 "ui.-moz-mac-vibrant-titlebar-dark",
292 "ui.-moz-mac-menupopup",
293 "ui.-moz-mac-menuitem",
294 "ui.-moz-mac-active-menuitem",
295 "ui.-moz-mac-source-list",
296 "ui.-moz-mac-source-list-selection",
297 "ui.-moz-mac-active-source-list-selection",
298 "ui.-moz-mac-tooltip",
299 "ui.-moz-accent-color",
300 "ui.-moz-accent-color-foreground",
301 "ui.-moz-autofill-background",
302 "ui.-moz-win-mediatext",
303 "ui.-moz-win-communicationstext",
304 "ui.-moz-nativehyperlinktext",
305 "ui.-moz-nativevisitedhyperlinktext",
306 "ui.-moz-hyperlinktext",
307 "ui.-moz-activehyperlinktext",
308 "ui.-moz-visitedhyperlinktext",
309 "ui.-moz-comboboxtext",
310 "ui.-moz-combobox",
311 "ui.-moz-colheadertext",
312 "ui.-moz-colheaderhovertext",
315 static_assert(ArrayLength(sColorPrefs) == size_t(LookAndFeel::ColorID::End),
316 "Should have a pref for each color value");
318 const char* nsXPLookAndFeel::GetColorPrefName(ColorID aId) {
319 return sColorPrefs[size_t(aId)];
322 bool nsXPLookAndFeel::sInitialized = false;
324 nsXPLookAndFeel* nsXPLookAndFeel::sInstance = nullptr;
325 bool nsXPLookAndFeel::sShutdown = false;
327 // static
328 nsXPLookAndFeel* nsXPLookAndFeel::GetInstance() {
329 if (sInstance) {
330 return sInstance;
333 NS_ENSURE_TRUE(!sShutdown, nullptr);
335 // If we're in a content process, then the parent process will have supplied
336 // us with an initial FullLookAndFeel object.
337 // We grab this data from the ContentChild,
338 // where it's been temporarily stashed, and initialize our new LookAndFeel
339 // object with it.
341 FullLookAndFeel* lnf = nullptr;
343 if (auto* cc = mozilla::dom::ContentChild::GetSingleton()) {
344 lnf = &cc->BorrowLookAndFeelData();
347 if (lnf) {
348 sInstance = new widget::RemoteLookAndFeel(std::move(*lnf));
349 } else if (gfxPlatform::IsHeadless()) {
350 sInstance = new widget::HeadlessLookAndFeel();
351 } else {
352 sInstance = new nsLookAndFeel();
355 // This is only ever used once during initialization, and can be cleared now.
356 if (lnf) {
357 *lnf = {};
360 widget::Theme::Init();
361 return sInstance;
364 // static
365 void nsXPLookAndFeel::Shutdown() {
366 if (sShutdown) {
367 return;
370 sShutdown = true;
371 delete sInstance;
372 sInstance = nullptr;
374 // This keeps strings alive, so need to clear to make leak checking happy.
375 sFontCache.Clear();
377 widget::Theme::Shutdown();
380 static void IntPrefChanged(const nsACString& aPref) {
381 // Most Int prefs can't change our system colors or fonts, but
382 // ui.systemUsesDarkTheme can, since it affects the effective color-scheme
383 // (affecting system colors).
384 auto changeKind = aPref.EqualsLiteral("ui.systemUsesDarkTheme")
385 ? widget::ThemeChangeKind::Style
386 : widget::ThemeChangeKind::MediaQueriesOnly;
387 LookAndFeel::NotifyChangedAllWindows(changeKind);
390 static void FloatPrefChanged() {
391 // Float prefs can't change our system colors or fonts.
392 LookAndFeel::NotifyChangedAllWindows(
393 widget::ThemeChangeKind::MediaQueriesOnly);
396 static void ColorPrefChanged() {
397 // Color prefs affect style, because they by definition change system colors.
398 LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind::Style);
401 // static
402 void nsXPLookAndFeel::OnPrefChanged(const char* aPref, void* aClosure) {
403 nsDependentCString prefName(aPref);
404 for (const char* pref : sIntPrefs) {
405 if (prefName.Equals(pref)) {
406 IntPrefChanged(prefName);
407 return;
411 for (const char* pref : sFloatPrefs) {
412 if (prefName.Equals(pref)) {
413 FloatPrefChanged();
414 return;
418 for (const char* pref : sColorPrefs) {
419 // We use StringBeginsWith to handle .dark prefs too.
420 if (StringBeginsWith(prefName, nsDependentCString(pref))) {
421 ColorPrefChanged();
422 return;
427 static constexpr struct {
428 nsLiteralCString mName;
429 widget::ThemeChangeKind mChangeKind =
430 widget::ThemeChangeKind::MediaQueriesOnly;
431 } kMediaQueryPrefs[] = {
432 {"browser.display.windows.native_menus"_ns},
433 {"browser.proton.places-tooltip.enabled"_ns},
434 {"layout.css.prefers-color-scheme.content-override"_ns},
435 // Affects media queries and scrollbar sizes, so gotta relayout.
436 {"widget.gtk.overlay-scrollbars.enabled"_ns,
437 widget::ThemeChangeKind::StyleAndLayout},
438 // This affects not only the media query, but also the native theme, so we
439 // need to re-layout.
440 {"browser.theme.toolbar-theme"_ns, widget::ThemeChangeKind::AllBits},
441 {"browser.theme.content-theme"_ns},
444 // Read values from the user's preferences.
445 // This is done once at startup, but since the user's preferences
446 // haven't actually been read yet at that time, we also have to
447 // set a callback to inform us of changes to each pref.
448 void nsXPLookAndFeel::Init() {
449 MOZ_RELEASE_ASSERT(NS_IsMainThread());
451 // Say we're already initialized, and take the chance that it might fail;
452 // protects against some other process writing to our static variables.
453 sInitialized = true;
455 RecomputeColorSchemes();
457 // XXX If we could reorganize the pref names, we should separate the branch
458 // for each types. Then, we could reduce the unnecessary loop from
459 // nsXPLookAndFeel::OnPrefChanged().
460 Preferences::RegisterPrefixCallback(OnPrefChanged, "ui.");
461 // We really do just want the accessibility.tabfocus pref, not other prefs
462 // that start with that string.
463 Preferences::RegisterCallback(OnPrefChanged, "accessibility.tabfocus");
465 for (auto& pref : kMediaQueryPrefs) {
466 Preferences::RegisterCallback(
467 [](const char*, void* aChangeKind) {
468 auto changeKind =
469 widget::ThemeChangeKind(reinterpret_cast<uintptr_t>(aChangeKind));
470 LookAndFeel::NotifyChangedAllWindows(changeKind);
472 pref.mName, reinterpret_cast<void*>(uintptr_t(pref.mChangeKind)));
476 nsXPLookAndFeel::~nsXPLookAndFeel() {
477 NS_ASSERTION(sInstance == this,
478 "This destroying instance isn't the singleton instance");
479 sInstance = nullptr;
482 static bool IsSpecialColor(LookAndFeel::ColorID aID, nscolor aColor) {
483 using ColorID = LookAndFeel::ColorID;
485 if (aColor == NS_SAME_AS_FOREGROUND_COLOR) {
486 return true;
489 switch (aID) {
490 case ColorID::IMESelectedRawTextBackground:
491 case ColorID::IMESelectedConvertedTextBackground:
492 case ColorID::IMERawInputBackground:
493 case ColorID::IMEConvertedTextBackground:
494 case ColorID::IMESelectedRawTextForeground:
495 case ColorID::IMESelectedConvertedTextForeground:
496 case ColorID::IMERawInputForeground:
497 case ColorID::IMEConvertedTextForeground:
498 case ColorID::IMERawInputUnderline:
499 case ColorID::IMEConvertedTextUnderline:
500 case ColorID::IMESelectedRawTextUnderline:
501 case ColorID::IMESelectedConvertedTextUnderline:
502 case ColorID::SpellCheckerUnderline:
503 return NS_IS_SELECTION_SPECIAL_COLOR(aColor);
504 default:
505 break;
508 * In GetColor(), every color that is not a special color is color
509 * corrected. Use false to make other colors color corrected.
511 return false;
514 nscolor nsXPLookAndFeel::GetStandinForNativeColor(ColorID aID,
515 ColorScheme aScheme) {
516 if (aScheme == ColorScheme::Dark) {
517 if (auto color = GenericDarkColor(aID)) {
518 return *color;
522 // The stand-in colors are taken from what the non-native theme needs (for
523 // field/button colors), the Windows 7 Aero theme except Mac-specific colors
524 // which are taken from Mac OS 10.7.
526 #define COLOR(name_, r, g, b) \
527 case ColorID::name_: \
528 return NS_RGB(r, g, b);
530 #define COLORA(name_, r, g, b, a) \
531 case ColorID::name_: \
532 return NS_RGBA(r, g, b, a);
534 switch (aID) {
535 // These are here for the purposes of headless mode.
536 case ColorID::IMESelectedRawTextBackground:
537 case ColorID::IMESelectedConvertedTextBackground:
538 case ColorID::IMERawInputBackground:
539 case ColorID::IMEConvertedTextBackground:
540 return NS_TRANSPARENT;
541 case ColorID::IMESelectedRawTextForeground:
542 case ColorID::IMESelectedConvertedTextForeground:
543 case ColorID::IMERawInputForeground:
544 case ColorID::IMEConvertedTextForeground:
545 return NS_SAME_AS_FOREGROUND_COLOR;
546 case ColorID::IMERawInputUnderline:
547 case ColorID::IMEConvertedTextUnderline:
548 return NS_40PERCENT_FOREGROUND_COLOR;
549 COLOR(MozAccentColor, 53, 132, 228)
550 COLOR(MozAccentColorForeground, 0xff, 0xff, 0xff)
551 COLOR(SpellCheckerUnderline, 0xff, 0x00, 0x00)
552 COLOR(TextSelectDisabledBackground, 0xaa, 0xaa, 0xaa)
554 // CSS 2 colors:
555 COLOR(Activeborder, 0xB4, 0xB4, 0xB4)
556 COLOR(Activecaption, 0x99, 0xB4, 0xD1)
557 COLOR(Appworkspace, 0xAB, 0xAB, 0xAB)
558 COLOR(Background, 0x00, 0x00, 0x00)
559 COLOR(Buttonhighlight, 0xFF, 0xFF, 0xFF)
560 COLOR(Buttonshadow, 0xA0, 0xA0, 0xA0)
562 // Buttons and comboboxes should be kept in sync since they are drawn with
563 // the same colors by the non-native theme.
564 COLOR(Buttonface, 0xe9, 0xe9, 0xed)
565 COLORA(MozButtondisabledface, 0xe9, 0xe9, 0xed, 128)
567 COLOR(MozCombobox, 0xe9, 0xe9, 0xed)
569 COLOR(Buttontext, 0x00, 0x00, 0x00)
570 COLOR(MozComboboxtext, 0x00, 0x00, 0x00)
572 COLOR(Captiontext, 0x00, 0x00, 0x00)
573 COLOR(Graytext, 0x6D, 0x6D, 0x6D)
574 COLOR(Highlight, 0x33, 0x99, 0xFF)
575 COLOR(Highlighttext, 0xFF, 0xFF, 0xFF)
576 COLOR(Inactiveborder, 0xF4, 0xF7, 0xFC)
577 COLOR(Inactivecaption, 0xBF, 0xCD, 0xDB)
578 COLOR(Inactivecaptiontext, 0x43, 0x4E, 0x54)
579 COLOR(Infobackground, 0xFF, 0xFF, 0xE1)
580 COLOR(Infotext, 0x00, 0x00, 0x00)
581 COLOR(Menu, 0xF0, 0xF0, 0xF0)
582 COLOR(Menutext, 0x00, 0x00, 0x00)
583 COLOR(Scrollbar, 0xC8, 0xC8, 0xC8)
584 COLOR(Threeddarkshadow, 0x69, 0x69, 0x69)
585 COLOR(Threedface, 0xF0, 0xF0, 0xF0)
586 COLOR(Threedhighlight, 0xFF, 0xFF, 0xFF)
587 COLOR(Threedlightshadow, 0xE3, 0xE3, 0xE3)
588 COLOR(Threedshadow, 0xA0, 0xA0, 0xA0)
589 COLOR(Window, 0xFF, 0xFF, 0xFF)
590 COLOR(Windowframe, 0x64, 0x64, 0x64)
591 COLOR(Windowtext, 0x00, 0x00, 0x00)
592 COLOR(MozButtondefault, 0x69, 0x69, 0x69)
593 COLOR(Field, 0xFF, 0xFF, 0xFF)
594 COLORA(MozDisabledfield, 0xFF, 0xFF, 0xFF, 128)
595 COLOR(Fieldtext, 0x00, 0x00, 0x00)
596 COLOR(MozDialog, 0xF0, 0xF0, 0xF0)
597 COLOR(MozDialogtext, 0x00, 0x00, 0x00)
598 COLOR(MozColheadertext, 0x00, 0x00, 0x00)
599 COLOR(MozColheaderhovertext, 0x00, 0x00, 0x00)
600 COLOR(MozDragtargetzone, 0xFF, 0xFF, 0xFF)
601 COLOR(MozCellhighlight, 0xF0, 0xF0, 0xF0)
602 COLOR(MozCellhighlighttext, 0x00, 0x00, 0x00)
603 COLOR(Selecteditem, 0x33, 0x99, 0xFF)
604 COLOR(Selecteditemtext, 0xFF, 0xFF, 0xFF)
605 COLOR(MozButtonhoverface, 0xd0, 0xd0, 0xd7)
606 COLOR(MozButtonhovertext, 0x00, 0x00, 0x00)
607 COLOR(MozButtonactiveface, 0xb1, 0xb1, 0xb9)
608 COLOR(MozButtonactivetext, 0x00, 0x00, 0x00)
609 COLOR(MozMenuhover, 0x33, 0x99, 0xFF)
610 COLOR(MozMenuhovertext, 0x00, 0x00, 0x00)
611 COLOR(MozMenubartext, 0x00, 0x00, 0x00)
612 COLOR(MozMenubarhovertext, 0x00, 0x00, 0x00)
613 COLOR(MozEventreerow, 0xFF, 0xFF, 0xFF)
614 COLOR(MozOddtreerow, 0xFF, 0xFF, 0xFF)
615 COLOR(MozMacChromeActive, 0xB2, 0xB2, 0xB2)
616 COLOR(MozMacChromeInactive, 0xE1, 0xE1, 0xE1)
617 COLOR(MozMacFocusring, 0x60, 0x9D, 0xD7)
618 COLOR(MozMacMenuselect, 0x38, 0x75, 0xD7)
619 COLOR(MozMacMenushadow, 0xA3, 0xA3, 0xA3)
620 COLOR(MozMacMenutextdisable, 0x88, 0x88, 0x88)
621 COLOR(MozMacMenutextselect, 0xFF, 0xFF, 0xFF)
622 COLOR(MozMacDisabledtoolbartext, 0x3F, 0x3F, 0x3F)
623 COLOR(MozMacSecondaryhighlight, 0xD4, 0xD4, 0xD4)
624 COLOR(MozMacVibrantTitlebarLight, 0xf7, 0xf7, 0xf7)
625 COLOR(MozMacVibrantTitlebarDark, 0x28, 0x28, 0x28)
626 COLOR(MozMacMenupopup, 0xe6, 0xe6, 0xe6)
627 COLOR(MozMacMenuitem, 0xe6, 0xe6, 0xe6)
628 COLOR(MozMacActiveMenuitem, 0x0a, 0x64, 0xdc)
629 COLOR(MozMacSourceList, 0xf7, 0xf7, 0xf7)
630 COLOR(MozMacSourceListSelection, 0xc8, 0xc8, 0xc8)
631 COLOR(MozMacActiveSourceListSelection, 0x0a, 0x64, 0xdc)
632 COLOR(MozMacTooltip, 0xf7, 0xf7, 0xf7)
633 // Seems to be the default color (hardcoded because of bug 1065998)
634 COLOR(MozWinMediatext, 0xFF, 0xFF, 0xFF)
635 COLOR(MozWinCommunicationstext, 0xFF, 0xFF, 0xFF)
636 COLOR(MozNativehyperlinktext, 0x00, 0x66, 0xCC)
637 COLOR(MozNativevisitedhyperlinktext, 0x55, 0x1A, 0x8B)
638 default:
639 break;
641 return NS_RGB(0xFF, 0xFF, 0xFF);
644 #undef COLOR
645 #undef COLORA
647 // Taken from in-content/common.inc.css's dark theme.
648 Maybe<nscolor> nsXPLookAndFeel::GenericDarkColor(ColorID aID) {
649 nscolor color = NS_RGB(0, 0, 0);
650 static constexpr nscolor kWindowBackground = NS_RGB(28, 27, 34);
651 static constexpr nscolor kWindowText = NS_RGB(251, 251, 254);
652 switch (aID) {
653 case ColorID::Window: // --in-content-page-background
654 case ColorID::Background:
655 case ColorID::Menu:
656 color = kWindowBackground;
657 break;
658 case ColorID::MozOddtreerow:
659 case ColorID::MozDialog: // --in-content-box-background
660 color = NS_RGB(35, 34, 43);
661 break;
662 case ColorID::Windowtext: // --in-content-page-color
663 case ColorID::Menutext:
664 case ColorID::MozDialogtext:
665 case ColorID::Fieldtext:
666 case ColorID::Buttontext: // --in-content-button-text-color (via
667 // --in-content-page-color)
668 case ColorID::MozComboboxtext:
669 case ColorID::MozButtonhovertext:
670 case ColorID::MozButtonactivetext:
671 color = kWindowText;
672 break;
673 case ColorID::Threedlightshadow: // --in-content-box-border-color computed
674 // with kWindowText above
675 // kWindowBackground.
676 case ColorID::Graytext: // opacity: 0.4 of kWindowText blended over the
677 // "Window" background color, which happens to be
678 // the same :-)
679 color = NS_ComposeColors(kWindowBackground, NS_RGBA(251, 251, 254, 102));
680 break;
681 case ColorID::MozCellhighlight:
682 case ColorID::Selecteditem: // --in-content-primary-button-background /
683 // --in-content-item-selected
684 color = NS_RGB(0, 221, 255);
685 break;
686 case ColorID::Field:
687 case ColorID::Buttonface: // --in-content-button-background
688 case ColorID::Threedface:
689 case ColorID::MozCombobox:
690 case ColorID::MozCellhighlighttext:
691 case ColorID::Selecteditemtext: // --in-content-primary-button-text-color /
692 // --in-content-item-selected-text
693 color = NS_RGB(43, 42, 51);
694 break;
695 case ColorID::Threeddarkshadow: // Same as Threedlightshadow but with the
696 // background.
697 case ColorID::MozDisabledfield: // opacity: 0.4 of the face above blended
698 // over the "Window" background color.
699 case ColorID::MozButtondisabledface:
700 color = NS_ComposeColors(kWindowBackground, NS_RGBA(43, 42, 51, 102));
701 break;
702 case ColorID::MozButtonhoverface: // --in-content-button-background-hover
703 color = NS_RGB(82, 82, 94);
704 break;
705 case ColorID::MozButtonactiveface: // --in-content-button-background-active
706 color = NS_RGB(91, 91, 102);
707 break;
708 case ColorID::Highlight:
709 color = NS_RGBA(0, 221, 255, 78);
710 break;
711 case ColorID::Highlighttext:
712 color = NS_SAME_AS_FOREGROUND_COLOR;
713 break;
714 case ColorID::MozNativehyperlinktext:
715 // If you change this color, you probably also want to change the default
716 // value of browser.anchor_color.dark.
717 color = NS_RGB(0x8c, 0x8c, 0xff);
718 break;
719 case ColorID::MozNativevisitedhyperlinktext:
720 // If you change this color, you probably also want to change the default
721 // value of browser.visited_color.dark.
722 color = NS_RGB(0xff, 0xad, 0xff);
723 break;
725 default:
726 return Nothing();
728 return Some(color);
731 // Uncomment the #define below if you want to debug system color use in a skin
732 // that uses them. When set, it will make all system color pairs that are
733 // appropriate for foreground/background pairing the same. This means if the
734 // skin is using system colors correctly you will not be able to see *any* text.
736 // #define DEBUG_SYSTEM_COLOR_USE
738 #ifdef DEBUG_SYSTEM_COLOR_USE
739 static nsresult SystemColorUseDebuggingColor(LookAndFeel::ColorID aID,
740 nscolor& aResult) {
741 using ColorID = LookAndFeel::ColorID;
743 switch (aID) {
744 // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
745 case ColorID::Activecaption:
746 // active window caption background
747 case ColorID::Captiontext:
748 // text in active window caption
749 aResult = NS_RGB(0xff, 0x00, 0x00);
750 break;
752 case ColorID::Highlight:
753 // background of selected item
754 case ColorID::Highlighttext:
755 // text of selected item
756 aResult = NS_RGB(0xff, 0xff, 0x00);
757 break;
759 case ColorID::Inactivecaption:
760 // inactive window caption
761 case ColorID::Inactivecaptiontext:
762 // text in inactive window caption
763 aResult = NS_RGB(0x66, 0x66, 0x00);
764 break;
766 case ColorID::Infobackground:
767 // tooltip background color
768 case ColorID::Infotext:
769 // tooltip text color
770 aResult = NS_RGB(0x00, 0xff, 0x00);
771 break;
773 case ColorID::Menu:
774 // menu background
775 case ColorID::Menutext:
776 // menu text
777 aResult = NS_RGB(0x00, 0xff, 0xff);
778 break;
780 case ColorID::Threedface:
781 case ColorID::Buttonface:
782 // 3-D face color
783 case ColorID::Buttontext:
784 // text on push buttons
785 aResult = NS_RGB(0x00, 0x66, 0x66);
786 break;
788 case ColorID::Window:
789 case ColorID::Windowtext:
790 aResult = NS_RGB(0x00, 0x00, 0xff);
791 break;
793 // from the CSS3 working draft (not yet finalized)
794 // http://www.w3.org/tr/2000/wd-css3-userint-20000216.html#color
796 case ColorID::Field:
797 case ColorID::Fieldtext:
798 aResult = NS_RGB(0xff, 0x00, 0xff);
799 break;
801 case ColorID::MozDialog:
802 case ColorID::MozDialogtext:
803 aResult = NS_RGB(0x66, 0x00, 0x66);
804 break;
806 default:
807 return NS_ERROR_NOT_AVAILABLE;
810 return NS_OK;
812 #endif
814 static nsresult GetPrefColor(const char* aPref, nscolor& aResult) {
815 nsAutoCString colorStr;
816 MOZ_TRY(Preferences::GetCString(aPref, colorStr));
817 if (!ServoCSSParser::ComputeColor(nullptr, NS_RGB(0, 0, 0), colorStr,
818 &aResult)) {
819 return NS_ERROR_FAILURE;
821 return NS_OK;
824 static nsresult GetColorFromPref(LookAndFeel::ColorID aID, ColorScheme aScheme,
825 nscolor& aResult) {
826 const char* prefName = sColorPrefs[size_t(aID)];
827 if (aScheme == ColorScheme::Dark) {
828 nsAutoCString darkPrefName(prefName);
829 darkPrefName.Append(".dark");
830 if (NS_SUCCEEDED(GetPrefColor(darkPrefName.get(), aResult))) {
831 return NS_OK;
834 return GetPrefColor(prefName, aResult);
837 // All these routines will return NS_OK if they have a value,
838 // in which case the nsLookAndFeel should use that value;
839 // otherwise we'll return NS_ERROR_NOT_AVAILABLE, in which case, the
840 // platform-specific nsLookAndFeel should use its own values instead.
841 nsresult nsXPLookAndFeel::GetColorValue(ColorID aID, ColorScheme aScheme,
842 UseStandins aUseStandins,
843 nscolor& aResult) {
844 if (!sInitialized) {
845 Init();
848 #ifdef DEBUG_SYSTEM_COLOR_USE
849 if (NS_SUCCEEDED(SystemColorUseDebuggingColor(aID, aResult))) {
850 return NS_OK;
852 #endif
854 if (aUseStandins == UseStandins::Yes) {
855 aResult = GetStandinForNativeColor(aID, aScheme);
856 return NS_OK;
859 auto& cache =
860 aScheme == ColorScheme::Light ? sLightColorCache : sDarkColorCache;
861 if (const auto* cached = cache.Get(aID)) {
862 if (cached->isNothing()) {
863 return NS_ERROR_FAILURE;
865 aResult = cached->value();
866 return NS_OK;
869 if (NS_SUCCEEDED(GetColorFromPref(aID, aScheme, aResult))) {
870 cache.Insert(aID, Some(aResult));
871 return NS_OK;
874 if (NS_SUCCEEDED(NativeGetColor(aID, aScheme, aResult))) {
875 if (gfxPlatform::GetCMSMode() == CMSMode::All &&
876 !IsSpecialColor(aID, aResult)) {
877 qcms_transform* transform = gfxPlatform::GetCMSInverseRGBTransform();
878 if (transform) {
879 uint8_t color[4];
880 color[0] = NS_GET_R(aResult);
881 color[1] = NS_GET_G(aResult);
882 color[2] = NS_GET_B(aResult);
883 color[3] = NS_GET_A(aResult);
884 qcms_transform_data(transform, color, color, 1);
885 aResult = NS_RGBA(color[0], color[1], color[2], color[3]);
889 // NOTE: Servo holds a lock and the main thread is paused, so writing to the
890 // global cache here is fine.
891 cache.Insert(aID, Some(aResult));
892 return NS_OK;
895 cache.Insert(aID, Nothing());
896 return NS_ERROR_FAILURE;
899 nsresult nsXPLookAndFeel::GetIntValue(IntID aID, int32_t& aResult) {
900 if (!sInitialized) {
901 Init();
904 if (const auto* cached = sIntCache.Get(aID)) {
905 if (cached->isNothing()) {
906 return NS_ERROR_FAILURE;
908 aResult = cached->value();
909 return NS_OK;
912 if (NS_SUCCEEDED(Preferences::GetInt(sIntPrefs[size_t(aID)], &aResult))) {
913 sIntCache.Insert(aID, Some(aResult));
914 return NS_OK;
917 if (NS_FAILED(NativeGetInt(aID, aResult))) {
918 sIntCache.Insert(aID, Nothing());
919 return NS_ERROR_FAILURE;
922 sIntCache.Insert(aID, Some(aResult));
923 return NS_OK;
926 nsresult nsXPLookAndFeel::GetFloatValue(FloatID aID, float& aResult) {
927 if (!sInitialized) {
928 Init();
931 if (const auto* cached = sFloatCache.Get(aID)) {
932 if (cached->isNothing()) {
933 return NS_ERROR_FAILURE;
935 aResult = cached->value();
936 return NS_OK;
939 int32_t pref = 0;
940 if (NS_SUCCEEDED(Preferences::GetInt(sFloatPrefs[size_t(aID)], &pref))) {
941 aResult = float(pref) / 100.0f;
942 sFloatCache.Insert(aID, Some(aResult));
943 return NS_OK;
946 if (NS_FAILED(NativeGetFloat(aID, aResult))) {
947 sFloatCache.Insert(aID, Nothing());
948 return NS_ERROR_FAILURE;
951 sFloatCache.Insert(aID, Some(aResult));
952 return NS_OK;
955 bool nsXPLookAndFeel::LookAndFeelFontToStyle(const LookAndFeelFont& aFont,
956 nsString& aName,
957 gfxFontStyle& aStyle) {
958 if (!aFont.haveFont()) {
959 return false;
961 aName = aFont.name();
962 aStyle = gfxFontStyle();
963 aStyle.size = aFont.size();
964 aStyle.weight = FontWeight(aFont.weight());
965 aStyle.style =
966 aFont.italic() ? FontSlantStyle::Italic() : FontSlantStyle::Normal();
967 aStyle.systemFont = true;
968 return true;
971 widget::LookAndFeelFont nsXPLookAndFeel::StyleToLookAndFeelFont(
972 const nsAString& aName, const gfxFontStyle& aStyle) {
973 LookAndFeelFont font;
974 font.haveFont() = true;
975 font.name() = aName;
976 font.size() = aStyle.size;
977 font.weight() = aStyle.weight.ToFloat();
978 font.italic() = aStyle.style.IsItalic();
979 MOZ_ASSERT(aStyle.style.IsNormal() || aStyle.style.IsItalic(),
980 "Cannot handle oblique font style");
981 #ifdef DEBUG
983 // Assert that all the remaining font style properties have their
984 // default values.
985 gfxFontStyle candidate = aStyle;
986 gfxFontStyle defaults{};
987 candidate.size = defaults.size;
988 candidate.weight = defaults.weight;
989 candidate.style = defaults.style;
990 MOZ_ASSERT(candidate.Equals(defaults),
991 "Some font style properties not supported");
993 #endif
994 return font;
997 bool nsXPLookAndFeel::GetFontValue(FontID aID, nsString& aName,
998 gfxFontStyle& aStyle) {
999 if (const LookAndFeelFont* cached = sFontCache.Get(aID)) {
1000 return LookAndFeelFontToStyle(*cached, aName, aStyle);
1002 LookAndFeelFont font;
1003 const bool haveFont = NativeGetFont(aID, aName, aStyle);
1004 font.haveFont() = haveFont;
1005 if (haveFont) {
1006 font = StyleToLookAndFeelFont(aName, aStyle);
1008 sFontCache.Insert(aID, std::move(font));
1009 return haveFont;
1012 void nsXPLookAndFeel::RefreshImpl() {
1013 // Wipe out our caches.
1014 sLightColorCache.Clear();
1015 sDarkColorCache.Clear();
1016 sFontCache.Clear();
1017 sFloatCache.Clear();
1018 sIntCache.Clear();
1019 RecomputeColorSchemes();
1021 // Clear any cached FullLookAndFeel data, which is now invalid.
1022 if (XRE_IsParentProcess()) {
1023 widget::RemoteLookAndFeel::ClearCachedData();
1027 static bool sRecordedLookAndFeelTelemetry = false;
1029 void nsXPLookAndFeel::RecordTelemetry() {
1030 if (!XRE_IsParentProcess()) {
1031 return;
1034 if (sRecordedLookAndFeelTelemetry) {
1035 return;
1038 sRecordedLookAndFeelTelemetry = true;
1040 int32_t i;
1041 Telemetry::ScalarSet(
1042 Telemetry::ScalarID::WIDGET_DARK_MODE,
1043 NS_SUCCEEDED(GetIntValue(IntID::SystemUsesDarkTheme, i)) && i != 0);
1045 RecordLookAndFeelSpecificTelemetry();
1048 namespace mozilla {
1050 static widget::ThemeChangeKind sGlobalThemeChangeKind{0};
1052 void LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind aKind) {
1053 sGlobalThemeChanged = true;
1054 sGlobalThemeChangeKind |= aKind;
1056 if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
1057 const char16_t kind[] = {char16_t(aKind), 0};
1058 obs->NotifyObservers(nullptr, "internal-look-and-feel-changed", kind);
1062 void LookAndFeel::DoHandleGlobalThemeChange() {
1063 MOZ_ASSERT(sGlobalThemeChanged);
1064 sGlobalThemeChanged = false;
1065 auto kind = std::exchange(sGlobalThemeChangeKind, widget::ThemeChangeKind(0));
1067 // Tell the theme that it changed, so it can flush any handles to stale theme
1068 // data.
1070 // We can use the *DoNotUseDirectly functions directly here, because we want
1071 // to notify all possible themes in a given process (but just once).
1072 if (XRE_IsParentProcess() ||
1073 !StaticPrefs::widget_non_native_theme_enabled()) {
1074 if (nsCOMPtr<nsITheme> theme = do_GetNativeThemeDoNotUseDirectly()) {
1075 theme->ThemeChanged();
1078 if (nsCOMPtr<nsITheme> theme = do_GetBasicNativeThemeDoNotUseDirectly()) {
1079 theme->ThemeChanged();
1082 // Clear all cached LookAndFeel colors.
1083 LookAndFeel::Refresh();
1085 // Reset default background and foreground colors for the document since they
1086 // may be using system colors.
1087 PreferenceSheet::Refresh();
1089 // Vector images (SVG) may be using theme colors so we discard all cached
1090 // surfaces. (We could add a vector image only version of DiscardAll, but
1091 // in bug 940625 we decided theme changes are rare enough not to bother.)
1092 image::SurfaceCacheUtils::DiscardAll();
1094 if (XRE_IsParentProcess()) {
1095 dom::ContentParent::BroadcastThemeUpdate(kind);
1098 nsContentUtils::AddScriptRunner(
1099 NS_NewRunnableFunction("HandleGlobalThemeChange", [] {
1100 if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
1101 obs->NotifyObservers(nullptr, "look-and-feel-changed", nullptr);
1103 }));
1106 static bool ShouldUseStandinsForNativeColorForNonNativeTheme(
1107 const dom::Document& aDoc, LookAndFeel::ColorID aColor) {
1108 using ColorID = LookAndFeel::ColorID;
1109 if (!aDoc.ShouldAvoidNativeTheme()) {
1110 return false;
1113 // The native theme doesn't use native system colors backgrounds etc, except
1114 // when in high-contrast mode, so spoof some of the colors with stand-ins to
1115 // prevent lack of contrast.
1116 switch (aColor) {
1117 case ColorID::Buttonface:
1118 case ColorID::Buttontext:
1119 case ColorID::MozButtonhoverface:
1120 case ColorID::MozButtonhovertext:
1121 case ColorID::MozButtonactiveface:
1122 case ColorID::MozButtonactivetext:
1123 case ColorID::MozButtondisabledface:
1125 case ColorID::Threedlightshadow:
1126 case ColorID::Threeddarkshadow:
1127 case ColorID::Threedface:
1129 case ColorID::MozCombobox:
1130 case ColorID::MozComboboxtext:
1132 case ColorID::Field:
1133 case ColorID::MozDisabledfield:
1134 case ColorID::Fieldtext:
1136 case ColorID::Graytext:
1138 return !PreferenceSheet::PrefsFor(aDoc)
1139 .NonNativeThemeShouldBeHighContrast();
1141 default:
1142 break;
1145 return false;
1148 ColorScheme LookAndFeel::sChromeColorScheme;
1149 ColorScheme LookAndFeel::sContentColorScheme;
1150 bool LookAndFeel::sColorSchemeInitialized;
1151 bool LookAndFeel::sGlobalThemeChanged;
1153 auto LookAndFeel::ColorSchemeSettingForChrome() -> ChromeColorSchemeSetting {
1154 switch (StaticPrefs::browser_theme_toolbar_theme()) {
1155 case 0: // Dark
1156 return ChromeColorSchemeSetting::Dark;
1157 case 1: // Light
1158 return ChromeColorSchemeSetting::Light;
1159 default:
1160 return ChromeColorSchemeSetting::System;
1164 ColorScheme LookAndFeel::ThemeDerivedColorSchemeForContent() {
1165 switch (StaticPrefs::browser_theme_content_theme()) {
1166 case 0: // Dark
1167 return ColorScheme::Dark;
1168 case 1: // Light
1169 return ColorScheme::Light;
1170 default:
1171 return SystemColorScheme();
1175 void LookAndFeel::RecomputeColorSchemes() {
1176 sColorSchemeInitialized = true;
1178 sChromeColorScheme = [] {
1179 switch (ColorSchemeSettingForChrome()) {
1180 case ChromeColorSchemeSetting::Light:
1181 return ColorScheme::Light;
1182 case ChromeColorSchemeSetting::Dark:
1183 return ColorScheme::Dark;
1184 case ChromeColorSchemeSetting::System:
1185 break;
1187 return SystemColorScheme();
1188 }();
1190 sContentColorScheme = [] {
1191 switch (StaticPrefs::layout_css_prefers_color_scheme_content_override()) {
1192 case 0:
1193 return ColorScheme::Dark;
1194 case 1:
1195 return ColorScheme::Light;
1196 case 2:
1197 return SystemColorScheme();
1198 default:
1199 return ThemeDerivedColorSchemeForContent();
1201 }();
1204 ColorScheme LookAndFeel::ColorSchemeForStyle(
1205 const dom::Document& aDoc, const StyleColorSchemeFlags& aFlags) {
1206 if (PreferenceSheet::MayForceColors()) {
1207 auto& prefs = PreferenceSheet::PrefsFor(aDoc);
1208 if (!prefs.mUseDocumentColors) {
1209 // When forcing colors, we can use our preferred color-scheme. Do this
1210 // only if we're using system colors, as dark preference colors are not
1211 // exposed on the UI.
1213 // Also, use light if we're using a high-contrast-theme on Windows, since
1214 // Windows overrides the light colors with HCM colors when HCM is active.
1215 #ifdef XP_WIN
1216 if (prefs.mUseAccessibilityTheme) {
1217 return ColorScheme::Light;
1219 #endif
1220 if (StaticPrefs::browser_display_use_system_colors()) {
1221 return aDoc.PreferredColorScheme();
1223 return ColorScheme::Light;
1227 StyleColorSchemeFlags style(aFlags);
1228 if (!style) {
1229 style.bits = aDoc.GetColorSchemeBits();
1231 const bool supportsDark = bool(style & StyleColorSchemeFlags::DARK);
1232 const bool supportsLight = bool(style & StyleColorSchemeFlags::LIGHT);
1233 if (supportsLight && supportsDark) {
1234 // Both color-schemes are explicitly supported, use the preferred one.
1235 return aDoc.PreferredColorScheme();
1237 if (supportsDark || supportsLight) {
1238 // One color-scheme is explicitly supported and one isn't, so use the one
1239 // the content supports.
1240 return supportsDark ? ColorScheme::Dark : ColorScheme::Light;
1242 // No value specified. Chrome docs always supports both, so use the preferred
1243 // color-scheme.
1244 if (nsContentUtils::IsChromeDoc(&aDoc)) {
1245 return aDoc.PreferredColorScheme();
1247 // Default content to light.
1248 return ColorScheme::Light;
1251 LookAndFeel::ColorScheme LookAndFeel::ColorSchemeForFrame(
1252 const nsIFrame* aFrame) {
1253 return ColorSchemeForStyle(*aFrame->PresContext()->Document(),
1254 aFrame->StyleUI()->mColorScheme.bits);
1257 // static
1258 Maybe<nscolor> LookAndFeel::GetColor(ColorID aId, ColorScheme aScheme,
1259 UseStandins aUseStandins) {
1260 nscolor result;
1261 nsresult rv = nsLookAndFeel::GetInstance()->GetColorValue(
1262 aId, aScheme, aUseStandins, result);
1263 if (NS_FAILED(rv)) {
1264 return Nothing();
1266 return Some(result);
1269 // Returns whether there is a CSS color name for this color.
1270 static bool ColorIsCSSAccessible(LookAndFeel::ColorID aId) {
1271 using ColorID = LookAndFeel::ColorID;
1273 switch (aId) {
1274 case ColorID::TextSelectDisabledBackground:
1275 case ColorID::TextSelectAttentionBackground:
1276 case ColorID::TextSelectAttentionForeground:
1277 case ColorID::TextHighlightBackground:
1278 case ColorID::TextHighlightForeground:
1279 case ColorID::ThemedScrollbar:
1280 case ColorID::ThemedScrollbarInactive:
1281 case ColorID::ThemedScrollbarThumb:
1282 case ColorID::ThemedScrollbarThumbActive:
1283 case ColorID::ThemedScrollbarThumbInactive:
1284 case ColorID::ThemedScrollbarThumbHover:
1285 case ColorID::IMERawInputBackground:
1286 case ColorID::IMERawInputForeground:
1287 case ColorID::IMERawInputUnderline:
1288 case ColorID::IMESelectedRawTextBackground:
1289 case ColorID::IMESelectedRawTextForeground:
1290 case ColorID::IMESelectedRawTextUnderline:
1291 case ColorID::IMEConvertedTextBackground:
1292 case ColorID::IMEConvertedTextForeground:
1293 case ColorID::IMEConvertedTextUnderline:
1294 case ColorID::IMESelectedConvertedTextBackground:
1295 case ColorID::IMESelectedConvertedTextForeground:
1296 case ColorID::IMESelectedConvertedTextUnderline:
1297 case ColorID::SpellCheckerUnderline:
1298 return false;
1299 default:
1300 break;
1303 return true;
1306 LookAndFeel::UseStandins LookAndFeel::ShouldUseStandins(
1307 const dom::Document& aDoc, ColorID aId) {
1308 if (ShouldUseStandinsForNativeColorForNonNativeTheme(aDoc, aId)) {
1309 return UseStandins::Yes;
1311 if (nsContentUtils::UseStandinsForNativeColors() &&
1312 ColorIsCSSAccessible(aId) && !nsContentUtils::IsChromeDoc(&aDoc)) {
1313 return UseStandins::Yes;
1315 if (aDoc.IsStaticDocument() &&
1316 !PreferenceSheet::ContentPrefs().mUseDocumentColors) {
1317 return UseStandins::Yes;
1319 return UseStandins::No;
1322 Maybe<nscolor> LookAndFeel::GetColor(ColorID aId, const nsIFrame* aFrame) {
1323 const auto* doc = aFrame->PresContext()->Document();
1324 return GetColor(aId, ColorSchemeForFrame(aFrame),
1325 ShouldUseStandins(*doc, aId));
1328 // static
1329 nsresult LookAndFeel::GetInt(IntID aID, int32_t* aResult) {
1330 return nsLookAndFeel::GetInstance()->GetIntValue(aID, *aResult);
1333 // static
1334 nsresult LookAndFeel::GetFloat(FloatID aID, float* aResult) {
1335 return nsLookAndFeel::GetInstance()->GetFloatValue(aID, *aResult);
1338 // static
1339 bool LookAndFeel::GetFont(FontID aID, nsString& aName, gfxFontStyle& aStyle) {
1340 return nsLookAndFeel::GetInstance()->GetFontValue(aID, aName, aStyle);
1343 // static
1344 char16_t LookAndFeel::GetPasswordCharacter() {
1345 return nsLookAndFeel::GetInstance()->GetPasswordCharacterImpl();
1348 // static
1349 bool LookAndFeel::GetEchoPassword() {
1350 if (StaticPrefs::editor_password_mask_delay() >= 0) {
1351 return StaticPrefs::editor_password_mask_delay() > 0;
1353 return nsLookAndFeel::GetInstance()->GetEchoPasswordImpl();
1356 // static
1357 uint32_t LookAndFeel::GetPasswordMaskDelay() {
1358 int32_t delay = StaticPrefs::editor_password_mask_delay();
1359 if (delay < 0) {
1360 return nsLookAndFeel::GetInstance()->GetPasswordMaskDelayImpl();
1362 return delay;
1365 bool LookAndFeel::DrawInTitlebar() {
1366 switch (StaticPrefs::browser_tabs_inTitlebar()) {
1367 case 0:
1368 return false;
1369 case 1:
1370 return true;
1371 default:
1372 break;
1374 return nsLookAndFeel::GetInstance()->GetDefaultDrawInTitlebar();
1377 void LookAndFeel::GetThemeInfo(nsACString& aOut) {
1378 nsLookAndFeel::GetInstance()->GetThemeInfo(aOut);
1381 // static
1382 void LookAndFeel::Refresh() {
1383 nsLookAndFeel::GetInstance()->RefreshImpl();
1384 widget::Theme::LookAndFeelChanged();
1387 // static
1388 void LookAndFeel::NativeInit() { nsLookAndFeel::GetInstance()->NativeInit(); }
1390 // static
1391 void LookAndFeel::SetData(widget::FullLookAndFeel&& aTables) {
1392 nsLookAndFeel::GetInstance()->SetDataImpl(std::move(aTables));
1395 } // namespace mozilla