Bug 1829659 - Remove `import.py` because it's not used anymore r=glandium,bwc
[gecko.git] / widget / windows / nsLookAndFeel.cpp
blob0c86eaf65dc6a7c758ea844109cf9f31e272e233
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"
7 #include <stdint.h>
8 #include <windows.h>
9 #include <shellapi.h>
10 #include "nsStyleConsts.h"
11 #include "nsUXThemeData.h"
12 #include "nsUXThemeConstants.h"
13 #include "nsWindowsHelpers.h"
14 #include "WinUtils.h"
15 #include "WindowsUIUtils.h"
16 #include "mozilla/FontPropertyTypes.h"
17 #include "mozilla/Telemetry.h"
18 #include "mozilla/WindowsVersion.h"
19 #include "gfxFontConstants.h"
20 #include "gfxWindowsPlatform.h"
22 using namespace mozilla;
23 using namespace mozilla::widget;
25 static Maybe<nscolor> GetColorFromTheme(nsUXThemeClass cls, int32_t aPart,
26 int32_t aState, int32_t aPropId) {
27 COLORREF color;
28 HRESULT hr = GetThemeColor(nsUXThemeData::GetTheme(cls), aPart, aState,
29 aPropId, &color);
30 if (hr == S_OK) {
31 return Some(COLOREF_2_NSRGB(color));
33 return Nothing();
36 static int32_t GetSystemParam(long flag, int32_t def) {
37 DWORD value;
38 return ::SystemParametersInfo(flag, 0, &value, 0) ? value : def;
41 static nsresult SystemWantsDarkTheme(int32_t& darkThemeEnabled) {
42 if (!IsWin10OrLater()) {
43 darkThemeEnabled = 0;
44 return NS_OK;
47 nsresult rv = NS_OK;
48 nsCOMPtr<nsIWindowsRegKey> personalizeKey =
49 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
50 if (NS_WARN_IF(NS_FAILED(rv))) {
51 return rv;
54 rv = personalizeKey->Open(
55 nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
56 nsLiteralString(
57 u"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"),
58 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
59 if (NS_FAILED(rv)) {
60 return rv;
63 uint32_t lightThemeEnabled;
64 rv =
65 personalizeKey->ReadIntValue(u"AppsUseLightTheme"_ns, &lightThemeEnabled);
66 if (NS_SUCCEEDED(rv)) {
67 darkThemeEnabled = !lightThemeEnabled;
70 return rv;
73 static int32_t SystemColorFilter() {
74 nsresult rv = NS_OK;
75 nsCOMPtr<nsIWindowsRegKey> colorFilteringKey =
76 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
77 if (NS_WARN_IF(NS_FAILED(rv))) {
78 return 0;
81 rv = colorFilteringKey->Open(
82 nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
83 u"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Accessibility\\ATConfig\\colorfiltering"_ns,
84 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
85 if (NS_FAILED(rv)) {
86 return 0;
89 // The Active value is set to 1 when the "Turn on color filters" setting
90 // in the Color filters section of Windows' Ease of Access settings is turned
91 // on. If it is disabled (Active == 0 or does not exist), do not report having
92 // a color filter.
93 uint32_t active;
94 rv = colorFilteringKey->ReadIntValue(u"Active"_ns, &active);
95 if (NS_FAILED(rv) || active == 0) {
96 return 0;
99 // The FilterType value is set to whichever filter is enabled.
100 uint32_t filterType;
101 rv = colorFilteringKey->ReadIntValue(u"FilterType"_ns, &filterType);
102 if (NS_SUCCEEDED(rv)) {
103 return filterType;
106 return 0;
109 nsLookAndFeel::nsLookAndFeel() {
110 mozilla::Telemetry::Accumulate(mozilla::Telemetry::TOUCH_ENABLED_DEVICE,
111 WinUtils::IsTouchDeviceSupportPresent());
114 nsLookAndFeel::~nsLookAndFeel() = default;
116 void nsLookAndFeel::NativeInit() { EnsureInit(); }
118 /* virtual */
119 void nsLookAndFeel::RefreshImpl() {
120 mInitialized = false; // Fetch system colors next time they're used.
121 nsXPLookAndFeel::RefreshImpl();
124 static bool UseNonNativeMenuColors(ColorScheme aScheme) {
125 if (!LookAndFeel::WindowsNonNativeMenusEnabled()) {
126 return false;
128 return LookAndFeel::GetInt(LookAndFeel::IntID::WindowsDefaultTheme) ||
129 aScheme == ColorScheme::Dark;
132 nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme,
133 nscolor& aColor) {
134 EnsureInit();
136 auto IsHighlightColor = [&] {
137 switch (aID) {
138 case ColorID::MozMenuhover:
139 return !UseNonNativeMenuColors(aScheme);
140 case ColorID::Highlight:
141 case ColorID::Selecteditem:
142 // We prefer the generic dark selection color if we don't have an
143 // explicit one.
144 return aScheme != ColorScheme::Dark || mDarkHighlight;
145 case ColorID::IMESelectedRawTextBackground:
146 case ColorID::IMESelectedConvertedTextBackground:
147 return true;
148 default:
149 return false;
153 auto IsHighlightTextColor = [&] {
154 switch (aID) {
155 case ColorID::MozMenubarhovertext:
156 if (UseNonNativeMenuColors(aScheme)) {
157 return false;
159 if (!nsUXThemeData::IsAppThemed()) {
160 return nsUXThemeData::AreFlatMenusEnabled();
162 [[fallthrough]];
163 case ColorID::MozMenuhovertext:
164 if (UseNonNativeMenuColors(aScheme)) {
165 return false;
167 return !mColorMenuHoverText;
168 case ColorID::Highlighttext:
169 case ColorID::Selecteditemtext:
170 // We prefer the generic dark selection color if we don't have an
171 // explicit one.
172 return aScheme != ColorScheme::Dark || mDarkHighlightText;
173 case ColorID::IMESelectedRawTextForeground:
174 case ColorID::IMESelectedConvertedTextForeground:
175 case ColorID::MozDragtargetzone:
176 return true;
177 default:
178 return false;
182 if (IsHighlightColor()) {
183 if (aScheme == ColorScheme::Dark && mDarkHighlight) {
184 aColor = *mDarkHighlight;
185 } else {
186 aColor = GetColorForSysColorIndex(COLOR_HIGHLIGHT);
188 return NS_OK;
191 if (IsHighlightTextColor()) {
192 if (aScheme == ColorScheme::Dark && mDarkHighlightText) {
193 aColor = *mDarkHighlightText;
194 } else {
195 aColor = GetColorForSysColorIndex(COLOR_HIGHLIGHTTEXT);
197 return NS_OK;
200 if (aScheme == ColorScheme::Dark) {
201 if (auto color = GenericDarkColor(aID)) {
202 aColor = *color;
203 return NS_OK;
207 static constexpr auto kNonNativeMenuText = NS_RGB(0x15, 0x14, 0x1a);
208 nsresult res = NS_OK;
209 int idx;
210 switch (aID) {
211 case ColorID::IMERawInputBackground:
212 case ColorID::IMEConvertedTextBackground:
213 aColor = NS_TRANSPARENT;
214 return NS_OK;
215 case ColorID::IMERawInputForeground:
216 case ColorID::IMEConvertedTextForeground:
217 aColor = NS_SAME_AS_FOREGROUND_COLOR;
218 return NS_OK;
219 case ColorID::IMERawInputUnderline:
220 case ColorID::IMEConvertedTextUnderline:
221 aColor = NS_SAME_AS_FOREGROUND_COLOR;
222 return NS_OK;
223 case ColorID::IMESelectedRawTextUnderline:
224 case ColorID::IMESelectedConvertedTextUnderline:
225 aColor = NS_TRANSPARENT;
226 return NS_OK;
228 // New CSS 2 Color definitions
229 case ColorID::Activeborder:
230 idx = COLOR_ACTIVEBORDER;
231 break;
232 case ColorID::Activecaption:
233 idx = COLOR_ACTIVECAPTION;
234 break;
235 case ColorID::Appworkspace:
236 idx = COLOR_APPWORKSPACE;
237 break;
238 case ColorID::Background:
239 idx = COLOR_BACKGROUND;
240 break;
241 case ColorID::Buttonface:
242 case ColorID::MozButtonhoverface:
243 case ColorID::MozButtonactiveface:
244 case ColorID::MozButtondisabledface:
245 idx = COLOR_BTNFACE;
246 break;
247 case ColorID::Buttonhighlight:
248 idx = COLOR_BTNHIGHLIGHT;
249 break;
250 case ColorID::Buttonshadow:
251 idx = COLOR_BTNSHADOW;
252 break;
253 case ColorID::Buttontext:
254 case ColorID::MozButtonhovertext:
255 case ColorID::MozButtonactivetext:
256 idx = COLOR_BTNTEXT;
257 break;
258 case ColorID::Captiontext:
259 idx = COLOR_CAPTIONTEXT;
260 break;
261 case ColorID::MozCellhighlighttext:
262 aColor = NS_RGB(0, 0, 0);
263 return NS_OK;
264 case ColorID::MozCellhighlight:
265 aColor = NS_RGB(206, 206, 206);
266 return NS_OK;
267 case ColorID::Graytext:
268 idx = COLOR_GRAYTEXT;
269 break;
270 case ColorID::MozMenubarhovertext:
271 if (UseNonNativeMenuColors(aScheme)) {
272 aColor = kNonNativeMenuText;
273 return NS_OK;
275 if (!nsUXThemeData::IsAppThemed()) {
276 idx = COLOR_MENUTEXT;
277 break;
279 [[fallthrough]];
280 case ColorID::MozMenuhovertext:
281 if (UseNonNativeMenuColors(aScheme)) {
282 aColor = kNonNativeMenuText;
283 return NS_OK;
285 if (mColorMenuHoverText) {
286 aColor = *mColorMenuHoverText;
287 return NS_OK;
289 idx = COLOR_HIGHLIGHTTEXT;
290 break;
291 case ColorID::MozMenuhover:
292 MOZ_ASSERT(UseNonNativeMenuColors(aScheme));
293 aColor = NS_RGB(0xe0, 0xe0, 0xe6);
294 return NS_OK;
295 case ColorID::MozMenuhoverdisabled:
296 if (UseNonNativeMenuColors(aScheme)) {
297 aColor = NS_RGB(0xf0, 0xf0, 0xf3);
298 return NS_OK;
300 aColor = NS_TRANSPARENT;
301 return NS_OK;
302 case ColorID::Inactiveborder:
303 idx = COLOR_INACTIVEBORDER;
304 break;
305 case ColorID::Inactivecaption:
306 idx = COLOR_INACTIVECAPTION;
307 break;
308 case ColorID::Inactivecaptiontext:
309 idx = COLOR_INACTIVECAPTIONTEXT;
310 break;
311 case ColorID::Infobackground:
312 idx = COLOR_INFOBK;
313 break;
314 case ColorID::Infotext:
315 idx = COLOR_INFOTEXT;
316 break;
317 case ColorID::Menu:
318 if (UseNonNativeMenuColors(aScheme)) {
319 aColor = NS_RGB(0xf9, 0xf9, 0xfb);
320 return NS_OK;
322 idx = COLOR_MENU;
323 break;
324 case ColorID::Menutext:
325 case ColorID::MozMenubartext:
326 if (UseNonNativeMenuColors(aScheme)) {
327 aColor = kNonNativeMenuText;
328 return NS_OK;
330 idx = COLOR_MENUTEXT;
331 break;
332 case ColorID::Scrollbar:
333 idx = COLOR_SCROLLBAR;
334 break;
335 case ColorID::Threeddarkshadow:
336 idx = COLOR_3DDKSHADOW;
337 break;
338 case ColorID::Threedface:
339 idx = COLOR_3DFACE;
340 break;
341 case ColorID::Threedhighlight:
342 idx = COLOR_3DHIGHLIGHT;
343 break;
344 case ColorID::Threedlightshadow:
345 case ColorID::Buttonborder:
346 case ColorID::MozDisabledfield:
347 idx = COLOR_3DLIGHT;
348 break;
349 case ColorID::Threedshadow:
350 idx = COLOR_3DSHADOW;
351 break;
352 case ColorID::Window:
353 idx = COLOR_WINDOW;
354 break;
355 case ColorID::Windowframe:
356 idx = COLOR_WINDOWFRAME;
357 break;
358 case ColorID::Windowtext:
359 idx = COLOR_WINDOWTEXT;
360 break;
361 case ColorID::MozEventreerow:
362 case ColorID::MozOddtreerow:
363 case ColorID::Field:
364 case ColorID::MozCombobox:
365 idx = COLOR_WINDOW;
366 break;
367 case ColorID::Fieldtext:
368 case ColorID::MozComboboxtext:
369 idx = COLOR_WINDOWTEXT;
370 break;
371 case ColorID::MozDialog:
372 idx = COLOR_3DFACE;
373 break;
374 case ColorID::Accentcolor:
375 if (mColorAccent) {
376 aColor = *mColorAccent;
377 } else {
378 // Seems to be the default color (hardcoded because of bug 1065998)
379 aColor = NS_RGB(0, 120, 215);
381 return NS_OK;
382 case ColorID::Accentcolortext:
383 if (mColorAccentText) {
384 aColor = *mColorAccentText;
385 } else {
386 aColor = NS_RGB(255, 255, 255);
388 return NS_OK;
389 case ColorID::MozWinMediatext:
390 if (mColorMediaText) {
391 aColor = *mColorMediaText;
392 return NS_OK;
394 // if we've gotten here just return -moz-dialogtext instead
395 idx = COLOR_WINDOWTEXT;
396 break;
397 case ColorID::MozWinCommunicationstext:
398 if (mColorCommunicationsText) {
399 aColor = *mColorCommunicationsText;
400 return NS_OK;
402 // if we've gotten here just return -moz-dialogtext instead
403 idx = COLOR_WINDOWTEXT;
404 break;
405 case ColorID::MozDialogtext:
406 case ColorID::MozColheadertext:
407 case ColorID::MozColheaderhovertext:
408 idx = COLOR_WINDOWTEXT;
409 break;
410 case ColorID::MozButtondefault:
411 idx = COLOR_3DDKSHADOW;
412 break;
413 case ColorID::MozNativehyperlinktext:
414 idx = COLOR_HOTLIGHT;
415 break;
416 case ColorID::Marktext:
417 case ColorID::Mark:
418 case ColorID::SpellCheckerUnderline:
419 aColor = GetStandinForNativeColor(aID, aScheme);
420 return NS_OK;
421 default:
422 idx = COLOR_WINDOW;
423 res = NS_ERROR_FAILURE;
424 break;
427 aColor = GetColorForSysColorIndex(idx);
429 return res;
432 nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
433 EnsureInit();
434 nsresult res = NS_OK;
436 switch (aID) {
437 case IntID::ScrollButtonLeftMouseButtonAction:
438 aResult = 0;
439 break;
440 case IntID::ScrollButtonMiddleMouseButtonAction:
441 case IntID::ScrollButtonRightMouseButtonAction:
442 aResult = 3;
443 break;
444 case IntID::CaretBlinkTime:
445 aResult = static_cast<int32_t>(::GetCaretBlinkTime());
446 break;
447 case IntID::CaretBlinkCount: {
448 int32_t timeout = GetSystemParam(SPI_GETCARETTIMEOUT, 5000);
449 auto blinkTime = ::GetCaretBlinkTime();
450 if (timeout <= 0 || blinkTime <= 0) {
451 aResult = -1;
452 break;
454 // 2 * blinkTime because this integer is a full blink cycle.
455 aResult = std::ceil(float(timeout) / (2.0f * float(blinkTime)));
456 break;
459 case IntID::CaretWidth:
460 aResult = 1;
461 break;
462 case IntID::ShowCaretDuringSelection:
463 aResult = 0;
464 break;
465 case IntID::SelectTextfieldsOnKeyFocus:
466 // Select textfield content when focused by kbd
467 // used by EventStateManager::sTextfieldSelectModel
468 aResult = 1;
469 break;
470 case IntID::SubmenuDelay:
471 // This will default to the Windows' default
472 // (400ms) on error.
473 aResult = GetSystemParam(SPI_GETMENUSHOWDELAY, 400);
474 break;
475 case IntID::TooltipDelay:
476 aResult = 500;
477 break;
478 case IntID::MenusCanOverlapOSBar:
479 // we want XUL popups to be able to overlap the task bar.
480 aResult = 1;
481 break;
482 case IntID::DragThresholdX:
483 // The system metric is the number of pixels at which a drag should
484 // start. Our look and feel metric is the number of pixels you can
485 // move before starting a drag, so subtract 1.
486 aResult = ::GetSystemMetrics(SM_CXDRAG) - 1;
487 break;
488 case IntID::DragThresholdY:
489 aResult = ::GetSystemMetrics(SM_CYDRAG) - 1;
490 break;
491 case IntID::UseAccessibilityTheme:
492 // High contrast is a misnomer under Win32 -- any theme can be used with
493 // it, e.g. normal contrast with large fonts, low contrast, etc. The high
494 // contrast flag really means -- use this theme and don't override it.
495 aResult = nsUXThemeData::IsHighContrastOn();
496 break;
497 case IntID::ScrollArrowStyle:
498 aResult = eScrollArrowStyle_Single;
499 break;
500 case IntID::TreeOpenDelay:
501 aResult = 1000;
502 break;
503 case IntID::TreeCloseDelay:
504 aResult = 0;
505 break;
506 case IntID::TreeLazyScrollDelay:
507 aResult = 150;
508 break;
509 case IntID::TreeScrollDelay:
510 aResult = 100;
511 break;
512 case IntID::TreeScrollLinesMax:
513 aResult = 3;
514 break;
515 case IntID::WindowsClassic:
516 aResult = !nsUXThemeData::IsAppThemed();
517 break;
518 case IntID::WindowsDefaultTheme:
519 aResult = nsUXThemeData::IsDefaultWindowTheme();
520 break;
521 case IntID::DWMCompositor:
522 aResult = gfxWindowsPlatform::GetPlatform()->DwmCompositionEnabled();
523 break;
524 case IntID::WindowsAccentColorInTitlebar: {
525 aResult = 0;
526 if (NS_WARN_IF(!mColorAccent)) {
527 break;
530 if (!mDwmKey) {
531 mDwmKey = do_CreateInstance("@mozilla.org/windows-registry-key;1");
532 if (!mDwmKey) {
533 break;
536 uint32_t colorPrevalence;
537 nsresult rv = mDwmKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
538 u"SOFTWARE\\Microsoft\\Windows\\DWM"_ns,
539 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
540 if (NS_WARN_IF(NS_FAILED(rv))) {
541 return rv;
544 // The ColorPrevalence value is set to 1 when the "Show color on title
545 // bar" setting in the Color section of Window's Personalization settings
546 // is turned on.
547 aResult = (NS_SUCCEEDED(mDwmKey->ReadIntValue(u"ColorPrevalence"_ns,
548 &colorPrevalence)) &&
549 colorPrevalence == 1)
551 : 0;
553 mDwmKey->Close();
554 } break;
555 case IntID::WindowsGlass:
556 // Aero Glass is only available prior to Windows 8 when DWM is used.
557 aResult = (gfxWindowsPlatform::GetPlatform()->DwmCompositionEnabled() &&
558 !IsWin8OrLater());
559 break;
560 case IntID::AlertNotificationOrigin:
561 aResult = 0;
563 // Get task bar window handle
564 HWND shellWindow = FindWindowW(L"Shell_TrayWnd", nullptr);
566 if (shellWindow != nullptr) {
567 // Determine position
568 APPBARDATA appBarData;
569 appBarData.hWnd = shellWindow;
570 appBarData.cbSize = sizeof(appBarData);
571 if (SHAppBarMessage(ABM_GETTASKBARPOS, &appBarData)) {
572 // Set alert origin as a bit field - see LookAndFeel.h
573 // 0 represents bottom right, sliding vertically.
574 switch (appBarData.uEdge) {
575 case ABE_LEFT:
576 aResult = NS_ALERT_HORIZONTAL | NS_ALERT_LEFT;
577 break;
578 case ABE_RIGHT:
579 aResult = NS_ALERT_HORIZONTAL;
580 break;
581 case ABE_TOP:
582 aResult = NS_ALERT_TOP;
583 [[fallthrough]];
584 case ABE_BOTTOM:
585 // If the task bar is right-to-left,
586 // move the origin to the left
587 if (::GetWindowLong(shellWindow, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
588 aResult |= NS_ALERT_LEFT;
589 break;
594 break;
595 case IntID::IMERawInputUnderlineStyle:
596 case IntID::IMEConvertedTextUnderlineStyle:
597 aResult = static_cast<int32_t>(StyleTextDecorationStyle::Dashed);
598 break;
599 case IntID::IMESelectedRawTextUnderlineStyle:
600 case IntID::IMESelectedConvertedTextUnderline:
601 aResult = static_cast<int32_t>(StyleTextDecorationStyle::None);
602 break;
603 case IntID::SpellCheckerUnderlineStyle:
604 aResult = static_cast<int32_t>(StyleTextDecorationStyle::Wavy);
605 break;
606 case IntID::ScrollbarButtonAutoRepeatBehavior:
607 aResult = 0;
608 break;
609 case IntID::SwipeAnimationEnabled:
610 // Forcibly enable the swipe animation on Windows. It doesn't matter on
611 // platforms where "Drag two fingers to scroll" isn't supported since on
612 // the platforms we will never generate any swipe gesture events.
613 aResult = 1;
614 break;
615 case IntID::UseOverlayScrollbars:
616 aResult = WindowsUIUtils::ComputeOverlayScrollbars();
617 break;
618 case IntID::AllowOverlayScrollbarsOverlap:
619 aResult = 0;
620 break;
621 case IntID::ScrollbarDisplayOnMouseMove:
622 aResult = 1;
623 break;
624 case IntID::ScrollbarFadeBeginDelay:
625 aResult = 2500;
626 break;
627 case IntID::ScrollbarFadeDuration:
628 aResult = 350;
629 break;
630 case IntID::ContextMenuOffsetVertical:
631 case IntID::ContextMenuOffsetHorizontal:
632 aResult = 2;
633 break;
634 case IntID::SystemUsesDarkTheme:
635 res = SystemWantsDarkTheme(aResult);
636 break;
637 case IntID::SystemScrollbarSize:
638 aResult = std::max(WinUtils::GetSystemMetricsForDpi(SM_CXVSCROLL, 96),
639 WinUtils::GetSystemMetricsForDpi(SM_CXHSCROLL, 96));
640 break;
641 case IntID::PrefersReducedMotion: {
642 BOOL enable = TRUE;
643 ::SystemParametersInfoW(SPI_GETCLIENTAREAANIMATION, 0, &enable, 0);
644 aResult = !enable;
645 break;
647 case IntID::PrefersReducedTransparency: {
648 // Prefers reduced transparency if the option for "Transparency Effects"
649 // is disabled
650 aResult = !WindowsUIUtils::ComputeTransparencyEffects();
651 break;
653 case IntID::InvertedColors: {
654 int32_t colorFilter = SystemColorFilter();
656 // Color filter values
657 // 1: Inverted
658 // 2: Grayscale inverted
659 aResult = colorFilter == 1 || colorFilter == 2 ? 1 : 0;
660 break;
662 case IntID::PrimaryPointerCapabilities: {
663 aResult = static_cast<int32_t>(
664 widget::WinUtils::GetPrimaryPointerCapabilities());
665 break;
667 case IntID::AllPointerCapabilities: {
668 aResult =
669 static_cast<int32_t>(widget::WinUtils::GetAllPointerCapabilities());
670 break;
672 case IntID::TouchDeviceSupportPresent:
673 aResult = WinUtils::IsTouchDeviceSupportPresent() ? 1 : 0;
674 break;
675 case IntID::PanelAnimations:
676 aResult = 1;
677 break;
678 default:
679 aResult = 0;
680 res = NS_ERROR_FAILURE;
682 return res;
685 nsresult nsLookAndFeel::NativeGetFloat(FloatID aID, float& aResult) {
686 nsresult res = NS_OK;
688 switch (aID) {
689 case FloatID::IMEUnderlineRelativeSize:
690 aResult = 1.0f;
691 break;
692 case FloatID::SpellCheckerUnderlineRelativeSize:
693 aResult = 1.0f;
694 break;
695 case FloatID::TextScaleFactor:
696 aResult = WindowsUIUtils::ComputeTextScaleFactor();
697 break;
698 default:
699 aResult = -1.0;
700 res = NS_ERROR_FAILURE;
702 return res;
705 LookAndFeelFont nsLookAndFeel::GetLookAndFeelFontInternal(
706 const LOGFONTW& aLogFont, bool aUseShellDlg) {
707 LookAndFeelFont result{};
709 result.haveFont() = false;
711 // Get scaling factor from physical to logical pixels
712 double pixelScale =
713 1.0 / WinUtils::SystemScaleFactor() / LookAndFeel::GetTextScaleFactor();
715 // The lfHeight is in pixels, and it needs to be adjusted for the
716 // device it will be displayed on.
717 // Screens and Printers will differ in DPI
719 // So this accounts for the difference in the DeviceContexts
720 // The pixelScale will typically be 1.0 for the screen
721 // (though larger for hi-dpi screens where the Windows resolution
722 // scale factor is 125% or 150% or even more), and could be
723 // any value when going to a printer, for example pixelScale is
724 // 6.25 when going to a 600dpi printer.
725 float pixelHeight = -aLogFont.lfHeight;
726 if (pixelHeight < 0) {
727 nsAutoFont hFont(::CreateFontIndirectW(&aLogFont));
728 if (!hFont) {
729 return result;
732 nsAutoHDC dc(::GetDC(nullptr));
733 HGDIOBJ hObject = ::SelectObject(dc, hFont);
734 TEXTMETRIC tm;
735 ::GetTextMetrics(dc, &tm);
736 ::SelectObject(dc, hObject);
738 pixelHeight = tm.tmAscent;
741 pixelHeight *= pixelScale;
743 // we have problem on Simplified Chinese system because the system
744 // report the default font size is 8 points. but if we use 8, the text
745 // display very ugly. force it to be at 9 points (12 pixels) on that
746 // system (cp936), but leave other sizes alone.
747 if (pixelHeight < 12 && ::GetACP() == 936) {
748 pixelHeight = 12;
751 result.haveFont() = true;
753 if (aUseShellDlg) {
754 result.name() = u"MS Shell Dlg 2"_ns;
755 } else {
756 result.name() = aLogFont.lfFaceName;
759 result.size() = pixelHeight;
760 result.italic() = !!aLogFont.lfItalic;
761 // FIXME: Other weights?
762 result.weight() =
763 ((aLogFont.lfWeight == FW_BOLD) ? FontWeight::BOLD : FontWeight::NORMAL)
764 .ToFloat();
766 return result;
769 LookAndFeelFont nsLookAndFeel::GetLookAndFeelFont(LookAndFeel::FontID anID) {
770 LookAndFeelFont result{};
772 result.haveFont() = false;
774 // FontID::Icon is handled differently than the others
775 if (anID == LookAndFeel::FontID::Icon) {
776 LOGFONTW logFont;
777 if (::SystemParametersInfoW(SPI_GETICONTITLELOGFONT, sizeof(logFont),
778 (PVOID)&logFont, 0)) {
779 result = GetLookAndFeelFontInternal(logFont, false);
781 return result;
784 NONCLIENTMETRICSW ncm;
785 ncm.cbSize = sizeof(NONCLIENTMETRICSW);
786 if (!::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm),
787 (PVOID)&ncm, 0)) {
788 return result;
791 switch (anID) {
792 case LookAndFeel::FontID::Menu:
793 case LookAndFeel::FontID::MozPullDownMenu:
794 result = GetLookAndFeelFontInternal(ncm.lfMenuFont, false);
795 break;
796 case LookAndFeel::FontID::Caption:
797 result = GetLookAndFeelFontInternal(ncm.lfCaptionFont, false);
798 break;
799 case LookAndFeel::FontID::SmallCaption:
800 result = GetLookAndFeelFontInternal(ncm.lfSmCaptionFont, false);
801 break;
802 case LookAndFeel::FontID::StatusBar:
803 result = GetLookAndFeelFontInternal(ncm.lfStatusFont, false);
804 break;
805 case LookAndFeel::FontID::MozButton:
806 case LookAndFeel::FontID::MozField:
807 case LookAndFeel::FontID::MozList:
808 // XXX It's not clear to me whether this is exactly the right
809 // set of LookAndFeel values to map to the dialog font; we may
810 // want to add or remove cases here after reviewing the visual
811 // results under various Windows versions.
812 result = GetLookAndFeelFontInternal(ncm.lfMessageFont, true);
813 break;
814 default:
815 result = GetLookAndFeelFontInternal(ncm.lfMessageFont, false);
816 break;
819 return result;
822 bool nsLookAndFeel::NativeGetFont(LookAndFeel::FontID anID, nsString& aFontName,
823 gfxFontStyle& aFontStyle) {
824 LookAndFeelFont font = GetLookAndFeelFont(anID);
825 return LookAndFeelFontToStyle(font, aFontName, aFontStyle);
828 /* virtual */
829 char16_t nsLookAndFeel::GetPasswordCharacterImpl() {
830 #define UNICODE_BLACK_CIRCLE_CHAR 0x25cf
831 return UNICODE_BLACK_CIRCLE_CHAR;
834 static Maybe<nscolor> GetAccentColorText(const Maybe<nscolor>& aAccentColor) {
835 if (!aAccentColor) {
836 return Nothing();
838 // We want the color that we return for text that will be drawn over
839 // a background that has the accent color to have good contrast with
840 // the accent color. Windows itself uses either white or black text
841 // depending on how light or dark the accent color is. We do the same
842 // here based on the luminance of the accent color with a threshhold
843 // value. This algorithm should match what Windows does. It comes from:
845 // https://docs.microsoft.com/en-us/windows/uwp/style/color
846 float luminance = (NS_GET_R(*aAccentColor) * 2 + NS_GET_G(*aAccentColor) * 5 +
847 NS_GET_B(*aAccentColor)) /
850 return Some(luminance <= 128 ? NS_RGB(255, 255, 255) : NS_RGB(0, 0, 0));
853 nscolor nsLookAndFeel::GetColorForSysColorIndex(int index) {
854 MOZ_ASSERT(index >= SYS_COLOR_MIN && index <= SYS_COLOR_MAX);
855 return mSysColorTable[index - SYS_COLOR_MIN];
858 void nsLookAndFeel::EnsureInit() {
859 if (mInitialized) {
860 return;
862 mInitialized = true;
864 mColorAccent = WindowsUIUtils::GetAccentColor();
865 mColorAccentText = GetAccentColorText(mColorAccent);
867 if (nsUXThemeData::IsAppThemed()) {
868 mColorMenuHoverText =
869 ::GetColorFromTheme(eUXMenu, MENU_POPUPITEM, MPI_HOT, TMT_TEXTCOLOR);
870 mColorMediaText = ::GetColorFromTheme(eUXMediaToolbar, TP_BUTTON, TS_NORMAL,
871 TMT_TEXTCOLOR);
872 mColorCommunicationsText = ::GetColorFromTheme(
873 eUXCommunicationsToolbar, TP_BUTTON, TS_NORMAL, TMT_TEXTCOLOR);
876 // Fill out the sys color table.
877 for (int i = SYS_COLOR_MIN; i <= SYS_COLOR_MAX; ++i) {
878 mSysColorTable[i - SYS_COLOR_MIN] = [&] {
879 if (auto c = WindowsUIUtils::GetSystemColor(ColorScheme::Light, i)) {
880 return *c;
882 DWORD color = ::GetSysColor(i);
883 return COLOREF_2_NSRGB(color);
884 }();
887 mDarkHighlight =
888 WindowsUIUtils::GetSystemColor(ColorScheme::Dark, COLOR_HIGHLIGHT);
889 mDarkHighlightText =
890 WindowsUIUtils::GetSystemColor(ColorScheme::Dark, COLOR_HIGHLIGHTTEXT);
892 RecordTelemetry();