1 /* -*- Mode: C++; tab-width: 2; 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 "nsLookAndFeel.h"
10 #include "nsStyleConsts.h"
11 #include "nsUXThemeData.h"
12 #include "nsUXThemeConstants.h"
13 #include "nsWindowsHelpers.h"
15 #include "WindowsUIUtils.h"
16 #include "mozilla/FontPropertyTypes.h"
17 #include "mozilla/Telemetry.h"
18 #include "mozilla/widget/WinRegistry.h"
20 using namespace mozilla
;
21 using namespace mozilla::widget
;
23 static Maybe
<nscolor
> GetColorFromTheme(nsUXThemeClass cls
, int32_t aPart
,
24 int32_t aState
, int32_t aPropId
) {
26 HRESULT hr
= GetThemeColor(nsUXThemeData::GetTheme(cls
), aPart
, aState
,
29 return Some(COLOREF_2_NSRGB(color
));
34 static int32_t GetSystemParam(long flag
, int32_t def
) {
36 return ::SystemParametersInfo(flag
, 0, &value
, 0) ? value
: def
;
39 static bool SystemWantsDarkTheme() {
40 if (nsUXThemeData::IsHighContrastOn()) {
41 return LookAndFeel::IsDarkColor(
42 LookAndFeel::Color(StyleSystemColor::Window
, ColorScheme::Light
,
43 LookAndFeel::UseStandins::No
));
48 u
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"_ns
,
49 WinRegistry::KeyMode::QueryValue
);
50 if (NS_WARN_IF(!key
)) {
53 uint32_t light
= key
.GetValueAsDword(u
"AppsUseLightTheme"_ns
).valueOr(1);
57 uint32_t nsLookAndFeel::SystemColorFilter() {
58 if (NS_WARN_IF(!mColorFilterWatcher
)) {
62 const auto& key
= mColorFilterWatcher
->GetKey();
63 if (!key
.GetValueAsDword(u
"Active"_ns
).valueOr(0)) {
66 return key
.GetValueAsDword(u
"FilterType"_ns
).valueOr(0);
69 nsLookAndFeel::nsLookAndFeel() {
70 mozilla::Telemetry::Accumulate(mozilla::Telemetry::TOUCH_ENABLED_DEVICE
,
71 WinUtils::IsTouchDeviceSupportPresent());
74 nsLookAndFeel::~nsLookAndFeel() = default;
76 void nsLookAndFeel::NativeInit() { EnsureInit(); }
79 void nsLookAndFeel::RefreshImpl() {
80 mInitialized
= false; // Fetch system colors next time they're used.
81 nsXPLookAndFeel::RefreshImpl();
84 static bool UseNonNativeMenuColors(ColorScheme aScheme
) {
85 return !LookAndFeel::GetInt(LookAndFeel::IntID::UseAccessibilityTheme
) ||
86 aScheme
== ColorScheme::Dark
;
89 nsresult
nsLookAndFeel::NativeGetColor(ColorID aID
, ColorScheme aScheme
,
93 auto IsHighlightColor
= [&] {
95 case ColorID::MozMenuhover
:
96 return !UseNonNativeMenuColors(aScheme
);
97 case ColorID::Highlight
:
98 case ColorID::Selecteditem
:
99 // We prefer the generic dark selection color if we don't have an
101 return aScheme
!= ColorScheme::Dark
|| mDarkHighlight
;
102 case ColorID::IMESelectedRawTextBackground
:
103 case ColorID::IMESelectedConvertedTextBackground
:
110 auto IsHighlightTextColor
= [&] {
112 case ColorID::MozMenubarhovertext
:
113 if (UseNonNativeMenuColors(aScheme
)) {
117 case ColorID::MozMenuhovertext
:
118 if (UseNonNativeMenuColors(aScheme
)) {
121 return !mColorMenuHoverText
;
122 case ColorID::Highlighttext
:
123 case ColorID::Selecteditemtext
:
124 // We prefer the generic dark selection color if we don't have an
126 return aScheme
!= ColorScheme::Dark
|| mDarkHighlightText
;
127 case ColorID::IMESelectedRawTextForeground
:
128 case ColorID::IMESelectedConvertedTextForeground
:
135 if (IsHighlightColor()) {
136 if (aScheme
== ColorScheme::Dark
&& mDarkHighlight
) {
137 aColor
= *mDarkHighlight
;
139 aColor
= GetColorForSysColorIndex(COLOR_HIGHLIGHT
);
144 if (IsHighlightTextColor()) {
145 if (aScheme
== ColorScheme::Dark
&& mDarkHighlightText
) {
146 aColor
= *mDarkHighlightText
;
148 aColor
= GetColorForSysColorIndex(COLOR_HIGHLIGHTTEXT
);
153 // Titlebar colors are color-scheme aware.
155 case ColorID::Activecaption
:
156 aColor
= mTitlebarColors
.Get(aScheme
, true).mBg
;
158 case ColorID::Captiontext
:
159 aColor
= mTitlebarColors
.Get(aScheme
, true).mFg
;
161 case ColorID::Activeborder
:
162 aColor
= mTitlebarColors
.Get(aScheme
, true).mBorder
;
164 case ColorID::Inactivecaption
:
165 aColor
= mTitlebarColors
.Get(aScheme
, false).mBg
;
167 case ColorID::Inactivecaptiontext
:
168 aColor
= mTitlebarColors
.Get(aScheme
, false).mFg
;
170 case ColorID::Inactiveborder
:
171 aColor
= mTitlebarColors
.Get(aScheme
, false).mBorder
;
177 if (aScheme
== ColorScheme::Dark
) {
178 if (auto color
= GenericDarkColor(aID
)) {
184 static constexpr auto kNonNativeMenuText
= NS_RGB(0x15, 0x14, 0x1a);
185 nsresult res
= NS_OK
;
188 case ColorID::IMERawInputBackground
:
189 case ColorID::IMEConvertedTextBackground
:
190 aColor
= NS_TRANSPARENT
;
192 case ColorID::IMERawInputForeground
:
193 case ColorID::IMEConvertedTextForeground
:
194 aColor
= NS_SAME_AS_FOREGROUND_COLOR
;
196 case ColorID::IMERawInputUnderline
:
197 case ColorID::IMEConvertedTextUnderline
:
198 aColor
= NS_SAME_AS_FOREGROUND_COLOR
;
200 case ColorID::IMESelectedRawTextUnderline
:
201 case ColorID::IMESelectedConvertedTextUnderline
:
202 aColor
= NS_TRANSPARENT
;
205 // New CSS 2 Color definitions
206 case ColorID::Appworkspace
:
207 idx
= COLOR_APPWORKSPACE
;
209 case ColorID::Background
:
210 idx
= COLOR_BACKGROUND
;
212 case ColorID::Buttonface
:
213 case ColorID::MozButtonhoverface
:
214 case ColorID::MozButtonactiveface
:
215 case ColorID::MozButtondisabledface
:
216 case ColorID::MozColheader
:
217 case ColorID::MozColheaderhover
:
218 case ColorID::MozColheaderactive
:
221 case ColorID::Buttonhighlight
:
222 idx
= COLOR_BTNHIGHLIGHT
;
224 case ColorID::Buttonshadow
:
225 idx
= COLOR_BTNSHADOW
;
227 case ColorID::Buttontext
:
228 case ColorID::MozButtonhovertext
:
229 case ColorID::MozButtonactivetext
:
232 case ColorID::MozCellhighlighttext
:
233 aColor
= NS_RGB(0, 0, 0);
235 case ColorID::MozCellhighlight
:
236 aColor
= NS_RGB(206, 206, 206);
238 case ColorID::Graytext
:
239 idx
= COLOR_GRAYTEXT
;
241 case ColorID::MozMenubarhovertext
:
242 if (UseNonNativeMenuColors(aScheme
)) {
243 aColor
= kNonNativeMenuText
;
247 case ColorID::MozMenuhovertext
:
248 if (UseNonNativeMenuColors(aScheme
)) {
249 aColor
= kNonNativeMenuText
;
252 if (mColorMenuHoverText
) {
253 aColor
= *mColorMenuHoverText
;
256 idx
= COLOR_HIGHLIGHTTEXT
;
258 case ColorID::MozMenuhover
:
259 MOZ_ASSERT(UseNonNativeMenuColors(aScheme
));
260 aColor
= NS_RGB(0xe0, 0xe0, 0xe6);
262 case ColorID::MozMenuhoverdisabled
:
263 if (UseNonNativeMenuColors(aScheme
)) {
264 aColor
= NS_RGB(0xf0, 0xf0, 0xf3);
267 aColor
= NS_TRANSPARENT
;
269 case ColorID::Infobackground
:
272 case ColorID::Infotext
:
273 idx
= COLOR_INFOTEXT
;
276 if (UseNonNativeMenuColors(aScheme
)) {
277 aColor
= NS_RGB(0xf9, 0xf9, 0xfb);
282 case ColorID::Menutext
:
283 if (UseNonNativeMenuColors(aScheme
)) {
284 aColor
= kNonNativeMenuText
;
287 idx
= COLOR_MENUTEXT
;
289 case ColorID::Scrollbar
:
290 idx
= COLOR_SCROLLBAR
;
292 case ColorID::Threeddarkshadow
:
293 idx
= COLOR_3DDKSHADOW
;
295 case ColorID::Threedface
:
298 case ColorID::Threedhighlight
:
299 idx
= COLOR_3DHIGHLIGHT
;
301 case ColorID::Threedlightshadow
:
302 case ColorID::Buttonborder
:
303 case ColorID::MozDisabledfield
:
304 case ColorID::MozSidebarborder
:
307 case ColorID::Threedshadow
:
308 idx
= COLOR_3DSHADOW
;
310 case ColorID::Window
:
313 case ColorID::Windowframe
:
314 idx
= COLOR_WINDOWFRAME
;
316 case ColorID::Windowtext
:
317 idx
= COLOR_WINDOWTEXT
;
319 case ColorID::MozEventreerow
:
320 case ColorID::MozOddtreerow
:
322 case ColorID::MozSidebar
:
323 case ColorID::MozCombobox
:
326 case ColorID::Fieldtext
:
327 case ColorID::MozSidebartext
:
328 case ColorID::MozComboboxtext
:
329 idx
= COLOR_WINDOWTEXT
;
331 case ColorID::MozHeaderbar
:
332 case ColorID::MozHeaderbarinactive
:
333 case ColorID::MozDialog
:
336 case ColorID::Accentcolor
:
337 aColor
= mColorAccent
;
339 case ColorID::Accentcolortext
:
340 aColor
= mColorAccentText
;
342 case ColorID::MozHeaderbartext
:
343 case ColorID::MozHeaderbarinactivetext
:
344 case ColorID::MozDialogtext
:
345 case ColorID::MozColheadertext
:
346 case ColorID::MozColheaderhovertext
:
347 case ColorID::MozColheaderactivetext
:
348 idx
= COLOR_WINDOWTEXT
;
350 case ColorID::MozNativehyperlinktext
:
351 idx
= COLOR_HOTLIGHT
;
353 case ColorID::Marktext
:
355 case ColorID::SpellCheckerUnderline
:
356 aColor
= GetStandinForNativeColor(aID
, aScheme
);
360 res
= NS_ERROR_FAILURE
;
364 aColor
= GetColorForSysColorIndex(idx
);
369 nsresult
nsLookAndFeel::NativeGetInt(IntID aID
, int32_t& aResult
) {
371 nsresult res
= NS_OK
;
374 case IntID::ScrollButtonLeftMouseButtonAction
:
377 case IntID::ScrollButtonMiddleMouseButtonAction
:
378 case IntID::ScrollButtonRightMouseButtonAction
:
381 case IntID::CaretBlinkTime
:
382 aResult
= static_cast<int32_t>(::GetCaretBlinkTime());
384 case IntID::CaretBlinkCount
: {
385 int32_t timeout
= GetSystemParam(SPI_GETCARETTIMEOUT
, 5000);
386 auto blinkTime
= ::GetCaretBlinkTime();
387 if (timeout
<= 0 || blinkTime
<= 0) {
391 // 2 * blinkTime because this integer is a full blink cycle.
392 aResult
= std::ceil(float(timeout
) / (2.0f
* float(blinkTime
)));
396 case IntID::CaretWidth
:
399 case IntID::ShowCaretDuringSelection
:
402 case IntID::SelectTextfieldsOnKeyFocus
:
403 // Select textfield content when focused by kbd
404 // used by EventStateManager::sTextfieldSelectModel
407 case IntID::SubmenuDelay
:
408 // This will default to the Windows' default
410 aResult
= GetSystemParam(SPI_GETMENUSHOWDELAY
, 400);
412 case IntID::MenusCanOverlapOSBar
:
413 // we want XUL popups to be able to overlap the task bar.
416 case IntID::DragThresholdX
:
417 // The system metric is the number of pixels at which a drag should
418 // start. Our look and feel metric is the number of pixels you can
419 // move before starting a drag, so subtract 1.
420 aResult
= ::GetSystemMetrics(SM_CXDRAG
) - 1;
422 case IntID::DragThresholdY
:
423 aResult
= ::GetSystemMetrics(SM_CYDRAG
) - 1;
425 case IntID::UseAccessibilityTheme
:
426 // High contrast is a misnomer under Win32 -- any theme can be used with
427 // it, e.g. normal contrast with large fonts, low contrast, etc. The high
428 // contrast flag really means -- use this theme and don't override it.
429 aResult
= nsUXThemeData::IsHighContrastOn();
431 case IntID::ScrollArrowStyle
:
432 aResult
= eScrollArrowStyle_Single
;
434 case IntID::TreeOpenDelay
:
437 case IntID::TreeCloseDelay
:
440 case IntID::TreeLazyScrollDelay
:
443 case IntID::TreeScrollDelay
:
446 case IntID::TreeScrollLinesMax
:
449 case IntID::WindowsAccentColorInTitlebar
: {
450 aResult
= mTitlebarColors
.mUseAccent
;
452 case IntID::AlertNotificationOrigin
:
455 // Get task bar window handle
456 HWND shellWindow
= FindWindowW(L
"Shell_TrayWnd", nullptr);
458 if (shellWindow
!= nullptr) {
459 // Determine position
460 APPBARDATA appBarData
;
461 appBarData
.hWnd
= shellWindow
;
462 appBarData
.cbSize
= sizeof(appBarData
);
463 if (SHAppBarMessage(ABM_GETTASKBARPOS
, &appBarData
)) {
464 // Set alert origin as a bit field - see LookAndFeel.h
465 // 0 represents bottom right, sliding vertically.
466 switch (appBarData
.uEdge
) {
468 aResult
= NS_ALERT_HORIZONTAL
| NS_ALERT_LEFT
;
471 aResult
= NS_ALERT_HORIZONTAL
;
474 aResult
= NS_ALERT_TOP
;
477 // If the task bar is right-to-left,
478 // move the origin to the left
479 if (::GetWindowLong(shellWindow
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
)
480 aResult
|= NS_ALERT_LEFT
;
487 case IntID::IMERawInputUnderlineStyle
:
488 case IntID::IMEConvertedTextUnderlineStyle
:
489 aResult
= static_cast<int32_t>(StyleTextDecorationStyle::Dashed
);
491 case IntID::IMESelectedRawTextUnderlineStyle
:
492 case IntID::IMESelectedConvertedTextUnderline
:
493 aResult
= static_cast<int32_t>(StyleTextDecorationStyle::None
);
495 case IntID::SpellCheckerUnderlineStyle
:
496 aResult
= static_cast<int32_t>(StyleTextDecorationStyle::Wavy
);
498 case IntID::ScrollbarButtonAutoRepeatBehavior
:
501 case IntID::SwipeAnimationEnabled
:
502 // Forcibly enable the swipe animation on Windows. It doesn't matter on
503 // platforms where "Drag two fingers to scroll" isn't supported since on
504 // the platforms we will never generate any swipe gesture events.
507 case IntID::UseOverlayScrollbars
:
508 aResult
= WindowsUIUtils::ComputeOverlayScrollbars();
510 case IntID::AllowOverlayScrollbarsOverlap
:
513 case IntID::ScrollbarDisplayOnMouseMove
:
516 case IntID::ScrollbarFadeBeginDelay
:
519 case IntID::ScrollbarFadeDuration
:
522 case IntID::ContextMenuOffsetVertical
:
523 case IntID::ContextMenuOffsetHorizontal
:
526 case IntID::SystemUsesDarkTheme
:
527 aResult
= SystemWantsDarkTheme();
529 case IntID::SystemScrollbarSize
:
530 aResult
= std::max(WinUtils::GetSystemMetricsForDpi(SM_CXVSCROLL
, 96),
531 WinUtils::GetSystemMetricsForDpi(SM_CXHSCROLL
, 96));
533 case IntID::PrefersReducedMotion
: {
535 ::SystemParametersInfoW(SPI_GETCLIENTAREAANIMATION
, 0, &enable
, 0);
539 case IntID::PrefersReducedTransparency
: {
540 // Prefers reduced transparency if the option for "Transparency Effects"
542 aResult
= !WindowsUIUtils::ComputeTransparencyEffects();
545 case IntID::InvertedColors
: {
546 // Color filter values
548 // 2: Grayscale inverted
549 aResult
= mCurrentColorFilter
== 1 || mCurrentColorFilter
== 2;
552 case IntID::PrimaryPointerCapabilities
: {
553 aResult
= static_cast<int32_t>(
554 widget::WinUtils::GetPrimaryPointerCapabilities());
557 case IntID::AllPointerCapabilities
: {
559 static_cast<int32_t>(widget::WinUtils::GetAllPointerCapabilities());
562 case IntID::TouchDeviceSupportPresent
:
563 aResult
= !!WinUtils::IsTouchDeviceSupportPresent();
565 case IntID::PanelAnimations
:
568 case IntID::HideCursorWhileTyping
: {
570 ::SystemParametersInfoW(SPI_GETMOUSEVANISH
, 0, &enable
, 0);
576 res
= NS_ERROR_FAILURE
;
581 nsresult
nsLookAndFeel::NativeGetFloat(FloatID aID
, float& aResult
) {
582 nsresult res
= NS_OK
;
585 case FloatID::IMEUnderlineRelativeSize
:
588 case FloatID::SpellCheckerUnderlineRelativeSize
:
591 case FloatID::TextScaleFactor
:
592 aResult
= WindowsUIUtils::ComputeTextScaleFactor();
596 res
= NS_ERROR_FAILURE
;
601 LookAndFeelFont
nsLookAndFeel::GetLookAndFeelFontInternal(
602 const LOGFONTW
& aLogFont
, bool aUseShellDlg
) {
603 LookAndFeelFont result
{};
605 result
.haveFont() = false;
607 // Get scaling factor from physical to logical pixels
609 1.0 / WinUtils::SystemScaleFactor() / LookAndFeel::GetTextScaleFactor();
611 // The lfHeight is in pixels, and it needs to be adjusted for the
612 // device it will be displayed on.
613 // Screens and Printers will differ in DPI
615 // So this accounts for the difference in the DeviceContexts
616 // The pixelScale will typically be 1.0 for the screen
617 // (though larger for hi-dpi screens where the Windows resolution
618 // scale factor is 125% or 150% or even more), and could be
619 // any value when going to a printer, for example pixelScale is
620 // 6.25 when going to a 600dpi printer.
621 float pixelHeight
= -aLogFont
.lfHeight
;
622 if (pixelHeight
< 0) {
623 nsAutoFont
hFont(::CreateFontIndirectW(&aLogFont
));
628 nsAutoHDC
dc(::GetDC(nullptr));
629 HGDIOBJ hObject
= ::SelectObject(dc
, hFont
);
631 ::GetTextMetrics(dc
, &tm
);
632 ::SelectObject(dc
, hObject
);
634 pixelHeight
= tm
.tmAscent
;
637 pixelHeight
*= pixelScale
;
639 // we have problem on Simplified Chinese system because the system
640 // report the default font size is 8 points. but if we use 8, the text
641 // display very ugly. force it to be at 9 points (12 pixels) on that
642 // system (cp936), but leave other sizes alone.
643 if (pixelHeight
< 12 && ::GetACP() == 936) {
647 result
.haveFont() = true;
650 result
.name() = u
"MS Shell Dlg 2"_ns
;
652 result
.name() = aLogFont
.lfFaceName
;
655 result
.size() = pixelHeight
;
656 result
.italic() = !!aLogFont
.lfItalic
;
657 // FIXME: Other weights?
659 ((aLogFont
.lfWeight
== FW_BOLD
) ? FontWeight::BOLD
: FontWeight::NORMAL
)
665 LookAndFeelFont
nsLookAndFeel::GetLookAndFeelFont(LookAndFeel::FontID anID
) {
666 LookAndFeelFont result
{};
668 result
.haveFont() = false;
670 // FontID::Icon is handled differently than the others
671 if (anID
== LookAndFeel::FontID::Icon
) {
673 if (::SystemParametersInfoW(SPI_GETICONTITLELOGFONT
, sizeof(logFont
),
674 (PVOID
)&logFont
, 0)) {
675 result
= GetLookAndFeelFontInternal(logFont
, false);
680 NONCLIENTMETRICSW ncm
;
681 ncm
.cbSize
= sizeof(NONCLIENTMETRICSW
);
682 if (!::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
),
688 case LookAndFeel::FontID::Menu
:
689 case LookAndFeel::FontID::MozPullDownMenu
:
690 result
= GetLookAndFeelFontInternal(ncm
.lfMenuFont
, false);
692 case LookAndFeel::FontID::Caption
:
693 result
= GetLookAndFeelFontInternal(ncm
.lfCaptionFont
, false);
695 case LookAndFeel::FontID::SmallCaption
:
696 result
= GetLookAndFeelFontInternal(ncm
.lfSmCaptionFont
, false);
698 case LookAndFeel::FontID::StatusBar
:
699 result
= GetLookAndFeelFontInternal(ncm
.lfStatusFont
, false);
701 case LookAndFeel::FontID::MozButton
:
702 case LookAndFeel::FontID::MozField
:
703 case LookAndFeel::FontID::MozList
:
704 // XXX It's not clear to me whether this is exactly the right
705 // set of LookAndFeel values to map to the dialog font; we may
706 // want to add or remove cases here after reviewing the visual
707 // results under various Windows versions.
708 result
= GetLookAndFeelFontInternal(ncm
.lfMessageFont
, true);
711 result
= GetLookAndFeelFontInternal(ncm
.lfMessageFont
, false);
718 bool nsLookAndFeel::NativeGetFont(LookAndFeel::FontID anID
, nsString
& aFontName
,
719 gfxFontStyle
& aFontStyle
) {
720 LookAndFeelFont font
= GetLookAndFeelFont(anID
);
721 return LookAndFeelFontToStyle(font
, aFontName
, aFontStyle
);
725 char16_t
nsLookAndFeel::GetPasswordCharacterImpl() {
726 #define UNICODE_BLACK_CIRCLE_CHAR 0x25cf
727 return UNICODE_BLACK_CIRCLE_CHAR
;
730 static nscolor
GetAccentColorText(const nscolor aAccentColor
) {
731 // We want the color that we return for text that will be drawn over
732 // a background that has the accent color to have good contrast with
733 // the accent color. Windows itself uses either white or black text
734 // depending on how light or dark the accent color is. We do the same
735 // here based on the luminance of the accent color with a threshhold
736 // value. This algorithm should match what Windows does. It comes from:
738 // https://docs.microsoft.com/en-us/windows/uwp/style/color
739 float luminance
= (NS_GET_R(aAccentColor
) * 2 + NS_GET_G(aAccentColor
) * 5 +
740 NS_GET_B(aAccentColor
)) /
742 return luminance
<= 128 ? NS_RGB(255, 255, 255) : NS_RGB(0, 0, 0);
745 static Maybe
<nscolor
> GetAccentColorText(const Maybe
<nscolor
>& aAccentColor
) {
749 return Some(GetAccentColorText(*aAccentColor
));
752 nscolor
nsLookAndFeel::GetColorForSysColorIndex(int index
) {
753 MOZ_ASSERT(index
>= SYS_COLOR_MIN
&& index
<= SYS_COLOR_MAX
);
754 return mSysColorTable
[index
- SYS_COLOR_MIN
];
757 auto nsLookAndFeel::ComputeTitlebarColors() -> TitlebarColors
{
758 TitlebarColors result
;
760 // Start with the native / non-accent-in-titlebar colors.
761 result
.mActiveLight
= {GetColorForSysColorIndex(COLOR_ACTIVECAPTION
),
762 GetColorForSysColorIndex(COLOR_CAPTIONTEXT
),
763 GetColorForSysColorIndex(COLOR_ACTIVEBORDER
)};
765 result
.mInactiveLight
= {GetColorForSysColorIndex(COLOR_INACTIVECAPTION
),
766 GetColorForSysColorIndex(COLOR_INACTIVECAPTIONTEXT
),
767 GetColorForSysColorIndex(COLOR_INACTIVEBORDER
)};
769 if (!nsUXThemeData::IsHighContrastOn()) {
770 // Use our non-native colors.
771 result
.mActiveLight
= {
772 GetStandinForNativeColor(ColorID::Activecaption
, ColorScheme::Light
),
773 GetStandinForNativeColor(ColorID::Captiontext
, ColorScheme::Light
),
774 GetStandinForNativeColor(ColorID::Activeborder
, ColorScheme::Light
)};
775 result
.mInactiveLight
= {
776 GetStandinForNativeColor(ColorID::Inactivecaption
, ColorScheme::Light
),
777 GetStandinForNativeColor(ColorID::Inactivecaptiontext
,
779 GetStandinForNativeColor(ColorID::Inactiveborder
, ColorScheme::Light
)};
782 // Our dark colors are always non-native.
783 result
.mActiveDark
= {*GenericDarkColor(ColorID::Activecaption
),
784 *GenericDarkColor(ColorID::Captiontext
),
785 *GenericDarkColor(ColorID::Activeborder
)};
786 result
.mInactiveDark
= {*GenericDarkColor(ColorID::Inactivecaption
),
787 *GenericDarkColor(ColorID::Inactivecaptiontext
),
788 *GenericDarkColor(ColorID::Inactiveborder
)};
790 // TODO(bug 1825241): Somehow get notified when this changes? Hopefully the
791 // sys color notification is enough.
792 WinRegistry::Key
dwmKey(HKEY_CURRENT_USER
,
793 u
"SOFTWARE\\Microsoft\\Windows\\DWM"_ns
,
794 WinRegistry::KeyMode::QueryValue
);
795 if (NS_WARN_IF(!dwmKey
)) {
799 // The order of the color components in the DWORD stored in the registry
800 // happens to be the same order as we store the components in nscolor
801 // so we can just assign directly here.
802 result
.mAccent
= dwmKey
.GetValueAsDword(u
"AccentColor"_ns
);
803 result
.mAccentText
= GetAccentColorText(result
.mAccent
);
805 if (!result
.mAccent
) {
809 result
.mAccentInactive
= dwmKey
.GetValueAsDword(u
"AccentColorInactive"_ns
);
810 result
.mAccentInactiveText
= GetAccentColorText(result
.mAccentInactive
);
812 // The ColorPrevalence value is set to 1 when the "Show color on title bar"
813 // setting in the Color section of Window's Personalization settings is
816 dwmKey
.GetValueAsDword(u
"ColorPrevalence"_ns
).valueOr(0) == 1;
817 if (!result
.mUseAccent
) {
821 // TODO(emilio): Consider reading ColorizationColorBalance to compute a
822 // more correct border color, see [1]. Though for opaque accent colors this
826 // https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:ui/color/win/accent_color_observer.cc;l=42;drc=9d4eb7ed25296abba8fd525a6bdd0fdbf4bcdd9f
827 result
.mActiveDark
.mBorder
= result
.mActiveLight
.mBorder
= *result
.mAccent
;
828 result
.mInactiveDark
.mBorder
= result
.mInactiveLight
.mBorder
=
829 result
.mAccentInactive
.valueOr(NS_RGB(57, 57, 57));
830 result
.mActiveLight
.mBg
= result
.mActiveDark
.mBg
= *result
.mAccent
;
831 result
.mActiveLight
.mFg
= result
.mActiveDark
.mFg
= *result
.mAccentText
;
832 if (result
.mAccentInactive
) {
833 result
.mInactiveLight
.mBg
= result
.mInactiveDark
.mBg
=
834 *result
.mAccentInactive
;
835 result
.mInactiveLight
.mFg
= result
.mInactiveDark
.mFg
=
836 *result
.mAccentInactiveText
;
838 // This is hand-picked to .8 to change the accent color a bit but not too
840 constexpr uint8_t kBgAlpha
= 208;
841 const auto BlendWithAlpha
= [](nscolor aBg
, nscolor aFg
,
842 uint8_t aAlpha
) -> nscolor
{
843 return NS_ComposeColors(
844 aBg
, NS_RGBA(NS_GET_R(aFg
), NS_GET_G(aFg
), NS_GET_B(aFg
), aAlpha
));
846 result
.mInactiveLight
.mBg
=
847 BlendWithAlpha(NS_RGB(255, 255, 255), *result
.mAccent
, kBgAlpha
);
848 result
.mInactiveDark
.mBg
=
849 BlendWithAlpha(NS_RGB(0, 0, 0), *result
.mAccent
, kBgAlpha
);
850 result
.mInactiveLight
.mFg
= result
.mInactiveDark
.mFg
= *result
.mAccentText
;
855 void nsLookAndFeel::EnsureInit() {
861 mColorMenuHoverText
=
862 ::GetColorFromTheme(eUXMenu
, MENU_POPUPITEM
, MPI_HOT
, TMT_TEXTCOLOR
);
864 // Fill out the sys color table.
865 for (int i
= SYS_COLOR_MIN
; i
<= SYS_COLOR_MAX
; ++i
) {
866 mSysColorTable
[i
- SYS_COLOR_MIN
] = [&] {
867 if (auto c
= WindowsUIUtils::GetSystemColor(ColorScheme::Light
, i
)) {
870 DWORD color
= ::GetSysColor(i
);
871 return COLOREF_2_NSRGB(color
);
876 WindowsUIUtils::GetSystemColor(ColorScheme::Dark
, COLOR_HIGHLIGHT
);
878 WindowsUIUtils::GetSystemColor(ColorScheme::Dark
, COLOR_HIGHLIGHTTEXT
);
880 mTitlebarColors
= ComputeTitlebarColors();
883 if (auto accent
= WindowsUIUtils::GetAccentColor()) {
886 // Try the titlebar accent as a fallback.
887 if (mTitlebarColors
.mAccent
) {
888 return *mTitlebarColors
.mAccent
;
890 // Seems to be the default color (hardcoded because of bug 1065998)
891 return NS_RGB(0, 120, 215);
893 mColorAccentText
= GetAccentColorText(mColorAccent
);
895 if (!mColorFilterWatcher
) {
896 WinRegistry::Key
key(
897 HKEY_CURRENT_USER
, u
"Software\\Microsoft\\ColorFiltering"_ns
,
898 WinRegistry::KeyMode::QueryValue
| WinRegistry::KeyMode::Notify
);
900 mColorFilterWatcher
= MakeUnique
<WinRegistry::KeyWatcher
>(
901 std::move(key
), GetCurrentSerialEventTarget(), [this] {
902 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
903 if (mCurrentColorFilter
!= SystemColorFilter()) {
904 LookAndFeel::NotifyChangedAllWindows(
905 widget::ThemeChangeKind::MediaQueriesOnly
);
910 mCurrentColorFilter
= SystemColorFilter();