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