Bug 1761003 [wpt PR 33324] - Add comment pointing to followup bug, and fix typos...
[gecko.git] / widget / windows / WinUtils.cpp
blob80f79ada3086d9ece1ba7f2ef38da14df3fb4874
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sts=2 sw=2 et cin: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "WinUtils.h"
9 #include <knownfolders.h>
10 #include <winioctl.h>
12 #include "gfxPlatform.h"
13 #include "gfxUtils.h"
14 #include "nsWindow.h"
15 #include "nsWindowDefs.h"
16 #include "InputDeviceUtils.h"
17 #include "KeyboardLayout.h"
18 #include "mozilla/ArrayUtils.h"
19 #include "mozilla/BackgroundHangMonitor.h"
20 #include "mozilla/ClearOnShutdown.h"
21 #include "mozilla/dom/MouseEventBinding.h"
22 #include "mozilla/gfx/2D.h"
23 #include "mozilla/gfx/DataSurfaceHelpers.h"
24 #include "mozilla/gfx/Logging.h"
25 #include "mozilla/Preferences.h"
26 #include "mozilla/ProfilerThreadSleep.h"
27 #include "mozilla/RefPtr.h"
28 #include "mozilla/SchedulerGroup.h"
29 #include "mozilla/WinHeaderOnlyUtils.h"
30 #include "mozilla/WindowsVersion.h"
31 #include "mozilla/Unused.h"
32 #include "nsIContentPolicy.h"
33 #include "WindowsUIUtils.h"
34 #include "nsContentUtils.h"
36 #include "mozilla/Logging.h"
38 #include "nsString.h"
39 #include "nsDirectoryServiceUtils.h"
40 #include "imgIContainer.h"
41 #include "imgITools.h"
42 #include "nsNetUtil.h"
43 #include "nsIOutputStream.h"
44 #include "nsNetCID.h"
45 #include "prtime.h"
46 #ifdef MOZ_PLACES
47 # include "nsIFaviconService.h"
48 #endif
49 #include "nsIDownloader.h"
50 #include "nsIChannel.h"
51 #include "nsIThread.h"
52 #include "MainThreadUtils.h"
53 #include "nsLookAndFeel.h"
54 #include "nsUnicharUtils.h"
55 #include "nsWindowsHelpers.h"
56 #include "WinContentSystemParameters.h"
57 #include "WinWindowOcclusionTracker.h"
59 #include <textstor.h>
60 #include "TSFTextStore.h"
62 #include <shlobj.h>
63 #include <shlwapi.h>
65 mozilla::LazyLogModule gWindowsLog("Widget");
67 #define LOG_E(...) MOZ_LOG(gWindowsLog, LogLevel::Error, (__VA_ARGS__))
68 #define LOG_D(...) MOZ_LOG(gWindowsLog, LogLevel::Debug, (__VA_ARGS__))
70 using namespace mozilla::gfx;
72 namespace mozilla {
73 namespace widget {
75 #define ENTRY(_msg) \
76 { \
77 _msg, { #_msg, _msg } \
79 std::unordered_map<UINT, EventMsgInfo> gAllEvents = {
80 ENTRY(WM_NULL),
81 ENTRY(WM_CREATE),
82 ENTRY(WM_DESTROY),
83 ENTRY(WM_MOVE),
84 ENTRY(WM_SIZE),
85 ENTRY(WM_ACTIVATE),
86 ENTRY(WM_SETFOCUS),
87 ENTRY(WM_KILLFOCUS),
88 ENTRY(WM_ENABLE),
89 ENTRY(WM_SETREDRAW),
90 ENTRY(WM_SETTEXT),
91 ENTRY(WM_GETTEXT),
92 ENTRY(WM_GETTEXTLENGTH),
93 ENTRY(WM_PAINT),
94 ENTRY(WM_CLOSE),
95 ENTRY(WM_QUERYENDSESSION),
96 ENTRY(WM_QUIT),
97 ENTRY(WM_QUERYOPEN),
98 ENTRY(WM_ERASEBKGND),
99 ENTRY(WM_SYSCOLORCHANGE),
100 ENTRY(WM_ENDSESSION),
101 ENTRY(WM_SHOWWINDOW),
102 ENTRY(WM_SETTINGCHANGE),
103 ENTRY(WM_DEVMODECHANGE),
104 ENTRY(WM_ACTIVATEAPP),
105 ENTRY(WM_FONTCHANGE),
106 ENTRY(WM_TIMECHANGE),
107 ENTRY(WM_CANCELMODE),
108 ENTRY(WM_SETCURSOR),
109 ENTRY(WM_MOUSEACTIVATE),
110 ENTRY(WM_CHILDACTIVATE),
111 ENTRY(WM_QUEUESYNC),
112 ENTRY(WM_GETMINMAXINFO),
113 ENTRY(WM_PAINTICON),
114 ENTRY(WM_ICONERASEBKGND),
115 ENTRY(WM_NEXTDLGCTL),
116 ENTRY(WM_SPOOLERSTATUS),
117 ENTRY(WM_DRAWITEM),
118 ENTRY(WM_MEASUREITEM),
119 ENTRY(WM_DELETEITEM),
120 ENTRY(WM_VKEYTOITEM),
121 ENTRY(WM_CHARTOITEM),
122 ENTRY(WM_SETFONT),
123 ENTRY(WM_GETFONT),
124 ENTRY(WM_SETHOTKEY),
125 ENTRY(WM_GETHOTKEY),
126 ENTRY(WM_QUERYDRAGICON),
127 ENTRY(WM_COMPAREITEM),
128 ENTRY(WM_GETOBJECT),
129 ENTRY(WM_COMPACTING),
130 ENTRY(WM_COMMNOTIFY),
131 ENTRY(WM_WINDOWPOSCHANGING),
132 ENTRY(WM_WINDOWPOSCHANGED),
133 ENTRY(WM_POWER),
134 ENTRY(WM_COPYDATA),
135 ENTRY(WM_CANCELJOURNAL),
136 ENTRY(WM_NOTIFY),
137 ENTRY(WM_INPUTLANGCHANGEREQUEST),
138 ENTRY(WM_INPUTLANGCHANGE),
139 ENTRY(WM_TCARD),
140 ENTRY(WM_HELP),
141 ENTRY(WM_USERCHANGED),
142 ENTRY(WM_NOTIFYFORMAT),
143 ENTRY(WM_CONTEXTMENU),
144 ENTRY(WM_STYLECHANGING),
145 ENTRY(WM_STYLECHANGED),
146 ENTRY(WM_DISPLAYCHANGE),
147 ENTRY(WM_GETICON),
148 ENTRY(WM_SETICON),
149 ENTRY(WM_NCCREATE),
150 ENTRY(WM_NCDESTROY),
151 ENTRY(WM_NCCALCSIZE),
152 ENTRY(WM_NCHITTEST),
153 ENTRY(WM_NCPAINT),
154 ENTRY(WM_NCACTIVATE),
155 ENTRY(WM_GETDLGCODE),
156 ENTRY(WM_SYNCPAINT),
157 ENTRY(WM_NCMOUSEMOVE),
158 ENTRY(WM_NCLBUTTONDOWN),
159 ENTRY(WM_NCLBUTTONUP),
160 ENTRY(WM_NCLBUTTONDBLCLK),
161 ENTRY(WM_NCRBUTTONDOWN),
162 ENTRY(WM_NCRBUTTONUP),
163 ENTRY(WM_NCRBUTTONDBLCLK),
164 ENTRY(WM_NCMBUTTONDOWN),
165 ENTRY(WM_NCMBUTTONUP),
166 ENTRY(WM_NCMBUTTONDBLCLK),
167 ENTRY(EM_GETSEL),
168 ENTRY(EM_SETSEL),
169 ENTRY(EM_GETRECT),
170 ENTRY(EM_SETRECT),
171 ENTRY(EM_SETRECTNP),
172 ENTRY(EM_SCROLL),
173 ENTRY(EM_LINESCROLL),
174 ENTRY(EM_SCROLLCARET),
175 ENTRY(EM_GETMODIFY),
176 ENTRY(EM_SETMODIFY),
177 ENTRY(EM_GETLINECOUNT),
178 ENTRY(EM_LINEINDEX),
179 ENTRY(EM_SETHANDLE),
180 ENTRY(EM_GETHANDLE),
181 ENTRY(EM_GETTHUMB),
182 ENTRY(EM_LINELENGTH),
183 ENTRY(EM_REPLACESEL),
184 ENTRY(EM_GETLINE),
185 ENTRY(EM_LIMITTEXT),
186 ENTRY(EM_CANUNDO),
187 ENTRY(EM_UNDO),
188 ENTRY(EM_FMTLINES),
189 ENTRY(EM_LINEFROMCHAR),
190 ENTRY(EM_SETTABSTOPS),
191 ENTRY(EM_SETPASSWORDCHAR),
192 ENTRY(EM_EMPTYUNDOBUFFER),
193 ENTRY(EM_GETFIRSTVISIBLELINE),
194 ENTRY(EM_SETREADONLY),
195 ENTRY(EM_SETWORDBREAKPROC),
196 ENTRY(EM_GETWORDBREAKPROC),
197 ENTRY(EM_GETPASSWORDCHAR),
198 ENTRY(EM_SETMARGINS),
199 ENTRY(EM_GETMARGINS),
200 ENTRY(EM_GETLIMITTEXT),
201 ENTRY(EM_POSFROMCHAR),
202 ENTRY(EM_CHARFROMPOS),
203 ENTRY(EM_SETIMESTATUS),
204 ENTRY(EM_GETIMESTATUS),
205 ENTRY(SBM_SETPOS),
206 ENTRY(SBM_GETPOS),
207 ENTRY(SBM_SETRANGE),
208 ENTRY(SBM_SETRANGEREDRAW),
209 ENTRY(SBM_GETRANGE),
210 ENTRY(SBM_ENABLE_ARROWS),
211 ENTRY(SBM_SETSCROLLINFO),
212 ENTRY(SBM_GETSCROLLINFO),
213 ENTRY(WM_KEYDOWN),
214 ENTRY(WM_KEYUP),
215 ENTRY(WM_CHAR),
216 ENTRY(WM_DEADCHAR),
217 ENTRY(WM_SYSKEYDOWN),
218 ENTRY(WM_SYSKEYUP),
219 ENTRY(WM_SYSCHAR),
220 ENTRY(WM_SYSDEADCHAR),
221 ENTRY(WM_KEYLAST),
222 ENTRY(WM_IME_STARTCOMPOSITION),
223 ENTRY(WM_IME_ENDCOMPOSITION),
224 ENTRY(WM_IME_COMPOSITION),
225 ENTRY(WM_INITDIALOG),
226 ENTRY(WM_COMMAND),
227 ENTRY(WM_SYSCOMMAND),
228 ENTRY(WM_TIMER),
229 ENTRY(WM_HSCROLL),
230 ENTRY(WM_VSCROLL),
231 ENTRY(WM_INITMENU),
232 ENTRY(WM_INITMENUPOPUP),
233 ENTRY(WM_MENUSELECT),
234 ENTRY(WM_MENUCHAR),
235 ENTRY(WM_ENTERIDLE),
236 ENTRY(WM_MENURBUTTONUP),
237 ENTRY(WM_MENUDRAG),
238 ENTRY(WM_MENUGETOBJECT),
239 ENTRY(WM_UNINITMENUPOPUP),
240 ENTRY(WM_MENUCOMMAND),
241 ENTRY(WM_CHANGEUISTATE),
242 ENTRY(WM_UPDATEUISTATE),
243 ENTRY(WM_CTLCOLORMSGBOX),
244 ENTRY(WM_CTLCOLOREDIT),
245 ENTRY(WM_CTLCOLORLISTBOX),
246 ENTRY(WM_CTLCOLORBTN),
247 ENTRY(WM_CTLCOLORDLG),
248 ENTRY(WM_CTLCOLORSCROLLBAR),
249 ENTRY(WM_CTLCOLORSTATIC),
250 ENTRY(CB_GETEDITSEL),
251 ENTRY(CB_LIMITTEXT),
252 ENTRY(CB_SETEDITSEL),
253 ENTRY(CB_ADDSTRING),
254 ENTRY(CB_DELETESTRING),
255 ENTRY(CB_DIR),
256 ENTRY(CB_GETCOUNT),
257 ENTRY(CB_GETCURSEL),
258 ENTRY(CB_GETLBTEXT),
259 ENTRY(CB_GETLBTEXTLEN),
260 ENTRY(CB_INSERTSTRING),
261 ENTRY(CB_RESETCONTENT),
262 ENTRY(CB_FINDSTRING),
263 ENTRY(CB_SELECTSTRING),
264 ENTRY(CB_SETCURSEL),
265 ENTRY(CB_SHOWDROPDOWN),
266 ENTRY(CB_GETITEMDATA),
267 ENTRY(CB_SETITEMDATA),
268 ENTRY(CB_GETDROPPEDCONTROLRECT),
269 ENTRY(CB_SETITEMHEIGHT),
270 ENTRY(CB_GETITEMHEIGHT),
271 ENTRY(CB_SETEXTENDEDUI),
272 ENTRY(CB_GETEXTENDEDUI),
273 ENTRY(CB_GETDROPPEDSTATE),
274 ENTRY(CB_FINDSTRINGEXACT),
275 ENTRY(CB_SETLOCALE),
276 ENTRY(CB_GETLOCALE),
277 ENTRY(CB_GETTOPINDEX),
278 ENTRY(CB_SETTOPINDEX),
279 ENTRY(CB_GETHORIZONTALEXTENT),
280 ENTRY(CB_SETHORIZONTALEXTENT),
281 ENTRY(CB_GETDROPPEDWIDTH),
282 ENTRY(CB_SETDROPPEDWIDTH),
283 ENTRY(CB_INITSTORAGE),
284 ENTRY(CB_MSGMAX),
285 ENTRY(LB_ADDSTRING),
286 ENTRY(LB_INSERTSTRING),
287 ENTRY(LB_DELETESTRING),
288 ENTRY(LB_SELITEMRANGEEX),
289 ENTRY(LB_RESETCONTENT),
290 ENTRY(LB_SETSEL),
291 ENTRY(LB_SETCURSEL),
292 ENTRY(LB_GETSEL),
293 ENTRY(LB_GETCURSEL),
294 ENTRY(LB_GETTEXT),
295 ENTRY(LB_GETTEXTLEN),
296 ENTRY(LB_GETCOUNT),
297 ENTRY(LB_SELECTSTRING),
298 ENTRY(LB_DIR),
299 ENTRY(LB_GETTOPINDEX),
300 ENTRY(LB_FINDSTRING),
301 ENTRY(LB_GETSELCOUNT),
302 ENTRY(LB_GETSELITEMS),
303 ENTRY(LB_SETTABSTOPS),
304 ENTRY(LB_GETHORIZONTALEXTENT),
305 ENTRY(LB_SETHORIZONTALEXTENT),
306 ENTRY(LB_SETCOLUMNWIDTH),
307 ENTRY(LB_ADDFILE),
308 ENTRY(LB_SETTOPINDEX),
309 ENTRY(LB_GETITEMRECT),
310 ENTRY(LB_GETITEMDATA),
311 ENTRY(LB_SETITEMDATA),
312 ENTRY(LB_SELITEMRANGE),
313 ENTRY(LB_SETANCHORINDEX),
314 ENTRY(LB_GETANCHORINDEX),
315 ENTRY(LB_SETCARETINDEX),
316 ENTRY(LB_GETCARETINDEX),
317 ENTRY(LB_SETITEMHEIGHT),
318 ENTRY(LB_GETITEMHEIGHT),
319 ENTRY(LB_FINDSTRINGEXACT),
320 ENTRY(LB_SETLOCALE),
321 ENTRY(LB_GETLOCALE),
322 ENTRY(LB_SETCOUNT),
323 ENTRY(LB_INITSTORAGE),
324 ENTRY(LB_ITEMFROMPOINT),
325 ENTRY(LB_MSGMAX),
326 ENTRY(WM_MOUSEMOVE),
327 ENTRY(WM_LBUTTONDOWN),
328 ENTRY(WM_LBUTTONUP),
329 ENTRY(WM_LBUTTONDBLCLK),
330 ENTRY(WM_RBUTTONDOWN),
331 ENTRY(WM_RBUTTONUP),
332 ENTRY(WM_RBUTTONDBLCLK),
333 ENTRY(WM_MBUTTONDOWN),
334 ENTRY(WM_MBUTTONUP),
335 ENTRY(WM_MBUTTONDBLCLK),
336 ENTRY(WM_MOUSEWHEEL),
337 ENTRY(WM_MOUSEHWHEEL),
338 ENTRY(WM_PARENTNOTIFY),
339 ENTRY(WM_ENTERMENULOOP),
340 ENTRY(WM_EXITMENULOOP),
341 ENTRY(WM_NEXTMENU),
342 ENTRY(WM_SIZING),
343 ENTRY(WM_CAPTURECHANGED),
344 ENTRY(WM_MOVING),
345 ENTRY(WM_POWERBROADCAST),
346 ENTRY(WM_DEVICECHANGE),
347 ENTRY(WM_MDICREATE),
348 ENTRY(WM_MDIDESTROY),
349 ENTRY(WM_MDIACTIVATE),
350 ENTRY(WM_MDIRESTORE),
351 ENTRY(WM_MDINEXT),
352 ENTRY(WM_MDIMAXIMIZE),
353 ENTRY(WM_MDITILE),
354 ENTRY(WM_MDICASCADE),
355 ENTRY(WM_MDIICONARRANGE),
356 ENTRY(WM_MDIGETACTIVE),
357 ENTRY(WM_MDISETMENU),
358 ENTRY(WM_ENTERSIZEMOVE),
359 ENTRY(WM_EXITSIZEMOVE),
360 ENTRY(WM_DROPFILES),
361 ENTRY(WM_MDIREFRESHMENU),
362 ENTRY(WM_IME_SETCONTEXT),
363 ENTRY(WM_IME_NOTIFY),
364 ENTRY(WM_IME_CONTROL),
365 ENTRY(WM_IME_COMPOSITIONFULL),
366 ENTRY(WM_IME_SELECT),
367 ENTRY(WM_IME_CHAR),
368 ENTRY(WM_IME_REQUEST),
369 ENTRY(WM_IME_KEYDOWN),
370 ENTRY(WM_IME_KEYUP),
371 ENTRY(WM_NCMOUSEHOVER),
372 ENTRY(WM_MOUSEHOVER),
373 ENTRY(WM_MOUSELEAVE),
374 ENTRY(WM_CUT),
375 ENTRY(WM_COPY),
376 ENTRY(WM_PASTE),
377 ENTRY(WM_CLEAR),
378 ENTRY(WM_UNDO),
379 ENTRY(WM_RENDERFORMAT),
380 ENTRY(WM_RENDERALLFORMATS),
381 ENTRY(WM_DESTROYCLIPBOARD),
382 ENTRY(WM_DRAWCLIPBOARD),
383 ENTRY(WM_PAINTCLIPBOARD),
384 ENTRY(WM_VSCROLLCLIPBOARD),
385 ENTRY(WM_SIZECLIPBOARD),
386 ENTRY(WM_ASKCBFORMATNAME),
387 ENTRY(WM_CHANGECBCHAIN),
388 ENTRY(WM_HSCROLLCLIPBOARD),
389 ENTRY(WM_QUERYNEWPALETTE),
390 ENTRY(WM_PALETTEISCHANGING),
391 ENTRY(WM_PALETTECHANGED),
392 ENTRY(WM_HOTKEY),
393 ENTRY(WM_PRINT),
394 ENTRY(WM_PRINTCLIENT),
395 ENTRY(WM_THEMECHANGED),
396 ENTRY(WM_HANDHELDFIRST),
397 ENTRY(WM_HANDHELDLAST),
398 ENTRY(WM_AFXFIRST),
399 ENTRY(WM_AFXLAST),
400 ENTRY(WM_PENWINFIRST),
401 ENTRY(WM_PENWINLAST),
402 ENTRY(WM_APP),
403 ENTRY(WM_DWMCOMPOSITIONCHANGED),
404 ENTRY(WM_DWMNCRENDERINGCHANGED),
405 ENTRY(WM_DWMCOLORIZATIONCOLORCHANGED),
406 ENTRY(WM_DWMWINDOWMAXIMIZEDCHANGE),
407 ENTRY(WM_DWMSENDICONICTHUMBNAIL),
408 ENTRY(WM_DWMSENDICONICLIVEPREVIEWBITMAP),
409 ENTRY(WM_TABLET_QUERYSYSTEMGESTURESTATUS),
410 ENTRY(WM_GESTURE),
411 ENTRY(WM_GESTURENOTIFY),
412 ENTRY(WM_GETTITLEBARINFOEX),
413 {0x0, {nullptr, 0x0}}};
414 #undef ENTRY
416 #ifdef MOZ_PLACES
417 NS_IMPL_ISUPPORTS(myDownloadObserver, nsIDownloadObserver)
418 NS_IMPL_ISUPPORTS(AsyncFaviconDataReady, nsIFaviconDataCallback)
419 #endif
420 NS_IMPL_ISUPPORTS(AsyncEncodeAndWriteIcon, nsIRunnable)
421 NS_IMPL_ISUPPORTS(AsyncDeleteAllFaviconsFromDisk, nsIRunnable)
423 const char FaviconHelper::kJumpListCacheDir[] = "jumpListCache";
424 const char FaviconHelper::kShortcutCacheDir[] = "shortcutCache";
426 // Prefix for path used by NT calls.
427 const wchar_t kNTPrefix[] = L"\\??\\";
428 const size_t kNTPrefixLen = ArrayLength(kNTPrefix) - 1;
430 struct CoTaskMemFreePolicy {
431 void operator()(void* aPtr) { ::CoTaskMemFree(aPtr); }
434 SetThreadDpiAwarenessContextProc WinUtils::sSetThreadDpiAwarenessContext = NULL;
435 EnableNonClientDpiScalingProc WinUtils::sEnableNonClientDpiScaling = NULL;
436 GetSystemMetricsForDpiProc WinUtils::sGetSystemMetricsForDpi = NULL;
437 bool WinUtils::sHasPackageIdentity = false;
439 using GetDpiForWindowProc = UINT(WINAPI*)(HWND);
440 static GetDpiForWindowProc sGetDpiForWindow = NULL;
442 /* static */
443 void WinUtils::Initialize() {
444 // Dpi-Awareness is not supported with Win32k Lockdown enabled, so we don't
445 // initialize DPI-related members and assert later that nothing accidently
446 // uses these static members
447 if (IsWin10OrLater() && !IsWin32kLockedDown()) {
448 HMODULE user32Dll = ::GetModuleHandleW(L"user32");
449 if (user32Dll) {
450 auto getThreadDpiAwarenessContext =
451 (decltype(GetThreadDpiAwarenessContext)*)::GetProcAddress(
452 user32Dll, "GetThreadDpiAwarenessContext");
453 auto areDpiAwarenessContextsEqual =
454 (decltype(AreDpiAwarenessContextsEqual)*)::GetProcAddress(
455 user32Dll, "AreDpiAwarenessContextsEqual");
456 if (getThreadDpiAwarenessContext && areDpiAwarenessContextsEqual &&
457 areDpiAwarenessContextsEqual(
458 getThreadDpiAwarenessContext(),
459 DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE)) {
460 // Only per-monitor v1 requires these workarounds.
461 sEnableNonClientDpiScaling =
462 (EnableNonClientDpiScalingProc)::GetProcAddress(
463 user32Dll, "EnableNonClientDpiScaling");
464 sSetThreadDpiAwarenessContext =
465 (SetThreadDpiAwarenessContextProc)::GetProcAddress(
466 user32Dll, "SetThreadDpiAwarenessContext");
469 sGetSystemMetricsForDpi = (GetSystemMetricsForDpiProc)::GetProcAddress(
470 user32Dll, "GetSystemMetricsForDpi");
471 sGetDpiForWindow =
472 (GetDpiForWindowProc)::GetProcAddress(user32Dll, "GetDpiForWindow");
476 if (IsWin8OrLater()) {
477 sHasPackageIdentity = mozilla::HasPackageIdentity();
481 // static
482 LRESULT WINAPI WinUtils::NonClientDpiScalingDefWindowProcW(HWND hWnd, UINT msg,
483 WPARAM wParam,
484 LPARAM lParam) {
485 MOZ_DIAGNOSTIC_ASSERT(!IsWin32kLockedDown());
487 // NOTE: this function was copied out into the body of the pre-XUL skeleton
488 // UI window proc (PreXULSkeletonUI.cpp). If this function changes at any
489 // point, we should probably factor this out and use it from both locations.
490 if (msg == WM_NCCREATE && sEnableNonClientDpiScaling) {
491 sEnableNonClientDpiScaling(hWnd);
493 return ::DefWindowProcW(hWnd, msg, wParam, lParam);
496 // static
497 void WinUtils::LogW(const wchar_t* fmt, ...) {
498 va_list args = nullptr;
499 if (!lstrlenW(fmt)) {
500 return;
502 va_start(args, fmt);
503 int buflen = _vscwprintf(fmt, args);
504 wchar_t* buffer = new wchar_t[buflen + 1];
505 if (!buffer) {
506 va_end(args);
507 return;
509 vswprintf(buffer, buflen, fmt, args);
510 va_end(args);
512 // MSVC, including remote debug sessions
513 OutputDebugStringW(buffer);
514 OutputDebugStringW(L"\n");
516 int len =
517 WideCharToMultiByte(CP_ACP, 0, buffer, -1, nullptr, 0, nullptr, nullptr);
518 if (len) {
519 char* utf8 = new char[len];
520 if (WideCharToMultiByte(CP_ACP, 0, buffer, -1, utf8, len, nullptr,
521 nullptr) > 0) {
522 // desktop console
523 printf("%s\n", utf8);
524 NS_ASSERTION(gWindowsLog,
525 "Called WinUtils Log() but Widget "
526 "log module doesn't exist!");
527 MOZ_LOG(gWindowsLog, LogLevel::Error, (utf8));
529 delete[] utf8;
531 delete[] buffer;
534 // static
535 void WinUtils::Log(const char* fmt, ...) {
536 va_list args = nullptr;
537 if (!strlen(fmt)) {
538 return;
540 va_start(args, fmt);
541 int buflen = _vscprintf(fmt, args);
542 char* buffer = new char[buflen + 1];
543 if (!buffer) {
544 va_end(args);
545 return;
547 vsprintf(buffer, fmt, args);
548 va_end(args);
550 // MSVC, including remote debug sessions
551 OutputDebugStringA(buffer);
552 OutputDebugStringW(L"\n");
554 // desktop console
555 printf("%s\n", buffer);
557 NS_ASSERTION(gWindowsLog,
558 "Called WinUtils Log() but Widget "
559 "log module doesn't exist!");
560 MOZ_LOG(gWindowsLog, LogLevel::Error, (buffer));
561 delete[] buffer;
564 // static
565 float WinUtils::SystemDPI() {
566 if (XRE_IsContentProcess()) {
567 return WinContentSystemParameters::GetSingleton()->SystemDPI();
569 // The result of GetDeviceCaps won't change dynamically, as it predates
570 // per-monitor DPI and support for on-the-fly resolution changes.
571 // Therefore, we only need to look it up once.
572 static float dpi = 0;
573 if (dpi <= 0) {
574 HDC screenDC = GetDC(nullptr);
575 dpi = GetDeviceCaps(screenDC, LOGPIXELSY);
576 ReleaseDC(nullptr, screenDC);
579 // Bug 1012487 - dpi can be 0 when the Screen DC is used off the
580 // main thread on windows. For now just assume a 100% DPI for this
581 // drawing call.
582 // XXX - fixme!
583 return dpi > 0 ? dpi : 96;
586 // static
587 double WinUtils::SystemScaleFactor() { return SystemDPI() / 96.0; }
589 #if WINVER < 0x603
590 typedef enum {
591 MDT_EFFECTIVE_DPI = 0,
592 MDT_ANGULAR_DPI = 1,
593 MDT_RAW_DPI = 2,
594 MDT_DEFAULT = MDT_EFFECTIVE_DPI
595 } MONITOR_DPI_TYPE;
597 typedef enum {
598 PROCESS_DPI_UNAWARE = 0,
599 PROCESS_SYSTEM_DPI_AWARE = 1,
600 PROCESS_PER_MONITOR_DPI_AWARE = 2
601 } PROCESS_DPI_AWARENESS;
602 #endif
604 typedef HRESULT(WINAPI* GETDPIFORMONITORPROC)(HMONITOR, MONITOR_DPI_TYPE, UINT*,
605 UINT*);
607 typedef HRESULT(WINAPI* GETPROCESSDPIAWARENESSPROC)(HANDLE,
608 PROCESS_DPI_AWARENESS*);
610 GETDPIFORMONITORPROC sGetDpiForMonitor;
611 GETPROCESSDPIAWARENESSPROC sGetProcessDpiAwareness;
613 static bool SlowIsPerMonitorDPIAware() {
614 // Intentionally leak the handle.
615 HMODULE shcore = LoadLibraryEx(L"shcore", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
616 if (shcore) {
617 sGetDpiForMonitor =
618 (GETDPIFORMONITORPROC)GetProcAddress(shcore, "GetDpiForMonitor");
619 sGetProcessDpiAwareness = (GETPROCESSDPIAWARENESSPROC)GetProcAddress(
620 shcore, "GetProcessDpiAwareness");
622 PROCESS_DPI_AWARENESS dpiAwareness;
623 return sGetDpiForMonitor && sGetProcessDpiAwareness &&
624 SUCCEEDED(
625 sGetProcessDpiAwareness(GetCurrentProcess(), &dpiAwareness)) &&
626 dpiAwareness == PROCESS_PER_MONITOR_DPI_AWARE;
629 /* static */
630 bool WinUtils::IsPerMonitorDPIAware() {
631 if (XRE_IsContentProcess()) {
632 return WinContentSystemParameters::GetSingleton()->IsPerMonitorDPIAware();
634 static bool perMonitorDPIAware = SlowIsPerMonitorDPIAware();
635 return perMonitorDPIAware;
638 /* static */
639 float WinUtils::MonitorDPI(HMONITOR aMonitor) {
640 if (IsPerMonitorDPIAware()) {
641 UINT dpiX, dpiY = 96;
642 sGetDpiForMonitor(aMonitor ? aMonitor : GetPrimaryMonitor(),
643 MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
644 return dpiY;
647 // We're not per-monitor aware, use system DPI instead.
648 return SystemDPI();
651 /* static */
652 double WinUtils::LogToPhysFactor(HMONITOR aMonitor) {
653 return MonitorDPI(aMonitor) / 96.0;
656 /* static */
657 int32_t WinUtils::LogToPhys(HMONITOR aMonitor, double aValue) {
658 return int32_t(NS_round(aValue * LogToPhysFactor(aMonitor)));
661 /* static */
662 double WinUtils::LogToPhysFactor(HWND aWnd) {
663 // if there's an ancestor window, we want to share its DPI setting
664 HWND ancestor = ::GetAncestor(aWnd, GA_ROOTOWNER);
666 // The GetDpiForWindow api is not available everywhere where we run as
667 // per-monitor, but if it is available rely on it to tell us the scale
668 // factor of the window. See bug 1722085.
669 if (sGetDpiForWindow) {
670 UINT dpi = sGetDpiForWindow(ancestor ? ancestor : aWnd);
671 if (dpi > 0) {
672 return static_cast<double>(dpi) / 96.0;
675 return LogToPhysFactor(::MonitorFromWindow(ancestor ? ancestor : aWnd,
676 MONITOR_DEFAULTTOPRIMARY));
679 /* static */
680 HMONITOR
681 WinUtils::GetPrimaryMonitor() {
682 const POINT pt = {0, 0};
683 return ::MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
686 /* static */
687 HMONITOR
688 WinUtils::MonitorFromRect(const gfx::Rect& rect) {
689 // convert coordinates from desktop to device pixels for MonitorFromRect
690 double dpiScale =
691 IsPerMonitorDPIAware() ? 1.0 : LogToPhysFactor(GetPrimaryMonitor());
693 RECT globalWindowBounds = {NSToIntRound(dpiScale * rect.X()),
694 NSToIntRound(dpiScale * rect.Y()),
695 NSToIntRound(dpiScale * (rect.XMost())),
696 NSToIntRound(dpiScale * (rect.YMost()))};
698 return ::MonitorFromRect(&globalWindowBounds, MONITOR_DEFAULTTONEAREST);
701 /* static */
702 bool WinUtils::HasSystemMetricsForDpi() {
703 MOZ_DIAGNOSTIC_ASSERT(!IsWin32kLockedDown());
704 return (sGetSystemMetricsForDpi != NULL);
707 /* static */
708 int WinUtils::GetSystemMetricsForDpi(int nIndex, UINT dpi) {
709 MOZ_DIAGNOSTIC_ASSERT(!IsWin32kLockedDown());
710 if (HasSystemMetricsForDpi()) {
711 return sGetSystemMetricsForDpi(nIndex, dpi);
712 } else {
713 double scale = IsPerMonitorDPIAware() ? dpi / SystemDPI() : 1.0;
714 return NSToIntRound(::GetSystemMetrics(nIndex) * scale);
718 /* static */
719 gfx::MarginDouble WinUtils::GetUnwriteableMarginsForDeviceInInches(HDC aHdc) {
720 if (!aHdc) {
721 return gfx::MarginDouble();
724 int pixelsPerInchY = ::GetDeviceCaps(aHdc, LOGPIXELSY);
725 int marginTop = ::GetDeviceCaps(aHdc, PHYSICALOFFSETY);
726 int printableAreaHeight = ::GetDeviceCaps(aHdc, VERTRES);
727 int physicalHeight = ::GetDeviceCaps(aHdc, PHYSICALHEIGHT);
729 double marginTopInch = double(marginTop) / pixelsPerInchY;
731 double printableAreaHeightInch = double(printableAreaHeight) / pixelsPerInchY;
732 double physicalHeightInch = double(physicalHeight) / pixelsPerInchY;
733 double marginBottomInch =
734 physicalHeightInch - printableAreaHeightInch - marginTopInch;
736 int pixelsPerInchX = ::GetDeviceCaps(aHdc, LOGPIXELSX);
737 int marginLeft = ::GetDeviceCaps(aHdc, PHYSICALOFFSETX);
738 int printableAreaWidth = ::GetDeviceCaps(aHdc, HORZRES);
739 int physicalWidth = ::GetDeviceCaps(aHdc, PHYSICALWIDTH);
741 double marginLeftInch = double(marginLeft) / pixelsPerInchX;
743 double printableAreaWidthInch = double(printableAreaWidth) / pixelsPerInchX;
744 double physicalWidthInch = double(physicalWidth) / pixelsPerInchX;
745 double marginRightInch =
746 physicalWidthInch - printableAreaWidthInch - marginLeftInch;
748 return gfx::MarginDouble(marginTopInch, marginRightInch, marginBottomInch,
749 marginLeftInch);
752 #ifdef ACCESSIBILITY
753 /* static */
754 a11y::LocalAccessible* WinUtils::GetRootAccessibleForHWND(HWND aHwnd) {
755 nsWindow* window = GetNSWindowPtr(aHwnd);
756 if (!window) {
757 return nullptr;
760 return window->GetAccessible();
762 #endif // ACCESSIBILITY
764 /* static */
765 bool WinUtils::PeekMessage(LPMSG aMsg, HWND aWnd, UINT aFirstMessage,
766 UINT aLastMessage, UINT aOption) {
767 RefPtr<ITfMessagePump> msgPump = TSFTextStore::GetMessagePump();
768 if (msgPump) {
769 BOOL ret = FALSE;
770 HRESULT hr = msgPump->PeekMessageW(aMsg, aWnd, aFirstMessage, aLastMessage,
771 aOption, &ret);
772 NS_ENSURE_TRUE(SUCCEEDED(hr), false);
773 return ret;
775 return ::PeekMessageW(aMsg, aWnd, aFirstMessage, aLastMessage, aOption);
778 /* static */
779 bool WinUtils::GetMessage(LPMSG aMsg, HWND aWnd, UINT aFirstMessage,
780 UINT aLastMessage) {
781 RefPtr<ITfMessagePump> msgPump = TSFTextStore::GetMessagePump();
782 if (msgPump) {
783 BOOL ret = FALSE;
784 HRESULT hr =
785 msgPump->GetMessageW(aMsg, aWnd, aFirstMessage, aLastMessage, &ret);
786 NS_ENSURE_TRUE(SUCCEEDED(hr), false);
787 return ret;
789 return ::GetMessageW(aMsg, aWnd, aFirstMessage, aLastMessage);
792 #if defined(ACCESSIBILITY)
793 static DWORD GetWaitFlags() {
794 DWORD result = MWMO_INPUTAVAILABLE;
795 if (XRE_IsContentProcess()) {
796 result |= MWMO_ALERTABLE;
798 return result;
800 #endif
802 /* static */
803 void WinUtils::WaitForMessage(DWORD aTimeoutMs) {
804 #if defined(ACCESSIBILITY)
805 static const DWORD waitFlags = GetWaitFlags();
806 #else
807 const DWORD waitFlags = MWMO_INPUTAVAILABLE;
808 #endif
810 const DWORD waitStart = ::GetTickCount();
811 DWORD elapsed = 0;
812 while (true) {
813 if (aTimeoutMs != INFINITE) {
814 elapsed = ::GetTickCount() - waitStart;
816 if (elapsed >= aTimeoutMs) {
817 break;
819 DWORD result;
821 AUTO_PROFILER_THREAD_SLEEP;
822 result = ::MsgWaitForMultipleObjectsEx(0, NULL, aTimeoutMs - elapsed,
823 MOZ_QS_ALLEVENT, waitFlags);
825 NS_WARNING_ASSERTION(result != WAIT_FAILED, "Wait failed");
826 if (result == WAIT_TIMEOUT) {
827 break;
829 #if defined(ACCESSIBILITY)
830 if (result == WAIT_IO_COMPLETION) {
831 if (NS_IsMainThread()) {
832 // We executed an APC that would have woken up the hang monitor. Since
833 // there are no more APCs pending and we are now going to sleep again,
834 // we should notify the hang monitor.
835 mozilla::BackgroundHangMonitor().NotifyWait();
837 continue;
839 #endif // defined(ACCESSIBILITY)
841 // Sent messages (via SendMessage and friends) are processed differently
842 // than queued messages (via PostMessage); the destination window procedure
843 // of the sent message is called during (Get|Peek)Message. Since PeekMessage
844 // does not tell us whether it processed any sent messages, we need to query
845 // this ahead of time.
846 bool haveSentMessagesPending =
847 (HIWORD(::GetQueueStatus(QS_SENDMESSAGE)) & QS_SENDMESSAGE) != 0;
849 MSG msg = {0};
850 if (haveSentMessagesPending ||
851 ::PeekMessageW(&msg, nullptr, 0, 0, PM_NOREMOVE)) {
852 break;
854 // The message is intended for another thread that has been synchronized
855 // with our input queue; yield to give other threads an opportunity to
856 // process the message. This should prevent busy waiting if resumed due
857 // to another thread's message.
858 ::SwitchToThread();
862 /* static */
863 bool WinUtils::GetRegistryKey(HKEY aRoot, char16ptr_t aKeyName,
864 char16ptr_t aValueName, wchar_t* aBuffer,
865 DWORD aBufferLength) {
866 MOZ_ASSERT(aKeyName, "The key name is NULL");
868 HKEY key;
869 LONG result =
870 ::RegOpenKeyExW(aRoot, aKeyName, 0, KEY_READ | KEY_WOW64_32KEY, &key);
871 if (result != ERROR_SUCCESS) {
872 result =
873 ::RegOpenKeyExW(aRoot, aKeyName, 0, KEY_READ | KEY_WOW64_64KEY, &key);
874 if (result != ERROR_SUCCESS) {
875 return false;
879 DWORD type;
880 result = ::RegQueryValueExW(key, aValueName, nullptr, &type, (BYTE*)aBuffer,
881 &aBufferLength);
882 ::RegCloseKey(key);
883 if (result != ERROR_SUCCESS || (type != REG_SZ && type != REG_EXPAND_SZ)) {
884 return false;
886 if (aBuffer) {
887 aBuffer[aBufferLength / sizeof(*aBuffer) - 1] = 0;
889 return true;
892 /* static */
893 bool WinUtils::HasRegistryKey(HKEY aRoot, char16ptr_t aKeyName) {
894 MOZ_ASSERT(aRoot, "aRoot must not be NULL");
895 MOZ_ASSERT(aKeyName, "aKeyName must not be NULL");
896 HKEY key;
897 LONG result =
898 ::RegOpenKeyExW(aRoot, aKeyName, 0, KEY_READ | KEY_WOW64_32KEY, &key);
899 if (result != ERROR_SUCCESS) {
900 result =
901 ::RegOpenKeyExW(aRoot, aKeyName, 0, KEY_READ | KEY_WOW64_64KEY, &key);
902 if (result != ERROR_SUCCESS) {
903 return false;
906 ::RegCloseKey(key);
907 return true;
910 /* static */
911 HWND WinUtils::GetTopLevelHWND(HWND aWnd, bool aStopIfNotChild,
912 bool aStopIfNotPopup) {
913 HWND curWnd = aWnd;
914 HWND topWnd = nullptr;
916 while (curWnd) {
917 topWnd = curWnd;
919 if (aStopIfNotChild) {
920 DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
922 VERIFY_WINDOW_STYLE(style);
924 if (!(style & WS_CHILD)) // first top-level window
925 break;
928 HWND upWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
930 // GetParent will only return the owner if the passed in window
931 // has the WS_POPUP style.
932 if (!upWnd && !aStopIfNotPopup) {
933 upWnd = ::GetWindow(curWnd, GW_OWNER);
935 curWnd = upWnd;
938 return topWnd;
941 static const wchar_t* GetNSWindowPropName() {
942 static wchar_t sPropName[40] = L"";
943 if (!*sPropName) {
944 _snwprintf(sPropName, 39, L"MozillansIWidgetPtr%u",
945 ::GetCurrentProcessId());
946 sPropName[39] = '\0';
948 return sPropName;
951 /* static */
952 bool WinUtils::SetNSWindowBasePtr(HWND aWnd, nsWindow* aWidget) {
953 if (!aWidget) {
954 ::RemovePropW(aWnd, GetNSWindowPropName());
955 return true;
957 return ::SetPropW(aWnd, GetNSWindowPropName(), (HANDLE)aWidget);
960 /* static */
961 nsWindow* WinUtils::GetNSWindowBasePtr(HWND aWnd) {
962 return static_cast<nsWindow*>(::GetPropW(aWnd, GetNSWindowPropName()));
965 /* static */
966 nsWindow* WinUtils::GetNSWindowPtr(HWND aWnd) {
967 return static_cast<nsWindow*>(::GetPropW(aWnd, GetNSWindowPropName()));
970 static BOOL CALLBACK AddMonitor(HMONITOR, HDC, LPRECT, LPARAM aParam) {
971 (*(int32_t*)aParam)++;
972 return TRUE;
975 /* static */
976 int32_t WinUtils::GetMonitorCount() {
977 int32_t monitorCount = 0;
978 EnumDisplayMonitors(nullptr, nullptr, AddMonitor, (LPARAM)&monitorCount);
979 return monitorCount;
982 /* static */
983 bool WinUtils::IsOurProcessWindow(HWND aWnd) {
984 if (!aWnd) {
985 return false;
987 DWORD processId = 0;
988 ::GetWindowThreadProcessId(aWnd, &processId);
989 return (processId == ::GetCurrentProcessId());
992 /* static */
993 HWND WinUtils::FindOurProcessWindow(HWND aWnd) {
994 for (HWND wnd = ::GetParent(aWnd); wnd; wnd = ::GetParent(wnd)) {
995 if (IsOurProcessWindow(wnd)) {
996 return wnd;
999 return nullptr;
1002 static bool IsPointInWindow(HWND aWnd, const POINT& aPointInScreen) {
1003 RECT bounds;
1004 if (!::GetWindowRect(aWnd, &bounds)) {
1005 return false;
1008 return (aPointInScreen.x >= bounds.left && aPointInScreen.x < bounds.right &&
1009 aPointInScreen.y >= bounds.top && aPointInScreen.y < bounds.bottom);
1013 * FindTopmostWindowAtPoint() returns the topmost child window (topmost means
1014 * forground in this context) of aWnd.
1017 static HWND FindTopmostWindowAtPoint(HWND aWnd, const POINT& aPointInScreen) {
1018 if (!::IsWindowVisible(aWnd) || !IsPointInWindow(aWnd, aPointInScreen)) {
1019 return nullptr;
1022 HWND childWnd = ::GetTopWindow(aWnd);
1023 while (childWnd) {
1024 HWND topmostWnd = FindTopmostWindowAtPoint(childWnd, aPointInScreen);
1025 if (topmostWnd) {
1026 return topmostWnd;
1028 childWnd = ::GetNextWindow(childWnd, GW_HWNDNEXT);
1031 return aWnd;
1034 struct FindOurWindowAtPointInfo {
1035 POINT mInPointInScreen;
1036 HWND mOutWnd;
1039 static BOOL CALLBACK FindOurWindowAtPointCallback(HWND aWnd, LPARAM aLPARAM) {
1040 if (!WinUtils::IsOurProcessWindow(aWnd)) {
1041 // This isn't one of our top-level windows; continue enumerating.
1042 return TRUE;
1045 // Get the top-most child window under the point. If there's no child
1046 // window, and the point is within the top-level window, then the top-level
1047 // window will be returned. (This is the usual case. A child window
1048 // would be returned for plugins.)
1049 FindOurWindowAtPointInfo* info =
1050 reinterpret_cast<FindOurWindowAtPointInfo*>(aLPARAM);
1051 HWND childWnd = FindTopmostWindowAtPoint(aWnd, info->mInPointInScreen);
1052 if (!childWnd) {
1053 // This window doesn't contain the point; continue enumerating.
1054 return TRUE;
1057 // Return the HWND and stop enumerating.
1058 info->mOutWnd = childWnd;
1059 return FALSE;
1062 /* static */
1063 HWND WinUtils::FindOurWindowAtPoint(const POINT& aPointInScreen) {
1064 FindOurWindowAtPointInfo info;
1065 info.mInPointInScreen = aPointInScreen;
1066 info.mOutWnd = nullptr;
1068 // This will enumerate all top-level windows in order from top to bottom.
1069 EnumWindows(FindOurWindowAtPointCallback, reinterpret_cast<LPARAM>(&info));
1070 return info.mOutWnd;
1073 /* static */
1074 UINT WinUtils::GetInternalMessage(UINT aNativeMessage) {
1075 switch (aNativeMessage) {
1076 case WM_MOUSEWHEEL:
1077 return MOZ_WM_MOUSEVWHEEL;
1078 case WM_MOUSEHWHEEL:
1079 return MOZ_WM_MOUSEHWHEEL;
1080 case WM_VSCROLL:
1081 return MOZ_WM_VSCROLL;
1082 case WM_HSCROLL:
1083 return MOZ_WM_HSCROLL;
1084 default:
1085 return aNativeMessage;
1089 /* static */
1090 UINT WinUtils::GetNativeMessage(UINT aInternalMessage) {
1091 switch (aInternalMessage) {
1092 case MOZ_WM_MOUSEVWHEEL:
1093 return WM_MOUSEWHEEL;
1094 case MOZ_WM_MOUSEHWHEEL:
1095 return WM_MOUSEHWHEEL;
1096 case MOZ_WM_VSCROLL:
1097 return WM_VSCROLL;
1098 case MOZ_WM_HSCROLL:
1099 return WM_HSCROLL;
1100 default:
1101 return aInternalMessage;
1105 /* static */
1106 uint16_t WinUtils::GetMouseInputSource() {
1107 int32_t inputSource = dom::MouseEvent_Binding::MOZ_SOURCE_MOUSE;
1108 LPARAM lParamExtraInfo = ::GetMessageExtraInfo();
1109 if ((lParamExtraInfo & TABLET_INK_SIGNATURE) == TABLET_INK_CHECK) {
1110 inputSource = (lParamExtraInfo & TABLET_INK_TOUCH)
1111 ? dom::MouseEvent_Binding::MOZ_SOURCE_TOUCH
1112 : dom::MouseEvent_Binding::MOZ_SOURCE_PEN;
1114 return static_cast<uint16_t>(inputSource);
1117 /* static */
1118 uint16_t WinUtils::GetMousePointerID() {
1119 LPARAM lParamExtraInfo = ::GetMessageExtraInfo();
1120 return lParamExtraInfo & TABLET_INK_ID_MASK;
1123 /* static */
1124 bool WinUtils::GetIsMouseFromTouch(EventMessage aEventMessage) {
1125 const uint32_t MOZ_T_I_SIGNATURE = TABLET_INK_TOUCH | TABLET_INK_SIGNATURE;
1126 const uint32_t MOZ_T_I_CHECK_TCH = TABLET_INK_TOUCH | TABLET_INK_CHECK;
1127 return ((aEventMessage == eMouseMove || aEventMessage == eMouseDown ||
1128 aEventMessage == eMouseUp || aEventMessage == eMouseAuxClick ||
1129 aEventMessage == eMouseDoubleClick) &&
1130 (GetMessageExtraInfo() & MOZ_T_I_SIGNATURE) == MOZ_T_I_CHECK_TCH);
1133 /* static */
1134 MSG WinUtils::InitMSG(UINT aMessage, WPARAM wParam, LPARAM lParam, HWND aWnd) {
1135 MSG msg;
1136 msg.message = aMessage;
1137 msg.wParam = wParam;
1138 msg.lParam = lParam;
1139 msg.hwnd = aWnd;
1140 return msg;
1143 static BOOL WINAPI EnumFirstChild(HWND hwnd, LPARAM lParam) {
1144 *((HWND*)lParam) = hwnd;
1145 return FALSE;
1148 /* static */
1149 void WinUtils::InvalidatePluginAsWorkaround(nsIWidget* aWidget,
1150 const LayoutDeviceIntRect& aRect) {
1151 aWidget->Invalidate(aRect);
1153 // XXX - Even more evil workaround!! See bug 762948, flash's bottom
1154 // level sandboxed window doesn't seem to get our invalidate. We send
1155 // an invalidate to it manually. This is totally specialized for this
1156 // bug, for other child window structures this will just be a more or
1157 // less bogus invalidate but since that should not have any bad
1158 // side-effects this will have to do for now.
1159 HWND current = (HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW);
1161 RECT windowRect;
1162 RECT parentRect;
1164 ::GetWindowRect(current, &parentRect);
1166 HWND next = current;
1167 do {
1168 current = next;
1169 ::EnumChildWindows(current, &EnumFirstChild, (LPARAM)&next);
1170 ::GetWindowRect(next, &windowRect);
1171 // This is relative to the screen, adjust it to be relative to the
1172 // window we're reconfiguring.
1173 windowRect.left -= parentRect.left;
1174 windowRect.top -= parentRect.top;
1175 } while (next != current && windowRect.top == 0 && windowRect.left == 0);
1177 if (windowRect.top == 0 && windowRect.left == 0) {
1178 RECT rect;
1179 rect.left = aRect.X();
1180 rect.top = aRect.Y();
1181 rect.right = aRect.XMost();
1182 rect.bottom = aRect.YMost();
1184 ::InvalidateRect(next, &rect, FALSE);
1188 #ifdef MOZ_PLACES
1189 /************************************************************************
1190 * Constructs as AsyncFaviconDataReady Object
1191 * @param aIOThread : the thread which performs the action
1192 * @param aURLShortcut : Differentiates between (false)Jumplistcache and
1193 * (true)Shortcutcache
1194 * @param aRunnable : Executed in the aIOThread when the favicon cache is
1195 * avaiable
1196 ************************************************************************/
1198 AsyncFaviconDataReady::AsyncFaviconDataReady(
1199 nsIURI* aNewURI, nsCOMPtr<nsIThread>& aIOThread, const bool aURLShortcut,
1200 already_AddRefed<nsIRunnable> aRunnable)
1201 : mNewURI(aNewURI),
1202 mIOThread(aIOThread),
1203 mRunnable(aRunnable),
1204 mURLShortcut(aURLShortcut) {}
1206 NS_IMETHODIMP
1207 myDownloadObserver::OnDownloadComplete(nsIDownloader* downloader,
1208 nsIRequest* request, nsresult status,
1209 nsIFile* result) {
1210 return NS_OK;
1213 nsresult AsyncFaviconDataReady::OnFaviconDataNotAvailable(void) {
1214 if (!mURLShortcut) {
1215 return NS_OK;
1218 nsCOMPtr<nsIFile> icoFile;
1219 nsresult rv =
1220 FaviconHelper::GetOutputIconPath(mNewURI, icoFile, mURLShortcut);
1221 NS_ENSURE_SUCCESS(rv, rv);
1223 nsCOMPtr<nsIURI> mozIconURI;
1224 rv = NS_NewURI(getter_AddRefs(mozIconURI), "moz-icon://.html?size=32");
1225 if (NS_FAILED(rv)) {
1226 return rv;
1229 nsCOMPtr<nsIChannel> channel;
1230 rv = NS_NewChannel(getter_AddRefs(channel), mozIconURI,
1231 nsContentUtils::GetSystemPrincipal(),
1232 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
1233 nsIContentPolicy::TYPE_INTERNAL_IMAGE);
1235 NS_ENSURE_SUCCESS(rv, rv);
1237 nsCOMPtr<nsIDownloadObserver> downloadObserver = new myDownloadObserver;
1238 nsCOMPtr<nsIStreamListener> listener;
1239 rv = NS_NewDownloader(getter_AddRefs(listener), downloadObserver, icoFile);
1240 NS_ENSURE_SUCCESS(rv, rv);
1242 return channel->AsyncOpen(listener);
1245 NS_IMETHODIMP
1246 AsyncFaviconDataReady::OnComplete(nsIURI* aFaviconURI, uint32_t aDataLen,
1247 const uint8_t* aData,
1248 const nsACString& aMimeType,
1249 uint16_t aWidth) {
1250 if (!aDataLen || !aData) {
1251 if (mURLShortcut) {
1252 OnFaviconDataNotAvailable();
1255 return NS_OK;
1258 nsCOMPtr<nsIFile> icoFile;
1259 nsresult rv =
1260 FaviconHelper::GetOutputIconPath(mNewURI, icoFile, mURLShortcut);
1261 NS_ENSURE_SUCCESS(rv, rv);
1263 nsAutoString path;
1264 rv = icoFile->GetPath(path);
1265 NS_ENSURE_SUCCESS(rv, rv);
1267 // Decode the image from the format it was returned to us in (probably PNG)
1268 nsCOMPtr<imgIContainer> container;
1269 nsCOMPtr<imgITools> imgtool = do_CreateInstance("@mozilla.org/image/tools;1");
1270 rv = imgtool->DecodeImageFromBuffer(reinterpret_cast<const char*>(aData),
1271 aDataLen, aMimeType,
1272 getter_AddRefs(container));
1273 NS_ENSURE_SUCCESS(rv, rv);
1275 RefPtr<SourceSurface> surface = container->GetFrame(
1276 imgIContainer::FRAME_FIRST,
1277 imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY);
1278 NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE);
1280 RefPtr<DataSourceSurface> dataSurface;
1281 IntSize size;
1283 if (mURLShortcut &&
1284 (surface->GetSize().width < 48 || surface->GetSize().height < 48)) {
1285 // Create a 48x48 surface and paint the icon into the central rect.
1286 size.width = std::max(surface->GetSize().width, 48);
1287 size.height = std::max(surface->GetSize().height, 48);
1288 dataSurface =
1289 Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8);
1290 NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
1292 DataSourceSurface::MappedSurface map;
1293 if (!dataSurface->Map(DataSourceSurface::MapType::WRITE, &map)) {
1294 return NS_ERROR_FAILURE;
1297 RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(
1298 BackendType::CAIRO, map.mData, dataSurface->GetSize(), map.mStride,
1299 dataSurface->GetFormat());
1300 if (!dt) {
1301 gfxWarning() << "AsyncFaviconDataReady::OnComplete failed in "
1302 "CreateDrawTargetForData";
1303 return NS_ERROR_OUT_OF_MEMORY;
1305 dt->FillRect(Rect(0, 0, size.width, size.height),
1306 ColorPattern(ToDeviceColor(sRGBColor::OpaqueWhite())));
1307 IntPoint point;
1308 point.x = (size.width - surface->GetSize().width) / 2;
1309 point.y = (size.height - surface->GetSize().height) / 2;
1310 dt->DrawSurface(surface,
1311 Rect(point.x, point.y, surface->GetSize().width,
1312 surface->GetSize().height),
1313 Rect(Point(0, 0), Size(surface->GetSize().width,
1314 surface->GetSize().height)));
1316 dataSurface->Unmap();
1317 } else {
1318 // By using the input image surface's size, we may end up encoding
1319 // to a different size than a 16x16 (or bigger for higher DPI) ICO, but
1320 // Windows will resize appropriately for us. If we want to encode ourselves
1321 // one day because we like our resizing better, we'd have to manually
1322 // resize the image here and use GetSystemMetrics w/ SM_CXSMICON and
1323 // SM_CYSMICON. We don't support resizing images asynchronously at the
1324 // moment anyway so getting the DPI aware icon size won't help.
1325 size.width = surface->GetSize().width;
1326 size.height = surface->GetSize().height;
1327 dataSurface = surface->GetDataSurface();
1328 NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
1331 // Allocate a new buffer that we own and can use out of line in
1332 // another thread.
1333 UniquePtr<uint8_t[]> data = SurfaceToPackedBGRA(dataSurface);
1334 if (!data) {
1335 return NS_ERROR_OUT_OF_MEMORY;
1337 int32_t stride = 4 * size.width;
1339 // AsyncEncodeAndWriteIcon takes ownership of the heap allocated buffer
1340 nsCOMPtr<nsIRunnable> event =
1341 new AsyncEncodeAndWriteIcon(path, std::move(data), stride, size.width,
1342 size.height, mRunnable.forget());
1343 mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
1345 return NS_OK;
1347 #endif
1349 // Warning: AsyncEncodeAndWriteIcon assumes ownership of the aData buffer passed
1350 // in
1351 AsyncEncodeAndWriteIcon::AsyncEncodeAndWriteIcon(
1352 const nsAString& aIconPath, UniquePtr<uint8_t[]> aBuffer, uint32_t aStride,
1353 uint32_t aWidth, uint32_t aHeight, already_AddRefed<nsIRunnable> aRunnable)
1354 : mIconPath(aIconPath),
1355 mBuffer(std::move(aBuffer)),
1356 mRunnable(aRunnable),
1357 mStride(aStride),
1358 mWidth(aWidth),
1359 mHeight(aHeight) {}
1361 NS_IMETHODIMP AsyncEncodeAndWriteIcon::Run() {
1362 MOZ_ASSERT(!NS_IsMainThread(), "Should not be called on the main thread.");
1364 // Note that since we're off the main thread we can't use
1365 // gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget()
1366 RefPtr<DataSourceSurface> surface = Factory::CreateWrappingDataSourceSurface(
1367 mBuffer.get(), mStride, IntSize(mWidth, mHeight),
1368 SurfaceFormat::B8G8R8A8);
1370 FILE* file = _wfopen(mIconPath.get(), L"wb");
1371 if (!file) {
1372 // Maybe the directory doesn't exist; try creating it, then fopen again.
1373 nsresult rv = NS_ERROR_FAILURE;
1374 nsCOMPtr<nsIFile> comFile = do_CreateInstance("@mozilla.org/file/local;1");
1375 if (comFile) {
1376 rv = comFile->InitWithPath(mIconPath);
1377 if (NS_SUCCEEDED(rv)) {
1378 nsCOMPtr<nsIFile> dirPath;
1379 comFile->GetParent(getter_AddRefs(dirPath));
1380 if (dirPath) {
1381 rv = dirPath->Create(nsIFile::DIRECTORY_TYPE, 0777);
1382 if (NS_SUCCEEDED(rv) || rv == NS_ERROR_FILE_ALREADY_EXISTS) {
1383 file = _wfopen(mIconPath.get(), L"wb");
1384 if (!file) {
1385 rv = NS_ERROR_FAILURE;
1391 if (!file) {
1392 return rv;
1395 nsresult rv = gfxUtils::EncodeSourceSurface(surface, ImageType::ICO, u""_ns,
1396 gfxUtils::eBinaryEncode, file);
1397 fclose(file);
1398 NS_ENSURE_SUCCESS(rv, rv);
1400 if (mRunnable) {
1401 mRunnable->Run();
1403 return rv;
1406 AsyncEncodeAndWriteIcon::~AsyncEncodeAndWriteIcon() {}
1408 AsyncDeleteAllFaviconsFromDisk::AsyncDeleteAllFaviconsFromDisk(
1409 bool aIgnoreRecent)
1410 : mIgnoreRecent(aIgnoreRecent) {
1411 // We can't call FaviconHelper::GetICOCacheSecondsTimeout() on non-main
1412 // threads, as it reads a pref, so cache its value here.
1413 mIcoNoDeleteSeconds = FaviconHelper::GetICOCacheSecondsTimeout() + 600;
1415 // Prepare the profile directory cache on the main thread, to ensure we wont
1416 // do this on non-main threads.
1417 Unused << NS_GetSpecialDirectory("ProfLDS",
1418 getter_AddRefs(mJumpListCacheDir));
1421 NS_IMETHODIMP AsyncDeleteAllFaviconsFromDisk::Run() {
1422 if (!mJumpListCacheDir) {
1423 return NS_ERROR_FAILURE;
1425 // Construct the path of our jump list cache
1426 nsresult rv = mJumpListCacheDir->AppendNative(
1427 nsDependentCString(FaviconHelper::kJumpListCacheDir));
1428 NS_ENSURE_SUCCESS(rv, rv);
1430 nsCOMPtr<nsIDirectoryEnumerator> entries;
1431 rv = mJumpListCacheDir->GetDirectoryEntries(getter_AddRefs(entries));
1432 NS_ENSURE_SUCCESS(rv, rv);
1434 // Loop through each directory entry and remove all ICO files found
1435 do {
1436 nsCOMPtr<nsIFile> currFile;
1437 if (NS_FAILED(entries->GetNextFile(getter_AddRefs(currFile))) || !currFile)
1438 break;
1440 nsAutoString path;
1441 if (NS_FAILED(currFile->GetPath(path))) continue;
1443 if (StringTail(path, 4).LowerCaseEqualsASCII(".ico")) {
1444 // Check if the cached ICO file exists
1445 bool exists;
1446 if (NS_FAILED(currFile->Exists(&exists)) || !exists) continue;
1448 if (mIgnoreRecent) {
1449 // Check to make sure the icon wasn't just recently created.
1450 // If it was created recently, don't delete it yet.
1451 int64_t fileModTime = 0;
1452 rv = currFile->GetLastModifiedTime(&fileModTime);
1453 fileModTime /= PR_MSEC_PER_SEC;
1454 // If the icon is older than the regeneration time (+ 10 min to be
1455 // safe), then it's old and we can get rid of it.
1456 // This code is only hit directly after a regeneration.
1457 int64_t nowTime = PR_Now() / int64_t(PR_USEC_PER_SEC);
1458 if (NS_FAILED(rv) || (nowTime - fileModTime) < mIcoNoDeleteSeconds) {
1459 continue;
1463 // We found an ICO file that exists, so we should remove it
1464 currFile->Remove(false);
1466 } while (true);
1468 return NS_OK;
1471 AsyncDeleteAllFaviconsFromDisk::~AsyncDeleteAllFaviconsFromDisk() {}
1474 * (static) If the data is available, will return the path on disk where
1475 * the favicon for page aFaviconPageURI is stored. If the favicon does not
1476 * exist, or its cache is expired, this method will kick off an async request
1477 * for the icon so that next time the method is called it will be available.
1478 * @param aFaviconPageURI The URI of the page to obtain
1479 * @param aICOFilePath The path of the icon file
1480 * @param aIOThread The thread to perform the Fetch on
1481 * @param aURLShortcut to distinguish between jumplistcache(false) and
1482 * shortcutcache(true)
1483 * @param aRunnable Executed in the aIOThread when the favicon cache is
1484 * avaiable
1486 nsresult FaviconHelper::ObtainCachedIconFile(
1487 nsCOMPtr<nsIURI> aFaviconPageURI, nsString& aICOFilePath,
1488 nsCOMPtr<nsIThread>& aIOThread, bool aURLShortcut,
1489 already_AddRefed<nsIRunnable> aRunnable) {
1490 nsCOMPtr<nsIRunnable> runnable = aRunnable;
1491 // Obtain the ICO file path
1492 nsCOMPtr<nsIFile> icoFile;
1493 nsresult rv = GetOutputIconPath(aFaviconPageURI, icoFile, aURLShortcut);
1494 NS_ENSURE_SUCCESS(rv, rv);
1496 // Check if the cached ICO file already exists
1497 bool exists;
1498 rv = icoFile->Exists(&exists);
1499 NS_ENSURE_SUCCESS(rv, rv);
1501 if (exists) {
1502 // Obtain the file's last modification date in seconds
1503 int64_t fileModTime = 0;
1504 rv = icoFile->GetLastModifiedTime(&fileModTime);
1505 fileModTime /= PR_MSEC_PER_SEC;
1506 int32_t icoReCacheSecondsTimeout = GetICOCacheSecondsTimeout();
1507 int64_t nowTime = PR_Now() / int64_t(PR_USEC_PER_SEC);
1509 // If the last mod call failed or the icon is old then re-cache it
1510 // This check is in case the favicon of a page changes
1511 // the next time we try to build the jump list, the data will be available.
1512 if (NS_FAILED(rv) || (nowTime - fileModTime) > icoReCacheSecondsTimeout) {
1513 CacheIconFileFromFaviconURIAsync(aFaviconPageURI, icoFile, aIOThread,
1514 aURLShortcut, runnable.forget());
1515 return NS_ERROR_NOT_AVAILABLE;
1517 } else {
1518 // The file does not exist yet, obtain it async from the favicon service so
1519 // that the next time we try to build the jump list it'll be available.
1520 CacheIconFileFromFaviconURIAsync(aFaviconPageURI, icoFile, aIOThread,
1521 aURLShortcut, runnable.forget());
1522 return NS_ERROR_NOT_AVAILABLE;
1525 // The icoFile is filled with a path that exists, get its path
1526 rv = icoFile->GetPath(aICOFilePath);
1527 return rv;
1530 nsresult FaviconHelper::HashURI(nsCOMPtr<nsICryptoHash>& aCryptoHash,
1531 nsIURI* aUri, nsACString& aUriHash) {
1532 if (!aUri) return NS_ERROR_INVALID_ARG;
1534 nsAutoCString spec;
1535 nsresult rv = aUri->GetSpec(spec);
1536 NS_ENSURE_SUCCESS(rv, rv);
1538 if (!aCryptoHash) {
1539 aCryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
1540 NS_ENSURE_SUCCESS(rv, rv);
1543 rv = aCryptoHash->Init(nsICryptoHash::MD5);
1544 NS_ENSURE_SUCCESS(rv, rv);
1545 rv = aCryptoHash->Update(
1546 reinterpret_cast<const uint8_t*>(spec.BeginReading()), spec.Length());
1547 NS_ENSURE_SUCCESS(rv, rv);
1548 rv = aCryptoHash->Finish(true, aUriHash);
1549 NS_ENSURE_SUCCESS(rv, rv);
1551 return NS_OK;
1554 // (static) Obtains the ICO file for the favicon at page aFaviconPageURI
1555 // If successful, the file path on disk is in the format:
1556 // <ProfLDS>\jumpListCache\<hash(aFaviconPageURI)>.ico
1557 nsresult FaviconHelper::GetOutputIconPath(nsCOMPtr<nsIURI> aFaviconPageURI,
1558 nsCOMPtr<nsIFile>& aICOFile,
1559 bool aURLShortcut) {
1560 // Hash the input URI and replace any / with _
1561 nsAutoCString inputURIHash;
1562 nsCOMPtr<nsICryptoHash> cryptoHash;
1563 nsresult rv = HashURI(cryptoHash, aFaviconPageURI, inputURIHash);
1564 NS_ENSURE_SUCCESS(rv, rv);
1565 char* cur = inputURIHash.BeginWriting();
1566 char* end = inputURIHash.EndWriting();
1567 for (; cur < end; ++cur) {
1568 if ('/' == *cur) {
1569 *cur = '_';
1573 // Obtain the local profile directory and construct the output icon file path
1574 rv = NS_GetSpecialDirectory("ProfLDS", getter_AddRefs(aICOFile));
1575 NS_ENSURE_SUCCESS(rv, rv);
1576 if (!aURLShortcut)
1577 rv = aICOFile->AppendNative(nsDependentCString(kJumpListCacheDir));
1578 else
1579 rv = aICOFile->AppendNative(nsDependentCString(kShortcutCacheDir));
1580 NS_ENSURE_SUCCESS(rv, rv);
1582 // Append the icon extension
1583 inputURIHash.AppendLiteral(".ico");
1584 rv = aICOFile->AppendNative(inputURIHash);
1586 return rv;
1589 // (static) Asynchronously creates a cached ICO file on disk for the favicon of
1590 // page aFaviconPageURI and stores it to disk at the path of aICOFile.
1591 nsresult FaviconHelper::CacheIconFileFromFaviconURIAsync(
1592 nsCOMPtr<nsIURI> aFaviconPageURI, nsCOMPtr<nsIFile> aICOFile,
1593 nsCOMPtr<nsIThread>& aIOThread, bool aURLShortcut,
1594 already_AddRefed<nsIRunnable> aRunnable) {
1595 nsCOMPtr<nsIRunnable> runnable = aRunnable;
1596 #ifdef MOZ_PLACES
1597 // Obtain the favicon service and get the favicon for the specified page
1598 nsCOMPtr<nsIFaviconService> favIconSvc(
1599 do_GetService("@mozilla.org/browser/favicon-service;1"));
1600 NS_ENSURE_TRUE(favIconSvc, NS_ERROR_FAILURE);
1602 nsCOMPtr<nsIFaviconDataCallback> callback =
1603 new mozilla::widget::AsyncFaviconDataReady(
1604 aFaviconPageURI, aIOThread, aURLShortcut, runnable.forget());
1606 favIconSvc->GetFaviconDataForPage(aFaviconPageURI, callback, 0);
1607 #endif
1608 return NS_OK;
1611 // Obtains the jump list 'ICO cache timeout in seconds' pref
1612 int32_t FaviconHelper::GetICOCacheSecondsTimeout() {
1613 // Only obtain the setting at most once from the pref service.
1614 // In the rare case that 2 threads call this at the same
1615 // time it is no harm and we will simply obtain the pref twice.
1616 // None of the taskbar list prefs are currently updated via a
1617 // pref observer so I think this should suffice.
1618 const int32_t kSecondsPerDay = 86400;
1619 static bool alreadyObtained = false;
1620 static int32_t icoReCacheSecondsTimeout = kSecondsPerDay;
1621 if (alreadyObtained) {
1622 return icoReCacheSecondsTimeout;
1625 // Obtain the pref
1626 const char PREF_ICOTIMEOUT[] = "browser.taskbar.lists.icoTimeoutInSeconds";
1627 icoReCacheSecondsTimeout =
1628 Preferences::GetInt(PREF_ICOTIMEOUT, kSecondsPerDay);
1629 alreadyObtained = true;
1630 return icoReCacheSecondsTimeout;
1633 /* static */
1634 bool WinUtils::GetShellItemPath(IShellItem* aItem, nsString& aResultString) {
1635 NS_ENSURE_TRUE(aItem, false);
1636 LPWSTR str = nullptr;
1637 if (FAILED(aItem->GetDisplayName(SIGDN_FILESYSPATH, &str))) return false;
1638 aResultString.Assign(str);
1639 CoTaskMemFree(str);
1640 return !aResultString.IsEmpty();
1643 /* static */
1644 LayoutDeviceIntRegion WinUtils::ConvertHRGNToRegion(HRGN aRgn) {
1645 NS_ASSERTION(aRgn, "Don't pass NULL region here");
1647 LayoutDeviceIntRegion rgn;
1649 DWORD size = ::GetRegionData(aRgn, 0, nullptr);
1650 AutoTArray<uint8_t, 100> buffer;
1651 buffer.SetLength(size);
1653 RGNDATA* data = reinterpret_cast<RGNDATA*>(buffer.Elements());
1654 if (!::GetRegionData(aRgn, size, data)) return rgn;
1656 if (data->rdh.nCount > MAX_RECTS_IN_REGION) {
1657 rgn = ToIntRect(data->rdh.rcBound);
1658 return rgn;
1661 RECT* rects = reinterpret_cast<RECT*>(data->Buffer);
1662 for (uint32_t i = 0; i < data->rdh.nCount; ++i) {
1663 RECT* r = rects + i;
1664 rgn.Or(rgn, ToIntRect(*r));
1667 return rgn;
1670 LayoutDeviceIntRect WinUtils::ToIntRect(const RECT& aRect) {
1671 return LayoutDeviceIntRect(aRect.left, aRect.top, aRect.right - aRect.left,
1672 aRect.bottom - aRect.top);
1675 /* static */
1676 bool WinUtils::IsIMEEnabled(const InputContext& aInputContext) {
1677 return IsIMEEnabled(aInputContext.mIMEState.mEnabled);
1680 /* static */
1681 bool WinUtils::IsIMEEnabled(IMEEnabled aIMEState) {
1682 return aIMEState == IMEEnabled::Enabled;
1685 /* static */
1686 void WinUtils::SetupKeyModifiersSequence(nsTArray<KeyPair>* aArray,
1687 uint32_t aModifiers, UINT aMessage) {
1688 MOZ_ASSERT(!(aModifiers & nsIWidget::ALTGRAPH) ||
1689 !(aModifiers & (nsIWidget::CTRL_L | nsIWidget::ALT_R)));
1690 if (aMessage == WM_KEYUP) {
1691 // If AltGr is released, ControlLeft key is released first, then,
1692 // AltRight key is released.
1693 if (aModifiers & nsIWidget::ALTGRAPH) {
1694 aArray->AppendElement(
1695 KeyPair(VK_CONTROL, VK_LCONTROL, ScanCode::eControlLeft));
1696 aArray->AppendElement(KeyPair(VK_MENU, VK_RMENU, ScanCode::eAltRight));
1698 for (uint32_t i = ArrayLength(sModifierKeyMap); i; --i) {
1699 const uint32_t* map = sModifierKeyMap[i - 1];
1700 if (aModifiers & map[0]) {
1701 aArray->AppendElement(KeyPair(map[1], map[2], map[3]));
1704 } else {
1705 for (uint32_t i = 0; i < ArrayLength(sModifierKeyMap); ++i) {
1706 const uint32_t* map = sModifierKeyMap[i];
1707 if (aModifiers & map[0]) {
1708 aArray->AppendElement(KeyPair(map[1], map[2], map[3]));
1711 // If AltGr is pressed, ControlLeft key is pressed first, then,
1712 // AltRight key is pressed.
1713 if (aModifiers & nsIWidget::ALTGRAPH) {
1714 aArray->AppendElement(
1715 KeyPair(VK_CONTROL, VK_LCONTROL, ScanCode::eControlLeft));
1716 aArray->AppendElement(KeyPair(VK_MENU, VK_RMENU, ScanCode::eAltRight));
1721 /* static */
1722 nsresult WinUtils::WriteBitmap(nsIFile* aFile, imgIContainer* aImage) {
1723 RefPtr<SourceSurface> surface = aImage->GetFrame(
1724 imgIContainer::FRAME_FIRST,
1725 imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY);
1726 NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE);
1728 return WriteBitmap(aFile, surface);
1731 /* static */
1732 nsresult WinUtils::WriteBitmap(nsIFile* aFile, SourceSurface* surface) {
1733 nsresult rv;
1735 // For either of the following formats we want to set the biBitCount member
1736 // of the BITMAPINFOHEADER struct to 32, below. For that value the bitmap
1737 // format defines that the A8/X8 WORDs in the bitmap byte stream be ignored
1738 // for the BI_RGB value we use for the biCompression member.
1739 MOZ_ASSERT(surface->GetFormat() == SurfaceFormat::B8G8R8A8 ||
1740 surface->GetFormat() == SurfaceFormat::B8G8R8X8);
1742 RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface();
1743 NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
1745 int32_t width = dataSurface->GetSize().width;
1746 int32_t height = dataSurface->GetSize().height;
1747 int32_t bytesPerPixel = 4 * sizeof(uint8_t);
1748 uint32_t bytesPerRow = bytesPerPixel * width;
1749 bool hasAlpha = surface->GetFormat() == SurfaceFormat::B8G8R8A8;
1751 // initialize these bitmap structs which we will later
1752 // serialize directly to the head of the bitmap file
1753 BITMAPV4HEADER bmi;
1754 memset(&bmi, 0, sizeof(BITMAPV4HEADER));
1755 bmi.bV4Size = sizeof(BITMAPV4HEADER);
1756 bmi.bV4Width = width;
1757 bmi.bV4Height = height;
1758 bmi.bV4Planes = 1;
1759 bmi.bV4BitCount = (WORD)bytesPerPixel * 8;
1760 bmi.bV4V4Compression = hasAlpha ? BI_BITFIELDS : BI_RGB;
1761 bmi.bV4SizeImage = bytesPerRow * height;
1762 bmi.bV4CSType = LCS_sRGB;
1763 if (hasAlpha) {
1764 bmi.bV4RedMask = 0x00FF0000;
1765 bmi.bV4GreenMask = 0x0000FF00;
1766 bmi.bV4BlueMask = 0x000000FF;
1767 bmi.bV4AlphaMask = 0xFF000000;
1770 BITMAPFILEHEADER bf;
1771 DWORD colormask[3];
1772 bf.bfType = 0x4D42; // 'BM'
1773 bf.bfReserved1 = 0;
1774 bf.bfReserved2 = 0;
1775 bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPV4HEADER) +
1776 (hasAlpha ? sizeof(colormask) : 0);
1777 bf.bfSize = bf.bfOffBits + bmi.bV4SizeImage;
1779 // get a file output stream
1780 nsCOMPtr<nsIOutputStream> stream;
1781 rv = NS_NewLocalFileOutputStream(getter_AddRefs(stream), aFile);
1782 NS_ENSURE_SUCCESS(rv, rv);
1784 DataSourceSurface::MappedSurface map;
1785 if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) {
1786 return NS_ERROR_FAILURE;
1789 // write the bitmap headers and rgb pixel data to the file
1790 rv = NS_ERROR_FAILURE;
1791 if (stream) {
1792 uint32_t written;
1793 stream->Write((const char*)&bf, sizeof(BITMAPFILEHEADER), &written);
1794 if (written == sizeof(BITMAPFILEHEADER)) {
1795 stream->Write((const char*)&bmi, sizeof(BITMAPV4HEADER), &written);
1796 if (written == sizeof(BITMAPV4HEADER)) {
1797 if (hasAlpha) {
1798 // color mask
1799 colormask[0] = 0x00FF0000;
1800 colormask[1] = 0x0000FF00;
1801 colormask[2] = 0x000000FF;
1803 stream->Write((const char*)colormask, sizeof(colormask), &written);
1805 if (!hasAlpha || written == sizeof(colormask)) {
1806 // write out the image data backwards because the desktop won't
1807 // show bitmaps with negative heights for top-to-bottom
1808 uint32_t i = map.mStride * height;
1809 do {
1810 i -= map.mStride;
1811 stream->Write(((const char*)map.mData) + i, bytesPerRow, &written);
1812 if (written == bytesPerRow) {
1813 rv = NS_OK;
1814 } else {
1815 rv = NS_ERROR_FAILURE;
1816 break;
1818 } while (i != 0);
1823 stream->Close();
1826 dataSurface->Unmap();
1828 return rv;
1831 // This is in use here and in dom/events/TouchEvent.cpp
1832 /* static */
1833 uint32_t WinUtils::IsTouchDeviceSupportPresent() {
1834 int32_t touchCapabilities = ::GetSystemMetrics(SM_DIGITIZER);
1835 return (touchCapabilities & NID_READY) &&
1836 (touchCapabilities & (NID_EXTERNAL_TOUCH | NID_INTEGRATED_TOUCH));
1839 /* static */
1840 uint32_t WinUtils::GetMaxTouchPoints() {
1841 if (IsTouchDeviceSupportPresent()) {
1842 return GetSystemMetrics(SM_MAXIMUMTOUCHES);
1844 return 0;
1847 /* static */
1848 POWER_PLATFORM_ROLE
1849 WinUtils::GetPowerPlatformRole() {
1850 typedef POWER_PLATFORM_ROLE(WINAPI *
1851 PowerDeterminePlatformRoleEx)(ULONG Version);
1852 static PowerDeterminePlatformRoleEx power_determine_platform_role =
1853 reinterpret_cast<PowerDeterminePlatformRoleEx>(::GetProcAddress(
1854 ::LoadLibraryW(L"PowrProf.dll"), "PowerDeterminePlatformRoleEx"));
1856 POWER_PLATFORM_ROLE powerPlatformRole = PlatformRoleUnspecified;
1857 if (!power_determine_platform_role) {
1858 return powerPlatformRole;
1861 return power_determine_platform_role(POWER_PLATFORM_ROLE_V2);
1864 static bool CallGetAutoRotationState(AR_STATE* aRotationState) {
1865 typedef BOOL(WINAPI * GetAutoRotationStateFunc)(PAR_STATE pState);
1866 static GetAutoRotationStateFunc get_auto_rotation_state_func =
1867 reinterpret_cast<GetAutoRotationStateFunc>(::GetProcAddress(
1868 GetModuleHandleW(L"user32.dll"), "GetAutoRotationState"));
1869 if (get_auto_rotation_state_func) {
1870 ZeroMemory(aRotationState, sizeof(AR_STATE));
1871 return get_auto_rotation_state_func(aRotationState);
1873 return false;
1876 static bool IsTabletDevice() {
1877 // Guarantees that:
1878 // - The device has a touch screen.
1879 // - It is used as a tablet which means that it has no keyboard connected.
1880 // On Windows 10 it means that it is verifying with ConvertibleSlateMode.
1882 if (!IsWin8OrLater()) {
1883 return false;
1886 if (WindowsUIUtils::GetInTabletMode()) {
1887 return true;
1890 if (!GetSystemMetrics(SM_MAXIMUMTOUCHES)) {
1891 return false;
1894 // If the device is docked, the user is treating the device as a PC.
1895 if (GetSystemMetrics(SM_SYSTEMDOCKED)) {
1896 return false;
1899 // If the device is not supporting rotation, it's unlikely to be a tablet,
1900 // a convertible or a detachable. See:
1901 // https://msdn.microsoft.com/en-us/library/windows/desktop/dn629263(v=vs.85).aspx
1902 AR_STATE rotation_state;
1903 if (CallGetAutoRotationState(&rotation_state) &&
1904 (rotation_state & (AR_NOT_SUPPORTED | AR_LAPTOP | AR_NOSENSOR))) {
1905 return false;
1908 // PlatformRoleSlate was added in Windows 8+.
1909 POWER_PLATFORM_ROLE role = WinUtils::GetPowerPlatformRole();
1910 if (role == PlatformRoleMobile || role == PlatformRoleSlate) {
1911 return !GetSystemMetrics(SM_CONVERTIBLESLATEMODE);
1913 return false;
1916 static bool IsMousePresent() {
1917 if (!::GetSystemMetrics(SM_MOUSEPRESENT)) {
1918 return false;
1921 DWORD count = InputDeviceUtils::CountMouseDevices();
1922 if (!count) {
1923 return false;
1926 // If there is a mouse device and if this machine is a tablet or has a
1927 // digitizer, that's counted as the mouse device.
1928 // FIXME: Bug 1495938: We should drop this heuristic way once we find out a
1929 // reliable way to tell there is no mouse or not.
1930 if (count == 1 &&
1931 (WinUtils::IsTouchDeviceSupportPresent() || IsTabletDevice())) {
1932 return false;
1935 return true;
1938 /* static */
1939 PointerCapabilities WinUtils::GetPrimaryPointerCapabilities() {
1940 if (IsTabletDevice()) {
1941 return PointerCapabilities::Coarse;
1944 if (IsMousePresent()) {
1945 return PointerCapabilities::Fine | PointerCapabilities::Hover;
1948 if (IsTouchDeviceSupportPresent()) {
1949 return PointerCapabilities::Coarse;
1952 return PointerCapabilities::None;
1955 /* static */
1956 PointerCapabilities WinUtils::GetAllPointerCapabilities() {
1957 PointerCapabilities result = PointerCapabilities::None;
1959 if (IsTabletDevice() || IsTouchDeviceSupportPresent()) {
1960 result |= PointerCapabilities::Coarse;
1963 if (IsMousePresent()) {
1964 result |= PointerCapabilities::Fine | PointerCapabilities::Hover;
1967 return result;
1970 /* static */
1971 bool WinUtils::ResolveJunctionPointsAndSymLinks(std::wstring& aPath) {
1972 LOG_D("ResolveJunctionPointsAndSymLinks: Resolving path: %S", aPath.c_str());
1974 wchar_t path[MAX_PATH] = {0};
1976 nsAutoHandle handle(::CreateFileW(
1977 aPath.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1978 nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr));
1980 if (handle == INVALID_HANDLE_VALUE) {
1981 LOG_E("Failed to open file handle to resolve path. GetLastError=%d",
1982 GetLastError());
1983 return false;
1986 DWORD pathLen = GetFinalPathNameByHandleW(
1987 handle, path, MAX_PATH, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
1988 if (pathLen == 0 || pathLen >= MAX_PATH) {
1989 LOG_E("GetFinalPathNameByHandleW failed. GetLastError=%d", GetLastError());
1990 return false;
1992 aPath = path;
1994 // GetFinalPathNameByHandle sticks a '\\?\' in front of the path,
1995 // but that confuses some APIs so strip it off. It will also put
1996 // '\\?\UNC\' in front of network paths, we convert that to '\\'.
1997 if (aPath.compare(0, 7, L"\\\\?\\UNC") == 0) {
1998 aPath.erase(2, 6);
1999 } else if (aPath.compare(0, 4, L"\\\\?\\") == 0) {
2000 aPath.erase(0, 4);
2003 LOG_D("ResolveJunctionPointsAndSymLinks: Resolved path to: %S",
2004 aPath.c_str());
2005 return true;
2008 /* static */
2009 bool WinUtils::ResolveJunctionPointsAndSymLinks(nsIFile* aPath) {
2010 MOZ_ASSERT(aPath);
2012 nsAutoString filePath;
2013 nsresult rv = aPath->GetPath(filePath);
2014 if (NS_WARN_IF(NS_FAILED(rv))) {
2015 return false;
2018 std::wstring resolvedPath(filePath.get());
2019 if (!ResolveJunctionPointsAndSymLinks(resolvedPath)) {
2020 return false;
2023 rv = aPath->InitWithPath(nsDependentString(resolvedPath.c_str()));
2024 if (NS_WARN_IF(NS_FAILED(rv))) {
2025 return false;
2028 return true;
2031 /* static */
2032 bool WinUtils::RunningFromANetworkDrive() {
2033 wchar_t exePath[MAX_PATH];
2034 if (!::GetModuleFileNameW(nullptr, exePath, MAX_PATH)) {
2035 return false;
2038 std::wstring exeString(exePath);
2039 if (!widget::WinUtils::ResolveJunctionPointsAndSymLinks(exeString)) {
2040 return false;
2043 wchar_t volPath[MAX_PATH];
2044 if (!::GetVolumePathNameW(exeString.c_str(), volPath, MAX_PATH)) {
2045 return false;
2048 return (::GetDriveTypeW(volPath) == DRIVE_REMOTE);
2051 /* static */
2052 bool WinUtils::CanonicalizePath(nsAString& aPath) {
2053 wchar_t tempPath[MAX_PATH + 1];
2054 if (!PathCanonicalizeW(tempPath,
2055 (char16ptr_t)PromiseFlatString(aPath).get())) {
2056 return false;
2058 aPath = tempPath;
2059 MOZ_ASSERT(aPath.Length() <= MAX_PATH);
2060 return true;
2063 /* static */
2064 bool WinUtils::MakeLongPath(nsAString& aPath) {
2065 wchar_t tempPath[MAX_PATH + 1];
2066 DWORD longResult =
2067 GetLongPathNameW((char16ptr_t)PromiseFlatString(aPath).get(), tempPath,
2068 ArrayLength(tempPath));
2069 if (longResult > ArrayLength(tempPath)) {
2070 // Our buffer is too short, and we're guaranteeing <= MAX_PATH results.
2071 return false;
2072 } else if (longResult) {
2073 // Success.
2074 aPath = tempPath;
2075 MOZ_ASSERT(aPath.Length() <= MAX_PATH);
2077 // GetLongPathNameW returns 0 if the path is not found or is not rooted,
2078 // but we shouldn't consider that a failure condition.
2079 return true;
2082 /* static */
2083 bool WinUtils::UnexpandEnvVars(nsAString& aPath) {
2084 wchar_t tempPath[MAX_PATH + 1];
2085 // PathUnExpandEnvStringsW returns false if it doesn't make any
2086 // substitutions. Silently continue using the unaltered path.
2087 if (PathUnExpandEnvStringsW((char16ptr_t)PromiseFlatString(aPath).get(),
2088 tempPath, ArrayLength(tempPath))) {
2089 aPath = tempPath;
2090 MOZ_ASSERT(aPath.Length() <= MAX_PATH);
2092 return true;
2095 /* static */
2096 WinUtils::WhitelistVec WinUtils::BuildWhitelist() {
2097 WhitelistVec result;
2099 Unused << result.emplaceBack(
2100 std::make_pair(nsString(u"%ProgramFiles%"_ns), nsDependentString()));
2102 // When no substitution is required, set the void flag
2103 result.back().second.SetIsVoid(true);
2105 Unused << result.emplaceBack(
2106 std::make_pair(nsString(u"%SystemRoot%"_ns), nsDependentString()));
2107 result.back().second.SetIsVoid(true);
2109 wchar_t tmpPath[MAX_PATH + 1] = {};
2110 if (GetTempPath(MAX_PATH, tmpPath)) {
2111 // GetTempPath's result always ends with a backslash, which we don't want
2112 uint32_t tmpPathLen = wcslen(tmpPath);
2113 if (tmpPathLen) {
2114 tmpPath[tmpPathLen - 1] = 0;
2117 nsAutoString cleanTmpPath(tmpPath);
2118 if (UnexpandEnvVars(cleanTmpPath)) {
2119 constexpr auto tempVar = u"%TEMP%"_ns;
2120 Unused << result.emplaceBack(std::make_pair(
2121 nsString(cleanTmpPath), nsDependentString(tempVar, 0)));
2125 // If we add more items to the whitelist, ensure we still don't invoke an
2126 // unnecessary heap allocation.
2127 MOZ_ASSERT(result.length() <= kMaxWhitelistedItems);
2129 return result;
2133 * This function provides an array of (system path, substitution) pairs that are
2134 * considered to be acceptable with respect to privacy, for the purposes of
2135 * submitting within telemetry or crash reports.
2137 * The substitution string's void flag may be set. If it is, no subsitution is
2138 * necessary. Otherwise, the consumer should replace the system path with the
2139 * substitution.
2141 * @see PreparePathForTelemetry for an example of its usage.
2143 /* static */
2144 const WinUtils::WhitelistVec& WinUtils::GetWhitelistedPaths() {
2145 static WhitelistVec sWhitelist([]() -> WhitelistVec {
2146 auto setClearFn = [ptr = &sWhitelist]() -> void {
2147 RunOnShutdown([ptr]() -> void { ptr->clear(); },
2148 ShutdownPhase::XPCOMShutdownFinal);
2151 if (NS_IsMainThread()) {
2152 setClearFn();
2153 } else {
2154 SchedulerGroup::Dispatch(
2155 TaskCategory::Other,
2156 NS_NewRunnableFunction("WinUtils::GetWhitelistedPaths",
2157 std::move(setClearFn)));
2160 return BuildWhitelist();
2161 }());
2162 return sWhitelist;
2166 * This function is located here (as opposed to nsSystemInfo or elsewhere)
2167 * because we need to gather this information as early as possible during
2168 * startup.
2170 /* static */
2171 bool WinUtils::GetAppInitDLLs(nsAString& aOutput) {
2172 aOutput.Truncate();
2173 HKEY hkey = NULL;
2174 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2175 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows",
2176 0, KEY_QUERY_VALUE, &hkey)) {
2177 return false;
2179 nsAutoRegKey key(hkey);
2180 LONG status;
2181 const wchar_t kLoadAppInitDLLs[] = L"LoadAppInit_DLLs";
2182 DWORD loadAppInitDLLs = 0;
2183 DWORD loadAppInitDLLsLen = sizeof(loadAppInitDLLs);
2184 status = RegQueryValueExW(hkey, kLoadAppInitDLLs, nullptr, nullptr,
2185 (LPBYTE)&loadAppInitDLLs, &loadAppInitDLLsLen);
2186 if (status != ERROR_SUCCESS) {
2187 return false;
2189 if (!loadAppInitDLLs) {
2190 // If loadAppInitDLLs is zero then AppInit_DLLs is disabled.
2191 // In this case we'll return true along with an empty output string.
2192 return true;
2194 DWORD numBytes = 0;
2195 const wchar_t kAppInitDLLs[] = L"AppInit_DLLs";
2196 // Query for required buffer size
2197 status = RegQueryValueExW(hkey, kAppInitDLLs, nullptr, nullptr, nullptr,
2198 &numBytes);
2199 if (status != ERROR_SUCCESS) {
2200 return false;
2202 // Allocate the buffer and query for the actual data
2203 mozilla::UniquePtr<wchar_t[]> data =
2204 mozilla::MakeUnique<wchar_t[]>(numBytes / sizeof(wchar_t));
2205 status = RegQueryValueExW(hkey, kAppInitDLLs, nullptr, nullptr,
2206 (LPBYTE)data.get(), &numBytes);
2207 if (status != ERROR_SUCCESS) {
2208 return false;
2210 // For each token, split up the filename components and then check the
2211 // name of the file.
2212 const wchar_t kDelimiters[] = L", ";
2213 wchar_t* tokenContext = nullptr;
2214 wchar_t* token = wcstok_s(data.get(), kDelimiters, &tokenContext);
2215 while (token) {
2216 nsAutoString cleanPath(token);
2217 // Since these paths are short paths originating from the registry, we need
2218 // to canonicalize them, lengthen them, and sanitize them before we can
2219 // check them against the whitelist
2220 if (PreparePathForTelemetry(cleanPath)) {
2221 if (!aOutput.IsEmpty()) {
2222 aOutput += L";";
2224 aOutput += cleanPath;
2226 token = wcstok_s(nullptr, kDelimiters, &tokenContext);
2228 return true;
2231 /* static */
2232 bool WinUtils::PreparePathForTelemetry(nsAString& aPath,
2233 PathTransformFlags aFlags) {
2234 if (aFlags & PathTransformFlags::Canonicalize) {
2235 if (!CanonicalizePath(aPath)) {
2236 return false;
2239 if (aFlags & PathTransformFlags::Lengthen) {
2240 if (!MakeLongPath(aPath)) {
2241 return false;
2244 if (aFlags & PathTransformFlags::UnexpandEnvVars) {
2245 if (!UnexpandEnvVars(aPath)) {
2246 return false;
2250 const WhitelistVec& whitelistedPaths = GetWhitelistedPaths();
2252 for (uint32_t i = 0; i < whitelistedPaths.length(); ++i) {
2253 const nsString& testPath = whitelistedPaths[i].first;
2254 const nsDependentString& substitution = whitelistedPaths[i].second;
2255 if (StringBeginsWith(aPath, testPath, nsCaseInsensitiveStringComparator)) {
2256 if (!substitution.IsVoid()) {
2257 aPath.Replace(0, testPath.Length(), substitution);
2259 return true;
2263 // For non-whitelisted paths, we strip the path component and just leave
2264 // the filename. We can't use nsLocalFile to do this because these paths may
2265 // begin with environment variables, and nsLocalFile doesn't like
2266 // non-absolute paths.
2267 const nsString& flatPath = PromiseFlatString(aPath);
2268 LPCWSTR leafStart = ::PathFindFileNameW(flatPath.get());
2269 ptrdiff_t cutLen = leafStart - flatPath.get();
2270 if (cutLen) {
2271 aPath.Cut(0, cutLen);
2272 } else if (aFlags & PathTransformFlags::RequireFilePath) {
2273 return false;
2276 return true;
2279 nsString WinUtils::GetPackageFamilyName() {
2280 nsString rv;
2282 UniquePtr<wchar_t[]> packageIdentity = mozilla::GetPackageFamilyName();
2283 if (packageIdentity) {
2284 rv = packageIdentity.get();
2287 return rv;
2290 bool WinUtils::GetClassName(HWND aHwnd, nsAString& aClassName) {
2291 const int bufferLength = 256;
2292 aClassName.SetLength(bufferLength);
2294 int length = ::GetClassNameW(aHwnd, (char16ptr_t)aClassName.BeginWriting(),
2295 bufferLength);
2296 if (length == 0) {
2297 return false;
2299 MOZ_RELEASE_ASSERT(length <= (bufferLength - 1));
2300 aClassName.Truncate(length);
2301 return true;
2304 static BOOL CALLBACK EnumUpdateWindowOcclusionProc(HWND aHwnd, LPARAM aLParam) {
2305 const bool* const enable = reinterpret_cast<bool*>(aLParam);
2306 nsWindow* window = WinUtils::GetNSWindowPtr(aHwnd);
2307 if (window) {
2308 window->MaybeEnableWindowOcclusion(*enable);
2310 return TRUE;
2313 void WinUtils::EnableWindowOcclusion(const bool aEnable) {
2314 if (aEnable) {
2315 WinWindowOcclusionTracker::Ensure();
2317 ::EnumWindows(EnumUpdateWindowOcclusionProc,
2318 reinterpret_cast<LPARAM>(&aEnable));
2321 void WinUtils::GetDisplayOrientation(const char16ptr_t aName,
2322 hal::ScreenOrientation& aOrientation,
2323 uint16_t& aAngle) {
2324 aOrientation = hal::ScreenOrientation::None;
2325 aAngle = 0;
2327 DEVMODEW mode = {.dmSize = sizeof(DEVMODEW)};
2328 if (!EnumDisplaySettingsW(aName, ENUM_CURRENT_SETTINGS, &mode)) {
2329 return;
2331 MOZ_ASSERT(mode.dmFields & DM_DISPLAYORIENTATION);
2333 // conver to default/natural size
2334 if (mode.dmDisplayOrientation == DMDO_90 ||
2335 mode.dmDisplayOrientation == DMDO_270) {
2336 DWORD temp = mode.dmPelsHeight;
2337 mode.dmPelsHeight = mode.dmPelsWidth;
2338 mode.dmPelsWidth = temp;
2341 bool defaultIsLandscape = mode.dmPelsWidth >= mode.dmPelsHeight;
2342 switch (mode.dmDisplayOrientation) {
2343 case DMDO_DEFAULT:
2344 aOrientation = defaultIsLandscape
2345 ? hal::ScreenOrientation::LandscapePrimary
2346 : hal::ScreenOrientation::PortraitPrimary;
2347 aAngle = 0;
2348 break;
2349 case DMDO_90:
2350 aOrientation = defaultIsLandscape
2351 ? hal::ScreenOrientation::PortraitPrimary
2352 : hal::ScreenOrientation::LandscapeSecondary;
2353 aAngle = 270;
2354 break;
2355 case DMDO_180:
2356 aOrientation = defaultIsLandscape
2357 ? hal::ScreenOrientation::LandscapeSecondary
2358 : hal::ScreenOrientation::PortraitSecondary;
2359 aAngle = 180;
2360 break;
2361 case DMDO_270:
2362 aOrientation = defaultIsLandscape
2363 ? hal::ScreenOrientation::PortraitSecondary
2364 : hal::ScreenOrientation::LandscapePrimary;
2365 aAngle = 90;
2366 break;
2367 default:
2368 MOZ_ASSERT_UNREACHABLE("Unexpected angle");
2369 break;
2371 return;
2374 } // namespace widget
2375 } // namespace mozilla