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/. */
5
6 #include "nsLookAndFeel.h"
7 #include <windows.h>
8 #include <shellapi.h>
9 #include "nsStyleConsts.h"
10 #include "nsUXThemeData.h"
11 #include "nsUXThemeConstants.h"
12 #include "nsWindowsHelpers.h"
13 #include "WinUtils.h"
14 #include "mozilla/FontPropertyTypes.h"
15 #include "mozilla/Telemetry.h"
16 #include "mozilla/WindowsVersion.h"
17 #include "gfxFontConstants.h"
18 #include "gfxWindowsPlatform.h"
19
20 using namespace mozilla;
21 using namespace mozilla::widget;
22
23 // static
GetOperatingSystemVersion()24 LookAndFeel::OperatingSystemVersion nsLookAndFeel::GetOperatingSystemVersion() {
25 static OperatingSystemVersion version = OperatingSystemVersion::Unknown;
26
27 if (version != OperatingSystemVersion::Unknown) {
28 return version;
29 }
30
31 if (IsWin10OrLater()) {
32 version = OperatingSystemVersion::Windows10;
33 } else if (IsWin8OrLater()) {
34 version = OperatingSystemVersion::Windows8;
35 } else {
36 version = OperatingSystemVersion::Windows7;
37 }
38
39 return version;
40 }
41
GetColorFromTheme(nsUXThemeClass cls,int32_t aPart,int32_t aState,int32_t aPropId,nscolor & aColor)42 static nsresult GetColorFromTheme(nsUXThemeClass cls, int32_t aPart,
43 int32_t aState, int32_t aPropId,
44 nscolor& aColor) {
45 COLORREF color;
46 HRESULT hr = GetThemeColor(nsUXThemeData::GetTheme(cls), aPart, aState,
47 aPropId, &color);
48 if (hr == S_OK) {
49 aColor = COLOREF_2_NSRGB(color);
50 return NS_OK;
51 }
52 return NS_ERROR_FAILURE;
53 }
54
GetSystemParam(long flag,int32_t def)55 static int32_t GetSystemParam(long flag, int32_t def) {
56 DWORD value;
57 return ::SystemParametersInfo(flag, 0, &value, 0) ? value : def;
58 }
59
SystemWantsDarkTheme(int32_t & darkThemeEnabled)60 static nsresult SystemWantsDarkTheme(int32_t& darkThemeEnabled) {
61 if (!IsWin10OrLater()) {
62 darkThemeEnabled = 0;
63 return NS_OK;
64 }
65
66 nsresult rv = NS_OK;
67 nsCOMPtr<nsIWindowsRegKey> personalizeKey =
68 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
69 if (NS_WARN_IF(NS_FAILED(rv))) {
70 return rv;
71 }
72
73 rv = personalizeKey->Open(
74 nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
75 nsLiteralString(
76 u"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"),
77 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
78 if (NS_FAILED(rv)) {
79 return rv;
80 }
81
82 uint32_t lightThemeEnabled;
83 rv =
84 personalizeKey->ReadIntValue(u"AppsUseLightTheme"_ns, &lightThemeEnabled);
85 if (NS_SUCCEEDED(rv)) {
86 darkThemeEnabled = !lightThemeEnabled;
87 }
88
89 return rv;
90 }
91
nsLookAndFeel()92 nsLookAndFeel::nsLookAndFeel()
93 : nsXPLookAndFeel(),
94 mHasColorMenuHoverText(false),
95 mHasColorAccent(false),
96 mHasColorAccentText(false),
97 mHasColorMediaText(false),
98 mHasColorCommunicationsText(false),
99 mInitialized(false) {
100 mozilla::Telemetry::Accumulate(mozilla::Telemetry::TOUCH_ENABLED_DEVICE,
101 WinUtils::IsTouchDeviceSupportPresent());
102 }
103
~nsLookAndFeel()104 nsLookAndFeel::~nsLookAndFeel() {}
105
NativeInit()106 void nsLookAndFeel::NativeInit() { EnsureInit(); }
107
108 /* virtual */
RefreshImpl()109 void nsLookAndFeel::RefreshImpl() {
110 nsXPLookAndFeel::RefreshImpl();
111 mInitialized = false; // Fetch system colors next time they're used.
112 }
113
NativeGetColor(ColorID aID,ColorScheme,nscolor & aColor)114 nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme,
115 nscolor& aColor) {
116 EnsureInit();
117
118 nsresult res = NS_OK;
119
120 int idx;
121 switch (aID) {
122 case ColorID::WindowBackground:
123 idx = COLOR_WINDOW;
124 break;
125 case ColorID::WindowForeground:
126 idx = COLOR_WINDOWTEXT;
127 break;
128 case ColorID::WidgetBackground:
129 idx = COLOR_BTNFACE;
130 break;
131 case ColorID::WidgetForeground:
132 idx = COLOR_BTNTEXT;
133 break;
134 case ColorID::WidgetSelectBackground:
135 idx = COLOR_HIGHLIGHT;
136 break;
137 case ColorID::WidgetSelectForeground:
138 idx = COLOR_HIGHLIGHTTEXT;
139 break;
140 case ColorID::Widget3DHighlight:
141 idx = COLOR_BTNHIGHLIGHT;
142 break;
143 case ColorID::Widget3DShadow:
144 idx = COLOR_BTNSHADOW;
145 break;
146 case ColorID::TextBackground:
147 idx = COLOR_WINDOW;
148 break;
149 case ColorID::TextForeground:
150 idx = COLOR_WINDOWTEXT;
151 break;
152 case ColorID::TextSelectBackground:
153 case ColorID::IMESelectedRawTextBackground:
154 case ColorID::IMESelectedConvertedTextBackground:
155 idx = COLOR_HIGHLIGHT;
156 break;
157 case ColorID::TextSelectForeground:
158 case ColorID::IMESelectedRawTextForeground:
159 case ColorID::IMESelectedConvertedTextForeground:
160 idx = COLOR_HIGHLIGHTTEXT;
161 break;
162 case ColorID::IMERawInputBackground:
163 case ColorID::IMEConvertedTextBackground:
164 aColor = NS_TRANSPARENT;
165 return NS_OK;
166 case ColorID::IMERawInputForeground:
167 case ColorID::IMEConvertedTextForeground:
168 aColor = NS_SAME_AS_FOREGROUND_COLOR;
169 return NS_OK;
170 case ColorID::IMERawInputUnderline:
171 case ColorID::IMEConvertedTextUnderline:
172 aColor = NS_SAME_AS_FOREGROUND_COLOR;
173 return NS_OK;
174 case ColorID::IMESelectedRawTextUnderline:
175 case ColorID::IMESelectedConvertedTextUnderline:
176 aColor = NS_TRANSPARENT;
177 return NS_OK;
178 case ColorID::SpellCheckerUnderline:
179 aColor = NS_RGB(0xff, 0, 0);
180 return NS_OK;
181
182 // New CSS 2 Color definitions
183 case ColorID::Activeborder:
184 idx = COLOR_ACTIVEBORDER;
185 break;
186 case ColorID::Activecaption:
187 idx = COLOR_ACTIVECAPTION;
188 break;
189 case ColorID::Appworkspace:
190 idx = COLOR_APPWORKSPACE;
191 break;
192 case ColorID::Background:
193 idx = COLOR_BACKGROUND;
194 break;
195 case ColorID::Buttonface:
196 case ColorID::MozButtonhoverface:
197 idx = COLOR_BTNFACE;
198 break;
199 case ColorID::Buttonhighlight:
200 idx = COLOR_BTNHIGHLIGHT;
201 break;
202 case ColorID::Buttonshadow:
203 idx = COLOR_BTNSHADOW;
204 break;
205 case ColorID::Buttontext:
206 case ColorID::MozButtonhovertext:
207 idx = COLOR_BTNTEXT;
208 break;
209 case ColorID::Captiontext:
210 idx = COLOR_CAPTIONTEXT;
211 break;
212 case ColorID::Graytext:
213 idx = COLOR_GRAYTEXT;
214 break;
215 case ColorID::Highlight:
216 case ColorID::MozHtmlCellhighlight:
217 case ColorID::MozMenuhover:
218 idx = COLOR_HIGHLIGHT;
219 break;
220 case ColorID::MozMenubarhovertext:
221 if (!nsUXThemeData::IsAppThemed()) {
222 idx = nsUXThemeData::AreFlatMenusEnabled() ? COLOR_HIGHLIGHTTEXT
223 : COLOR_MENUTEXT;
224 break;
225 }
226 // Fall through
227 case ColorID::MozMenuhovertext:
228 if (mHasColorMenuHoverText) {
229 aColor = mColorMenuHoverText;
230 return NS_OK;
231 }
232 // Fall through
233 case ColorID::Highlighttext:
234 case ColorID::MozHtmlCellhighlighttext:
235 idx = COLOR_HIGHLIGHTTEXT;
236 break;
237 case ColorID::Inactiveborder:
238 idx = COLOR_INACTIVEBORDER;
239 break;
240 case ColorID::Inactivecaption:
241 idx = COLOR_INACTIVECAPTION;
242 break;
243 case ColorID::Inactivecaptiontext:
244 idx = COLOR_INACTIVECAPTIONTEXT;
245 break;
246 case ColorID::Infobackground:
247 idx = COLOR_INFOBK;
248 break;
249 case ColorID::Infotext:
250 idx = COLOR_INFOTEXT;
251 break;
252 case ColorID::Menu:
253 idx = COLOR_MENU;
254 break;
255 case ColorID::Menutext:
256 case ColorID::MozMenubartext:
257 idx = COLOR_MENUTEXT;
258 break;
259 case ColorID::Scrollbar:
260 idx = COLOR_SCROLLBAR;
261 break;
262 case ColorID::Threeddarkshadow:
263 idx = COLOR_3DDKSHADOW;
264 break;
265 case ColorID::Threedface:
266 idx = COLOR_3DFACE;
267 break;
268 case ColorID::Threedhighlight:
269 idx = COLOR_3DHIGHLIGHT;
270 break;
271 case ColorID::Threedlightshadow:
272 idx = COLOR_3DLIGHT;
273 break;
274 case ColorID::Threedshadow:
275 idx = COLOR_3DSHADOW;
276 break;
277 case ColorID::Window:
278 idx = COLOR_WINDOW;
279 break;
280 case ColorID::Windowframe:
281 idx = COLOR_WINDOWFRAME;
282 break;
283 case ColorID::Windowtext:
284 idx = COLOR_WINDOWTEXT;
285 break;
286 case ColorID::MozEventreerow:
287 case ColorID::MozOddtreerow:
288 case ColorID::Field:
289 case ColorID::MozCombobox:
290 idx = COLOR_WINDOW;
291 break;
292 case ColorID::Fieldtext:
293 case ColorID::MozComboboxtext:
294 idx = COLOR_WINDOWTEXT;
295 break;
296 case ColorID::MozDialog:
297 case ColorID::MozCellhighlight:
298 idx = COLOR_3DFACE;
299 break;
300 case ColorID::MozAccentColor:
301 if (mHasColorAccent) {
302 aColor = mColorAccent;
303 } else {
304 // Seems to be the default color (hardcoded because of bug 1065998)
305 aColor = NS_RGB(0, 120, 215);
306 }
307 return NS_OK;
308 case ColorID::MozAccentColorForeground:
309 if (mHasColorAccentText) {
310 aColor = mColorAccentText;
311 } else {
312 aColor = NS_RGB(255, 255, 255);
313 }
314 return NS_OK;
315 case ColorID::MozWinMediatext:
316 if (mHasColorMediaText) {
317 aColor = mColorMediaText;
318 return NS_OK;
319 }
320 // if we've gotten here just return -moz-dialogtext instead
321 idx = COLOR_WINDOWTEXT;
322 break;
323 case ColorID::MozWinCommunicationstext:
324 if (mHasColorCommunicationsText) {
325 aColor = mColorCommunicationsText;
326 return NS_OK;
327 }
328 // if we've gotten here just return -moz-dialogtext instead
329 idx = COLOR_WINDOWTEXT;
330 break;
331 case ColorID::MozDialogtext:
332 case ColorID::MozCellhighlighttext:
333 case ColorID::MozColheadertext:
334 case ColorID::MozColheaderhovertext:
335 idx = COLOR_WINDOWTEXT;
336 break;
337 case ColorID::MozDragtargetzone:
338 idx = COLOR_HIGHLIGHTTEXT;
339 break;
340 case ColorID::MozButtondefault:
341 idx = COLOR_3DDKSHADOW;
342 break;
343 case ColorID::MozNativehyperlinktext:
344 idx = COLOR_HOTLIGHT;
345 break;
346 default:
347 NS_WARNING("Unknown color for nsLookAndFeel");
348 idx = COLOR_WINDOW;
349 res = NS_ERROR_FAILURE;
350 break;
351 }
352
353 aColor = GetColorForSysColorIndex(idx);
354
355 return res;
356 }
357
NativeGetInt(IntID aID,int32_t & aResult)358 nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
359 nsresult res = NS_OK;
360
361 switch (aID) {
362 case IntID::ScrollButtonLeftMouseButtonAction:
363 aResult = 0;
364 break;
365 case IntID::ScrollButtonMiddleMouseButtonAction:
366 case IntID::ScrollButtonRightMouseButtonAction:
367 aResult = 3;
368 break;
369 case IntID::CaretBlinkTime:
370 aResult = static_cast<int32_t>(::GetCaretBlinkTime());
371 break;
372 case IntID::CaretWidth:
373 aResult = 1;
374 break;
375 case IntID::ShowCaretDuringSelection:
376 aResult = 0;
377 break;
378 case IntID::SelectTextfieldsOnKeyFocus:
379 // Select textfield content when focused by kbd
380 // used by EventStateManager::sTextfieldSelectModel
381 aResult = 1;
382 break;
383 case IntID::SubmenuDelay:
384 // This will default to the Windows' default
385 // (400ms) on error.
386 aResult = GetSystemParam(SPI_GETMENUSHOWDELAY, 400);
387 break;
388 case IntID::TooltipDelay:
389 aResult = 500;
390 break;
391 case IntID::MenusCanOverlapOSBar:
392 // we want XUL popups to be able to overlap the task bar.
393 aResult = 1;
394 break;
395 case IntID::DragThresholdX:
396 // The system metric is the number of pixels at which a drag should
397 // start. Our look and feel metric is the number of pixels you can
398 // move before starting a drag, so subtract 1.
399
400 aResult = ::GetSystemMetrics(SM_CXDRAG) - 1;
401 break;
402 case IntID::DragThresholdY:
403 aResult = ::GetSystemMetrics(SM_CYDRAG) - 1;
404 break;
405 case IntID::UseAccessibilityTheme:
406 // High contrast is a misnomer under Win32 -- any theme can be used with
407 // it, e.g. normal contrast with large fonts, low contrast, etc. The high
408 // contrast flag really means -- use this theme and don't override it.
409 aResult = nsUXThemeData::IsHighContrastOn();
410 break;
411 case IntID::ScrollArrowStyle:
412 aResult = eScrollArrowStyle_Single;
413 break;
414 case IntID::ScrollSliderStyle:
415 aResult = eScrollThumbStyle_Proportional;
416 break;
417 case IntID::TreeOpenDelay:
418 aResult = 1000;
419 break;
420 case IntID::TreeCloseDelay:
421 aResult = 0;
422 break;
423 case IntID::TreeLazyScrollDelay:
424 aResult = 150;
425 break;
426 case IntID::TreeScrollDelay:
427 aResult = 100;
428 break;
429 case IntID::TreeScrollLinesMax:
430 aResult = 3;
431 break;
432 case IntID::WindowsClassic:
433 aResult = !nsUXThemeData::IsAppThemed();
434 break;
435 case IntID::WindowsDefaultTheme:
436 aResult = nsUXThemeData::IsDefaultWindowTheme();
437 break;
438 case IntID::WindowsThemeIdentifier:
439 aResult = nsUXThemeData::GetNativeThemeId();
440 break;
441 case IntID::OperatingSystemVersionIdentifier: {
442 aResult = int32_t(GetOperatingSystemVersion());
443 break;
444 }
445
446 case IntID::MacGraphiteTheme:
447 aResult = 0;
448 res = NS_ERROR_NOT_IMPLEMENTED;
449 break;
450 case IntID::DWMCompositor:
451 aResult = gfxWindowsPlatform::GetPlatform()->DwmCompositionEnabled();
452 break;
453 case IntID::WindowsAccentColorInTitlebar: {
454 nscolor unused;
455 if (NS_WARN_IF(NS_FAILED(GetAccentColor(unused)))) {
456 aResult = 0;
457 break;
458 }
459
460 uint32_t colorPrevalence;
461 nsresult rv = mDwmKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
462 u"SOFTWARE\\Microsoft\\Windows\\DWM"_ns,
463 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
464 if (NS_WARN_IF(NS_FAILED(rv))) {
465 return rv;
466 }
467
468 // The ColorPrevalence value is set to 1 when the "Show color on title
469 // bar" setting in the Color section of Window's Personalization settings
470 // is turned on.
471 aResult = (NS_SUCCEEDED(mDwmKey->ReadIntValue(u"ColorPrevalence"_ns,
472 &colorPrevalence)) &&
473 colorPrevalence == 1)
474 ? 1
475 : 0;
476
477 mDwmKey->Close();
478 } break;
479 case IntID::WindowsGlass:
480 // Aero Glass is only available prior to Windows 8 when DWM is used.
481 aResult = (gfxWindowsPlatform::GetPlatform()->DwmCompositionEnabled() &&
482 !IsWin8OrLater());
483 break;
484 case IntID::AlertNotificationOrigin:
485 aResult = 0;
486 {
487 // Get task bar window handle
488 HWND shellWindow = FindWindowW(L"Shell_TrayWnd", nullptr);
489
490 if (shellWindow != nullptr) {
491 // Determine position
492 APPBARDATA appBarData;
493 appBarData.hWnd = shellWindow;
494 appBarData.cbSize = sizeof(appBarData);
495 if (SHAppBarMessage(ABM_GETTASKBARPOS, &appBarData)) {
496 // Set alert origin as a bit field - see LookAndFeel.h
497 // 0 represents bottom right, sliding vertically.
498 switch (appBarData.uEdge) {
499 case ABE_LEFT:
500 aResult = NS_ALERT_HORIZONTAL | NS_ALERT_LEFT;
501 break;
502 case ABE_RIGHT:
503 aResult = NS_ALERT_HORIZONTAL;
504 break;
505 case ABE_TOP:
506 aResult = NS_ALERT_TOP;
507 // fall through for the right-to-left handling.
508 case ABE_BOTTOM:
509 // If the task bar is right-to-left,
510 // move the origin to the left
511 if (::GetWindowLong(shellWindow, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
512 aResult |= NS_ALERT_LEFT;
513 break;
514 }
515 }
516 }
517 }
518 break;
519 case IntID::IMERawInputUnderlineStyle:
520 case IntID::IMEConvertedTextUnderlineStyle:
521 aResult = NS_STYLE_TEXT_DECORATION_STYLE_DASHED;
522 break;
523 case IntID::IMESelectedRawTextUnderlineStyle:
524 case IntID::IMESelectedConvertedTextUnderline:
525 aResult = NS_STYLE_TEXT_DECORATION_STYLE_NONE;
526 break;
527 case IntID::SpellCheckerUnderlineStyle:
528 aResult = NS_STYLE_TEXT_DECORATION_STYLE_WAVY;
529 break;
530 case IntID::ScrollbarButtonAutoRepeatBehavior:
531 aResult = 0;
532 break;
533 case IntID::SwipeAnimationEnabled:
534 aResult = 0;
535 break;
536 case IntID::UseOverlayScrollbars:
537 aResult = false;
538 break;
539 case IntID::AllowOverlayScrollbarsOverlap:
540 aResult = 0;
541 break;
542 case IntID::ScrollbarDisplayOnMouseMove:
543 aResult = 1;
544 break;
545 case IntID::ScrollbarFadeBeginDelay:
546 aResult = 2500;
547 break;
548 case IntID::ScrollbarFadeDuration:
549 aResult = 350;
550 break;
551 case IntID::ContextMenuOffsetVertical:
552 case IntID::ContextMenuOffsetHorizontal:
553 aResult = 2;
554 break;
555 case IntID::SystemUsesDarkTheme:
556 res = SystemWantsDarkTheme(aResult);
557 break;
558 case IntID::SystemVerticalScrollbarWidth:
559 aResult = WinUtils::GetSystemMetricsForDpi(SM_CXVSCROLL, 96);
560 break;
561 case IntID::SystemHorizontalScrollbarHeight:
562 aResult = WinUtils::GetSystemMetricsForDpi(SM_CXHSCROLL, 96);
563 break;
564 case IntID::PrefersReducedMotion: {
565 BOOL enableAnimation = TRUE;
566 ::SystemParametersInfoW(SPI_GETCLIENTAREAANIMATION, 0, &enableAnimation,
567 0);
568 aResult = enableAnimation ? 0 : 1;
569 break;
570 }
571 case IntID::PrimaryPointerCapabilities: {
572 aResult = static_cast<int32_t>(
573 widget::WinUtils::GetPrimaryPointerCapabilities());
574 break;
575 }
576 case IntID::AllPointerCapabilities: {
577 aResult =
578 static_cast<int32_t>(widget::WinUtils::GetAllPointerCapabilities());
579 break;
580 }
581 default:
582 aResult = 0;
583 res = NS_ERROR_FAILURE;
584 }
585 return res;
586 }
587
NativeGetFloat(FloatID aID,float & aResult)588 nsresult nsLookAndFeel::NativeGetFloat(FloatID aID, float& aResult) {
589 nsresult res = NS_OK;
590
591 switch (aID) {
592 case FloatID::IMEUnderlineRelativeSize:
593 aResult = 1.0f;
594 break;
595 case FloatID::SpellCheckerUnderlineRelativeSize:
596 aResult = 1.0f;
597 break;
598 default:
599 aResult = -1.0;
600 res = NS_ERROR_FAILURE;
601 }
602 return res;
603 }
604
GetLookAndFeelFontInternal(const LOGFONTW & aLogFont,bool aUseShellDlg)605 LookAndFeelFont nsLookAndFeel::GetLookAndFeelFontInternal(
606 const LOGFONTW& aLogFont, bool aUseShellDlg) {
607 LookAndFeelFont result{};
608
609 result.haveFont() = false;
610
611 // Get scaling factor from physical to logical pixels
612 double pixelScale = 1.0 / WinUtils::SystemScaleFactor();
613
614 // The lfHeight is in pixels, and it needs to be adjusted for the
615 // device it will be displayed on.
616 // Screens and Printers will differ in DPI
617 //
618 // So this accounts for the difference in the DeviceContexts
619 // The pixelScale will typically be 1.0 for the screen
620 // (though larger for hi-dpi screens where the Windows resolution
621 // scale factor is 125% or 150% or even more), and could be
622 // any value when going to a printer, for example pixelScale is
623 // 6.25 when going to a 600dpi printer.
624 float pixelHeight = -aLogFont.lfHeight;
625 if (pixelHeight < 0) {
626 nsAutoFont hFont(::CreateFontIndirectW(&aLogFont));
627 if (!hFont) {
628 return result;
629 }
630
631 nsAutoHDC dc(::GetDC(nullptr));
632 HGDIOBJ hObject = ::SelectObject(dc, hFont);
633 TEXTMETRIC tm;
634 ::GetTextMetrics(dc, &tm);
635 ::SelectObject(dc, hObject);
636
637 pixelHeight = tm.tmAscent;
638 }
639
640 pixelHeight *= pixelScale;
641
642 // we have problem on Simplified Chinese system because the system
643 // report the default font size is 8 points. but if we use 8, the text
644 // display very ugly. force it to be at 9 points (12 pixels) on that
645 // system (cp936), but leave other sizes alone.
646 if (pixelHeight < 12 && ::GetACP() == 936) {
647 pixelHeight = 12;
648 }
649
650 result.haveFont() = true;
651
652 if (aUseShellDlg) {
653 result.name() = u"MS Shell Dlg 2"_ns;
654 } else {
655 result.name() = aLogFont.lfFaceName;
656 }
657
658 result.size() = pixelHeight;
659 result.italic() = !!aLogFont.lfItalic;
660 // FIXME: Other weights?
661 result.weight() = ((aLogFont.lfWeight == FW_BOLD) ? FontWeight::Bold()
662 : FontWeight::Normal())
663 .ToFloat();
664
665 return result;
666 }
667
GetLookAndFeelFont(LookAndFeel::FontID anID)668 LookAndFeelFont nsLookAndFeel::GetLookAndFeelFont(LookAndFeel::FontID anID) {
669 LookAndFeelFont result{};
670
671 result.haveFont() = false;
672
673 // FontID::Icon is handled differently than the others
674 if (anID == LookAndFeel::FontID::Icon) {
675 LOGFONTW logFont;
676 if (::SystemParametersInfoW(SPI_GETICONTITLELOGFONT, sizeof(logFont),
677 (PVOID)&logFont, 0)) {
678 result = GetLookAndFeelFontInternal(logFont, false);
679 }
680 return result;
681 }
682
683 NONCLIENTMETRICSW ncm;
684 ncm.cbSize = sizeof(NONCLIENTMETRICSW);
685 if (!::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm),
686 (PVOID)&ncm, 0)) {
687 return result;
688 }
689
690 switch (anID) {
691 case LookAndFeel::FontID::Menu:
692 case LookAndFeel::FontID::MozPullDownMenu:
693 result = GetLookAndFeelFontInternal(ncm.lfMenuFont, false);
694 break;
695 case LookAndFeel::FontID::Caption:
696 result = GetLookAndFeelFontInternal(ncm.lfCaptionFont, false);
697 break;
698 case LookAndFeel::FontID::SmallCaption:
699 result = GetLookAndFeelFontInternal(ncm.lfSmCaptionFont, false);
700 break;
701 case LookAndFeel::FontID::StatusBar:
702 result = GetLookAndFeelFontInternal(ncm.lfStatusFont, false);
703 break;
704 case LookAndFeel::FontID::MozDialog:
705 case LookAndFeel::FontID::MozButton:
706 case LookAndFeel::FontID::MozField:
707 case LookAndFeel::FontID::MozList:
708 // XXX It's not clear to me whether this is exactly the right
709 // set of LookAndFeel values to map to the dialog font; we may
710 // want to add or remove cases here after reviewing the visual
711 // results under various Windows versions.
712 result = GetLookAndFeelFontInternal(ncm.lfMessageFont, true);
713 break;
714 default:
715 result = GetLookAndFeelFontInternal(ncm.lfMessageFont, false);
716 break;
717 }
718
719 return result;
720 }
721
NativeGetFont(LookAndFeel::FontID anID,nsString & aFontName,gfxFontStyle & aFontStyle)722 bool nsLookAndFeel::NativeGetFont(LookAndFeel::FontID anID, nsString& aFontName,
723 gfxFontStyle& aFontStyle) {
724 LookAndFeelFont font = GetLookAndFeelFont(anID);
725 return LookAndFeelFontToStyle(font, aFontName, aFontStyle);
726 }
727
728 /* virtual */
GetPasswordCharacterImpl()729 char16_t nsLookAndFeel::GetPasswordCharacterImpl() {
730 #define UNICODE_BLACK_CIRCLE_CHAR 0x25cf
731 return UNICODE_BLACK_CIRCLE_CHAR;
732 }
733
734 /* static */
GetAccentColor(nscolor & aColor)735 nsresult nsLookAndFeel::GetAccentColor(nscolor& aColor) {
736 nsresult rv;
737
738 if (!mDwmKey) {
739 mDwmKey = do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
740 if (NS_WARN_IF(NS_FAILED(rv))) {
741 return rv;
742 }
743 }
744
745 rv = mDwmKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
746 u"SOFTWARE\\Microsoft\\Windows\\DWM"_ns,
747 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
748 if (NS_WARN_IF(NS_FAILED(rv))) {
749 return rv;
750 }
751
752 uint32_t accentColor;
753 if (NS_SUCCEEDED(mDwmKey->ReadIntValue(u"AccentColor"_ns, &accentColor))) {
754 // The order of the color components in the DWORD stored in the registry
755 // happens to be the same order as we store the components in nscolor
756 // so we can just assign directly here.
757 aColor = accentColor;
758 rv = NS_OK;
759 } else {
760 rv = NS_ERROR_NOT_AVAILABLE;
761 }
762
763 mDwmKey->Close();
764
765 return rv;
766 }
767
768 /* static */
GetAccentColorText(nscolor & aColor)769 nsresult nsLookAndFeel::GetAccentColorText(nscolor& aColor) {
770 nscolor accentColor;
771 nsresult rv = GetAccentColor(accentColor);
772 if (NS_WARN_IF(NS_FAILED(rv))) {
773 return rv;
774 }
775
776 // We want the color that we return for text that will be drawn over
777 // a background that has the accent color to have good contrast with
778 // the accent color. Windows itself uses either white or black text
779 // depending on how light or dark the accent color is. We do the same
780 // here based on the luminance of the accent color with a threshhold
781 // value. This algorithm should match what Windows does. It comes from:
782 //
783 // https://docs.microsoft.com/en-us/windows/uwp/style/color
784
785 float luminance = (NS_GET_R(accentColor) * 2 + NS_GET_G(accentColor) * 5 +
786 NS_GET_B(accentColor)) /
787 8;
788
789 aColor = (luminance <= 128) ? NS_RGB(255, 255, 255) : NS_RGB(0, 0, 0);
790
791 return NS_OK;
792 }
793
GetColorForSysColorIndex(int index)794 nscolor nsLookAndFeel::GetColorForSysColorIndex(int index) {
795 MOZ_ASSERT(index >= SYS_COLOR_MIN && index <= SYS_COLOR_MAX);
796 return mSysColorTable[index - SYS_COLOR_MIN];
797 }
798
EnsureInit()799 void nsLookAndFeel::EnsureInit() {
800 if (mInitialized) {
801 return;
802 }
803 mInitialized = true;
804
805 nsresult res;
806
807 res = GetAccentColor(mColorAccent);
808 mHasColorAccent = NS_SUCCEEDED(res);
809
810 res = GetAccentColorText(mColorAccentText);
811 mHasColorAccentText = NS_SUCCEEDED(res);
812
813 if (nsUXThemeData::IsAppThemed()) {
814 res = ::GetColorFromTheme(eUXMenu, MENU_POPUPITEM, MPI_HOT, TMT_TEXTCOLOR,
815 mColorMenuHoverText);
816 mHasColorMenuHoverText = NS_SUCCEEDED(res);
817
818 res = ::GetColorFromTheme(eUXMediaToolbar, TP_BUTTON, TS_NORMAL,
819 TMT_TEXTCOLOR, mColorMediaText);
820 mHasColorMediaText = NS_SUCCEEDED(res);
821
822 res = ::GetColorFromTheme(eUXCommunicationsToolbar, TP_BUTTON, TS_NORMAL,
823 TMT_TEXTCOLOR, mColorCommunicationsText);
824 mHasColorCommunicationsText = NS_SUCCEEDED(res);
825 }
826
827 // Fill out the sys color table.
828 for (int i = SYS_COLOR_MIN; i <= SYS_COLOR_MAX; ++i) {
829 DWORD color = ::GetSysColor(i);
830 mSysColorTable[i - SYS_COLOR_MIN] = COLOREF_2_NSRGB(color);
831 }
832
833 RecordTelemetry();
834 }
835