Bug 1756130 [wpt PR 32898] - [CSP] Enhance unsafe-eval test to check both realms...
[gecko.git] / widget / nsXPLookAndFeel.cpp
blob2c70c51e7a13392cb0f3394bf55a2b64d6c1343a
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.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",
181 static_assert(ArrayLength(sIntPrefs) == size_t(LookAndFeel::IntID::End),
182 "Should have a pref for each int value");
184 // This array MUST be kept in the same order as the float id list in
185 // LookAndFeel.h
186 // clang-format off
187 static const char sFloatPrefs[][37] = {
188 "ui.IMEUnderlineRelativeSize",
189 "ui.SpellCheckerUnderlineRelativeSize",
190 "ui.caretAspectRatio",
191 "ui.textScaleFactor",
192 "ui.cursorScale",
194 // clang-format on
196 static_assert(ArrayLength(sFloatPrefs) == size_t(LookAndFeel::FloatID::End),
197 "Should have a pref for each float value");
199 // This array MUST be kept in the same order as the color list in
200 // specified/color.rs
201 static const char sColorPrefs[][41] = {
202 "ui.textSelectDisabledBackground",
203 "ui.textSelectAttentionBackground",
204 "ui.textSelectAttentionForeground",
205 "ui.textHighlightBackground",
206 "ui.textHighlightForeground",
207 "ui.IMERawInputBackground",
208 "ui.IMERawInputForeground",
209 "ui.IMERawInputUnderline",
210 "ui.IMESelectedRawTextBackground",
211 "ui.IMESelectedRawTextForeground",
212 "ui.IMESelectedRawTextUnderline",
213 "ui.IMEConvertedTextBackground",
214 "ui.IMEConvertedTextForeground",
215 "ui.IMEConvertedTextUnderline",
216 "ui.IMESelectedConvertedTextBackground",
217 "ui.IMESelectedConvertedTextForeground",
218 "ui.IMESelectedConvertedTextUnderline",
219 "ui.SpellCheckerUnderline",
220 "ui.themedScrollbar",
221 "ui.themedScrollbarInactive",
222 "ui.themedScrollbarThumb",
223 "ui.themedScrollbarThumbHover",
224 "ui.themedScrollbarThumbActive",
225 "ui.themedScrollbarThumbInactive",
226 "ui.activeborder",
227 "ui.activecaption",
228 "ui.appworkspace",
229 "ui.background",
230 "ui.buttonface",
231 "ui.buttonhighlight",
232 "ui.buttonshadow",
233 "ui.buttontext",
234 "ui.captiontext",
235 "ui.-moz-field",
236 "ui.-moz-disabledfield",
237 "ui.-moz-fieldtext",
238 "ui.graytext",
239 "ui.highlight",
240 "ui.highlighttext",
241 "ui.inactiveborder",
242 "ui.inactivecaption",
243 "ui.inactivecaptiontext",
244 "ui.infobackground",
245 "ui.infotext",
246 "ui.menu",
247 "ui.menutext",
248 "ui.scrollbar",
249 "ui.threeddarkshadow",
250 "ui.threedface",
251 "ui.threedhighlight",
252 "ui.threedlightshadow",
253 "ui.threedshadow",
254 "ui.window",
255 "ui.windowframe",
256 "ui.windowtext",
257 "ui.-moz-buttondefault",
258 "ui.-moz-default-color",
259 "ui.-moz-default-background-color",
260 "ui.-moz-dialog",
261 "ui.-moz-dialogtext",
262 "ui.-moz-dragtargetzone",
263 "ui.-moz-cellhighlight",
264 "ui.-moz_cellhighlighttext",
265 "ui.selecteditem",
266 "ui.selecteditemtext",
267 "ui.-moz-buttonhoverface",
268 "ui.-moz_buttonhovertext",
269 "ui.-moz_menuhover",
270 "ui.-moz_menuhovertext",
271 "ui.-moz_menubartext",
272 "ui.-moz_menubarhovertext",
273 "ui.-moz_eventreerow",
274 "ui.-moz_oddtreerow",
275 "ui.-moz-buttonactivetext",
276 "ui.-moz-buttonactiveface",
277 "ui.-moz-buttondisabledface",
278 "ui.-moz_mac_chrome_active",
279 "ui.-moz_mac_chrome_inactive",
280 "ui.-moz-mac-defaultbuttontext",
281 "ui.-moz-mac-focusring",
282 "ui.-moz-mac-menuselect",
283 "ui.-moz-mac-menushadow",
284 "ui.-moz-mac-menutextdisable",
285 "ui.-moz-mac-menutextselect",
286 "ui.-moz_mac_disabledtoolbartext",
287 "ui.-moz-mac-secondaryhighlight",
288 "ui.-moz-mac-vibrant-titlebar-light",
289 "ui.-moz-mac-vibrant-titlebar-dark",
290 "ui.-moz-mac-menupopup",
291 "ui.-moz-mac-menuitem",
292 "ui.-moz-mac-active-menuitem",
293 "ui.-moz-mac-source-list",
294 "ui.-moz-mac-source-list-selection",
295 "ui.-moz-mac-active-source-list-selection",
296 "ui.-moz-mac-tooltip",
297 "ui.-moz-accent-color",
298 "ui.-moz-accent-color-foreground",
299 "ui.-moz-autofill-background",
300 "ui.-moz-win-mediatext",
301 "ui.-moz-win-communicationstext",
302 "ui.-moz-nativehyperlinktext",
303 "ui.-moz-nativevisitedhyperlinktext",
304 "ui.-moz-hyperlinktext",
305 "ui.-moz-activehyperlinktext",
306 "ui.-moz-visitedhyperlinktext",
307 "ui.-moz-comboboxtext",
308 "ui.-moz-combobox",
309 "ui.-moz-colheadertext",
310 "ui.-moz-colheaderhovertext",
313 static_assert(ArrayLength(sColorPrefs) == size_t(LookAndFeel::ColorID::End),
314 "Should have a pref for each color value");
316 const char* nsXPLookAndFeel::GetColorPrefName(ColorID aId) {
317 return sColorPrefs[size_t(aId)];
320 bool nsXPLookAndFeel::sInitialized = false;
322 nsXPLookAndFeel* nsXPLookAndFeel::sInstance = nullptr;
323 bool nsXPLookAndFeel::sShutdown = false;
325 // static
326 nsXPLookAndFeel* nsXPLookAndFeel::GetInstance() {
327 if (sInstance) {
328 return sInstance;
331 NS_ENSURE_TRUE(!sShutdown, nullptr);
333 // If we're in a content process, then the parent process will have supplied
334 // us with an initial FullLookAndFeel object.
335 // We grab this data from the ContentChild,
336 // where it's been temporarily stashed, and initialize our new LookAndFeel
337 // object with it.
339 FullLookAndFeel* lnf = nullptr;
341 if (auto* cc = mozilla::dom::ContentChild::GetSingleton()) {
342 lnf = &cc->BorrowLookAndFeelData();
345 if (lnf) {
346 sInstance = new widget::RemoteLookAndFeel(std::move(*lnf));
347 } else if (gfxPlatform::IsHeadless()) {
348 sInstance = new widget::HeadlessLookAndFeel();
349 } else {
350 sInstance = new nsLookAndFeel();
353 // This is only ever used once during initialization, and can be cleared now.
354 if (lnf) {
355 *lnf = {};
358 widget::Theme::Init();
359 return sInstance;
362 // static
363 void nsXPLookAndFeel::Shutdown() {
364 if (sShutdown) {
365 return;
368 sShutdown = true;
369 delete sInstance;
370 sInstance = nullptr;
372 // This keeps strings alive, so need to clear to make leak checking happy.
373 sFontCache.Clear();
375 widget::Theme::Shutdown();
378 static void IntPrefChanged(const nsACString& aPref) {
379 // Most Int prefs can't change our system colors or fonts, but
380 // ui.systemUsesDarkTheme can, since it affects the effective color-scheme
381 // (affecting system colors).
382 auto changeKind = aPref.EqualsLiteral("ui.systemUsesDarkTheme")
383 ? widget::ThemeChangeKind::Style
384 : widget::ThemeChangeKind::MediaQueriesOnly;
385 LookAndFeel::NotifyChangedAllWindows(changeKind);
388 static void FloatPrefChanged() {
389 // Float prefs can't change our system colors or fonts.
390 LookAndFeel::NotifyChangedAllWindows(
391 widget::ThemeChangeKind::MediaQueriesOnly);
394 static void ColorPrefChanged() {
395 // Color prefs affect style, because they by definition change system colors.
396 LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind::Style);
399 // static
400 void nsXPLookAndFeel::OnPrefChanged(const char* aPref, void* aClosure) {
401 nsDependentCString prefName(aPref);
402 for (const char* pref : sIntPrefs) {
403 if (prefName.Equals(pref)) {
404 IntPrefChanged(prefName);
405 return;
409 for (const char* pref : sFloatPrefs) {
410 if (prefName.Equals(pref)) {
411 FloatPrefChanged();
412 return;
416 for (const char* pref : sColorPrefs) {
417 // We use StringBeginsWith to handle .dark prefs too.
418 if (StringBeginsWith(prefName, nsDependentCString(pref))) {
419 ColorPrefChanged();
420 return;
425 static constexpr struct {
426 nsLiteralCString mName;
427 widget::ThemeChangeKind mChangeKind =
428 widget::ThemeChangeKind::MediaQueriesOnly;
429 } kMediaQueryPrefs[] = {
430 {"browser.display.windows.native_menus"_ns},
431 {"browser.proton.places-tooltip.enabled"_ns},
432 {"layout.css.prefers-color-scheme.content-override"_ns},
433 // Affects media queries and scrollbar sizes, so gotta relayout.
434 {"widget.gtk.overlay-scrollbars.enabled"_ns,
435 widget::ThemeChangeKind::StyleAndLayout},
436 // This affects not only the media query, but also the native theme, so we
437 // need to re-layout.
438 {"browser.theme.toolbar-theme"_ns, widget::ThemeChangeKind::AllBits},
439 {"browser.theme.content-theme"_ns},
442 // Read values from the user's preferences.
443 // This is done once at startup, but since the user's preferences
444 // haven't actually been read yet at that time, we also have to
445 // set a callback to inform us of changes to each pref.
446 void nsXPLookAndFeel::Init() {
447 MOZ_RELEASE_ASSERT(NS_IsMainThread());
449 // Say we're already initialized, and take the chance that it might fail;
450 // protects against some other process writing to our static variables.
451 sInitialized = true;
453 RecomputeColorSchemes();
455 // XXX If we could reorganize the pref names, we should separate the branch
456 // for each types. Then, we could reduce the unnecessary loop from
457 // nsXPLookAndFeel::OnPrefChanged().
458 Preferences::RegisterPrefixCallback(OnPrefChanged, "ui.");
459 // We really do just want the accessibility.tabfocus pref, not other prefs
460 // that start with that string.
461 Preferences::RegisterCallback(OnPrefChanged, "accessibility.tabfocus");
463 for (auto& pref : kMediaQueryPrefs) {
464 Preferences::RegisterCallback(
465 [](const char*, void* aChangeKind) {
466 auto changeKind =
467 widget::ThemeChangeKind(reinterpret_cast<uintptr_t>(aChangeKind));
468 LookAndFeel::NotifyChangedAllWindows(changeKind);
470 pref.mName, reinterpret_cast<void*>(uintptr_t(pref.mChangeKind)));
474 nsXPLookAndFeel::~nsXPLookAndFeel() {
475 NS_ASSERTION(sInstance == this,
476 "This destroying instance isn't the singleton instance");
477 sInstance = nullptr;
480 static bool IsSpecialColor(LookAndFeel::ColorID aID, nscolor aColor) {
481 using ColorID = LookAndFeel::ColorID;
483 if (aColor == NS_SAME_AS_FOREGROUND_COLOR) {
484 return true;
487 switch (aID) {
488 case ColorID::IMESelectedRawTextBackground:
489 case ColorID::IMESelectedConvertedTextBackground:
490 case ColorID::IMERawInputBackground:
491 case ColorID::IMEConvertedTextBackground:
492 case ColorID::IMESelectedRawTextForeground:
493 case ColorID::IMESelectedConvertedTextForeground:
494 case ColorID::IMERawInputForeground:
495 case ColorID::IMEConvertedTextForeground:
496 case ColorID::IMERawInputUnderline:
497 case ColorID::IMEConvertedTextUnderline:
498 case ColorID::IMESelectedRawTextUnderline:
499 case ColorID::IMESelectedConvertedTextUnderline:
500 case ColorID::SpellCheckerUnderline:
501 return NS_IS_SELECTION_SPECIAL_COLOR(aColor);
502 default:
503 break;
506 * In GetColor(), every color that is not a special color is color
507 * corrected. Use false to make other colors color corrected.
509 return false;
512 nscolor nsXPLookAndFeel::GetStandinForNativeColor(ColorID aID,
513 ColorScheme aScheme) {
514 if (aScheme == ColorScheme::Dark) {
515 if (auto color = GenericDarkColor(aID)) {
516 return *color;
520 // The stand-in colors are taken from what the non-native theme needs (for
521 // field/button colors), the Windows 7 Aero theme except Mac-specific colors
522 // which are taken from Mac OS 10.7.
524 #define COLOR(name_, r, g, b) \
525 case ColorID::name_: \
526 return NS_RGB(r, g, b);
528 #define COLORA(name_, r, g, b, a) \
529 case ColorID::name_: \
530 return NS_RGBA(r, g, b, a);
532 switch (aID) {
533 // These are here for the purposes of headless mode.
534 case ColorID::IMESelectedRawTextBackground:
535 case ColorID::IMESelectedConvertedTextBackground:
536 case ColorID::IMERawInputBackground:
537 case ColorID::IMEConvertedTextBackground:
538 return NS_TRANSPARENT;
539 case ColorID::IMESelectedRawTextForeground:
540 case ColorID::IMESelectedConvertedTextForeground:
541 case ColorID::IMERawInputForeground:
542 case ColorID::IMEConvertedTextForeground:
543 return NS_SAME_AS_FOREGROUND_COLOR;
544 case ColorID::IMERawInputUnderline:
545 case ColorID::IMEConvertedTextUnderline:
546 return NS_40PERCENT_FOREGROUND_COLOR;
547 COLOR(MozAccentColor, 53, 132, 228)
548 COLOR(MozAccentColorForeground, 0xff, 0xff, 0xff)
549 COLOR(SpellCheckerUnderline, 0xff, 0x00, 0x00)
550 COLOR(TextSelectDisabledBackground, 0xaa, 0xaa, 0xaa)
552 // CSS 2 colors:
553 COLOR(Activeborder, 0xB4, 0xB4, 0xB4)
554 COLOR(Activecaption, 0x99, 0xB4, 0xD1)
555 COLOR(Appworkspace, 0xAB, 0xAB, 0xAB)
556 COLOR(Background, 0x00, 0x00, 0x00)
557 COLOR(Buttonhighlight, 0xFF, 0xFF, 0xFF)
558 COLOR(Buttonshadow, 0xA0, 0xA0, 0xA0)
560 // Buttons and comboboxes should be kept in sync since they are drawn with
561 // the same colors by the non-native theme.
562 COLOR(Buttonface, 0xe9, 0xe9, 0xed)
563 COLORA(MozButtondisabledface, 0xe9, 0xe9, 0xed, 128)
565 COLOR(MozCombobox, 0xe9, 0xe9, 0xed)
567 COLOR(Buttontext, 0x00, 0x00, 0x00)
568 COLOR(MozComboboxtext, 0x00, 0x00, 0x00)
570 COLOR(Captiontext, 0x00, 0x00, 0x00)
571 COLOR(Graytext, 0x6D, 0x6D, 0x6D)
572 COLOR(Highlight, 0x33, 0x99, 0xFF)
573 COLOR(Highlighttext, 0xFF, 0xFF, 0xFF)
574 COLOR(Inactiveborder, 0xF4, 0xF7, 0xFC)
575 COLOR(Inactivecaption, 0xBF, 0xCD, 0xDB)
576 COLOR(Inactivecaptiontext, 0x43, 0x4E, 0x54)
577 COLOR(Infobackground, 0xFF, 0xFF, 0xE1)
578 COLOR(Infotext, 0x00, 0x00, 0x00)
579 COLOR(Menu, 0xF0, 0xF0, 0xF0)
580 COLOR(Menutext, 0x00, 0x00, 0x00)
581 COLOR(Scrollbar, 0xC8, 0xC8, 0xC8)
582 COLOR(Threeddarkshadow, 0x69, 0x69, 0x69)
583 COLOR(Threedface, 0xF0, 0xF0, 0xF0)
584 COLOR(Threedhighlight, 0xFF, 0xFF, 0xFF)
585 COLOR(Threedlightshadow, 0xE3, 0xE3, 0xE3)
586 COLOR(Threedshadow, 0xA0, 0xA0, 0xA0)
587 COLOR(Window, 0xFF, 0xFF, 0xFF)
588 COLOR(Windowframe, 0x64, 0x64, 0x64)
589 COLOR(Windowtext, 0x00, 0x00, 0x00)
590 COLOR(MozButtondefault, 0x69, 0x69, 0x69)
591 COLOR(Field, 0xFF, 0xFF, 0xFF)
592 COLORA(MozDisabledfield, 0xFF, 0xFF, 0xFF, 128)
593 COLOR(Fieldtext, 0x00, 0x00, 0x00)
594 COLOR(MozDialog, 0xF0, 0xF0, 0xF0)
595 COLOR(MozDialogtext, 0x00, 0x00, 0x00)
596 COLOR(MozColheadertext, 0x00, 0x00, 0x00)
597 COLOR(MozColheaderhovertext, 0x00, 0x00, 0x00)
598 COLOR(MozDragtargetzone, 0xFF, 0xFF, 0xFF)
599 COLOR(MozCellhighlight, 0xF0, 0xF0, 0xF0)
600 COLOR(MozCellhighlighttext, 0x00, 0x00, 0x00)
601 COLOR(Selecteditem, 0x33, 0x99, 0xFF)
602 COLOR(Selecteditemtext, 0xFF, 0xFF, 0xFF)
603 COLOR(MozButtonhoverface, 0xd0, 0xd0, 0xd7)
604 COLOR(MozButtonhovertext, 0x00, 0x00, 0x00)
605 COLOR(MozButtonactiveface, 0xb1, 0xb1, 0xb9)
606 COLOR(MozButtonactivetext, 0x00, 0x00, 0x00)
607 COLOR(MozMenuhover, 0x33, 0x99, 0xFF)
608 COLOR(MozMenuhovertext, 0x00, 0x00, 0x00)
609 COLOR(MozMenubartext, 0x00, 0x00, 0x00)
610 COLOR(MozMenubarhovertext, 0x00, 0x00, 0x00)
611 COLOR(MozEventreerow, 0xFF, 0xFF, 0xFF)
612 COLOR(MozOddtreerow, 0xFF, 0xFF, 0xFF)
613 COLOR(MozMacChromeActive, 0xB2, 0xB2, 0xB2)
614 COLOR(MozMacChromeInactive, 0xE1, 0xE1, 0xE1)
615 COLOR(MozMacFocusring, 0x60, 0x9D, 0xD7)
616 COLOR(MozMacMenuselect, 0x38, 0x75, 0xD7)
617 COLOR(MozMacMenushadow, 0xA3, 0xA3, 0xA3)
618 COLOR(MozMacMenutextdisable, 0x88, 0x88, 0x88)
619 COLOR(MozMacMenutextselect, 0xFF, 0xFF, 0xFF)
620 COLOR(MozMacDisabledtoolbartext, 0x3F, 0x3F, 0x3F)
621 COLOR(MozMacSecondaryhighlight, 0xD4, 0xD4, 0xD4)
622 COLOR(MozMacVibrantTitlebarLight, 0xf7, 0xf7, 0xf7)
623 COLOR(MozMacVibrantTitlebarDark, 0x28, 0x28, 0x28)
624 COLOR(MozMacMenupopup, 0xe6, 0xe6, 0xe6)
625 COLOR(MozMacMenuitem, 0xe6, 0xe6, 0xe6)
626 COLOR(MozMacActiveMenuitem, 0x0a, 0x64, 0xdc)
627 COLOR(MozMacSourceList, 0xf7, 0xf7, 0xf7)
628 COLOR(MozMacSourceListSelection, 0xc8, 0xc8, 0xc8)
629 COLOR(MozMacActiveSourceListSelection, 0x0a, 0x64, 0xdc)
630 COLOR(MozMacTooltip, 0xf7, 0xf7, 0xf7)
631 // Seems to be the default color (hardcoded because of bug 1065998)
632 COLOR(MozWinMediatext, 0xFF, 0xFF, 0xFF)
633 COLOR(MozWinCommunicationstext, 0xFF, 0xFF, 0xFF)
634 COLOR(MozNativehyperlinktext, 0x00, 0x66, 0xCC)
635 COLOR(MozNativevisitedhyperlinktext, 0x55, 0x1A, 0x8B)
636 default:
637 break;
639 return NS_RGB(0xFF, 0xFF, 0xFF);
642 #undef COLOR
643 #undef COLORA
645 // Taken from in-content/common.inc.css's dark theme.
646 Maybe<nscolor> nsXPLookAndFeel::GenericDarkColor(ColorID aID) {
647 nscolor color = NS_RGB(0, 0, 0);
648 static constexpr nscolor kWindowBackground = NS_RGB(28, 27, 34);
649 static constexpr nscolor kWindowText = NS_RGB(251, 251, 254);
650 switch (aID) {
651 case ColorID::Window: // --in-content-page-background
652 case ColorID::Background:
653 case ColorID::Menu:
654 color = kWindowBackground;
655 break;
656 case ColorID::MozOddtreerow:
657 case ColorID::MozDialog: // --in-content-box-background
658 color = NS_RGB(35, 34, 43);
659 break;
660 case ColorID::Windowtext: // --in-content-page-color
661 case ColorID::Menutext:
662 case ColorID::MozDialogtext:
663 case ColorID::Fieldtext:
664 case ColorID::Buttontext: // --in-content-button-text-color (via
665 // --in-content-page-color)
666 case ColorID::MozComboboxtext:
667 case ColorID::MozButtonhovertext:
668 case ColorID::MozButtonactivetext:
669 color = kWindowText;
670 break;
671 case ColorID::Threedlightshadow: // --in-content-box-border-color computed
672 // with kWindowText above
673 // kWindowBackground.
674 case ColorID::Graytext: // opacity: 0.4 of kWindowText blended over the
675 // "Window" background color, which happens to be
676 // the same :-)
677 color = NS_ComposeColors(kWindowBackground, NS_RGBA(251, 251, 254, 102));
678 break;
679 case ColorID::MozCellhighlight:
680 case ColorID::Selecteditem: // --in-content-primary-button-background /
681 // --in-content-item-selected
682 color = NS_RGB(0, 221, 255);
683 break;
684 case ColorID::Field:
685 case ColorID::Buttonface: // --in-content-button-background
686 case ColorID::Threedface:
687 case ColorID::MozCombobox:
688 case ColorID::MozCellhighlighttext:
689 case ColorID::Selecteditemtext: // --in-content-primary-button-text-color /
690 // --in-content-item-selected-text
691 color = NS_RGB(43, 42, 51);
692 break;
693 case ColorID::Threeddarkshadow: // Same as Threedlightshadow but with the
694 // background.
695 case ColorID::MozDisabledfield: // opacity: 0.4 of the face above blended
696 // over the "Window" background color.
697 case ColorID::MozButtondisabledface:
698 color = NS_ComposeColors(kWindowBackground, NS_RGBA(43, 42, 51, 102));
699 break;
700 case ColorID::MozButtonhoverface: // --in-content-button-background-hover
701 color = NS_RGB(82, 82, 94);
702 break;
703 case ColorID::MozButtonactiveface: // --in-content-button-background-active
704 color = NS_RGB(91, 91, 102);
705 break;
706 case ColorID::Highlight:
707 color = NS_RGBA(0, 221, 255, 78);
708 break;
709 case ColorID::Highlighttext:
710 color = NS_SAME_AS_FOREGROUND_COLOR;
711 break;
712 case ColorID::MozNativehyperlinktext:
713 // If you change this color, you probably also want to change the default
714 // value of browser.anchor_color.dark.
715 color = NS_RGB(0x8c, 0x8c, 0xff);
716 break;
717 case ColorID::MozNativevisitedhyperlinktext:
718 // If you change this color, you probably also want to change the default
719 // value of browser.visited_color.dark.
720 color = NS_RGB(0xff, 0xad, 0xff);
721 break;
723 default:
724 return Nothing();
726 return Some(color);
729 // Uncomment the #define below if you want to debug system color use in a skin
730 // that uses them. When set, it will make all system color pairs that are
731 // appropriate for foreground/background pairing the same. This means if the
732 // skin is using system colors correctly you will not be able to see *any* text.
734 // #define DEBUG_SYSTEM_COLOR_USE
736 #ifdef DEBUG_SYSTEM_COLOR_USE
737 static nsresult SystemColorUseDebuggingColor(LookAndFeel::ColorID aID,
738 nscolor& aResult) {
739 using ColorID = LookAndFeel::ColorID;
741 switch (aID) {
742 // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
743 case ColorID::Activecaption:
744 // active window caption background
745 case ColorID::Captiontext:
746 // text in active window caption
747 aResult = NS_RGB(0xff, 0x00, 0x00);
748 break;
750 case ColorID::Highlight:
751 // background of selected item
752 case ColorID::Highlighttext:
753 // text of selected item
754 aResult = NS_RGB(0xff, 0xff, 0x00);
755 break;
757 case ColorID::Inactivecaption:
758 // inactive window caption
759 case ColorID::Inactivecaptiontext:
760 // text in inactive window caption
761 aResult = NS_RGB(0x66, 0x66, 0x00);
762 break;
764 case ColorID::Infobackground:
765 // tooltip background color
766 case ColorID::Infotext:
767 // tooltip text color
768 aResult = NS_RGB(0x00, 0xff, 0x00);
769 break;
771 case ColorID::Menu:
772 // menu background
773 case ColorID::Menutext:
774 // menu text
775 aResult = NS_RGB(0x00, 0xff, 0xff);
776 break;
778 case ColorID::Threedface:
779 case ColorID::Buttonface:
780 // 3-D face color
781 case ColorID::Buttontext:
782 // text on push buttons
783 aResult = NS_RGB(0x00, 0x66, 0x66);
784 break;
786 case ColorID::Window:
787 case ColorID::Windowtext:
788 aResult = NS_RGB(0x00, 0x00, 0xff);
789 break;
791 // from the CSS3 working draft (not yet finalized)
792 // http://www.w3.org/tr/2000/wd-css3-userint-20000216.html#color
794 case ColorID::Field:
795 case ColorID::Fieldtext:
796 aResult = NS_RGB(0xff, 0x00, 0xff);
797 break;
799 case ColorID::MozDialog:
800 case ColorID::MozDialogtext:
801 aResult = NS_RGB(0x66, 0x00, 0x66);
802 break;
804 default:
805 return NS_ERROR_NOT_AVAILABLE;
808 return NS_OK;
810 #endif
812 static nsresult GetPrefColor(const char* aPref, nscolor& aResult) {
813 nsAutoCString colorStr;
814 MOZ_TRY(Preferences::GetCString(aPref, colorStr));
815 if (!ServoCSSParser::ComputeColor(nullptr, NS_RGB(0, 0, 0), colorStr,
816 &aResult)) {
817 return NS_ERROR_FAILURE;
819 return NS_OK;
822 static nsresult GetColorFromPref(LookAndFeel::ColorID aID, ColorScheme aScheme,
823 nscolor& aResult) {
824 const char* prefName = sColorPrefs[size_t(aID)];
825 if (aScheme == ColorScheme::Dark) {
826 nsAutoCString darkPrefName(prefName);
827 darkPrefName.Append(".dark");
828 if (NS_SUCCEEDED(GetPrefColor(darkPrefName.get(), aResult))) {
829 return NS_OK;
832 return GetPrefColor(prefName, aResult);
835 // All these routines will return NS_OK if they have a value,
836 // in which case the nsLookAndFeel should use that value;
837 // otherwise we'll return NS_ERROR_NOT_AVAILABLE, in which case, the
838 // platform-specific nsLookAndFeel should use its own values instead.
839 nsresult nsXPLookAndFeel::GetColorValue(ColorID aID, ColorScheme aScheme,
840 UseStandins aUseStandins,
841 nscolor& aResult) {
842 if (!sInitialized) {
843 Init();
846 #ifdef DEBUG_SYSTEM_COLOR_USE
847 if (NS_SUCCEEDED(SystemColorUseDebuggingColor(aID, aResult))) {
848 return NS_OK;
850 #endif
852 if (aUseStandins == UseStandins::Yes) {
853 aResult = GetStandinForNativeColor(aID, aScheme);
854 return NS_OK;
857 auto& cache =
858 aScheme == ColorScheme::Light ? sLightColorCache : sDarkColorCache;
859 if (const auto* cached = cache.Get(aID)) {
860 if (cached->isNothing()) {
861 return NS_ERROR_FAILURE;
863 aResult = cached->value();
864 return NS_OK;
867 if (NS_SUCCEEDED(GetColorFromPref(aID, aScheme, aResult))) {
868 cache.Insert(aID, Some(aResult));
869 return NS_OK;
872 if (NS_SUCCEEDED(NativeGetColor(aID, aScheme, aResult))) {
873 if (gfxPlatform::GetCMSMode() == CMSMode::All &&
874 !IsSpecialColor(aID, aResult)) {
875 qcms_transform* transform = gfxPlatform::GetCMSInverseRGBTransform();
876 if (transform) {
877 uint8_t color[4];
878 color[0] = NS_GET_R(aResult);
879 color[1] = NS_GET_G(aResult);
880 color[2] = NS_GET_B(aResult);
881 color[3] = NS_GET_A(aResult);
882 qcms_transform_data(transform, color, color, 1);
883 aResult = NS_RGBA(color[0], color[1], color[2], color[3]);
887 // NOTE: Servo holds a lock and the main thread is paused, so writing to the
888 // global cache here is fine.
889 cache.Insert(aID, Some(aResult));
890 return NS_OK;
893 cache.Insert(aID, Nothing());
894 return NS_ERROR_FAILURE;
897 nsresult nsXPLookAndFeel::GetIntValue(IntID aID, int32_t& aResult) {
898 if (!sInitialized) {
899 Init();
902 if (const auto* cached = sIntCache.Get(aID)) {
903 if (cached->isNothing()) {
904 return NS_ERROR_FAILURE;
906 aResult = cached->value();
907 return NS_OK;
910 if (NS_SUCCEEDED(Preferences::GetInt(sIntPrefs[size_t(aID)], &aResult))) {
911 sIntCache.Insert(aID, Some(aResult));
912 return NS_OK;
915 if (NS_FAILED(NativeGetInt(aID, aResult))) {
916 sIntCache.Insert(aID, Nothing());
917 return NS_ERROR_FAILURE;
920 sIntCache.Insert(aID, Some(aResult));
921 return NS_OK;
924 nsresult nsXPLookAndFeel::GetFloatValue(FloatID aID, float& aResult) {
925 if (!sInitialized) {
926 Init();
929 if (const auto* cached = sFloatCache.Get(aID)) {
930 if (cached->isNothing()) {
931 return NS_ERROR_FAILURE;
933 aResult = cached->value();
934 return NS_OK;
937 int32_t pref = 0;
938 if (NS_SUCCEEDED(Preferences::GetInt(sFloatPrefs[size_t(aID)], &pref))) {
939 aResult = float(pref) / 100.0f;
940 sFloatCache.Insert(aID, Some(aResult));
941 return NS_OK;
944 if (NS_FAILED(NativeGetFloat(aID, aResult))) {
945 sFloatCache.Insert(aID, Nothing());
946 return NS_ERROR_FAILURE;
949 sFloatCache.Insert(aID, Some(aResult));
950 return NS_OK;
953 bool nsXPLookAndFeel::LookAndFeelFontToStyle(const LookAndFeelFont& aFont,
954 nsString& aName,
955 gfxFontStyle& aStyle) {
956 if (!aFont.haveFont()) {
957 return false;
959 aName = aFont.name();
960 aStyle = gfxFontStyle();
961 aStyle.size = aFont.size();
962 aStyle.weight = FontWeight(aFont.weight());
963 aStyle.style =
964 aFont.italic() ? FontSlantStyle::Italic() : FontSlantStyle::Normal();
965 aStyle.systemFont = true;
966 return true;
969 widget::LookAndFeelFont nsXPLookAndFeel::StyleToLookAndFeelFont(
970 const nsAString& aName, const gfxFontStyle& aStyle) {
971 LookAndFeelFont font;
972 font.haveFont() = true;
973 font.name() = aName;
974 font.size() = aStyle.size;
975 font.weight() = aStyle.weight.ToFloat();
976 font.italic() = aStyle.style.IsItalic();
977 MOZ_ASSERT(aStyle.style.IsNormal() || aStyle.style.IsItalic(),
978 "Cannot handle oblique font style");
979 #ifdef DEBUG
981 // Assert that all the remaining font style properties have their
982 // default values.
983 gfxFontStyle candidate = aStyle;
984 gfxFontStyle defaults{};
985 candidate.size = defaults.size;
986 candidate.weight = defaults.weight;
987 candidate.style = defaults.style;
988 MOZ_ASSERT(candidate.Equals(defaults),
989 "Some font style properties not supported");
991 #endif
992 return font;
995 bool nsXPLookAndFeel::GetFontValue(FontID aID, nsString& aName,
996 gfxFontStyle& aStyle) {
997 if (const LookAndFeelFont* cached = sFontCache.Get(aID)) {
998 return LookAndFeelFontToStyle(*cached, aName, aStyle);
1000 LookAndFeelFont font;
1001 const bool haveFont = NativeGetFont(aID, aName, aStyle);
1002 font.haveFont() = haveFont;
1003 if (haveFont) {
1004 font = StyleToLookAndFeelFont(aName, aStyle);
1006 sFontCache.Insert(aID, std::move(font));
1007 return haveFont;
1010 void nsXPLookAndFeel::RefreshImpl() {
1011 // Wipe out our caches.
1012 sLightColorCache.Clear();
1013 sDarkColorCache.Clear();
1014 sFontCache.Clear();
1015 sFloatCache.Clear();
1016 sIntCache.Clear();
1017 RecomputeColorSchemes();
1019 // Clear any cached FullLookAndFeel data, which is now invalid.
1020 if (XRE_IsParentProcess()) {
1021 widget::RemoteLookAndFeel::ClearCachedData();
1025 static bool sRecordedLookAndFeelTelemetry = false;
1027 void nsXPLookAndFeel::RecordTelemetry() {
1028 if (!XRE_IsParentProcess()) {
1029 return;
1032 if (sRecordedLookAndFeelTelemetry) {
1033 return;
1036 sRecordedLookAndFeelTelemetry = true;
1038 int32_t i;
1039 Telemetry::ScalarSet(
1040 Telemetry::ScalarID::WIDGET_DARK_MODE,
1041 NS_SUCCEEDED(GetIntValue(IntID::SystemUsesDarkTheme, i)) && i != 0);
1043 RecordLookAndFeelSpecificTelemetry();
1046 namespace mozilla {
1048 static widget::ThemeChangeKind sGlobalThemeChangeKind{0};
1050 void LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind aKind) {
1051 sGlobalThemeChanged = true;
1052 sGlobalThemeChangeKind |= aKind;
1054 if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
1055 const char16_t kind[] = {char16_t(aKind), 0};
1056 obs->NotifyObservers(nullptr, "internal-look-and-feel-changed", kind);
1060 void LookAndFeel::DoHandleGlobalThemeChange() {
1061 MOZ_ASSERT(sGlobalThemeChanged);
1062 sGlobalThemeChanged = false;
1063 auto kind = std::exchange(sGlobalThemeChangeKind, widget::ThemeChangeKind(0));
1065 // Tell the theme that it changed, so it can flush any handles to stale theme
1066 // data.
1068 // We can use the *DoNotUseDirectly functions directly here, because we want
1069 // to notify all possible themes in a given process (but just once).
1070 if (XRE_IsParentProcess() ||
1071 !StaticPrefs::widget_non_native_theme_enabled()) {
1072 if (nsCOMPtr<nsITheme> theme = do_GetNativeThemeDoNotUseDirectly()) {
1073 theme->ThemeChanged();
1076 if (nsCOMPtr<nsITheme> theme = do_GetBasicNativeThemeDoNotUseDirectly()) {
1077 theme->ThemeChanged();
1080 // Clear all cached LookAndFeel colors.
1081 LookAndFeel::Refresh();
1083 // Reset default background and foreground colors for the document since they
1084 // may be using system colors.
1085 PreferenceSheet::Refresh();
1087 // Vector images (SVG) may be using theme colors so we discard all cached
1088 // surfaces. (We could add a vector image only version of DiscardAll, but
1089 // in bug 940625 we decided theme changes are rare enough not to bother.)
1090 image::SurfaceCacheUtils::DiscardAll();
1092 if (XRE_IsParentProcess()) {
1093 dom::ContentParent::BroadcastThemeUpdate(kind);
1096 nsContentUtils::AddScriptRunner(
1097 NS_NewRunnableFunction("HandleGlobalThemeChange", [] {
1098 if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
1099 obs->NotifyObservers(nullptr, "look-and-feel-changed", nullptr);
1101 }));
1104 static bool ShouldUseStandinsForNativeColorForNonNativeTheme(
1105 const dom::Document& aDoc, LookAndFeel::ColorID aColor) {
1106 using ColorID = LookAndFeel::ColorID;
1107 if (!aDoc.ShouldAvoidNativeTheme()) {
1108 return false;
1111 // The native theme doesn't use native system colors backgrounds etc, except
1112 // when in high-contrast mode, so spoof some of the colors with stand-ins to
1113 // prevent lack of contrast.
1114 switch (aColor) {
1115 case ColorID::Buttonface:
1116 case ColorID::Buttontext:
1117 case ColorID::MozButtonhoverface:
1118 case ColorID::MozButtonhovertext:
1119 case ColorID::MozButtonactiveface:
1120 case ColorID::MozButtonactivetext:
1121 case ColorID::MozButtondisabledface:
1123 case ColorID::Threedlightshadow:
1124 case ColorID::Threeddarkshadow:
1125 case ColorID::Threedface:
1127 case ColorID::MozCombobox:
1128 case ColorID::MozComboboxtext:
1130 case ColorID::Field:
1131 case ColorID::MozDisabledfield:
1132 case ColorID::Fieldtext:
1134 case ColorID::Graytext:
1136 return !PreferenceSheet::PrefsFor(aDoc)
1137 .NonNativeThemeShouldBeHighContrast();
1139 default:
1140 break;
1143 return false;
1146 ColorScheme LookAndFeel::sChromeColorScheme;
1147 ColorScheme LookAndFeel::sContentColorScheme;
1148 bool LookAndFeel::sColorSchemeInitialized;
1149 bool LookAndFeel::sGlobalThemeChanged;
1151 auto LookAndFeel::ColorSchemeSettingForChrome() -> ChromeColorSchemeSetting {
1152 switch (StaticPrefs::browser_theme_toolbar_theme()) {
1153 case 0: // Dark
1154 return ChromeColorSchemeSetting::Dark;
1155 case 1: // Light
1156 return ChromeColorSchemeSetting::Light;
1157 default:
1158 return ChromeColorSchemeSetting::System;
1162 ColorScheme LookAndFeel::ThemeDerivedColorSchemeForContent() {
1163 switch (StaticPrefs::browser_theme_content_theme()) {
1164 case 0: // Dark
1165 return ColorScheme::Dark;
1166 case 1: // Light
1167 return ColorScheme::Light;
1168 default:
1169 return SystemColorScheme();
1173 void LookAndFeel::RecomputeColorSchemes() {
1174 sColorSchemeInitialized = true;
1176 sChromeColorScheme = [] {
1177 switch (ColorSchemeSettingForChrome()) {
1178 case ChromeColorSchemeSetting::Light:
1179 return ColorScheme::Light;
1180 case ChromeColorSchemeSetting::Dark:
1181 return ColorScheme::Dark;
1182 case ChromeColorSchemeSetting::System:
1183 break;
1185 return SystemColorScheme();
1186 }();
1188 sContentColorScheme = [] {
1189 switch (StaticPrefs::layout_css_prefers_color_scheme_content_override()) {
1190 case 0:
1191 return ColorScheme::Dark;
1192 case 1:
1193 return ColorScheme::Light;
1194 case 2:
1195 return SystemColorScheme();
1196 default:
1197 return ThemeDerivedColorSchemeForContent();
1199 }();
1202 ColorScheme LookAndFeel::ColorSchemeForStyle(
1203 const dom::Document& aDoc, const StyleColorSchemeFlags& aFlags) {
1204 if (PreferenceSheet::MayForceColors()) {
1205 auto& prefs = PreferenceSheet::PrefsFor(aDoc);
1206 if (!prefs.mUseDocumentColors) {
1207 // When forcing colors, we can use our preferred color-scheme. Do this
1208 // only if we're using system colors, as dark preference colors are not
1209 // exposed on the UI.
1211 // Also, use light if we're using a high-contrast-theme on Windows, since
1212 // Windows overrides the light colors with HCM colors when HCM is active.
1213 #ifdef XP_WIN
1214 if (prefs.mUseAccessibilityTheme) {
1215 return ColorScheme::Light;
1217 #endif
1218 if (StaticPrefs::browser_display_use_system_colors()) {
1219 return aDoc.PreferredColorScheme();
1221 return ColorScheme::Light;
1225 StyleColorSchemeFlags style(aFlags);
1226 if (!style) {
1227 style.bits = aDoc.GetColorSchemeBits();
1229 const bool supportsDark = bool(style & StyleColorSchemeFlags::DARK);
1230 const bool supportsLight = bool(style & StyleColorSchemeFlags::LIGHT);
1231 if (supportsLight && supportsDark) {
1232 // Both color-schemes are explicitly supported, use the preferred one.
1233 return aDoc.PreferredColorScheme();
1235 if (supportsDark || supportsLight) {
1236 // One color-scheme is explicitly supported and one isn't, so use the one
1237 // the content supports.
1238 return supportsDark ? ColorScheme::Dark : ColorScheme::Light;
1240 // No value specified. Chrome docs always supports both, so use the preferred
1241 // color-scheme.
1242 if (nsContentUtils::IsChromeDoc(&aDoc)) {
1243 return aDoc.PreferredColorScheme();
1245 // Default content to light.
1246 return ColorScheme::Light;
1249 LookAndFeel::ColorScheme LookAndFeel::ColorSchemeForFrame(
1250 const nsIFrame* aFrame) {
1251 return ColorSchemeForStyle(*aFrame->PresContext()->Document(),
1252 aFrame->StyleUI()->mColorScheme.bits);
1255 // static
1256 Maybe<nscolor> LookAndFeel::GetColor(ColorID aId, ColorScheme aScheme,
1257 UseStandins aUseStandins) {
1258 nscolor result;
1259 nsresult rv = nsLookAndFeel::GetInstance()->GetColorValue(
1260 aId, aScheme, aUseStandins, result);
1261 if (NS_FAILED(rv)) {
1262 return Nothing();
1264 return Some(result);
1267 // Returns whether there is a CSS color name for this color.
1268 static bool ColorIsCSSAccessible(LookAndFeel::ColorID aId) {
1269 using ColorID = LookAndFeel::ColorID;
1271 switch (aId) {
1272 case ColorID::TextSelectDisabledBackground:
1273 case ColorID::TextSelectAttentionBackground:
1274 case ColorID::TextSelectAttentionForeground:
1275 case ColorID::TextHighlightBackground:
1276 case ColorID::TextHighlightForeground:
1277 case ColorID::ThemedScrollbar:
1278 case ColorID::ThemedScrollbarInactive:
1279 case ColorID::ThemedScrollbarThumb:
1280 case ColorID::ThemedScrollbarThumbActive:
1281 case ColorID::ThemedScrollbarThumbInactive:
1282 case ColorID::ThemedScrollbarThumbHover:
1283 case ColorID::IMERawInputBackground:
1284 case ColorID::IMERawInputForeground:
1285 case ColorID::IMERawInputUnderline:
1286 case ColorID::IMESelectedRawTextBackground:
1287 case ColorID::IMESelectedRawTextForeground:
1288 case ColorID::IMESelectedRawTextUnderline:
1289 case ColorID::IMEConvertedTextBackground:
1290 case ColorID::IMEConvertedTextForeground:
1291 case ColorID::IMEConvertedTextUnderline:
1292 case ColorID::IMESelectedConvertedTextBackground:
1293 case ColorID::IMESelectedConvertedTextForeground:
1294 case ColorID::IMESelectedConvertedTextUnderline:
1295 case ColorID::SpellCheckerUnderline:
1296 return false;
1297 default:
1298 break;
1301 return true;
1304 LookAndFeel::UseStandins LookAndFeel::ShouldUseStandins(
1305 const dom::Document& aDoc, ColorID aId) {
1306 if (ShouldUseStandinsForNativeColorForNonNativeTheme(aDoc, aId)) {
1307 return UseStandins::Yes;
1309 if (nsContentUtils::UseStandinsForNativeColors() &&
1310 ColorIsCSSAccessible(aId) && !nsContentUtils::IsChromeDoc(&aDoc)) {
1311 return UseStandins::Yes;
1313 if (aDoc.IsStaticDocument() &&
1314 !PreferenceSheet::ContentPrefs().mUseDocumentColors) {
1315 return UseStandins::Yes;
1317 return UseStandins::No;
1320 Maybe<nscolor> LookAndFeel::GetColor(ColorID aId, const nsIFrame* aFrame) {
1321 const auto* doc = aFrame->PresContext()->Document();
1322 return GetColor(aId, ColorSchemeForFrame(aFrame),
1323 ShouldUseStandins(*doc, aId));
1326 // static
1327 nsresult LookAndFeel::GetInt(IntID aID, int32_t* aResult) {
1328 return nsLookAndFeel::GetInstance()->GetIntValue(aID, *aResult);
1331 // static
1332 nsresult LookAndFeel::GetFloat(FloatID aID, float* aResult) {
1333 return nsLookAndFeel::GetInstance()->GetFloatValue(aID, *aResult);
1336 // static
1337 bool LookAndFeel::GetFont(FontID aID, nsString& aName, gfxFontStyle& aStyle) {
1338 return nsLookAndFeel::GetInstance()->GetFontValue(aID, aName, aStyle);
1341 // static
1342 char16_t LookAndFeel::GetPasswordCharacter() {
1343 return nsLookAndFeel::GetInstance()->GetPasswordCharacterImpl();
1346 // static
1347 bool LookAndFeel::GetEchoPassword() {
1348 if (StaticPrefs::editor_password_mask_delay() >= 0) {
1349 return StaticPrefs::editor_password_mask_delay() > 0;
1351 return nsLookAndFeel::GetInstance()->GetEchoPasswordImpl();
1354 // static
1355 uint32_t LookAndFeel::GetPasswordMaskDelay() {
1356 int32_t delay = StaticPrefs::editor_password_mask_delay();
1357 if (delay < 0) {
1358 return nsLookAndFeel::GetInstance()->GetPasswordMaskDelayImpl();
1360 return delay;
1363 bool LookAndFeel::DrawInTitlebar() {
1364 switch (StaticPrefs::browser_tabs_inTitlebar()) {
1365 case 0:
1366 return false;
1367 case 1:
1368 return true;
1369 default:
1370 break;
1372 return nsLookAndFeel::GetInstance()->GetDefaultDrawInTitlebar();
1375 void LookAndFeel::GetThemeInfo(nsACString& aOut) {
1376 nsLookAndFeel::GetInstance()->GetThemeInfo(aOut);
1379 // static
1380 void LookAndFeel::Refresh() {
1381 nsLookAndFeel::GetInstance()->RefreshImpl();
1382 widget::Theme::LookAndFeelChanged();
1385 // static
1386 void LookAndFeel::NativeInit() { nsLookAndFeel::GetInstance()->NativeInit(); }
1388 // static
1389 void LookAndFeel::SetData(widget::FullLookAndFeel&& aTables) {
1390 nsLookAndFeel::GetInstance()->SetDataImpl(std::move(aTables));
1393 } // namespace mozilla