Bug 1769547 - Do not MOZ_CRASH() on missing process r=nika
[gecko.git] / accessible / windows / msaa / nsWinUtils.cpp
blob14aa023c7389c3c158d12accb4c68c46e420ed27
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:expandtab:shiftwidth=2:tabstop=2:
3 */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "nsWinUtils.h"
10 #include "Compatibility.h"
11 #include "DocAccessible.h"
12 #include "nsAccessibilityService.h"
13 #include "nsCoreUtils.h"
15 #include "mozilla/a11y/DocAccessibleParent.h"
16 #include "mozilla/Preferences.h"
17 #include "mozilla/StaticPrefs_accessibility.h"
18 #include "nsArrayUtils.h"
19 #include "nsICSSDeclaration.h"
20 #include "mozilla/dom/Document.h"
21 #include "mozilla/dom/Element.h"
22 #include "nsXULAppAPI.h"
24 using namespace mozilla;
25 using namespace mozilla::a11y;
26 using mozilla::dom::Element;
28 // Window property used by ipc related code in identifying accessible
29 // tab windows.
30 const wchar_t* kPropNameTabContent = L"AccessibleTabWindow";
32 /**
33 * WindowProc to process WM_GETOBJECT messages, used in windows emulation mode.
35 static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
36 LPARAM lParam);
38 bool nsWinUtils::sWindowEmulationStarted = false;
40 already_AddRefed<nsICSSDeclaration> nsWinUtils::GetComputedStyleDeclaration(
41 nsIContent* aContent) {
42 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aContent);
43 if (!elm) return nullptr;
45 // Returns number of items in style declaration
46 nsCOMPtr<nsPIDOMWindowInner> window = elm->OwnerDoc()->GetInnerWindow();
47 if (!window) return nullptr;
49 ErrorResult dummy;
50 nsCOMPtr<Element> domElement(do_QueryInterface(elm));
51 nsCOMPtr<nsICSSDeclaration> cssDecl =
52 window->GetComputedStyle(*domElement, u""_ns, dummy);
53 dummy.SuppressException();
54 return cssDecl.forget();
57 bool nsWinUtils::MaybeStartWindowEmulation() {
58 // Register window class that'll be used for document accessibles associated
59 // with tabs.
60 if (IPCAccessibilityActive()) return false;
62 if (Compatibility::IsJAWS() || Compatibility::IsWE() ||
63 Compatibility::IsDolphin() || Compatibility::IsVisperoShared()) {
64 RegisterNativeWindow(kClassNameTabContent);
65 sWindowEmulationStarted = true;
66 return true;
69 return false;
72 void nsWinUtils::ShutdownWindowEmulation() {
73 // Unregister window call that's used for document accessibles associated
74 // with tabs.
75 if (IsWindowEmulationStarted()) {
76 ::UnregisterClassW(kClassNameTabContent, GetModuleHandle(nullptr));
77 sWindowEmulationStarted = false;
81 void nsWinUtils::RegisterNativeWindow(LPCWSTR aWindowClass) {
82 WNDCLASSW wc;
83 wc.style = CS_GLOBALCLASS;
84 wc.lpfnWndProc = WindowProc;
85 wc.cbClsExtra = 0;
86 wc.cbWndExtra = 0;
87 wc.hInstance = GetModuleHandle(nullptr);
88 wc.hIcon = nullptr;
89 wc.hCursor = nullptr;
90 wc.hbrBackground = nullptr;
91 wc.lpszMenuName = nullptr;
92 wc.lpszClassName = aWindowClass;
93 ::RegisterClassW(&wc);
96 HWND nsWinUtils::CreateNativeWindow(LPCWSTR aWindowClass, HWND aParentWnd,
97 int aX, int aY, int aWidth, int aHeight,
98 bool aIsActive,
99 NativeWindowCreateProc* aOnCreateProc) {
100 return ::CreateWindowExW(
101 WS_EX_TRANSPARENT, aWindowClass, L"NetscapeDispatchWnd",
102 WS_CHILD | (aIsActive ? WS_VISIBLE : 0), aX, aY, aWidth, aHeight,
103 aParentWnd, nullptr, GetModuleHandle(nullptr), aOnCreateProc);
106 void nsWinUtils::ShowNativeWindow(HWND aWnd) { ::ShowWindow(aWnd, SW_SHOW); }
108 void nsWinUtils::HideNativeWindow(HWND aWnd) {
109 ::SetWindowPos(
110 aWnd, nullptr, 0, 0, 0, 0,
111 SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
114 LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
115 // Note, this window's message handling should not invoke any call that
116 // may result in a cross-process ipc call. Doing so may violate RPC
117 // message semantics.
119 switch (msg) {
120 case WM_CREATE: {
121 // Mark this window so that ipc related code can identify it.
122 ::SetPropW(hWnd, kPropNameTabContent, reinterpret_cast<HANDLE>(1));
124 auto createStruct = reinterpret_cast<CREATESTRUCT*>(lParam);
125 auto createProc = reinterpret_cast<nsWinUtils::NativeWindowCreateProc*>(
126 createStruct->lpCreateParams);
128 if (createProc && *createProc) {
129 (*createProc)(hWnd);
132 return 0;
134 case WM_GETOBJECT: {
135 // Do explicit casting to make it working on 64bit systems (see bug 649236
136 // for details).
137 int32_t objId = static_cast<DWORD>(lParam);
138 if (objId == OBJID_CLIENT) {
139 RefPtr<IAccessible> msaaAccessible;
140 DocAccessible* document =
141 reinterpret_cast<DocAccessible*>(::GetPropW(hWnd, kPropNameDocAcc));
142 if (document) {
143 document->GetNativeInterface(getter_AddRefs(msaaAccessible));
144 } else {
145 DocAccessibleParent* docParent = static_cast<DocAccessibleParent*>(
146 ::GetPropW(hWnd, kPropNameDocAccParent));
147 if (docParent) {
148 if (StaticPrefs::accessibility_cache_enabled_AtStartup()) {
149 msaaAccessible = MsaaAccessible::GetFrom(docParent);
150 } else {
151 docParent->GetCOMInterface(getter_AddRefs(msaaAccessible));
155 if (msaaAccessible) {
156 LRESULT result =
157 ::LresultFromObject(IID_IAccessible, wParam,
158 msaaAccessible); // does an addref
159 return result;
162 return 0;
164 case WM_NCHITTEST: {
165 LRESULT lRet = ::DefWindowProc(hWnd, msg, wParam, lParam);
166 if (HTCLIENT == lRet) lRet = HTTRANSPARENT;
167 return lRet;
171 return ::DefWindowProcW(hWnd, msg, wParam, lParam);