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"
10 #include "nsXPLookAndFeel.h"
11 #include "nsLookAndFeel.h"
14 #include "mozilla/Preferences.h"
15 #include "mozilla/gfx/2D.h"
17 #include "gfxPlatform.h"
24 using namespace mozilla
;
26 nsLookAndFeelIntPref
nsXPLookAndFeel::sIntPrefs
[] =
28 { "ui.caretBlinkTime",
29 eIntID_CaretBlinkTime
,
34 { "ui.caretVisibleWithSelection",
35 eIntID_ShowCaretDuringSelection
,
40 { "ui.dragThresholdX",
41 eIntID_DragThresholdX
,
43 { "ui.dragThresholdY",
44 eIntID_DragThresholdY
,
46 { "ui.useAccessibilityTheme",
47 eIntID_UseAccessibilityTheme
,
49 { "ui.menusCanOverlapOSBar",
50 eIntID_MenusCanOverlapOSBar
,
52 { "ui.useOverlayScrollbars",
53 eIntID_UseOverlayScrollbars
,
55 { "ui.scrollbarDisplayOnMouseMove",
56 eIntID_ScrollbarDisplayOnMouseMove
,
58 { "ui.scrollbarFadeBeginDelay",
59 eIntID_ScrollbarFadeBeginDelay
,
61 { "ui.scrollbarFadeDuration",
62 eIntID_ScrollbarFadeDuration
,
64 { "ui.showHideScrollbars",
65 eIntID_ShowHideScrollbars
,
67 { "ui.skipNavigatingDisabledMenuItem",
68 eIntID_SkipNavigatingDisabledMenuItem
,
73 { "ui.treeCloseDelay",
74 eIntID_TreeCloseDelay
,
76 { "ui.treeLazyScrollDelay",
77 eIntID_TreeLazyScrollDelay
,
79 { "ui.treeScrollDelay",
80 eIntID_TreeScrollDelay
,
82 { "ui.treeScrollLinesMax",
83 eIntID_TreeScrollLinesMax
,
85 { "accessibility.tabfocus",
88 { "ui.alertNotificationOrigin",
89 eIntID_AlertNotificationOrigin
,
94 { "ui.IMERawInputUnderlineStyle",
95 eIntID_IMERawInputUnderlineStyle
,
97 { "ui.IMESelectedRawTextUnderlineStyle",
98 eIntID_IMESelectedRawTextUnderlineStyle
,
100 { "ui.IMEConvertedTextUnderlineStyle",
101 eIntID_IMEConvertedTextUnderlineStyle
,
103 { "ui.IMESelectedConvertedTextUnderlineStyle",
104 eIntID_IMESelectedConvertedTextUnderline
,
106 { "ui.SpellCheckerUnderlineStyle",
107 eIntID_SpellCheckerUnderlineStyle
,
109 { "ui.scrollbarButtonAutoRepeatBehavior",
110 eIntID_ScrollbarButtonAutoRepeatBehavior
,
115 { "ui.physicalHomeButton",
116 eIntID_PhysicalHomeButton
,
120 nsLookAndFeelFloatPref
nsXPLookAndFeel::sFloatPrefs
[] =
122 { "ui.IMEUnderlineRelativeSize",
123 eFloatID_IMEUnderlineRelativeSize
,
125 { "ui.SpellCheckerUnderlineRelativeSize",
126 eFloatID_SpellCheckerUnderlineRelativeSize
,
128 { "ui.caretAspectRatio",
129 eFloatID_CaretAspectRatio
,
134 // This array MUST be kept in the same order as the color list in LookAndFeel.h.
135 /* XXX If you add any strings longer than
136 * "ui.IMESelectedConvertedTextBackground"
137 * to the following array then you MUST update the
138 * sizes of the sColorPrefs array in nsXPLookAndFeel.h
140 const char nsXPLookAndFeel::sColorPrefs
[][38] =
142 "ui.windowBackground",
143 "ui.windowForeground",
144 "ui.widgetBackground",
145 "ui.widgetForeground",
146 "ui.widgetSelectBackground",
147 "ui.widgetSelectForeground",
148 "ui.widget3DHighlight",
152 "ui.textSelectBackground",
153 "ui.textSelectForeground",
154 "ui.textSelectForegroundCustom",
155 "ui.textSelectBackgroundDisabled",
156 "ui.textSelectBackgroundAttention",
157 "ui.textHighlightBackground",
158 "ui.textHighlightForeground",
159 "ui.IMERawInputBackground",
160 "ui.IMERawInputForeground",
161 "ui.IMERawInputUnderline",
162 "ui.IMESelectedRawTextBackground",
163 "ui.IMESelectedRawTextForeground",
164 "ui.IMESelectedRawTextUnderline",
165 "ui.IMEConvertedTextBackground",
166 "ui.IMEConvertedTextForeground",
167 "ui.IMEConvertedTextUnderline",
168 "ui.IMESelectedConvertedTextBackground",
169 "ui.IMESelectedConvertedTextForeground",
170 "ui.IMESelectedConvertedTextUnderline",
171 "ui.SpellCheckerUnderline",
177 "ui.buttonhighlight",
185 "ui.inactivecaption",
186 "ui.inactivecaptiontext",
192 "ui.threeddarkshadow",
194 "ui.threedhighlight",
195 "ui.threedlightshadow",
200 "ui.-moz-buttondefault",
204 "ui.-moz-dialogtext",
205 "ui.-moz-dragtargetzone",
206 "ui.-moz-cellhighlight",
207 "ui.-moz_cellhighlighttext",
208 "ui.-moz-html-cellhighlight",
209 "ui.-moz-html-cellhighlighttext",
210 "ui.-moz-buttonhoverface",
211 "ui.-moz_buttonhovertext",
213 "ui.-moz_menuhovertext",
214 "ui.-moz_menubartext",
215 "ui.-moz_menubarhovertext",
216 "ui.-moz_eventreerow",
217 "ui.-moz_oddtreerow",
218 "ui.-moz-mac-buttonactivetext",
219 "ui.-moz_mac_chrome_active",
220 "ui.-moz_mac_chrome_inactive",
221 "ui.-moz-mac-defaultbuttontext",
222 "ui.-moz-mac-focusring",
223 "ui.-moz-mac-menuselect",
224 "ui.-moz-mac-menushadow",
225 "ui.-moz-mac-menutextdisable",
226 "ui.-moz-mac-menutextselect",
227 "ui.-moz_mac_disabledtoolbartext",
228 "ui.-moz-mac-secondaryhighlight",
229 "ui.-moz-win-mediatext",
230 "ui.-moz-win-communicationstext",
231 "ui.-moz-nativehyperlinktext",
232 "ui.-moz-comboboxtext",
236 int32_t nsXPLookAndFeel::sCachedColors
[LookAndFeel::eColorID_LAST_COLOR
] = {0};
237 int32_t nsXPLookAndFeel::sCachedColorBits
[COLOR_CACHE_SIZE
] = {0};
239 bool nsXPLookAndFeel::sInitialized
= false;
240 bool nsXPLookAndFeel::sUseNativeColors
= true;
242 nsLookAndFeel
* nsXPLookAndFeel::sInstance
= nullptr;
243 bool nsXPLookAndFeel::sShutdown
= false;
247 nsXPLookAndFeel::GetInstance()
253 NS_ENSURE_TRUE(!sShutdown
, nullptr);
255 sInstance
= new nsLookAndFeel();
261 nsXPLookAndFeel::Shutdown()
271 nsXPLookAndFeel::nsXPLookAndFeel() : LookAndFeel()
277 nsXPLookAndFeel::IntPrefChanged(nsLookAndFeelIntPref
*data
)
284 nsresult rv
= Preferences::GetInt(data
->name
, &intpref
);
288 data
->intVar
= intpref
;
291 printf("====== Changed int pref %s to %d\n", data
->name
, data
->intVar
);
297 nsXPLookAndFeel::FloatPrefChanged(nsLookAndFeelFloatPref
*data
)
304 nsresult rv
= Preferences::GetInt(data
->name
, &intpref
);
308 data
->floatVar
= (float)intpref
/ 100.0f
;
311 printf("====== Changed float pref %s to %f\n", data
->name
, data
->floatVar
);
317 nsXPLookAndFeel::ColorPrefChanged (unsigned int index
, const char *prefName
)
319 nsAutoString colorStr
;
320 nsresult rv
= Preferences::GetString(prefName
, &colorStr
);
324 if (!colorStr
.IsEmpty()) {
326 if (colorStr
[0] == char16_t('#')) {
327 if (NS_HexToRGB(nsDependentString(colorStr
, 1), &thecolor
)) {
328 int32_t id
= NS_PTR_TO_INT32(index
);
329 CACHE_COLOR(id
, thecolor
);
331 } else if (NS_ColorNameToRGB(colorStr
, &thecolor
)) {
332 int32_t id
= NS_PTR_TO_INT32(index
);
333 CACHE_COLOR(id
, thecolor
);
335 printf("====== Changed color pref %s to 0x%lx\n",
340 // Reset to the default color, by clearing the cache
341 // to force lookup when the color is next used
342 int32_t id
= NS_PTR_TO_INT32(index
);
343 CLEAR_COLOR_CACHE(id
);
348 nsXPLookAndFeel::InitFromPref(nsLookAndFeelIntPref
* aPref
)
351 nsresult rv
= Preferences::GetInt(aPref
->name
, &intpref
);
352 if (NS_SUCCEEDED(rv
)) {
354 aPref
->intVar
= intpref
;
359 nsXPLookAndFeel::InitFromPref(nsLookAndFeelFloatPref
* aPref
)
362 nsresult rv
= Preferences::GetInt(aPref
->name
, &intpref
);
363 if (NS_SUCCEEDED(rv
)) {
365 aPref
->floatVar
= (float)intpref
/ 100.0f
;
370 nsXPLookAndFeel::InitColorFromPref(int32_t i
)
372 nsAutoString colorStr
;
373 nsresult rv
= Preferences::GetString(sColorPrefs
[i
], &colorStr
);
374 if (NS_FAILED(rv
) || colorStr
.IsEmpty()) {
378 if (colorStr
[0] == char16_t('#')) {
379 nsAutoString hexString
;
380 colorStr
.Right(hexString
, colorStr
.Length() - 1);
381 if (NS_HexToRGB(hexString
, &thecolor
)) {
382 CACHE_COLOR(i
, thecolor
);
384 } else if (NS_ColorNameToRGB(colorStr
, &thecolor
)) {
385 CACHE_COLOR(i
, thecolor
);
391 nsXPLookAndFeel::OnPrefChanged(const char* aPref
, void* aClosure
)
394 // looping in the same order as in ::Init
396 nsDependentCString
prefName(aPref
);
398 for (i
= 0; i
< ArrayLength(sIntPrefs
); ++i
) {
399 if (prefName
.Equals(sIntPrefs
[i
].name
)) {
400 IntPrefChanged(&sIntPrefs
[i
]);
405 for (i
= 0; i
< ArrayLength(sFloatPrefs
); ++i
) {
406 if (prefName
.Equals(sFloatPrefs
[i
].name
)) {
407 FloatPrefChanged(&sFloatPrefs
[i
]);
412 for (i
= 0; i
< ArrayLength(sColorPrefs
); ++i
) {
413 if (prefName
.Equals(sColorPrefs
[i
])) {
414 ColorPrefChanged(i
, sColorPrefs
[i
]);
421 // Read values from the user's preferences.
422 // This is done once at startup, but since the user's preferences
423 // haven't actually been read yet at that time, we also have to
424 // set a callback to inform us of changes to each pref.
427 nsXPLookAndFeel::Init()
429 // Say we're already initialized, and take the chance that it might fail;
430 // protects against some other process writing to our static variables.
433 // XXX If we could reorganize the pref names, we should separate the branch
434 // for each types. Then, we could reduce the unnecessary loop from
435 // nsXPLookAndFeel::OnPrefChanged().
436 Preferences::RegisterCallback(OnPrefChanged
, "ui.");
437 Preferences::RegisterCallback(OnPrefChanged
, "accessibility.tabfocus");
440 for (i
= 0; i
< ArrayLength(sIntPrefs
); ++i
) {
441 InitFromPref(&sIntPrefs
[i
]);
444 for (i
= 0; i
< ArrayLength(sFloatPrefs
); ++i
) {
445 InitFromPref(&sFloatPrefs
[i
]);
448 for (i
= 0; i
< ArrayLength(sColorPrefs
); ++i
) {
449 InitColorFromPref(i
);
453 if (NS_SUCCEEDED(Preferences::GetBool("ui.use_native_colors", &val
))) {
454 sUseNativeColors
= val
;
458 nsXPLookAndFeel::~nsXPLookAndFeel()
460 NS_ASSERTION(sInstance
== this,
461 "This destroying instance isn't the singleton instance");
466 nsXPLookAndFeel::IsSpecialColor(ColorID aID
, nscolor
&aColor
)
469 case eColorID_TextSelectForeground
:
470 return (aColor
== NS_DONT_CHANGE_COLOR
);
471 case eColorID_IMESelectedRawTextBackground
:
472 case eColorID_IMESelectedConvertedTextBackground
:
473 case eColorID_IMERawInputBackground
:
474 case eColorID_IMEConvertedTextBackground
:
475 case eColorID_IMESelectedRawTextForeground
:
476 case eColorID_IMESelectedConvertedTextForeground
:
477 case eColorID_IMERawInputForeground
:
478 case eColorID_IMEConvertedTextForeground
:
479 case eColorID_IMERawInputUnderline
:
480 case eColorID_IMEConvertedTextUnderline
:
481 case eColorID_IMESelectedRawTextUnderline
:
482 case eColorID_IMESelectedConvertedTextUnderline
:
483 case eColorID_SpellCheckerUnderline
:
484 return NS_IS_SELECTION_SPECIAL_COLOR(aColor
);
487 * In GetColor(), every color that is not a special color is color
488 * corrected. Use false to make other colors color corrected.
496 // All these routines will return NS_OK if they have a value,
497 // in which case the nsLookAndFeel should use that value;
498 // otherwise we'll return NS_ERROR_NOT_AVAILABLE, in which case, the
499 // platform-specific nsLookAndFeel should use its own values instead.
502 nsXPLookAndFeel::GetColorImpl(ColorID aID
, nscolor
&aResult
)
507 // define DEBUG_SYSTEM_COLOR_USE if you want to debug system color
508 // use in a skin that uses them. When set, it will make all system
509 // color pairs that are appropriate for foreground/background
510 // pairing the same. This means if the skin is using system colors
511 // correctly you will not be able to see *any* text.
512 #undef DEBUG_SYSTEM_COLOR_USE
514 #ifdef DEBUG_SYSTEM_COLOR_USE
518 // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
519 case eColorID_activecaption
:
520 // active window caption background
521 case eColorID_captiontext
:
522 // text in active window caption
523 aResult
= NS_RGB(0xff, 0x00, 0x00);
526 case eColorID_highlight
:
527 // background of selected item
528 case eColorID_highlighttext
:
529 // text of selected item
530 aResult
= NS_RGB(0xff, 0xff, 0x00);
533 case eColorID_inactivecaption
:
534 // inactive window caption
535 case eColorID_inactivecaptiontext
:
536 // text in inactive window caption
537 aResult
= NS_RGB(0x66, 0x66, 0x00);
540 case eColorID_infobackground
:
541 // tooltip background color
542 case eColorID_infotext
:
543 // tooltip text color
544 aResult
= NS_RGB(0x00, 0xff, 0x00);
549 case eColorID_menutext
:
551 aResult
= NS_RGB(0x00, 0xff, 0xff);
554 case eColorID_threedface
:
555 case eColorID_buttonface
:
557 case eColorID_buttontext
:
558 // text on push buttons
559 aResult
= NS_RGB(0x00, 0x66, 0x66);
562 case eColorID_window
:
563 case eColorID_windowtext
:
564 aResult
= NS_RGB(0x00, 0x00, 0xff);
567 // from the CSS3 working draft (not yet finalized)
568 // http://www.w3.org/tr/2000/wd-css3-userint-20000216.html#color
570 case eColorID__moz_field
:
571 case eColorID__moz_fieldtext
:
572 aResult
= NS_RGB(0xff, 0x00, 0xff);
575 case eColorID__moz_dialog
:
576 case eColorID__moz_dialogtext
:
577 aResult
= NS_RGB(0x66, 0x00, 0x66);
581 rv
= NS_ERROR_NOT_AVAILABLE
;
583 if (NS_SUCCEEDED(rv
))
586 #endif // DEBUG_SYSTEM_COLOR_USE
588 if (IS_COLOR_CACHED(aID
)) {
589 aResult
= sCachedColors
[aID
];
593 // There are no system color settings for these, so set them manually
594 if (aID
== eColorID_TextSelectBackgroundDisabled
) {
595 // This is used to gray out the selection when it's not focused
596 // Used with nsISelectionController::SELECTION_DISABLED
597 aResult
= NS_RGB(0xb0, 0xb0, 0xb0);
601 if (aID
== eColorID_TextSelectBackgroundAttention
) {
602 // This makes the selection stand out when typeaheadfind is on
603 // Used with nsISelectionController::SELECTION_ATTENTION
604 aResult
= NS_RGB(0x38, 0xd8, 0x78);
608 if (aID
== eColorID_TextHighlightBackground
) {
609 // This makes the matched text stand out when findbar highlighting is on
610 // Used with nsISelectionController::SELECTION_FIND
611 aResult
= NS_RGB(0xef, 0x0f, 0xff);
615 if (aID
== eColorID_TextHighlightForeground
) {
616 // The foreground color for the matched text in findbar highlighting
617 // Used with nsISelectionController::SELECTION_FIND
618 aResult
= NS_RGB(0xff, 0xff, 0xff);
622 if (sUseNativeColors
&& NS_SUCCEEDED(NativeGetColor(aID
, aResult
))) {
623 if ((gfxPlatform::GetCMSMode() == eCMSMode_All
) &&
624 !IsSpecialColor(aID
, aResult
)) {
625 qcms_transform
*transform
= gfxPlatform::GetCMSInverseRGBTransform();
628 color
[0] = NS_GET_R(aResult
);
629 color
[1] = NS_GET_G(aResult
);
630 color
[2] = NS_GET_B(aResult
);
631 qcms_transform_data(transform
, color
, color
, 1);
632 aResult
= NS_RGB(color
[0], color
[1], color
[2]);
636 CACHE_COLOR(aID
, aResult
);
640 return NS_ERROR_NOT_AVAILABLE
;
644 nsXPLookAndFeel::GetIntImpl(IntID aID
, int32_t &aResult
)
649 // Set the default values for these prefs. but allow different platforms
650 // to override them in their nsLookAndFeel if desired.
652 case eIntID_ScrollButtonLeftMouseButtonAction
:
655 case eIntID_ScrollButtonMiddleMouseButtonAction
:
658 case eIntID_ScrollButtonRightMouseButtonAction
:
663 * The metrics above are hardcoded platform defaults. All the other
664 * metrics are stored in sIntPrefs and can be changed at runtime.
669 for (unsigned int i
= 0; i
< ArrayLength(sIntPrefs
); ++i
) {
670 if (sIntPrefs
[i
].isSet
&& (sIntPrefs
[i
].id
== aID
)) {
671 aResult
= sIntPrefs
[i
].intVar
;
676 return NS_ERROR_NOT_AVAILABLE
;
680 nsXPLookAndFeel::GetFloatImpl(FloatID aID
, float &aResult
)
685 for (unsigned int i
= 0; i
< ArrayLength(sFloatPrefs
); ++i
) {
686 if (sFloatPrefs
[i
].isSet
&& sFloatPrefs
[i
].id
== aID
) {
687 aResult
= sFloatPrefs
[i
].floatVar
;
692 return NS_ERROR_NOT_AVAILABLE
;
696 nsXPLookAndFeel::RefreshImpl()
698 // Wipe out our color cache.
700 for (i
= 0; i
< eColorID_LAST_COLOR
; i
++)
701 sCachedColors
[i
] = 0;
702 for (i
= 0; i
< COLOR_CACHE_SIZE
; i
++)
703 sCachedColorBits
[i
] = 0;
710 LookAndFeel::GetColor(ColorID aID
, nscolor
* aResult
)
712 return nsLookAndFeel::GetInstance()->GetColorImpl(aID
, *aResult
);
717 LookAndFeel::GetInt(IntID aID
, int32_t* aResult
)
719 return nsLookAndFeel::GetInstance()->GetIntImpl(aID
, *aResult
);
724 LookAndFeel::GetFloat(FloatID aID
, float* aResult
)
726 return nsLookAndFeel::GetInstance()->GetFloatImpl(aID
, *aResult
);
731 LookAndFeel::GetFont(FontID aID
, nsString
& aName
, gfxFontStyle
& aStyle
,
732 float aDevPixPerCSSPixel
)
734 return nsLookAndFeel::GetInstance()->GetFontImpl(aID
, aName
, aStyle
,
740 LookAndFeel::GetPasswordCharacter()
742 return nsLookAndFeel::GetInstance()->GetPasswordCharacterImpl();
747 LookAndFeel::GetEchoPassword()
749 return nsLookAndFeel::GetInstance()->GetEchoPasswordImpl();
754 LookAndFeel::GetPasswordMaskDelay()
756 return nsLookAndFeel::GetInstance()->GetPasswordMaskDelayImpl();
761 LookAndFeel::Refresh()
763 nsLookAndFeel::GetInstance()->RefreshImpl();
766 } // namespace mozilla