Bug 1691099 [wpt PR 27512] - Reorganize and augment beacon wpt, a=testonly
[gecko.git] / widget / nsXPLookAndFeel.cpp
blob3f981980814468a242273991967e2ff60f4d83ba
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 "nsIXULRuntime.h"
18 #include "nsNativeBasicTheme.h"
19 #include "mozilla/dom/ContentChild.h"
20 #include "mozilla/Preferences.h"
21 #include "mozilla/Services.h"
22 #include "mozilla/ServoStyleSet.h"
23 #include "mozilla/StaticPrefs_editor.h"
24 #include "mozilla/StaticPrefs_findbar.h"
25 #include "mozilla/StaticPrefs_ui.h"
26 #include "mozilla/StaticPrefs_widget.h"
27 #include "mozilla/gfx/2D.h"
28 #include "mozilla/widget/WidgetMessageUtils.h"
29 #include "mozilla/Telemetry.h"
30 #include "mozilla/TelemetryScalarEnums.h"
32 #include "gfxPlatform.h"
34 #include "qcms.h"
36 #ifdef DEBUG
37 # include "nsSize.h"
38 #endif
40 using namespace mozilla;
42 // To make one of these prefs toggleable from a reftest add a user
43 // pref in testing/profiles/reftest/user.js. For example, to make
44 // ui.useAccessibilityTheme toggleable, add:
46 // user_pref("ui.useAccessibilityTheme", 0);
48 nsLookAndFeelIntPref nsXPLookAndFeel::sIntPrefs[] = {
49 {"ui.caretBlinkTime", IntID::CaretBlinkTime, false, 0},
50 {"ui.caretWidth", IntID::CaretWidth, false, 0},
51 {"ui.caretVisibleWithSelection", IntID::ShowCaretDuringSelection, false, 0},
52 {"ui.submenuDelay", IntID::SubmenuDelay, false, 0},
53 {"ui.dragThresholdX", IntID::DragThresholdX, false, 0},
54 {"ui.dragThresholdY", IntID::DragThresholdY, false, 0},
55 {"ui.useAccessibilityTheme", IntID::UseAccessibilityTheme, false, 0},
56 {"ui.menusCanOverlapOSBar", IntID::MenusCanOverlapOSBar, false, 0},
57 {"ui.useOverlayScrollbars", IntID::UseOverlayScrollbars, false, 0},
58 {"ui.scrollbarDisplayOnMouseMove", IntID::ScrollbarDisplayOnMouseMove,
59 false, 0},
60 {"ui.scrollbarFadeBeginDelay", IntID::ScrollbarFadeBeginDelay, false, 0},
61 {"ui.scrollbarFadeDuration", IntID::ScrollbarFadeDuration, false, 0},
62 {"ui.showHideScrollbars", IntID::ShowHideScrollbars, false, 0},
63 {"ui.skipNavigatingDisabledMenuItem", IntID::SkipNavigatingDisabledMenuItem,
64 false, 0},
65 {"ui.treeOpenDelay", IntID::TreeOpenDelay, false, 0},
66 {"ui.treeCloseDelay", IntID::TreeCloseDelay, false, 0},
67 {"ui.treeLazyScrollDelay", IntID::TreeLazyScrollDelay, false, 0},
68 {"ui.treeScrollDelay", IntID::TreeScrollDelay, false, 0},
69 {"ui.treeScrollLinesMax", IntID::TreeScrollLinesMax, false, 0},
70 {"accessibility.tabfocus", IntID::TabFocusModel, false, 0},
71 {"ui.alertNotificationOrigin", IntID::AlertNotificationOrigin, false, 0},
72 {"ui.scrollToClick", IntID::ScrollToClick, false, 0},
73 {"ui.IMERawInputUnderlineStyle", IntID::IMERawInputUnderlineStyle, false,
74 0},
75 {"ui.IMESelectedRawTextUnderlineStyle",
76 IntID::IMESelectedRawTextUnderlineStyle, false, 0},
77 {"ui.IMEConvertedTextUnderlineStyle", IntID::IMEConvertedTextUnderlineStyle,
78 false, 0},
79 {"ui.IMESelectedConvertedTextUnderlineStyle",
80 IntID::IMESelectedConvertedTextUnderline, false, 0},
81 {"ui.SpellCheckerUnderlineStyle", IntID::SpellCheckerUnderlineStyle, false,
82 0},
83 {"ui.scrollbarButtonAutoRepeatBehavior",
84 IntID::ScrollbarButtonAutoRepeatBehavior, false, 0},
85 {"ui.tooltipDelay", IntID::TooltipDelay, false, 0},
86 {"ui.contextMenuOffsetVertical", IntID::ContextMenuOffsetVertical, false,
87 0},
88 {"ui.contextMenuOffsetHorizontal", IntID::ContextMenuOffsetHorizontal,
89 false, 0},
90 {"ui.GtkCSDAvailable", IntID::GTKCSDAvailable, false, 0},
91 {"ui.GtkCSDHideTitlebarByDefault", IntID::GTKCSDHideTitlebarByDefault,
92 false, 0},
93 {"ui.GtkCSDTransparentBackground", IntID::GTKCSDTransparentBackground,
94 false, 0},
95 {"ui.GtkCSDMinimizeButton", IntID::GTKCSDMinimizeButton, false, 0},
96 {"ui.GtkCSDMaximizeButton", IntID::GTKCSDMaximizeButton, false, 0},
97 {"ui.GtkCSDCloseButton", IntID::GTKCSDCloseButton, false, 0},
98 {"ui.systemUsesDarkTheme", IntID::SystemUsesDarkTheme, false, 0},
99 {"ui.prefersReducedMotion", IntID::PrefersReducedMotion, false, 0},
100 {"ui.primaryPointerCapabilities", IntID::PrimaryPointerCapabilities, false,
101 6 /* fine and hover-capable pointer, i.e. mouse-type */},
102 {"ui.allPointerCapabilities", IntID::AllPointerCapabilities, false,
103 6 /* fine and hover-capable pointer, i.e. mouse-type */},
104 {"ui.scrollArrowStyle", IntID::ScrollArrowStyle, false, 0},
107 nsLookAndFeelFloatPref nsXPLookAndFeel::sFloatPrefs[] = {
108 {"ui.IMEUnderlineRelativeSize", FloatID::IMEUnderlineRelativeSize, false,
110 {"ui.SpellCheckerUnderlineRelativeSize",
111 FloatID::SpellCheckerUnderlineRelativeSize, false, 0},
112 {"ui.caretAspectRatio", FloatID::CaretAspectRatio, false, 0},
115 // This array MUST be kept in the same order as the color list in
116 // specified/color.rs
117 /* XXX If you add any strings longer than
118 * "ui.-moz-mac-active-source-list-selection"
119 * to the following array then you MUST update the
120 * sizes of the sColorPrefs array in nsXPLookAndFeel.h
122 const char nsXPLookAndFeel::sColorPrefs[][41] = {
123 "ui.windowBackground",
124 "ui.windowForeground",
125 "ui.widgetBackground",
126 "ui.widgetForeground",
127 "ui.widgetSelectBackground",
128 "ui.widgetSelectForeground",
129 "ui.widget3DHighlight",
130 "ui.widget3DShadow",
131 "ui.textBackground",
132 "ui.textForeground",
133 "ui.textSelectBackground",
134 "ui.textSelectForeground",
135 "ui.textSelectForegroundCustom",
136 "ui.textSelectBackgroundDisabled",
137 "ui.textSelectBackgroundAttention",
138 "ui.textHighlightBackground",
139 "ui.textHighlightForeground",
140 "ui.IMERawInputBackground",
141 "ui.IMERawInputForeground",
142 "ui.IMERawInputUnderline",
143 "ui.IMESelectedRawTextBackground",
144 "ui.IMESelectedRawTextForeground",
145 "ui.IMESelectedRawTextUnderline",
146 "ui.IMEConvertedTextBackground",
147 "ui.IMEConvertedTextForeground",
148 "ui.IMEConvertedTextUnderline",
149 "ui.IMESelectedConvertedTextBackground",
150 "ui.IMESelectedConvertedTextForeground",
151 "ui.IMESelectedConvertedTextUnderline",
152 "ui.SpellCheckerUnderline",
153 "ui.themedScrollbar",
154 "ui.themedScrollbarInactive",
155 "ui.themedScrollbarThumb",
156 "ui.themedScrollbarThumbHover",
157 "ui.themedScrollbarThumbActive",
158 "ui.themedScrollbarThumbInactive",
159 "ui.activeborder",
160 "ui.activecaption",
161 "ui.appworkspace",
162 "ui.background",
163 "ui.buttonface",
164 "ui.buttonhighlight",
165 "ui.buttonshadow",
166 "ui.buttontext",
167 "ui.captiontext",
168 "ui.-moz-field",
169 "ui.-moz-fieldtext",
170 "ui.graytext",
171 "ui.highlight",
172 "ui.highlighttext",
173 "ui.inactiveborder",
174 "ui.inactivecaption",
175 "ui.inactivecaptiontext",
176 "ui.infobackground",
177 "ui.infotext",
178 "ui.menu",
179 "ui.menutext",
180 "ui.scrollbar",
181 "ui.threeddarkshadow",
182 "ui.threedface",
183 "ui.threedhighlight",
184 "ui.threedlightshadow",
185 "ui.threedshadow",
186 "ui.window",
187 "ui.windowframe",
188 "ui.windowtext",
189 "ui.-moz-buttondefault",
190 "ui.-moz-default-color",
191 "ui.-moz-default-background-color",
192 "ui.-moz-dialog",
193 "ui.-moz-dialogtext",
194 "ui.-moz-dragtargetzone",
195 "ui.-moz-cellhighlight",
196 "ui.-moz_cellhighlighttext",
197 "ui.-moz-html-cellhighlight",
198 "ui.-moz-html-cellhighlighttext",
199 "ui.-moz-buttonhoverface",
200 "ui.-moz_buttonhovertext",
201 "ui.-moz_menuhover",
202 "ui.-moz_menuhovertext",
203 "ui.-moz_menubartext",
204 "ui.-moz_menubarhovertext",
205 "ui.-moz_eventreerow",
206 "ui.-moz_oddtreerow",
207 "ui.-moz-gtk-buttonactivetext",
208 "ui.-moz-mac-buttonactivetext",
209 "ui.-moz_mac_chrome_active",
210 "ui.-moz_mac_chrome_inactive",
211 "ui.-moz-mac-defaultbuttontext",
212 "ui.-moz-mac-focusring",
213 "ui.-moz-mac-menuselect",
214 "ui.-moz-mac-menushadow",
215 "ui.-moz-mac-menutextdisable",
216 "ui.-moz-mac-menutextselect",
217 "ui.-moz_mac_disabledtoolbartext",
218 "ui.-moz-mac-secondaryhighlight",
219 "ui.-moz-mac-vibrancy-light",
220 "ui.-moz-mac-vibrancy-dark",
221 "ui.-moz-mac-vibrant-titlebar-light",
222 "ui.-moz-mac-vibrant-titlebar-dark",
223 "ui.-moz-mac-menupopup",
224 "ui.-moz-mac-menuitem",
225 "ui.-moz-mac-active-menuitem",
226 "ui.-moz-mac-source-list",
227 "ui.-moz-mac-source-list-selection",
228 "ui.-moz-mac-active-source-list-selection",
229 "ui.-moz-mac-tooltip",
230 "ui.-moz-accent-color",
231 "ui.-moz-accent-color-foreground",
232 "ui.-moz-win-accentcolor",
233 "ui.-moz-win-accentcolortext",
234 "ui.-moz-win-mediatext",
235 "ui.-moz-win-communicationstext",
236 "ui.-moz-nativehyperlinktext",
237 "ui.-moz-hyperlinktext",
238 "ui.-moz-activehyperlinktext",
239 "ui.-moz-visitedhyperlinktext",
240 "ui.-moz-comboboxtext",
241 "ui.-moz-combobox",
242 "ui.-moz-gtk-info-bar-text",
243 "ui.-moz-colheadertext",
244 "ui.-moz-colheaderhovertext"};
246 int32_t nsXPLookAndFeel::sCachedColors[size_t(LookAndFeel::ColorID::End)] = {0};
247 int32_t nsXPLookAndFeel::sCachedColorBits[COLOR_CACHE_SIZE] = {0};
249 bool nsXPLookAndFeel::sInitialized = false;
251 nsXPLookAndFeel* nsXPLookAndFeel::sInstance = nullptr;
252 bool nsXPLookAndFeel::sShutdown = false;
254 // static
255 nsXPLookAndFeel* nsXPLookAndFeel::GetInstance() {
256 if (sInstance) {
257 return sInstance;
260 NS_ENSURE_TRUE(!sShutdown, nullptr);
262 // If we're in a content process, then the parent process will have supplied
263 // us with an initial FullLookAndFeel object (for when the RemoteLookAndFeel
264 // is to be used) or an initial LookAndFeelCache object (for regular
265 // LookAndFeel implementations). We grab this data from the ContentChild,
266 // where it's been temporarily stashed, and initialize our new LookAndFeel
267 // object with it.
269 LookAndFeelCache* lnfCache = nullptr;
270 FullLookAndFeel* fullLnf = nullptr;
271 widget::LookAndFeelData* lnfData = nullptr;
273 if (auto* cc = mozilla::dom::ContentChild::GetSingleton()) {
274 lnfData = &cc->BorrowLookAndFeelData();
275 switch (lnfData->type()) {
276 case widget::LookAndFeelData::TLookAndFeelCache:
277 lnfCache = &lnfData->get_LookAndFeelCache();
278 break;
279 case widget::LookAndFeelData::TFullLookAndFeel:
280 fullLnf = &lnfData->get_FullLookAndFeel();
281 break;
282 default:
283 MOZ_ASSERT_UNREACHABLE("unexpected LookAndFeelData type");
287 if (fullLnf) {
288 sInstance = new widget::RemoteLookAndFeel(std::move(*fullLnf));
289 } else if (gfxPlatform::IsHeadless()) {
290 sInstance = new widget::HeadlessLookAndFeel(lnfCache);
291 } else {
292 sInstance = new nsLookAndFeel(lnfCache);
295 // This is only ever used once during initialization, and can be cleared now.
296 if (lnfData) {
297 *lnfData = widget::LookAndFeelData{};
300 nsNativeBasicTheme::Init();
301 return sInstance;
304 // static
305 void nsXPLookAndFeel::Shutdown() {
306 if (sShutdown) {
307 return;
309 sShutdown = true;
310 delete sInstance;
311 sInstance = nullptr;
312 nsNativeBasicTheme::Shutdown();
315 // static
316 void nsXPLookAndFeel::IntPrefChanged(nsLookAndFeelIntPref* data) {
317 if (!data) {
318 return;
321 int32_t intpref;
322 nsresult rv = Preferences::GetInt(data->name, &intpref);
323 if (NS_FAILED(rv)) {
324 data->isSet = false;
326 #ifdef DEBUG_akkana
327 printf("====== Cleared int pref %s\n", data->name);
328 #endif
329 } else {
330 data->intVar = intpref;
331 data->isSet = true;
333 #ifdef DEBUG_akkana
334 printf("====== Changed int pref %s to %d\n", data->name, data->intVar);
335 #endif
338 // Int prefs can't change our system colors or fonts.
339 NotifyChangedAllWindows(widget::ThemeChangeKind::MediaQueriesOnly);
342 // static
343 void nsXPLookAndFeel::FloatPrefChanged(nsLookAndFeelFloatPref* data) {
344 if (!data) {
345 return;
348 int32_t intpref;
349 nsresult rv = Preferences::GetInt(data->name, &intpref);
350 if (NS_FAILED(rv)) {
351 data->isSet = false;
353 #ifdef DEBUG_akkana
354 printf("====== Cleared float pref %s\n", data->name);
355 #endif
356 } else {
357 data->floatVar = (float)intpref / 100.0f;
358 data->isSet = true;
360 #ifdef DEBUG_akkana
361 printf("====== Changed float pref %s to %f\n", data->name);
362 #endif
365 // Float prefs can't change our system colors or fonts.
366 NotifyChangedAllWindows(widget::ThemeChangeKind::MediaQueriesOnly);
369 // static
370 void nsXPLookAndFeel::ColorPrefChanged(unsigned int index,
371 const char* prefName) {
372 nsAutoString colorStr;
373 nsresult rv = Preferences::GetString(prefName, colorStr);
374 if (NS_SUCCEEDED(rv) && !colorStr.IsEmpty()) {
375 nscolor thecolor;
376 if (colorStr[0] == char16_t('#')) {
377 if (NS_HexToRGBA(nsDependentString(colorStr, 1), nsHexColorType::NoAlpha,
378 &thecolor)) {
379 int32_t id = NS_PTR_TO_INT32(index);
380 CACHE_COLOR(id, thecolor);
382 } else if (NS_ColorNameToRGB(colorStr, &thecolor)) {
383 int32_t id = NS_PTR_TO_INT32(index);
384 CACHE_COLOR(id, thecolor);
385 #ifdef DEBUG_akkana
386 printf("====== Changed color pref %s to 0x%lx\n", prefName, thecolor);
387 #endif
389 } else {
390 // Reset to the default color, by clearing the cache
391 // to force lookup when the color is next used
392 int32_t id = NS_PTR_TO_INT32(index);
393 CLEAR_COLOR_CACHE(id);
395 #ifdef DEBUG_akkana
396 printf("====== Cleared color pref %s\n", prefName);
397 #endif
400 // Color prefs affect style, because they by definition change system colors.
401 NotifyChangedAllWindows(widget::ThemeChangeKind::Style);
404 void nsXPLookAndFeel::InitFromPref(nsLookAndFeelIntPref* aPref) {
405 int32_t intpref;
406 nsresult rv = Preferences::GetInt(aPref->name, &intpref);
407 if (NS_SUCCEEDED(rv)) {
408 aPref->isSet = true;
409 aPref->intVar = intpref;
413 void nsXPLookAndFeel::InitFromPref(nsLookAndFeelFloatPref* aPref) {
414 int32_t intpref;
415 nsresult rv = Preferences::GetInt(aPref->name, &intpref);
416 if (NS_SUCCEEDED(rv)) {
417 aPref->isSet = true;
418 aPref->floatVar = (float)intpref / 100.0f;
422 void nsXPLookAndFeel::InitColorFromPref(int32_t i) {
423 static_assert(ArrayLength(sColorPrefs) == size_t(ColorID::End),
424 "Should have a pref for each color value");
426 nsAutoString colorStr;
427 nsresult rv = Preferences::GetString(sColorPrefs[i], colorStr);
428 if (NS_FAILED(rv) || colorStr.IsEmpty()) {
429 return;
431 nscolor thecolor;
432 if (colorStr[0] == char16_t('#')) {
433 nsAutoString hexString;
434 colorStr.Right(hexString, colorStr.Length() - 1);
435 if (NS_HexToRGBA(hexString, nsHexColorType::NoAlpha, &thecolor)) {
436 CACHE_COLOR(i, thecolor);
438 } else if (NS_ColorNameToRGB(colorStr, &thecolor)) {
439 CACHE_COLOR(i, thecolor);
443 // static
444 void nsXPLookAndFeel::OnPrefChanged(const char* aPref, void* aClosure) {
445 // looping in the same order as in ::Init
447 nsDependentCString prefName(aPref);
448 unsigned int i;
449 for (i = 0; i < ArrayLength(sIntPrefs); ++i) {
450 if (prefName.Equals(sIntPrefs[i].name)) {
451 IntPrefChanged(&sIntPrefs[i]);
452 return;
456 for (i = 0; i < ArrayLength(sFloatPrefs); ++i) {
457 if (prefName.Equals(sFloatPrefs[i].name)) {
458 FloatPrefChanged(&sFloatPrefs[i]);
459 return;
463 for (i = 0; i < ArrayLength(sColorPrefs); ++i) {
464 if (prefName.Equals(sColorPrefs[i])) {
465 ColorPrefChanged(i, sColorPrefs[i]);
466 return;
472 // Read values from the user's preferences.
473 // This is done once at startup, but since the user's preferences
474 // haven't actually been read yet at that time, we also have to
475 // set a callback to inform us of changes to each pref.
477 void nsXPLookAndFeel::Init() {
478 MOZ_RELEASE_ASSERT(NS_IsMainThread());
480 // Say we're already initialized, and take the chance that it might fail;
481 // protects against some other process writing to our static variables.
482 sInitialized = true;
484 // XXX If we could reorganize the pref names, we should separate the branch
485 // for each types. Then, we could reduce the unnecessary loop from
486 // nsXPLookAndFeel::OnPrefChanged().
487 Preferences::RegisterPrefixCallback(OnPrefChanged, "ui.");
488 // We really do just want the accessibility.tabfocus pref, not other prefs
489 // that start with that string.
490 Preferences::RegisterCallback(OnPrefChanged, "accessibility.tabfocus");
492 unsigned int i;
493 for (i = 0; i < ArrayLength(sIntPrefs); ++i) {
494 InitFromPref(&sIntPrefs[i]);
497 for (i = 0; i < ArrayLength(sFloatPrefs); ++i) {
498 InitFromPref(&sFloatPrefs[i]);
501 for (i = 0; i < ArrayLength(sColorPrefs); ++i) {
502 InitColorFromPref(i);
506 nsXPLookAndFeel::~nsXPLookAndFeel() {
507 NS_ASSERTION(sInstance == this,
508 "This destroying instance isn't the singleton instance");
509 sInstance = nullptr;
512 bool nsXPLookAndFeel::IsSpecialColor(ColorID aID, nscolor& aColor) {
513 switch (aID) {
514 case ColorID::TextSelectForeground:
515 return (aColor == NS_DONT_CHANGE_COLOR);
516 case ColorID::IMESelectedRawTextBackground:
517 case ColorID::IMESelectedConvertedTextBackground:
518 case ColorID::IMERawInputBackground:
519 case ColorID::IMEConvertedTextBackground:
520 case ColorID::IMESelectedRawTextForeground:
521 case ColorID::IMESelectedConvertedTextForeground:
522 case ColorID::IMERawInputForeground:
523 case ColorID::IMEConvertedTextForeground:
524 case ColorID::IMERawInputUnderline:
525 case ColorID::IMEConvertedTextUnderline:
526 case ColorID::IMESelectedRawTextUnderline:
527 case ColorID::IMESelectedConvertedTextUnderline:
528 case ColorID::SpellCheckerUnderline:
529 return NS_IS_SELECTION_SPECIAL_COLOR(aColor);
530 default:
532 * In GetColor(), every color that is not a special color is color
533 * corrected. Use false to make other colors color corrected.
535 return false;
537 return false;
540 bool nsXPLookAndFeel::ColorIsNotCSSAccessible(ColorID aID) {
541 switch (aID) {
542 case ColorID::WindowBackground:
543 case ColorID::WindowForeground:
544 case ColorID::WidgetBackground:
545 case ColorID::WidgetForeground:
546 case ColorID::WidgetSelectBackground:
547 case ColorID::WidgetSelectForeground:
548 case ColorID::Widget3DHighlight:
549 case ColorID::Widget3DShadow:
550 case ColorID::TextBackground:
551 case ColorID::TextForeground:
552 case ColorID::TextSelectBackground:
553 case ColorID::TextSelectForeground:
554 case ColorID::TextSelectBackgroundDisabled:
555 case ColorID::TextSelectBackgroundAttention:
556 case ColorID::TextHighlightBackground:
557 case ColorID::TextHighlightForeground:
558 case ColorID::IMERawInputBackground:
559 case ColorID::IMERawInputForeground:
560 case ColorID::IMERawInputUnderline:
561 case ColorID::IMESelectedRawTextBackground:
562 case ColorID::IMESelectedRawTextForeground:
563 case ColorID::IMESelectedRawTextUnderline:
564 case ColorID::IMEConvertedTextBackground:
565 case ColorID::IMEConvertedTextForeground:
566 case ColorID::IMEConvertedTextUnderline:
567 case ColorID::IMESelectedConvertedTextBackground:
568 case ColorID::IMESelectedConvertedTextForeground:
569 case ColorID::IMESelectedConvertedTextUnderline:
570 case ColorID::SpellCheckerUnderline:
571 return true;
572 default:
573 break;
576 return false;
579 nscolor nsXPLookAndFeel::GetStandinForNativeColor(ColorID aID) {
580 nscolor result = NS_RGB(0xFF, 0xFF, 0xFF);
582 // The stand-in colors are taken from the Windows 7 Aero theme
583 // except Mac-specific colors which are taken from Mac OS 10.7.
584 switch (aID) {
585 // CSS 2 colors:
586 case ColorID::Activeborder:
587 result = NS_RGB(0xB4, 0xB4, 0xB4);
588 break;
589 case ColorID::Activecaption:
590 result = NS_RGB(0x99, 0xB4, 0xD1);
591 break;
592 case ColorID::Appworkspace:
593 result = NS_RGB(0xAB, 0xAB, 0xAB);
594 break;
595 case ColorID::Background:
596 result = NS_RGB(0x00, 0x00, 0x00);
597 break;
598 case ColorID::Buttonface:
599 result = NS_RGB(0xF0, 0xF0, 0xF0);
600 break;
601 case ColorID::Buttonhighlight:
602 result = NS_RGB(0xFF, 0xFF, 0xFF);
603 break;
604 case ColorID::Buttonshadow:
605 result = NS_RGB(0xA0, 0xA0, 0xA0);
606 break;
607 case ColorID::Buttontext:
608 result = NS_RGB(0x00, 0x00, 0x00);
609 break;
610 case ColorID::Captiontext:
611 result = NS_RGB(0x00, 0x00, 0x00);
612 break;
613 case ColorID::Graytext:
614 result = NS_RGB(0x6D, 0x6D, 0x6D);
615 break;
616 case ColorID::Highlight:
617 result = NS_RGB(0x33, 0x99, 0xFF);
618 break;
619 case ColorID::Highlighttext:
620 result = NS_RGB(0xFF, 0xFF, 0xFF);
621 break;
622 case ColorID::Inactiveborder:
623 result = NS_RGB(0xF4, 0xF7, 0xFC);
624 break;
625 case ColorID::Inactivecaption:
626 result = NS_RGB(0xBF, 0xCD, 0xDB);
627 break;
628 case ColorID::Inactivecaptiontext:
629 result = NS_RGB(0x43, 0x4E, 0x54);
630 break;
631 case ColorID::Infobackground:
632 result = NS_RGB(0xFF, 0xFF, 0xE1);
633 break;
634 case ColorID::Infotext:
635 result = NS_RGB(0x00, 0x00, 0x00);
636 break;
637 case ColorID::Menu:
638 result = NS_RGB(0xF0, 0xF0, 0xF0);
639 break;
640 case ColorID::Menutext:
641 result = NS_RGB(0x00, 0x00, 0x00);
642 break;
643 case ColorID::Scrollbar:
644 result = NS_RGB(0xC8, 0xC8, 0xC8);
645 break;
646 case ColorID::Threeddarkshadow:
647 result = NS_RGB(0x69, 0x69, 0x69);
648 break;
649 case ColorID::Threedface:
650 result = NS_RGB(0xF0, 0xF0, 0xF0);
651 break;
652 case ColorID::Threedhighlight:
653 result = NS_RGB(0xFF, 0xFF, 0xFF);
654 break;
655 case ColorID::Threedlightshadow:
656 result = NS_RGB(0xE3, 0xE3, 0xE3);
657 break;
658 case ColorID::Threedshadow:
659 result = NS_RGB(0xA0, 0xA0, 0xA0);
660 break;
661 case ColorID::Window:
662 result = NS_RGB(0xFF, 0xFF, 0xFF);
663 break;
664 case ColorID::Windowframe:
665 result = NS_RGB(0x64, 0x64, 0x64);
666 break;
667 case ColorID::Windowtext:
668 result = NS_RGB(0x00, 0x00, 0x00);
669 break;
670 case ColorID::MozButtondefault:
671 result = NS_RGB(0x69, 0x69, 0x69);
672 break;
673 case ColorID::Field:
674 result = NS_RGB(0xFF, 0xFF, 0xFF);
675 break;
676 case ColorID::Fieldtext:
677 result = NS_RGB(0x00, 0x00, 0x00);
678 break;
679 case ColorID::MozDialog:
680 result = NS_RGB(0xF0, 0xF0, 0xF0);
681 break;
682 case ColorID::MozDialogtext:
683 case ColorID::MozColheadertext:
684 case ColorID::MozColheaderhovertext:
685 result = NS_RGB(0x00, 0x00, 0x00);
686 break;
687 case ColorID::MozDragtargetzone:
688 result = NS_RGB(0xFF, 0xFF, 0xFF);
689 break;
690 case ColorID::MozCellhighlight:
691 result = NS_RGB(0xF0, 0xF0, 0xF0);
692 break;
693 case ColorID::MozCellhighlighttext:
694 result = NS_RGB(0x00, 0x00, 0x00);
695 break;
696 case ColorID::MozHtmlCellhighlight:
697 result = NS_RGB(0x33, 0x99, 0xFF);
698 break;
699 case ColorID::MozHtmlCellhighlighttext:
700 result = NS_RGB(0xFF, 0xFF, 0xFF);
701 break;
702 case ColorID::MozButtonhoverface:
703 result = NS_RGB(0xF0, 0xF0, 0xF0);
704 break;
705 case ColorID::MozGtkButtonactivetext:
706 case ColorID::MozButtonhovertext:
707 result = NS_RGB(0x00, 0x00, 0x00);
708 break;
709 case ColorID::MozMenuhover:
710 result = NS_RGB(0x33, 0x99, 0xFF);
711 break;
712 case ColorID::MozMenuhovertext:
713 result = NS_RGB(0x00, 0x00, 0x00);
714 break;
715 case ColorID::MozMenubartext:
716 result = NS_RGB(0x00, 0x00, 0x00);
717 break;
718 case ColorID::MozMenubarhovertext:
719 result = NS_RGB(0x00, 0x00, 0x00);
720 break;
721 case ColorID::MozOddtreerow:
722 result = NS_RGB(0xFF, 0xFF, 0xFF);
723 break;
724 case ColorID::MozMacChromeActive:
725 result = NS_RGB(0xB2, 0xB2, 0xB2);
726 break;
727 case ColorID::MozMacChromeInactive:
728 result = NS_RGB(0xE1, 0xE1, 0xE1);
729 break;
730 case ColorID::MozMacFocusring:
731 result = NS_RGB(0x60, 0x9D, 0xD7);
732 break;
733 case ColorID::MozMacMenuselect:
734 result = NS_RGB(0x38, 0x75, 0xD7);
735 break;
736 case ColorID::MozMacMenushadow:
737 result = NS_RGB(0xA3, 0xA3, 0xA3);
738 break;
739 case ColorID::MozMacMenutextdisable:
740 result = NS_RGB(0x88, 0x88, 0x88);
741 break;
742 case ColorID::MozMacMenutextselect:
743 result = NS_RGB(0xFF, 0xFF, 0xFF);
744 break;
745 case ColorID::MozMacDisabledtoolbartext:
746 result = NS_RGB(0x3F, 0x3F, 0x3F);
747 break;
748 case ColorID::MozMacSecondaryhighlight:
749 result = NS_RGB(0xD4, 0xD4, 0xD4);
750 break;
751 case ColorID::MozMacVibrancyLight:
752 case ColorID::MozMacVibrantTitlebarLight:
753 result = NS_RGB(0xf7, 0xf7, 0xf7);
754 break;
755 case ColorID::MozMacVibrancyDark:
756 case ColorID::MozMacVibrantTitlebarDark:
757 result = NS_RGB(0x28, 0x28, 0x28);
758 break;
759 case ColorID::MozMacMenupopup:
760 result = NS_RGB(0xe6, 0xe6, 0xe6);
761 break;
762 case ColorID::MozMacMenuitem:
763 result = NS_RGB(0xe6, 0xe6, 0xe6);
764 break;
765 case ColorID::MozMacActiveMenuitem:
766 result = NS_RGB(0x0a, 0x64, 0xdc);
767 break;
768 case ColorID::MozMacSourceList:
769 result = NS_RGB(0xf7, 0xf7, 0xf7);
770 break;
771 case ColorID::MozMacSourceListSelection:
772 result = NS_RGB(0xc8, 0xc8, 0xc8);
773 break;
774 case ColorID::MozMacActiveSourceListSelection:
775 result = NS_RGB(0x0a, 0x64, 0xdc);
776 break;
777 case ColorID::MozMacTooltip:
778 result = NS_RGB(0xf7, 0xf7, 0xf7);
779 break;
780 case ColorID::MozWinAccentcolor:
781 // Seems to be the default color (hardcoded because of bug 1065998)
782 result = NS_RGB(0x9E, 0x9E, 0x9E);
783 break;
784 case ColorID::MozWinAccentcolortext:
785 result = NS_RGB(0x00, 0x00, 0x00);
786 break;
787 case ColorID::MozWinMediatext:
788 result = NS_RGB(0xFF, 0xFF, 0xFF);
789 break;
790 case ColorID::MozWinCommunicationstext:
791 result = NS_RGB(0xFF, 0xFF, 0xFF);
792 break;
793 case ColorID::MozNativehyperlinktext:
794 result = NS_RGB(0x00, 0x66, 0xCC);
795 break;
796 case ColorID::MozComboboxtext:
797 result = NS_RGB(0x00, 0x00, 0x00);
798 break;
799 case ColorID::MozCombobox:
800 result = NS_RGB(0xFF, 0xFF, 0xFF);
801 break;
802 default:
803 break;
806 return result;
810 // All these routines will return NS_OK if they have a value,
811 // in which case the nsLookAndFeel should use that value;
812 // otherwise we'll return NS_ERROR_NOT_AVAILABLE, in which case, the
813 // platform-specific nsLookAndFeel should use its own values instead.
815 nsresult nsXPLookAndFeel::GetColorValue(ColorID aID,
816 bool aUseStandinsForNativeColors,
817 nscolor& aResult) {
818 if (!sInitialized) Init();
820 // define DEBUG_SYSTEM_COLOR_USE if you want to debug system color
821 // use in a skin that uses them. When set, it will make all system
822 // color pairs that are appropriate for foreground/background
823 // pairing the same. This means if the skin is using system colors
824 // correctly you will not be able to see *any* text.
825 #undef DEBUG_SYSTEM_COLOR_USE
827 #ifdef DEBUG_SYSTEM_COLOR_USE
829 nsresult rv = NS_OK;
830 switch (aID) {
831 // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
832 case ColorID::Activecaption:
833 // active window caption background
834 case ColorID::Captiontext:
835 // text in active window caption
836 aResult = NS_RGB(0xff, 0x00, 0x00);
837 break;
839 case ColorID::Highlight:
840 // background of selected item
841 case ColorID::Highlighttext:
842 // text of selected item
843 aResult = NS_RGB(0xff, 0xff, 0x00);
844 break;
846 case ColorID::Inactivecaption:
847 // inactive window caption
848 case ColorID::Inactivecaptiontext:
849 // text in inactive window caption
850 aResult = NS_RGB(0x66, 0x66, 0x00);
851 break;
853 case ColorID::Infobackground:
854 // tooltip background color
855 case ColorID::Infotext:
856 // tooltip text color
857 aResult = NS_RGB(0x00, 0xff, 0x00);
858 break;
860 case ColorID::Menu:
861 // menu background
862 case ColorID::Menutext:
863 // menu text
864 aResult = NS_RGB(0x00, 0xff, 0xff);
865 break;
867 case ColorID::Threedface:
868 case ColorID::Buttonface:
869 // 3-D face color
870 case ColorID::Buttontext:
871 // text on push buttons
872 aResult = NS_RGB(0x00, 0x66, 0x66);
873 break;
875 case ColorID::Window:
876 case ColorID::Windowtext:
877 aResult = NS_RGB(0x00, 0x00, 0xff);
878 break;
880 // from the CSS3 working draft (not yet finalized)
881 // http://www.w3.org/tr/2000/wd-css3-userint-20000216.html#color
883 case ColorID::Field:
884 case ColorID::Fieldtext:
885 aResult = NS_RGB(0xff, 0x00, 0xff);
886 break;
888 case ColorID::MozDialog:
889 case ColorID::MozDialogtext:
890 aResult = NS_RGB(0x66, 0x00, 0x66);
891 break;
893 default:
894 rv = NS_ERROR_NOT_AVAILABLE;
896 if (NS_SUCCEEDED(rv)) return rv;
898 #endif // DEBUG_SYSTEM_COLOR_USE
900 if (aUseStandinsForNativeColors && ColorIsNotCSSAccessible(aID)) {
901 aUseStandinsForNativeColors = false;
904 if (!aUseStandinsForNativeColors && IS_COLOR_CACHED(aID)) {
905 aResult = sCachedColors[uint32_t(aID)];
906 return NS_OK;
909 // There are no system color settings for these, so set them manually
910 #ifndef XP_MACOSX
911 if (aID == ColorID::TextSelectBackgroundDisabled) {
912 // This is used to gray out the selection when it's not focused
913 // Used with nsISelectionController::SELECTION_DISABLED
914 aResult = NS_RGB(0xb0, 0xb0, 0xb0);
915 return NS_OK;
917 #endif
919 if (aID == ColorID::TextSelectBackgroundAttention) {
920 if (StaticPrefs::findbar_modalHighlight() && !mozilla::FissionAutostart()) {
921 aResult = NS_RGBA(0, 0, 0, 0);
922 return NS_OK;
925 // This makes the selection stand out when typeaheadfind is on
926 // Used with nsISelectionController::SELECTION_ATTENTION
927 aResult = NS_RGB(0x38, 0xd8, 0x78);
928 return NS_OK;
931 if (aID == ColorID::TextHighlightBackground) {
932 // This makes the matched text stand out when findbar highlighting is on
933 // Used with nsISelectionController::SELECTION_FIND
934 aResult = NS_RGB(0xef, 0x0f, 0xff);
935 return NS_OK;
938 if (aID == ColorID::TextHighlightForeground) {
939 // The foreground color for the matched text in findbar highlighting
940 // Used with nsISelectionController::SELECTION_FIND
941 aResult = NS_RGB(0xff, 0xff, 0xff);
942 return NS_OK;
945 if (aUseStandinsForNativeColors) {
946 aResult = GetStandinForNativeColor(aID);
947 return NS_OK;
950 if (NS_SUCCEEDED(NativeGetColor(aID, aResult))) {
951 if (!mozilla::ServoStyleSet::IsInServoTraversal()) {
952 MOZ_ASSERT(NS_IsMainThread());
953 if ((gfxPlatform::GetCMSMode() == eCMSMode_All) &&
954 !IsSpecialColor(aID, aResult)) {
955 qcms_transform* transform = gfxPlatform::GetCMSInverseRGBTransform();
956 if (transform) {
957 uint8_t color[4];
958 color[0] = NS_GET_R(aResult);
959 color[1] = NS_GET_G(aResult);
960 color[2] = NS_GET_B(aResult);
961 color[3] = NS_GET_A(aResult);
962 qcms_transform_data(transform, color, color, 1);
963 aResult = NS_RGBA(color[0], color[1], color[2], color[3]);
967 CACHE_COLOR(aID, aResult);
969 return NS_OK;
972 return NS_ERROR_NOT_AVAILABLE;
975 nsresult nsXPLookAndFeel::GetIntValue(IntID aID, int32_t& aResult) {
976 if (!sInitialized) Init();
978 for (unsigned int i = 0; i < ArrayLength(sIntPrefs); ++i) {
979 if (sIntPrefs[i].isSet && (sIntPrefs[i].id == aID)) {
980 aResult = sIntPrefs[i].intVar;
981 return NS_OK;
985 return NativeGetInt(aID, aResult);
988 nsresult nsXPLookAndFeel::GetFloatValue(FloatID aID, float& aResult) {
989 if (!sInitialized) Init();
991 for (unsigned int i = 0; i < ArrayLength(sFloatPrefs); ++i) {
992 if (sFloatPrefs[i].isSet && sFloatPrefs[i].id == aID) {
993 aResult = sFloatPrefs[i].floatVar;
994 return NS_OK;
998 return NativeGetFloat(aID, aResult);
1001 void nsXPLookAndFeel::RefreshImpl() {
1002 // Wipe out our color cache.
1003 uint32_t i;
1004 for (i = 0; i < uint32_t(ColorID::End); i++) {
1005 sCachedColors[i] = 0;
1007 for (i = 0; i < COLOR_CACHE_SIZE; i++) {
1008 sCachedColorBits[i] = 0;
1011 // Reinit color cache from prefs.
1012 for (i = 0; i < uint32_t(ColorID::End); ++i) {
1013 InitColorFromPref(i);
1016 // Clear any cached FullLookAndFeel data, which is now invalid.
1017 if (XRE_IsParentProcess()) {
1018 widget::RemoteLookAndFeel::ClearCachedData();
1022 widget::LookAndFeelCache nsXPLookAndFeel::GetCacheImpl() {
1023 return LookAndFeelCache{};
1026 static bool sRecordedLookAndFeelTelemetry = false;
1028 void nsXPLookAndFeel::RecordTelemetry() {
1029 if (!XRE_IsParentProcess()) {
1030 return;
1033 if (sRecordedLookAndFeelTelemetry) {
1034 return;
1037 sRecordedLookAndFeelTelemetry = true;
1039 int32_t i;
1040 Telemetry::ScalarSet(
1041 Telemetry::ScalarID::WIDGET_DARK_MODE,
1042 NS_SUCCEEDED(GetIntValue(IntID::SystemUsesDarkTheme, i)) && i != 0);
1044 RecordLookAndFeelSpecificTelemetry();
1047 namespace mozilla {
1049 // static
1050 void LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind aKind) {
1051 if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
1052 obs->NotifyObservers(nullptr, "look-and-feel-changed",
1053 reinterpret_cast<char16_t*>(uintptr_t(aKind)));
1057 // static
1058 nsresult LookAndFeel::GetColor(ColorID aID, nscolor* aResult) {
1059 return nsLookAndFeel::GetInstance()->GetColorValue(aID, false, *aResult);
1062 nsresult LookAndFeel::GetColor(ColorID aID, bool aUseStandinsForNativeColors,
1063 nscolor* aResult) {
1064 return nsLookAndFeel::GetInstance()->GetColorValue(
1065 aID, aUseStandinsForNativeColors, *aResult);
1068 // static
1069 nsresult LookAndFeel::GetInt(IntID aID, int32_t* aResult) {
1070 return nsLookAndFeel::GetInstance()->GetIntValue(aID, *aResult);
1073 // static
1074 nsresult LookAndFeel::GetFloat(FloatID aID, float* aResult) {
1075 return nsLookAndFeel::GetInstance()->GetFloatValue(aID, *aResult);
1078 // static
1079 bool LookAndFeel::GetFont(FontID aID, nsString& aName, gfxFontStyle& aStyle) {
1080 return nsLookAndFeel::GetInstance()->GetFontValue(aID, aName, aStyle);
1083 // static
1084 char16_t LookAndFeel::GetPasswordCharacter() {
1085 return nsLookAndFeel::GetInstance()->GetPasswordCharacterImpl();
1088 // static
1089 bool LookAndFeel::GetEchoPassword() {
1090 if (StaticPrefs::editor_password_mask_delay() >= 0) {
1091 return StaticPrefs::editor_password_mask_delay() > 0;
1093 return nsLookAndFeel::GetInstance()->GetEchoPasswordImpl();
1096 // static
1097 uint32_t LookAndFeel::GetPasswordMaskDelay() {
1098 int32_t delay = StaticPrefs::editor_password_mask_delay();
1099 if (delay < 0) {
1100 return nsLookAndFeel::GetInstance()->GetPasswordMaskDelayImpl();
1102 return delay;
1105 // static
1106 void LookAndFeel::Refresh() {
1107 nsLookAndFeel::GetInstance()->RefreshImpl();
1108 nsNativeBasicTheme::LookAndFeelChanged();
1111 // static
1112 void LookAndFeel::NativeInit() { nsLookAndFeel::GetInstance()->NativeInit(); }
1114 // static
1115 widget::LookAndFeelCache LookAndFeel::GetCache() {
1116 return nsLookAndFeel::GetInstance()->GetCacheImpl();
1119 // static
1120 void LookAndFeel::SetCache(const widget::LookAndFeelCache& aCache) {
1121 nsLookAndFeel::GetInstance()->SetCacheImpl(aCache);
1124 // static
1125 void LookAndFeel::SetData(widget::FullLookAndFeel&& aTables) {
1126 nsLookAndFeel::GetInstance()->SetDataImpl(std::move(aTables));
1129 } // namespace mozilla