Bug 1753131 - wait for focus before dispatching devicechange events r=jib
[gecko.git] / widget / nsXPLookAndFeel.cpp
blob45ff1b50908d9a25fe7a60c561ee0af07644b63b
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[][43] = {
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.operatingSystemVersionIdentifier",
155 "ui.scrollbarButtonAutoRepeatBehavior",
156 "ui.tooltipDelay",
157 "ui.swipeAnimationEnabled",
158 "ui.scrollbarDisplayOnMouseMove",
159 "ui.scrollbarFadeBeginDelay",
160 "ui.scrollbarFadeDuration",
161 "ui.contextMenuOffsetVertical",
162 "ui.contextMenuOffsetHorizontal",
163 "ui.GtkCSDAvailable",
164 "ui.GtkCSDMinimizeButton",
165 "ui.GtkCSDMaximizeButton",
166 "ui.GtkCSDCloseButton",
167 "ui.GtkCSDMinimizeButtonPosition",
168 "ui.GtkCSDMaximizeButtonPosition",
169 "ui.GtkCSDCloseButtonPosition",
170 "ui.GtkCSDReversedPlacement",
171 "ui.systemUsesDarkTheme",
172 "ui.prefersReducedMotion",
173 "ui.primaryPointerCapabilities",
174 "ui.allPointerCapabilities",
175 "ui.systemVerticalScrollbarWidth",
176 "ui.systemHorizontalScrollbarHeight",
177 "ui.touchDeviceSupportPresent",
178 "ui.titlebarRadius",
179 "ui.GtkMenuRadius",
182 static_assert(ArrayLength(sIntPrefs) == size_t(LookAndFeel::IntID::End),
183 "Should have a pref for each int value");
185 // This array MUST be kept in the same order as the float id list in
186 // LookAndFeel.h
187 // clang-format off
188 static const char sFloatPrefs[][37] = {
189 "ui.IMEUnderlineRelativeSize",
190 "ui.SpellCheckerUnderlineRelativeSize",
191 "ui.caretAspectRatio",
192 "ui.textScaleFactor",
193 "ui.cursorScale",
195 // clang-format on
197 static_assert(ArrayLength(sFloatPrefs) == size_t(LookAndFeel::FloatID::End),
198 "Should have a pref for each float value");
200 // This array MUST be kept in the same order as the color list in
201 // specified/color.rs
202 static const char sColorPrefs[][41] = {
203 "ui.textSelectDisabledBackground",
204 "ui.textSelectAttentionBackground",
205 "ui.textSelectAttentionForeground",
206 "ui.textHighlightBackground",
207 "ui.textHighlightForeground",
208 "ui.IMERawInputBackground",
209 "ui.IMERawInputForeground",
210 "ui.IMERawInputUnderline",
211 "ui.IMESelectedRawTextBackground",
212 "ui.IMESelectedRawTextForeground",
213 "ui.IMESelectedRawTextUnderline",
214 "ui.IMEConvertedTextBackground",
215 "ui.IMEConvertedTextForeground",
216 "ui.IMEConvertedTextUnderline",
217 "ui.IMESelectedConvertedTextBackground",
218 "ui.IMESelectedConvertedTextForeground",
219 "ui.IMESelectedConvertedTextUnderline",
220 "ui.SpellCheckerUnderline",
221 "ui.themedScrollbar",
222 "ui.themedScrollbarInactive",
223 "ui.themedScrollbarThumb",
224 "ui.themedScrollbarThumbHover",
225 "ui.themedScrollbarThumbActive",
226 "ui.themedScrollbarThumbInactive",
227 "ui.activeborder",
228 "ui.activecaption",
229 "ui.appworkspace",
230 "ui.background",
231 "ui.buttonface",
232 "ui.buttonhighlight",
233 "ui.buttonshadow",
234 "ui.buttontext",
235 "ui.captiontext",
236 "ui.-moz-field",
237 "ui.-moz-disabledfield",
238 "ui.-moz-fieldtext",
239 "ui.graytext",
240 "ui.highlight",
241 "ui.highlighttext",
242 "ui.inactiveborder",
243 "ui.inactivecaption",
244 "ui.inactivecaptiontext",
245 "ui.infobackground",
246 "ui.infotext",
247 "ui.menu",
248 "ui.menutext",
249 "ui.scrollbar",
250 "ui.threeddarkshadow",
251 "ui.threedface",
252 "ui.threedhighlight",
253 "ui.threedlightshadow",
254 "ui.threedshadow",
255 "ui.window",
256 "ui.windowframe",
257 "ui.windowtext",
258 "ui.-moz-buttondefault",
259 "ui.-moz-default-color",
260 "ui.-moz-default-background-color",
261 "ui.-moz-dialog",
262 "ui.-moz-dialogtext",
263 "ui.-moz-dragtargetzone",
264 "ui.-moz-cellhighlight",
265 "ui.-moz_cellhighlighttext",
266 "ui.selecteditem",
267 "ui.selecteditemtext",
268 "ui.-moz-buttonhoverface",
269 "ui.-moz_buttonhovertext",
270 "ui.-moz_menuhover",
271 "ui.-moz_menuhovertext",
272 "ui.-moz_menubartext",
273 "ui.-moz_menubarhovertext",
274 "ui.-moz_eventreerow",
275 "ui.-moz_oddtreerow",
276 "ui.-moz-buttonactivetext",
277 "ui.-moz-buttonactiveface",
278 "ui.-moz-buttondisabledface",
279 "ui.-moz_mac_chrome_active",
280 "ui.-moz_mac_chrome_inactive",
281 "ui.-moz-mac-defaultbuttontext",
282 "ui.-moz-mac-focusring",
283 "ui.-moz-mac-menuselect",
284 "ui.-moz-mac-menushadow",
285 "ui.-moz-mac-menutextdisable",
286 "ui.-moz-mac-menutextselect",
287 "ui.-moz_mac_disabledtoolbartext",
288 "ui.-moz-mac-secondaryhighlight",
289 "ui.-moz-mac-vibrant-titlebar-light",
290 "ui.-moz-mac-vibrant-titlebar-dark",
291 "ui.-moz-mac-menupopup",
292 "ui.-moz-mac-menuitem",
293 "ui.-moz-mac-active-menuitem",
294 "ui.-moz-mac-source-list",
295 "ui.-moz-mac-source-list-selection",
296 "ui.-moz-mac-active-source-list-selection",
297 "ui.-moz-mac-tooltip",
298 "ui.-moz-accent-color",
299 "ui.-moz-accent-color-foreground",
300 "ui.-moz-autofill-background",
301 "ui.-moz-win-mediatext",
302 "ui.-moz-win-communicationstext",
303 "ui.-moz-nativehyperlinktext",
304 "ui.-moz-nativevisitedhyperlinktext",
305 "ui.-moz-hyperlinktext",
306 "ui.-moz-activehyperlinktext",
307 "ui.-moz-visitedhyperlinktext",
308 "ui.-moz-comboboxtext",
309 "ui.-moz-combobox",
310 "ui.-moz-colheadertext",
311 "ui.-moz-colheaderhovertext",
314 static_assert(ArrayLength(sColorPrefs) == size_t(LookAndFeel::ColorID::End),
315 "Should have a pref for each color value");
317 const char* nsXPLookAndFeel::GetColorPrefName(ColorID aId) {
318 return sColorPrefs[size_t(aId)];
321 bool nsXPLookAndFeel::sInitialized = false;
323 nsXPLookAndFeel* nsXPLookAndFeel::sInstance = nullptr;
324 bool nsXPLookAndFeel::sShutdown = false;
326 // static
327 nsXPLookAndFeel* nsXPLookAndFeel::GetInstance() {
328 if (sInstance) {
329 return sInstance;
332 NS_ENSURE_TRUE(!sShutdown, nullptr);
334 // If we're in a content process, then the parent process will have supplied
335 // us with an initial FullLookAndFeel object.
336 // We grab this data from the ContentChild,
337 // where it's been temporarily stashed, and initialize our new LookAndFeel
338 // object with it.
340 FullLookAndFeel* lnf = nullptr;
342 if (auto* cc = mozilla::dom::ContentChild::GetSingleton()) {
343 lnf = &cc->BorrowLookAndFeelData();
346 if (lnf) {
347 sInstance = new widget::RemoteLookAndFeel(std::move(*lnf));
348 } else if (gfxPlatform::IsHeadless()) {
349 sInstance = new widget::HeadlessLookAndFeel();
350 } else {
351 sInstance = new nsLookAndFeel();
354 // This is only ever used once during initialization, and can be cleared now.
355 if (lnf) {
356 *lnf = {};
359 widget::Theme::Init();
360 return sInstance;
363 // static
364 void nsXPLookAndFeel::Shutdown() {
365 if (sShutdown) {
366 return;
369 sShutdown = true;
370 delete sInstance;
371 sInstance = nullptr;
373 // This keeps strings alive, so need to clear to make leak checking happy.
374 sFontCache.Clear();
376 widget::Theme::Shutdown();
379 static void IntPrefChanged() {
380 // Int prefs can't change our system colors or fonts.
381 LookAndFeel::NotifyChangedAllWindows(
382 widget::ThemeChangeKind::MediaQueriesOnly);
385 static void FloatPrefChanged() {
386 // Float prefs can't change our system colors or fonts.
387 LookAndFeel::NotifyChangedAllWindows(
388 widget::ThemeChangeKind::MediaQueriesOnly);
391 static void ColorPrefChanged() {
392 // Color prefs affect style, because they by definition change system colors.
393 LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind::Style);
396 // static
397 void nsXPLookAndFeel::OnPrefChanged(const char* aPref, void* aClosure) {
398 nsDependentCString prefName(aPref);
399 for (const char* pref : sIntPrefs) {
400 if (prefName.Equals(pref)) {
401 IntPrefChanged();
402 return;
406 for (const char* pref : sFloatPrefs) {
407 if (prefName.Equals(pref)) {
408 FloatPrefChanged();
409 return;
413 for (const char* pref : sColorPrefs) {
414 // We use StringBeginsWith to handle .dark prefs too.
415 if (StringBeginsWith(prefName, nsDependentCString(pref))) {
416 ColorPrefChanged();
417 return;
422 static constexpr struct {
423 nsLiteralCString mName;
424 widget::ThemeChangeKind mChangeKind =
425 widget::ThemeChangeKind::MediaQueriesOnly;
426 } kMediaQueryPrefs[] = {
427 {"browser.display.windows.native_menus"_ns},
428 {"browser.proton.places-tooltip.enabled"_ns},
429 {"layout.css.prefers-color-scheme.content-override"_ns},
430 // This affects not only the media query, but also the native theme, so we
431 // need to re-layout.
432 {"browser.theme.toolbar-theme"_ns, widget::ThemeChangeKind::AllBits},
433 {"browser.theme.content-theme"_ns},
434 {"layout.css.color-scheme.content-override"_ns},
437 // Read values from the user's preferences.
438 // This is done once at startup, but since the user's preferences
439 // haven't actually been read yet at that time, we also have to
440 // set a callback to inform us of changes to each pref.
441 void nsXPLookAndFeel::Init() {
442 MOZ_RELEASE_ASSERT(NS_IsMainThread());
444 // Say we're already initialized, and take the chance that it might fail;
445 // protects against some other process writing to our static variables.
446 sInitialized = true;
448 RecomputeColorSchemes();
450 // XXX If we could reorganize the pref names, we should separate the branch
451 // for each types. Then, we could reduce the unnecessary loop from
452 // nsXPLookAndFeel::OnPrefChanged().
453 Preferences::RegisterPrefixCallback(OnPrefChanged, "ui.");
454 // We really do just want the accessibility.tabfocus pref, not other prefs
455 // that start with that string.
456 Preferences::RegisterCallback(OnPrefChanged, "accessibility.tabfocus");
458 for (auto& pref : kMediaQueryPrefs) {
459 Preferences::RegisterCallback(
460 [](const char*, void* aChangeKind) {
461 auto changeKind =
462 widget::ThemeChangeKind(reinterpret_cast<uintptr_t>(aChangeKind));
463 LookAndFeel::NotifyChangedAllWindows(changeKind);
465 pref.mName, reinterpret_cast<void*>(uintptr_t(pref.mChangeKind)));
469 nsXPLookAndFeel::~nsXPLookAndFeel() {
470 NS_ASSERTION(sInstance == this,
471 "This destroying instance isn't the singleton instance");
472 sInstance = nullptr;
475 static bool IsSpecialColor(LookAndFeel::ColorID aID, nscolor aColor) {
476 using ColorID = LookAndFeel::ColorID;
478 if (aColor == NS_SAME_AS_FOREGROUND_COLOR) {
479 return true;
482 switch (aID) {
483 case ColorID::IMESelectedRawTextBackground:
484 case ColorID::IMESelectedConvertedTextBackground:
485 case ColorID::IMERawInputBackground:
486 case ColorID::IMEConvertedTextBackground:
487 case ColorID::IMESelectedRawTextForeground:
488 case ColorID::IMESelectedConvertedTextForeground:
489 case ColorID::IMERawInputForeground:
490 case ColorID::IMEConvertedTextForeground:
491 case ColorID::IMERawInputUnderline:
492 case ColorID::IMEConvertedTextUnderline:
493 case ColorID::IMESelectedRawTextUnderline:
494 case ColorID::IMESelectedConvertedTextUnderline:
495 case ColorID::SpellCheckerUnderline:
496 return NS_IS_SELECTION_SPECIAL_COLOR(aColor);
497 default:
498 break;
501 * In GetColor(), every color that is not a special color is color
502 * corrected. Use false to make other colors color corrected.
504 return false;
507 nscolor nsXPLookAndFeel::GetStandinForNativeColor(ColorID aID,
508 ColorScheme aScheme) {
509 if (aScheme == ColorScheme::Dark) {
510 if (auto color = GenericDarkColor(aID)) {
511 return *color;
515 // The stand-in colors are taken from what the non-native theme needs (for
516 // field/button colors), the Windows 7 Aero theme except Mac-specific colors
517 // which are taken from Mac OS 10.7.
519 #define COLOR(name_, r, g, b) \
520 case ColorID::name_: \
521 return NS_RGB(r, g, b);
523 #define COLORA(name_, r, g, b, a) \
524 case ColorID::name_: \
525 return NS_RGBA(r, g, b, a);
527 switch (aID) {
528 // These are here for the purposes of headless mode.
529 case ColorID::IMESelectedRawTextBackground:
530 case ColorID::IMESelectedConvertedTextBackground:
531 case ColorID::IMERawInputBackground:
532 case ColorID::IMEConvertedTextBackground:
533 return NS_TRANSPARENT;
534 case ColorID::IMESelectedRawTextForeground:
535 case ColorID::IMESelectedConvertedTextForeground:
536 case ColorID::IMERawInputForeground:
537 case ColorID::IMEConvertedTextForeground:
538 return NS_SAME_AS_FOREGROUND_COLOR;
539 case ColorID::IMERawInputUnderline:
540 case ColorID::IMEConvertedTextUnderline:
541 return NS_40PERCENT_FOREGROUND_COLOR;
542 COLOR(MozAccentColor, 53, 132, 228)
543 COLOR(MozAccentColorForeground, 0xff, 0xff, 0xff)
544 COLOR(SpellCheckerUnderline, 0xff, 0x00, 0x00)
545 COLOR(TextSelectDisabledBackground, 0xaa, 0xaa, 0xaa)
547 // CSS 2 colors:
548 COLOR(Activeborder, 0xB4, 0xB4, 0xB4)
549 COLOR(Activecaption, 0x99, 0xB4, 0xD1)
550 COLOR(Appworkspace, 0xAB, 0xAB, 0xAB)
551 COLOR(Background, 0x00, 0x00, 0x00)
552 COLOR(Buttonhighlight, 0xFF, 0xFF, 0xFF)
553 COLOR(Buttonshadow, 0xA0, 0xA0, 0xA0)
555 // Buttons and comboboxes should be kept in sync since they are drawn with
556 // the same colors by the non-native theme.
557 COLOR(Buttonface, 0xe9, 0xe9, 0xed)
558 COLORA(MozButtondisabledface, 0xe9, 0xe9, 0xed, 128)
560 COLOR(MozCombobox, 0xe9, 0xe9, 0xed)
562 COLOR(Buttontext, 0x00, 0x00, 0x00)
563 COLOR(MozComboboxtext, 0x00, 0x00, 0x00)
565 COLOR(Captiontext, 0x00, 0x00, 0x00)
566 COLOR(Graytext, 0x6D, 0x6D, 0x6D)
567 COLOR(Highlight, 0x33, 0x99, 0xFF)
568 COLOR(Highlighttext, 0xFF, 0xFF, 0xFF)
569 COLOR(Inactiveborder, 0xF4, 0xF7, 0xFC)
570 COLOR(Inactivecaption, 0xBF, 0xCD, 0xDB)
571 COLOR(Inactivecaptiontext, 0x43, 0x4E, 0x54)
572 COLOR(Infobackground, 0xFF, 0xFF, 0xE1)
573 COLOR(Infotext, 0x00, 0x00, 0x00)
574 COLOR(Menu, 0xF0, 0xF0, 0xF0)
575 COLOR(Menutext, 0x00, 0x00, 0x00)
576 COLOR(Scrollbar, 0xC8, 0xC8, 0xC8)
577 COLOR(Threeddarkshadow, 0x69, 0x69, 0x69)
578 COLOR(Threedface, 0xF0, 0xF0, 0xF0)
579 COLOR(Threedhighlight, 0xFF, 0xFF, 0xFF)
580 COLOR(Threedlightshadow, 0xE3, 0xE3, 0xE3)
581 COLOR(Threedshadow, 0xA0, 0xA0, 0xA0)
582 COLOR(Window, 0xFF, 0xFF, 0xFF)
583 COLOR(Windowframe, 0x64, 0x64, 0x64)
584 COLOR(Windowtext, 0x00, 0x00, 0x00)
585 COLOR(MozButtondefault, 0x69, 0x69, 0x69)
586 COLOR(Field, 0xFF, 0xFF, 0xFF)
587 COLORA(MozDisabledfield, 0xFF, 0xFF, 0xFF, 128)
588 COLOR(Fieldtext, 0x00, 0x00, 0x00)
589 COLOR(MozDialog, 0xF0, 0xF0, 0xF0)
590 COLOR(MozDialogtext, 0x00, 0x00, 0x00)
591 COLOR(MozColheadertext, 0x00, 0x00, 0x00)
592 COLOR(MozColheaderhovertext, 0x00, 0x00, 0x00)
593 COLOR(MozDragtargetzone, 0xFF, 0xFF, 0xFF)
594 COLOR(MozCellhighlight, 0xF0, 0xF0, 0xF0)
595 COLOR(MozCellhighlighttext, 0x00, 0x00, 0x00)
596 COLOR(Selecteditem, 0x33, 0x99, 0xFF)
597 COLOR(Selecteditemtext, 0xFF, 0xFF, 0xFF)
598 COLOR(MozButtonhoverface, 0xd0, 0xd0, 0xd7)
599 COLOR(MozButtonhovertext, 0x00, 0x00, 0x00)
600 COLOR(MozButtonactiveface, 0xb1, 0xb1, 0xb9)
601 COLOR(MozButtonactivetext, 0x00, 0x00, 0x00)
602 COLOR(MozMenuhover, 0x33, 0x99, 0xFF)
603 COLOR(MozMenuhovertext, 0x00, 0x00, 0x00)
604 COLOR(MozMenubartext, 0x00, 0x00, 0x00)
605 COLOR(MozMenubarhovertext, 0x00, 0x00, 0x00)
606 COLOR(MozEventreerow, 0xFF, 0xFF, 0xFF)
607 COLOR(MozOddtreerow, 0xFF, 0xFF, 0xFF)
608 COLOR(MozMacChromeActive, 0xB2, 0xB2, 0xB2)
609 COLOR(MozMacChromeInactive, 0xE1, 0xE1, 0xE1)
610 COLOR(MozMacFocusring, 0x60, 0x9D, 0xD7)
611 COLOR(MozMacMenuselect, 0x38, 0x75, 0xD7)
612 COLOR(MozMacMenushadow, 0xA3, 0xA3, 0xA3)
613 COLOR(MozMacMenutextdisable, 0x88, 0x88, 0x88)
614 COLOR(MozMacMenutextselect, 0xFF, 0xFF, 0xFF)
615 COLOR(MozMacDisabledtoolbartext, 0x3F, 0x3F, 0x3F)
616 COLOR(MozMacSecondaryhighlight, 0xD4, 0xD4, 0xD4)
617 COLOR(MozMacVibrantTitlebarLight, 0xf7, 0xf7, 0xf7)
618 COLOR(MozMacVibrantTitlebarDark, 0x28, 0x28, 0x28)
619 COLOR(MozMacMenupopup, 0xe6, 0xe6, 0xe6)
620 COLOR(MozMacMenuitem, 0xe6, 0xe6, 0xe6)
621 COLOR(MozMacActiveMenuitem, 0x0a, 0x64, 0xdc)
622 COLOR(MozMacSourceList, 0xf7, 0xf7, 0xf7)
623 COLOR(MozMacSourceListSelection, 0xc8, 0xc8, 0xc8)
624 COLOR(MozMacActiveSourceListSelection, 0x0a, 0x64, 0xdc)
625 COLOR(MozMacTooltip, 0xf7, 0xf7, 0xf7)
626 // Seems to be the default color (hardcoded because of bug 1065998)
627 COLOR(MozWinMediatext, 0xFF, 0xFF, 0xFF)
628 COLOR(MozWinCommunicationstext, 0xFF, 0xFF, 0xFF)
629 COLOR(MozNativehyperlinktext, 0x00, 0x66, 0xCC)
630 COLOR(MozNativevisitedhyperlinktext, 0x55, 0x1A, 0x8B)
631 default:
632 break;
634 return NS_RGB(0xFF, 0xFF, 0xFF);
637 #undef COLOR
638 #undef COLORA
640 // Taken from in-content/common.inc.css's dark theme.
641 Maybe<nscolor> nsXPLookAndFeel::GenericDarkColor(ColorID aID) {
642 nscolor color = NS_RGB(0, 0, 0);
643 static constexpr nscolor kWindowBackground = NS_RGB(28, 27, 34);
644 static constexpr nscolor kWindowText = NS_RGB(251, 251, 254);
645 switch (aID) {
646 case ColorID::Window: // --in-content-page-background
647 case ColorID::Background:
648 case ColorID::Menu:
649 color = kWindowBackground;
650 break;
651 case ColorID::MozOddtreerow:
652 case ColorID::MozDialog: // --in-content-box-background
653 color = NS_RGB(35, 34, 43);
654 break;
655 case ColorID::Windowtext: // --in-content-page-color
656 case ColorID::Menutext:
657 case ColorID::MozDialogtext:
658 case ColorID::Fieldtext:
659 case ColorID::Buttontext: // --in-content-button-text-color (via
660 // --in-content-page-color)
661 case ColorID::MozComboboxtext:
662 case ColorID::MozButtonhovertext:
663 case ColorID::MozButtonactivetext:
664 color = kWindowText;
665 break;
666 case ColorID::Threedlightshadow: // --in-content-box-border-color computed
667 // with kWindowText above
668 // kWindowBackground.
669 case ColorID::Graytext: // opacity: 0.4 of kWindowText blended over the
670 // "Window" background color, which happens to be
671 // the same :-)
672 color = NS_ComposeColors(kWindowBackground, NS_RGBA(251, 251, 254, 102));
673 break;
674 case ColorID::MozCellhighlight:
675 case ColorID::Selecteditem: // --in-content-primary-button-background /
676 // --in-content-item-selected
677 color = NS_RGB(0, 221, 255);
678 break;
679 case ColorID::Field:
680 case ColorID::Buttonface: // --in-content-button-background
681 case ColorID::Threedface:
682 case ColorID::MozCombobox:
683 case ColorID::MozCellhighlighttext:
684 case ColorID::Selecteditemtext: // --in-content-primary-button-text-color /
685 // --in-content-item-selected-text
686 color = NS_RGB(43, 42, 51);
687 break;
688 case ColorID::Threeddarkshadow: // Same as Threedlightshadow but with the
689 // background.
690 case ColorID::MozDisabledfield: // opacity: 0.4 of the face above blended
691 // over the "Window" background color.
692 case ColorID::MozButtondisabledface:
693 color = NS_ComposeColors(kWindowBackground, NS_RGBA(43, 42, 51, 102));
694 break;
695 case ColorID::MozButtonhoverface: // --in-content-button-background-hover
696 color = NS_RGB(82, 82, 94);
697 break;
698 case ColorID::MozButtonactiveface: // --in-content-button-background-active
699 color = NS_RGB(91, 91, 102);
700 break;
701 case ColorID::Highlight:
702 color = NS_RGBA(0, 221, 255, 78);
703 break;
704 case ColorID::Highlighttext:
705 color = NS_SAME_AS_FOREGROUND_COLOR;
706 break;
707 case ColorID::MozNativehyperlinktext:
708 // If you change this color, you probably also want to change the default
709 // value of browser.anchor_color.dark.
710 color = NS_RGB(0x8c, 0x8c, 0xff);
711 break;
712 case ColorID::MozNativevisitedhyperlinktext:
713 // If you change this color, you probably also want to change the default
714 // value of browser.visited_color.dark.
715 color = NS_RGB(0xff, 0xad, 0xff);
716 break;
718 default:
719 return Nothing();
721 return Some(color);
724 // Uncomment the #define below if you want to debug system color use in a skin
725 // that uses them. When set, it will make all system color pairs that are
726 // appropriate for foreground/background pairing the same. This means if the
727 // skin is using system colors correctly you will not be able to see *any* text.
729 // #define DEBUG_SYSTEM_COLOR_USE
731 #ifdef DEBUG_SYSTEM_COLOR_USE
732 static nsresult SystemColorUseDebuggingColor(LookAndFeel::ColorID aID,
733 nscolor& aResult) {
734 using ColorID = LookAndFeel::ColorID;
736 switch (aID) {
737 // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
738 case ColorID::Activecaption:
739 // active window caption background
740 case ColorID::Captiontext:
741 // text in active window caption
742 aResult = NS_RGB(0xff, 0x00, 0x00);
743 break;
745 case ColorID::Highlight:
746 // background of selected item
747 case ColorID::Highlighttext:
748 // text of selected item
749 aResult = NS_RGB(0xff, 0xff, 0x00);
750 break;
752 case ColorID::Inactivecaption:
753 // inactive window caption
754 case ColorID::Inactivecaptiontext:
755 // text in inactive window caption
756 aResult = NS_RGB(0x66, 0x66, 0x00);
757 break;
759 case ColorID::Infobackground:
760 // tooltip background color
761 case ColorID::Infotext:
762 // tooltip text color
763 aResult = NS_RGB(0x00, 0xff, 0x00);
764 break;
766 case ColorID::Menu:
767 // menu background
768 case ColorID::Menutext:
769 // menu text
770 aResult = NS_RGB(0x00, 0xff, 0xff);
771 break;
773 case ColorID::Threedface:
774 case ColorID::Buttonface:
775 // 3-D face color
776 case ColorID::Buttontext:
777 // text on push buttons
778 aResult = NS_RGB(0x00, 0x66, 0x66);
779 break;
781 case ColorID::Window:
782 case ColorID::Windowtext:
783 aResult = NS_RGB(0x00, 0x00, 0xff);
784 break;
786 // from the CSS3 working draft (not yet finalized)
787 // http://www.w3.org/tr/2000/wd-css3-userint-20000216.html#color
789 case ColorID::Field:
790 case ColorID::Fieldtext:
791 aResult = NS_RGB(0xff, 0x00, 0xff);
792 break;
794 case ColorID::MozDialog:
795 case ColorID::MozDialogtext:
796 aResult = NS_RGB(0x66, 0x00, 0x66);
797 break;
799 default:
800 return NS_ERROR_NOT_AVAILABLE;
803 return NS_OK;
805 #endif
807 static nsresult GetPrefColor(const char* aPref, nscolor& aResult) {
808 nsAutoCString colorStr;
809 MOZ_TRY(Preferences::GetCString(aPref, colorStr));
810 if (!ServoCSSParser::ComputeColor(nullptr, NS_RGB(0, 0, 0), colorStr,
811 &aResult)) {
812 return NS_ERROR_FAILURE;
814 return NS_OK;
817 static nsresult GetColorFromPref(LookAndFeel::ColorID aID, ColorScheme aScheme,
818 nscolor& aResult) {
819 const char* prefName = sColorPrefs[size_t(aID)];
820 if (aScheme == ColorScheme::Dark) {
821 nsAutoCString darkPrefName(prefName);
822 darkPrefName.Append(".dark");
823 if (NS_SUCCEEDED(GetPrefColor(darkPrefName.get(), aResult))) {
824 return NS_OK;
827 return GetPrefColor(prefName, aResult);
830 // All these routines will return NS_OK if they have a value,
831 // in which case the nsLookAndFeel should use that value;
832 // otherwise we'll return NS_ERROR_NOT_AVAILABLE, in which case, the
833 // platform-specific nsLookAndFeel should use its own values instead.
834 nsresult nsXPLookAndFeel::GetColorValue(ColorID aID, ColorScheme aScheme,
835 UseStandins aUseStandins,
836 nscolor& aResult) {
837 if (!sInitialized) {
838 Init();
841 #ifdef DEBUG_SYSTEM_COLOR_USE
842 if (NS_SUCCEEDED(SystemColorUseDebuggingColor(aID, aResult))) {
843 return NS_OK;
845 #endif
847 if (aUseStandins == UseStandins::Yes) {
848 aResult = GetStandinForNativeColor(aID, aScheme);
849 return NS_OK;
852 auto& cache =
853 aScheme == ColorScheme::Light ? sLightColorCache : sDarkColorCache;
854 if (const auto* cached = cache.Get(aID)) {
855 if (cached->isNothing()) {
856 return NS_ERROR_FAILURE;
858 aResult = cached->value();
859 return NS_OK;
862 if (NS_SUCCEEDED(GetColorFromPref(aID, aScheme, aResult))) {
863 cache.Insert(aID, Some(aResult));
864 return NS_OK;
867 if (NS_SUCCEEDED(NativeGetColor(aID, aScheme, aResult))) {
868 if (gfxPlatform::GetCMSMode() == CMSMode::All &&
869 !IsSpecialColor(aID, aResult)) {
870 qcms_transform* transform = gfxPlatform::GetCMSInverseRGBTransform();
871 if (transform) {
872 uint8_t color[4];
873 color[0] = NS_GET_R(aResult);
874 color[1] = NS_GET_G(aResult);
875 color[2] = NS_GET_B(aResult);
876 color[3] = NS_GET_A(aResult);
877 qcms_transform_data(transform, color, color, 1);
878 aResult = NS_RGBA(color[0], color[1], color[2], color[3]);
882 // NOTE: Servo holds a lock and the main thread is paused, so writing to the
883 // global cache here is fine.
884 cache.Insert(aID, Some(aResult));
885 return NS_OK;
888 cache.Insert(aID, Nothing());
889 return NS_ERROR_FAILURE;
892 nsresult nsXPLookAndFeel::GetIntValue(IntID aID, int32_t& aResult) {
893 if (!sInitialized) {
894 Init();
897 if (const auto* cached = sIntCache.Get(aID)) {
898 if (cached->isNothing()) {
899 return NS_ERROR_FAILURE;
901 aResult = cached->value();
902 return NS_OK;
905 if (NS_SUCCEEDED(Preferences::GetInt(sIntPrefs[size_t(aID)], &aResult))) {
906 sIntCache.Insert(aID, Some(aResult));
907 return NS_OK;
910 if (NS_FAILED(NativeGetInt(aID, aResult))) {
911 sIntCache.Insert(aID, Nothing());
912 return NS_ERROR_FAILURE;
915 sIntCache.Insert(aID, Some(aResult));
916 return NS_OK;
919 nsresult nsXPLookAndFeel::GetFloatValue(FloatID aID, float& aResult) {
920 if (!sInitialized) {
921 Init();
924 if (const auto* cached = sFloatCache.Get(aID)) {
925 if (cached->isNothing()) {
926 return NS_ERROR_FAILURE;
928 aResult = cached->value();
929 return NS_OK;
932 int32_t pref = 0;
933 if (NS_SUCCEEDED(Preferences::GetInt(sFloatPrefs[size_t(aID)], &pref))) {
934 aResult = float(pref) / 100.0f;
935 sFloatCache.Insert(aID, Some(aResult));
936 return NS_OK;
939 if (NS_FAILED(NativeGetFloat(aID, aResult))) {
940 sFloatCache.Insert(aID, Nothing());
941 return NS_ERROR_FAILURE;
944 sFloatCache.Insert(aID, Some(aResult));
945 return NS_OK;
948 bool nsXPLookAndFeel::LookAndFeelFontToStyle(const LookAndFeelFont& aFont,
949 nsString& aName,
950 gfxFontStyle& aStyle) {
951 if (!aFont.haveFont()) {
952 return false;
954 aName = aFont.name();
955 aStyle = gfxFontStyle();
956 aStyle.size = aFont.size();
957 aStyle.weight = FontWeight(aFont.weight());
958 aStyle.style =
959 aFont.italic() ? FontSlantStyle::Italic() : FontSlantStyle::Normal();
960 aStyle.systemFont = true;
961 return true;
964 widget::LookAndFeelFont nsXPLookAndFeel::StyleToLookAndFeelFont(
965 const nsAString& aName, const gfxFontStyle& aStyle) {
966 LookAndFeelFont font;
967 font.haveFont() = true;
968 font.name() = aName;
969 font.size() = aStyle.size;
970 font.weight() = aStyle.weight.ToFloat();
971 font.italic() = aStyle.style.IsItalic();
972 MOZ_ASSERT(aStyle.style.IsNormal() || aStyle.style.IsItalic(),
973 "Cannot handle oblique font style");
974 #ifdef DEBUG
976 // Assert that all the remaining font style properties have their
977 // default values.
978 gfxFontStyle candidate = aStyle;
979 gfxFontStyle defaults{};
980 candidate.size = defaults.size;
981 candidate.weight = defaults.weight;
982 candidate.style = defaults.style;
983 MOZ_ASSERT(candidate.Equals(defaults),
984 "Some font style properties not supported");
986 #endif
987 return font;
990 bool nsXPLookAndFeel::GetFontValue(FontID aID, nsString& aName,
991 gfxFontStyle& aStyle) {
992 if (const LookAndFeelFont* cached = sFontCache.Get(aID)) {
993 return LookAndFeelFontToStyle(*cached, aName, aStyle);
995 LookAndFeelFont font;
996 const bool haveFont = NativeGetFont(aID, aName, aStyle);
997 font.haveFont() = haveFont;
998 if (haveFont) {
999 font = StyleToLookAndFeelFont(aName, aStyle);
1001 sFontCache.Insert(aID, std::move(font));
1002 return haveFont;
1005 void nsXPLookAndFeel::RefreshImpl() {
1006 // Wipe out our caches.
1007 sLightColorCache.Clear();
1008 sDarkColorCache.Clear();
1009 sFontCache.Clear();
1010 sFloatCache.Clear();
1011 sIntCache.Clear();
1012 RecomputeColorSchemes();
1014 // Clear any cached FullLookAndFeel data, which is now invalid.
1015 if (XRE_IsParentProcess()) {
1016 widget::RemoteLookAndFeel::ClearCachedData();
1020 static bool sRecordedLookAndFeelTelemetry = false;
1022 void nsXPLookAndFeel::RecordTelemetry() {
1023 if (!XRE_IsParentProcess()) {
1024 return;
1027 if (sRecordedLookAndFeelTelemetry) {
1028 return;
1031 sRecordedLookAndFeelTelemetry = true;
1033 int32_t i;
1034 Telemetry::ScalarSet(
1035 Telemetry::ScalarID::WIDGET_DARK_MODE,
1036 NS_SUCCEEDED(GetIntValue(IntID::SystemUsesDarkTheme, i)) && i != 0);
1038 RecordLookAndFeelSpecificTelemetry();
1041 namespace mozilla {
1043 static widget::ThemeChangeKind sGlobalThemeChangeKind{0};
1045 void LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind aKind) {
1046 sGlobalThemeChanged = true;
1047 sGlobalThemeChangeKind |= aKind;
1049 if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
1050 const char16_t kind[] = {char16_t(aKind), 0};
1051 obs->NotifyObservers(nullptr, "internal-look-and-feel-changed", kind);
1055 void LookAndFeel::DoHandleGlobalThemeChange() {
1056 MOZ_ASSERT(sGlobalThemeChanged);
1057 sGlobalThemeChanged = false;
1058 auto kind = std::exchange(sGlobalThemeChangeKind, widget::ThemeChangeKind(0));
1060 // Tell the theme that it changed, so it can flush any handles to stale theme
1061 // data.
1063 // We can use the *DoNotUseDirectly functions directly here, because we want
1064 // to notify all possible themes in a given process (but just once).
1065 if (XRE_IsParentProcess() ||
1066 !StaticPrefs::widget_non_native_theme_enabled()) {
1067 if (nsCOMPtr<nsITheme> theme = do_GetNativeThemeDoNotUseDirectly()) {
1068 theme->ThemeChanged();
1071 if (nsCOMPtr<nsITheme> theme = do_GetBasicNativeThemeDoNotUseDirectly()) {
1072 theme->ThemeChanged();
1075 // Clear all cached LookAndFeel colors.
1076 LookAndFeel::Refresh();
1078 // Reset default background and foreground colors for the document since they
1079 // may be using system colors.
1080 PreferenceSheet::Refresh();
1082 // Vector images (SVG) may be using theme colors so we discard all cached
1083 // surfaces. (We could add a vector image only version of DiscardAll, but
1084 // in bug 940625 we decided theme changes are rare enough not to bother.)
1085 image::SurfaceCacheUtils::DiscardAll();
1087 if (XRE_IsParentProcess()) {
1088 dom::ContentParent::BroadcastThemeUpdate(kind);
1091 nsContentUtils::AddScriptRunner(
1092 NS_NewRunnableFunction("HandleGlobalThemeChange", [] {
1093 if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
1094 obs->NotifyObservers(nullptr, "look-and-feel-changed", nullptr);
1096 }));
1099 static bool ShouldUseStandinsForNativeColorForNonNativeTheme(
1100 const dom::Document& aDoc, LookAndFeel::ColorID aColor) {
1101 using ColorID = LookAndFeel::ColorID;
1102 if (!aDoc.ShouldAvoidNativeTheme()) {
1103 return false;
1106 // The native theme doesn't use native system colors backgrounds etc, except
1107 // when in high-contrast mode, so spoof some of the colors with stand-ins to
1108 // prevent lack of contrast.
1109 switch (aColor) {
1110 case ColorID::Buttonface:
1111 case ColorID::Buttontext:
1112 case ColorID::MozButtonhoverface:
1113 case ColorID::MozButtonhovertext:
1114 case ColorID::MozButtonactiveface:
1115 case ColorID::MozButtonactivetext:
1116 case ColorID::MozButtondisabledface:
1118 case ColorID::Threedlightshadow:
1119 case ColorID::Threeddarkshadow:
1120 case ColorID::Threedface:
1122 case ColorID::MozCombobox:
1123 case ColorID::MozComboboxtext:
1125 case ColorID::Field:
1126 case ColorID::MozDisabledfield:
1127 case ColorID::Fieldtext:
1129 case ColorID::Graytext:
1131 return !PreferenceSheet::PrefsFor(aDoc)
1132 .NonNativeThemeShouldBeHighContrast();
1134 default:
1135 break;
1138 return false;
1141 ColorScheme LookAndFeel::sChromeColorScheme;
1142 ColorScheme LookAndFeel::sContentColorScheme;
1143 bool LookAndFeel::sColorSchemeInitialized;
1144 bool LookAndFeel::sGlobalThemeChanged;
1146 auto LookAndFeel::ColorSchemeSettingForChrome() -> ChromeColorSchemeSetting {
1147 switch (StaticPrefs::browser_theme_toolbar_theme()) {
1148 case 0: // Dark
1149 return ChromeColorSchemeSetting::Dark;
1150 case 1: // Light
1151 return ChromeColorSchemeSetting::Light;
1152 default:
1153 return ChromeColorSchemeSetting::System;
1157 void LookAndFeel::RecomputeColorSchemes() {
1158 sColorSchemeInitialized = true;
1160 sChromeColorScheme = [] {
1161 switch (ColorSchemeSettingForChrome()) {
1162 case ChromeColorSchemeSetting::Light:
1163 return ColorScheme::Light;
1164 case ChromeColorSchemeSetting::Dark:
1165 return ColorScheme::Dark;
1166 case ChromeColorSchemeSetting::System:
1167 break;
1169 return SystemColorScheme();
1170 }();
1172 sContentColorScheme = [] {
1173 switch (StaticPrefs::layout_css_prefers_color_scheme_content_override()) {
1174 case 0:
1175 return ColorScheme::Dark;
1176 case 1:
1177 return ColorScheme::Light;
1178 case 2:
1179 return SystemColorScheme();
1180 default:
1181 break; // Use the browser theme.
1184 switch (StaticPrefs::browser_theme_content_theme()) {
1185 case 0: // Dark
1186 return ColorScheme::Dark;
1187 case 1: // Light
1188 return ColorScheme::Light;
1189 default:
1190 return ColorSchemeForChrome();
1192 }();
1195 ColorScheme LookAndFeel::ColorSchemeForStyle(
1196 const dom::Document& aDoc, const StyleColorSchemeFlags& aFlags) {
1197 if (PreferenceSheet::MayForceColors()) {
1198 auto& prefs = PreferenceSheet::PrefsFor(aDoc);
1199 if (!prefs.mUseDocumentColors) {
1200 // When forcing colors, we can use our preferred color-scheme. Do this
1201 // only if we're using system colors, as dark preference colors are not
1202 // exposed on the UI.
1204 // Also, use light if we're using a high-contrast-theme on Windows, since
1205 // Windows overrides the light colors with HCM colors when HCM is active.
1206 #ifdef XP_WIN
1207 if (prefs.mUseAccessibilityTheme) {
1208 return ColorScheme::Light;
1210 #endif
1211 if (StaticPrefs::browser_display_use_system_colors()) {
1212 return aDoc.PreferredColorScheme();
1214 return ColorScheme::Light;
1218 StyleColorSchemeFlags style(aFlags);
1219 if (!style) {
1220 style.bits = aDoc.GetColorSchemeBits();
1222 const bool supportsDark = bool(style & StyleColorSchemeFlags::DARK);
1223 const bool supportsLight = bool(style & StyleColorSchemeFlags::LIGHT);
1224 if (supportsLight && supportsDark) {
1225 // Both color-schemes are explicitly supported, use the preferred one.
1226 return aDoc.PreferredColorScheme();
1228 if (supportsDark || supportsLight) {
1229 // One color-scheme is explicitly supported and one isn't, so use the one
1230 // the content supports.
1231 return supportsDark ? ColorScheme::Dark : ColorScheme::Light;
1233 // No value specified. Chrome docs always supports both, so use the preferred
1234 // color-scheme.
1235 if (nsContentUtils::IsChromeDoc(&aDoc)) {
1236 return aDoc.PreferredColorScheme();
1238 // Default content to light.
1239 return ColorScheme::Light;
1242 LookAndFeel::ColorScheme LookAndFeel::ColorSchemeForFrame(
1243 const nsIFrame* aFrame) {
1244 return ColorSchemeForStyle(*aFrame->PresContext()->Document(),
1245 aFrame->StyleUI()->mColorScheme.bits);
1248 // static
1249 Maybe<nscolor> LookAndFeel::GetColor(ColorID aId, ColorScheme aScheme,
1250 UseStandins aUseStandins) {
1251 nscolor result;
1252 nsresult rv = nsLookAndFeel::GetInstance()->GetColorValue(
1253 aId, aScheme, aUseStandins, result);
1254 if (NS_FAILED(rv)) {
1255 return Nothing();
1257 return Some(result);
1260 // Returns whether there is a CSS color name for this color.
1261 static bool ColorIsCSSAccessible(LookAndFeel::ColorID aId) {
1262 using ColorID = LookAndFeel::ColorID;
1264 switch (aId) {
1265 case ColorID::TextSelectDisabledBackground:
1266 case ColorID::TextSelectAttentionBackground:
1267 case ColorID::TextSelectAttentionForeground:
1268 case ColorID::TextHighlightBackground:
1269 case ColorID::TextHighlightForeground:
1270 case ColorID::ThemedScrollbar:
1271 case ColorID::ThemedScrollbarInactive:
1272 case ColorID::ThemedScrollbarThumb:
1273 case ColorID::ThemedScrollbarThumbActive:
1274 case ColorID::ThemedScrollbarThumbInactive:
1275 case ColorID::ThemedScrollbarThumbHover:
1276 case ColorID::IMERawInputBackground:
1277 case ColorID::IMERawInputForeground:
1278 case ColorID::IMERawInputUnderline:
1279 case ColorID::IMESelectedRawTextBackground:
1280 case ColorID::IMESelectedRawTextForeground:
1281 case ColorID::IMESelectedRawTextUnderline:
1282 case ColorID::IMEConvertedTextBackground:
1283 case ColorID::IMEConvertedTextForeground:
1284 case ColorID::IMEConvertedTextUnderline:
1285 case ColorID::IMESelectedConvertedTextBackground:
1286 case ColorID::IMESelectedConvertedTextForeground:
1287 case ColorID::IMESelectedConvertedTextUnderline:
1288 case ColorID::SpellCheckerUnderline:
1289 return false;
1290 default:
1291 break;
1294 return true;
1297 LookAndFeel::UseStandins LookAndFeel::ShouldUseStandins(
1298 const dom::Document& aDoc, ColorID aId) {
1299 if (ShouldUseStandinsForNativeColorForNonNativeTheme(aDoc, aId)) {
1300 return UseStandins::Yes;
1302 if (nsContentUtils::UseStandinsForNativeColors() &&
1303 ColorIsCSSAccessible(aId) && !nsContentUtils::IsChromeDoc(&aDoc)) {
1304 return UseStandins::Yes;
1306 if (aDoc.IsStaticDocument() &&
1307 !PreferenceSheet::ContentPrefs().mUseDocumentColors) {
1308 return UseStandins::Yes;
1310 return UseStandins::No;
1313 Maybe<nscolor> LookAndFeel::GetColor(ColorID aId, const nsIFrame* aFrame) {
1314 const auto* doc = aFrame->PresContext()->Document();
1315 return GetColor(aId, ColorSchemeForFrame(aFrame),
1316 ShouldUseStandins(*doc, aId));
1319 // static
1320 nsresult LookAndFeel::GetInt(IntID aID, int32_t* aResult) {
1321 return nsLookAndFeel::GetInstance()->GetIntValue(aID, *aResult);
1324 // static
1325 nsresult LookAndFeel::GetFloat(FloatID aID, float* aResult) {
1326 return nsLookAndFeel::GetInstance()->GetFloatValue(aID, *aResult);
1329 // static
1330 bool LookAndFeel::GetFont(FontID aID, nsString& aName, gfxFontStyle& aStyle) {
1331 return nsLookAndFeel::GetInstance()->GetFontValue(aID, aName, aStyle);
1334 // static
1335 char16_t LookAndFeel::GetPasswordCharacter() {
1336 return nsLookAndFeel::GetInstance()->GetPasswordCharacterImpl();
1339 // static
1340 bool LookAndFeel::GetEchoPassword() {
1341 if (StaticPrefs::editor_password_mask_delay() >= 0) {
1342 return StaticPrefs::editor_password_mask_delay() > 0;
1344 return nsLookAndFeel::GetInstance()->GetEchoPasswordImpl();
1347 // static
1348 uint32_t LookAndFeel::GetPasswordMaskDelay() {
1349 int32_t delay = StaticPrefs::editor_password_mask_delay();
1350 if (delay < 0) {
1351 return nsLookAndFeel::GetInstance()->GetPasswordMaskDelayImpl();
1353 return delay;
1356 bool LookAndFeel::DrawInTitlebar() {
1357 switch (StaticPrefs::browser_tabs_inTitlebar()) {
1358 case 0:
1359 return false;
1360 case 1:
1361 return true;
1362 default:
1363 break;
1365 return nsLookAndFeel::GetInstance()->GetDefaultDrawInTitlebar();
1368 void LookAndFeel::GetThemeInfo(nsACString& aOut) {
1369 nsLookAndFeel::GetInstance()->GetThemeInfo(aOut);
1372 // static
1373 void LookAndFeel::Refresh() {
1374 nsLookAndFeel::GetInstance()->RefreshImpl();
1375 widget::Theme::LookAndFeelChanged();
1378 // static
1379 void LookAndFeel::NativeInit() { nsLookAndFeel::GetInstance()->NativeInit(); }
1381 // static
1382 void LookAndFeel::SetData(widget::FullLookAndFeel&& aTables) {
1383 nsLookAndFeel::GetInstance()->SetDataImpl(std::move(aTables));
1386 } // namespace mozilla