Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* vim:expandtab:shiftwidth=2:tabstop=2: |
michael@0 | 3 | */ |
michael@0 | 4 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 7 | |
michael@0 | 8 | #include "nsWinUtils.h" |
michael@0 | 9 | |
michael@0 | 10 | #include "Compatibility.h" |
michael@0 | 11 | #include "DocAccessible.h" |
michael@0 | 12 | #include "nsCoreUtils.h" |
michael@0 | 13 | |
michael@0 | 14 | #include "mozilla/Preferences.h" |
michael@0 | 15 | #include "nsArrayUtils.h" |
michael@0 | 16 | #include "nsIArray.h" |
michael@0 | 17 | #include "nsIDocument.h" |
michael@0 | 18 | #include "nsIDocShellTreeItem.h" |
michael@0 | 19 | #include "nsXULAppAPI.h" |
michael@0 | 20 | |
michael@0 | 21 | using namespace mozilla; |
michael@0 | 22 | using namespace mozilla::a11y; |
michael@0 | 23 | |
michael@0 | 24 | // Window property used by ipc related code in identifying accessible |
michael@0 | 25 | // tab windows. |
michael@0 | 26 | const wchar_t* kPropNameTabContent = L"AccessibleTabWindow"; |
michael@0 | 27 | |
michael@0 | 28 | /** |
michael@0 | 29 | * WindowProc to process WM_GETOBJECT messages, used in windows emulation mode. |
michael@0 | 30 | */ |
michael@0 | 31 | static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, |
michael@0 | 32 | WPARAM wParam, LPARAM lParam); |
michael@0 | 33 | |
michael@0 | 34 | nsRefPtrHashtable<nsPtrHashKey<void>, DocAccessible>* nsWinUtils::sHWNDCache = nullptr; |
michael@0 | 35 | |
michael@0 | 36 | already_AddRefed<nsIDOMCSSStyleDeclaration> |
michael@0 | 37 | nsWinUtils::GetComputedStyleDeclaration(nsIContent* aContent) |
michael@0 | 38 | { |
michael@0 | 39 | nsIContent* elm = nsCoreUtils::GetDOMElementFor(aContent); |
michael@0 | 40 | if (!elm) |
michael@0 | 41 | return nullptr; |
michael@0 | 42 | |
michael@0 | 43 | // Returns number of items in style declaration |
michael@0 | 44 | nsCOMPtr<nsIDOMWindow> window = |
michael@0 | 45 | do_QueryInterface(elm->OwnerDoc()->GetWindow()); |
michael@0 | 46 | if (!window) |
michael@0 | 47 | return nullptr; |
michael@0 | 48 | |
michael@0 | 49 | nsCOMPtr<nsIDOMCSSStyleDeclaration> cssDecl; |
michael@0 | 50 | nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(elm)); |
michael@0 | 51 | window->GetComputedStyle(domElement, EmptyString(), getter_AddRefs(cssDecl)); |
michael@0 | 52 | return cssDecl.forget(); |
michael@0 | 53 | } |
michael@0 | 54 | |
michael@0 | 55 | bool |
michael@0 | 56 | nsWinUtils::MaybeStartWindowEmulation() |
michael@0 | 57 | { |
michael@0 | 58 | // Register window class that'll be used for document accessibles associated |
michael@0 | 59 | // with tabs. |
michael@0 | 60 | if (Compatibility::IsJAWS() || Compatibility::IsWE() || |
michael@0 | 61 | Compatibility::IsDolphin() || |
michael@0 | 62 | XRE_GetProcessType() == GeckoProcessType_Content) { |
michael@0 | 63 | RegisterNativeWindow(kClassNameTabContent); |
michael@0 | 64 | sHWNDCache = new nsRefPtrHashtable<nsPtrHashKey<void>, DocAccessible>(4); |
michael@0 | 65 | return true; |
michael@0 | 66 | } |
michael@0 | 67 | |
michael@0 | 68 | return false; |
michael@0 | 69 | } |
michael@0 | 70 | |
michael@0 | 71 | void |
michael@0 | 72 | nsWinUtils::ShutdownWindowEmulation() |
michael@0 | 73 | { |
michael@0 | 74 | // Unregister window call that's used for document accessibles associated |
michael@0 | 75 | // with tabs. |
michael@0 | 76 | if (IsWindowEmulationStarted()) |
michael@0 | 77 | ::UnregisterClassW(kClassNameTabContent, GetModuleHandle(nullptr)); |
michael@0 | 78 | } |
michael@0 | 79 | |
michael@0 | 80 | bool |
michael@0 | 81 | nsWinUtils::IsWindowEmulationStarted() |
michael@0 | 82 | { |
michael@0 | 83 | return sHWNDCache != nullptr; |
michael@0 | 84 | } |
michael@0 | 85 | |
michael@0 | 86 | void |
michael@0 | 87 | nsWinUtils::RegisterNativeWindow(LPCWSTR aWindowClass) |
michael@0 | 88 | { |
michael@0 | 89 | WNDCLASSW wc; |
michael@0 | 90 | wc.style = CS_GLOBALCLASS; |
michael@0 | 91 | wc.lpfnWndProc = WindowProc; |
michael@0 | 92 | wc.cbClsExtra = 0; |
michael@0 | 93 | wc.cbWndExtra = 0; |
michael@0 | 94 | wc.hInstance = GetModuleHandle(nullptr); |
michael@0 | 95 | wc.hIcon = nullptr; |
michael@0 | 96 | wc.hCursor = nullptr; |
michael@0 | 97 | wc.hbrBackground = nullptr; |
michael@0 | 98 | wc.lpszMenuName = nullptr; |
michael@0 | 99 | wc.lpszClassName = aWindowClass; |
michael@0 | 100 | ::RegisterClassW(&wc); |
michael@0 | 101 | } |
michael@0 | 102 | |
michael@0 | 103 | HWND |
michael@0 | 104 | nsWinUtils::CreateNativeWindow(LPCWSTR aWindowClass, HWND aParentWnd, |
michael@0 | 105 | int aX, int aY, int aWidth, int aHeight, |
michael@0 | 106 | bool aIsActive) |
michael@0 | 107 | { |
michael@0 | 108 | HWND hwnd = ::CreateWindowExW(WS_EX_TRANSPARENT, aWindowClass, |
michael@0 | 109 | L"NetscapeDispatchWnd", |
michael@0 | 110 | WS_CHILD | (aIsActive ? WS_VISIBLE : 0), |
michael@0 | 111 | aX, aY, aWidth, aHeight, |
michael@0 | 112 | aParentWnd, |
michael@0 | 113 | nullptr, |
michael@0 | 114 | GetModuleHandle(nullptr), |
michael@0 | 115 | nullptr); |
michael@0 | 116 | if (hwnd) { |
michael@0 | 117 | // Mark this window so that ipc related code can identify it. |
michael@0 | 118 | ::SetPropW(hwnd, kPropNameTabContent, (HANDLE)1); |
michael@0 | 119 | } |
michael@0 | 120 | return hwnd; |
michael@0 | 121 | } |
michael@0 | 122 | |
michael@0 | 123 | void |
michael@0 | 124 | nsWinUtils::ShowNativeWindow(HWND aWnd) |
michael@0 | 125 | { |
michael@0 | 126 | ::ShowWindow(aWnd, SW_SHOW); |
michael@0 | 127 | } |
michael@0 | 128 | |
michael@0 | 129 | void |
michael@0 | 130 | nsWinUtils::HideNativeWindow(HWND aWnd) |
michael@0 | 131 | { |
michael@0 | 132 | ::SetWindowPos(aWnd, nullptr, 0, 0, 0, 0, |
michael@0 | 133 | SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | |
michael@0 | 134 | SWP_NOZORDER | SWP_NOACTIVATE); |
michael@0 | 135 | } |
michael@0 | 136 | |
michael@0 | 137 | LRESULT CALLBACK |
michael@0 | 138 | WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) |
michael@0 | 139 | { |
michael@0 | 140 | // Note, this window's message handling should not invoke any call that |
michael@0 | 141 | // may result in a cross-process ipc call. Doing so may violate RPC |
michael@0 | 142 | // message semantics. |
michael@0 | 143 | |
michael@0 | 144 | switch (msg) { |
michael@0 | 145 | case WM_GETOBJECT: |
michael@0 | 146 | { |
michael@0 | 147 | if (lParam == OBJID_CLIENT) { |
michael@0 | 148 | DocAccessible* document = |
michael@0 | 149 | nsWinUtils::sHWNDCache->GetWeak(static_cast<void*>(hWnd)); |
michael@0 | 150 | if (document) { |
michael@0 | 151 | IAccessible* msaaAccessible = nullptr; |
michael@0 | 152 | document->GetNativeInterface((void**)&msaaAccessible); // does an addref |
michael@0 | 153 | if (msaaAccessible) { |
michael@0 | 154 | LRESULT result = ::LresultFromObject(IID_IAccessible, wParam, |
michael@0 | 155 | msaaAccessible); // does an addref |
michael@0 | 156 | msaaAccessible->Release(); // release extra addref |
michael@0 | 157 | return result; |
michael@0 | 158 | } |
michael@0 | 159 | } |
michael@0 | 160 | } |
michael@0 | 161 | return 0; |
michael@0 | 162 | } |
michael@0 | 163 | case WM_NCHITTEST: |
michael@0 | 164 | { |
michael@0 | 165 | LRESULT lRet = ::DefWindowProc(hWnd, msg, wParam, lParam); |
michael@0 | 166 | if (HTCLIENT == lRet) |
michael@0 | 167 | lRet = HTTRANSPARENT; |
michael@0 | 168 | return lRet; |
michael@0 | 169 | } |
michael@0 | 170 | } |
michael@0 | 171 | |
michael@0 | 172 | return ::DefWindowProcW(hWnd, msg, wParam, lParam); |
michael@0 | 173 | } |