1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/accessible/src/windows/msaa/AccessibleWrap.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1336 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "AccessibleWrap.h" 1.11 +#include "Accessible-inl.h" 1.12 + 1.13 +#include "Compatibility.h" 1.14 +#include "DocAccessible-inl.h" 1.15 +#include "EnumVariant.h" 1.16 +#include "nsAccUtils.h" 1.17 +#include "nsCoreUtils.h" 1.18 +#include "nsIAccessibleEvent.h" 1.19 +#include "nsIAccessibleRelation.h" 1.20 +#include "nsWinUtils.h" 1.21 +#include "ServiceProvider.h" 1.22 +#include "Relation.h" 1.23 +#include "Role.h" 1.24 +#include "RootAccessible.h" 1.25 +#include "sdnAccessible.h" 1.26 +#include "States.h" 1.27 + 1.28 +#ifdef A11Y_LOG 1.29 +#include "Logging.h" 1.30 +#endif 1.31 + 1.32 +#include "nsIMutableArray.h" 1.33 +#include "nsIFrame.h" 1.34 +#include "nsIScrollableFrame.h" 1.35 +#include "nsINodeInfo.h" 1.36 +#include "nsIServiceManager.h" 1.37 +#include "nsNameSpaceManager.h" 1.38 +#include "nsTextFormatter.h" 1.39 +#include "nsView.h" 1.40 +#include "nsViewManager.h" 1.41 +#include "nsEventMap.h" 1.42 +#include "nsArrayUtils.h" 1.43 +#include "mozilla/Preferences.h" 1.44 + 1.45 +#include "oleacc.h" 1.46 + 1.47 +using namespace mozilla; 1.48 +using namespace mozilla::a11y; 1.49 + 1.50 +const uint32_t USE_ROLE_STRING = 0; 1.51 + 1.52 +/* For documentation of the accessibility architecture, 1.53 + * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html 1.54 + */ 1.55 + 1.56 +//#define DEBUG_LEAKS 1.57 + 1.58 +#ifdef DEBUG_LEAKS 1.59 +static gAccessibles = 0; 1.60 +#endif 1.61 + 1.62 +static const int32_t kIEnumVariantDisconnected = -1; 1.63 + 1.64 +//////////////////////////////////////////////////////////////////////////////// 1.65 +// AccessibleWrap 1.66 +//////////////////////////////////////////////////////////////////////////////// 1.67 + 1.68 +ITypeInfo* AccessibleWrap::gTypeInfo = nullptr; 1.69 + 1.70 +NS_IMPL_ISUPPORTS_INHERITED0(AccessibleWrap, Accessible) 1.71 + 1.72 +//----------------------------------------------------- 1.73 +// IUnknown interface methods - see iunknown.h for documentation 1.74 +//----------------------------------------------------- 1.75 + 1.76 +// Microsoft COM QueryInterface 1.77 +STDMETHODIMP 1.78 +AccessibleWrap::QueryInterface(REFIID iid, void** ppv) 1.79 +{ 1.80 + A11Y_TRYBLOCK_BEGIN 1.81 + 1.82 + if (!ppv) 1.83 + return E_INVALIDARG; 1.84 + 1.85 + *ppv = nullptr; 1.86 + 1.87 + if (IID_IUnknown == iid || IID_IDispatch == iid || IID_IAccessible == iid) 1.88 + *ppv = static_cast<IAccessible*>(this); 1.89 + else if (IID_IEnumVARIANT == iid) { 1.90 + // Don't support this interface for leaf elements. 1.91 + if (!HasChildren() || nsAccUtils::MustPrune(this)) 1.92 + return E_NOINTERFACE; 1.93 + 1.94 + *ppv = static_cast<IEnumVARIANT*>(new ChildrenEnumVariant(this)); 1.95 + } else if (IID_IServiceProvider == iid) 1.96 + *ppv = new ServiceProvider(this); 1.97 + else if (IID_ISimpleDOMNode == iid) { 1.98 + if (IsDefunct() || (!HasOwnContent() && !IsDoc())) 1.99 + return E_NOINTERFACE; 1.100 + 1.101 + *ppv = static_cast<ISimpleDOMNode*>(new sdnAccessible(GetNode())); 1.102 + } 1.103 + 1.104 + if (nullptr == *ppv) { 1.105 + HRESULT hr = ia2Accessible::QueryInterface(iid, ppv); 1.106 + if (SUCCEEDED(hr)) 1.107 + return hr; 1.108 + } 1.109 + 1.110 + if (nullptr == *ppv) { 1.111 + HRESULT hr = ia2AccessibleComponent::QueryInterface(iid, ppv); 1.112 + if (SUCCEEDED(hr)) 1.113 + return hr; 1.114 + } 1.115 + 1.116 + if (nullptr == *ppv) { 1.117 + HRESULT hr = ia2AccessibleHyperlink::QueryInterface(iid, ppv); 1.118 + if (SUCCEEDED(hr)) 1.119 + return hr; 1.120 + } 1.121 + 1.122 + if (nullptr == *ppv) { 1.123 + HRESULT hr = ia2AccessibleValue::QueryInterface(iid, ppv); 1.124 + if (SUCCEEDED(hr)) 1.125 + return hr; 1.126 + } 1.127 + 1.128 + if (nullptr == *ppv) 1.129 + return E_NOINTERFACE; 1.130 + 1.131 + (reinterpret_cast<IUnknown*>(*ppv))->AddRef(); 1.132 + return S_OK; 1.133 + 1.134 + A11Y_TRYBLOCK_END 1.135 +} 1.136 + 1.137 +//----------------------------------------------------- 1.138 +// IAccessible methods 1.139 +//----------------------------------------------------- 1.140 + 1.141 +STDMETHODIMP 1.142 +AccessibleWrap::get_accParent( IDispatch __RPC_FAR *__RPC_FAR *ppdispParent) 1.143 +{ 1.144 + A11Y_TRYBLOCK_BEGIN 1.145 + 1.146 + if (!ppdispParent) 1.147 + return E_INVALIDARG; 1.148 + 1.149 + *ppdispParent = nullptr; 1.150 + 1.151 + if (IsDefunct()) 1.152 + return CO_E_OBJNOTCONNECTED; 1.153 + 1.154 + DocAccessible* doc = AsDoc(); 1.155 + if (doc) { 1.156 + // Return window system accessible object for root document and tab document 1.157 + // accessibles. 1.158 + if (!doc->ParentDocument() || 1.159 + (nsWinUtils::IsWindowEmulationStarted() && 1.160 + nsCoreUtils::IsTabDocument(doc->DocumentNode()))) { 1.161 + HWND hwnd = static_cast<HWND>(doc->GetNativeWindow()); 1.162 + if (hwnd && SUCCEEDED(::AccessibleObjectFromWindow(hwnd, OBJID_WINDOW, 1.163 + IID_IAccessible, 1.164 + (void**)ppdispParent))) { 1.165 + return S_OK; 1.166 + } 1.167 + } 1.168 + } 1.169 + 1.170 + Accessible* xpParentAcc = Parent(); 1.171 + if (!xpParentAcc) 1.172 + return S_FALSE; 1.173 + 1.174 + *ppdispParent = NativeAccessible(xpParentAcc); 1.175 + return S_OK; 1.176 + 1.177 + A11Y_TRYBLOCK_END 1.178 +} 1.179 + 1.180 +STDMETHODIMP 1.181 +AccessibleWrap::get_accChildCount( long __RPC_FAR *pcountChildren) 1.182 +{ 1.183 + A11Y_TRYBLOCK_BEGIN 1.184 + 1.185 + if (!pcountChildren) 1.186 + return E_INVALIDARG; 1.187 + 1.188 + *pcountChildren = 0; 1.189 + 1.190 + if (IsDefunct()) 1.191 + return CO_E_OBJNOTCONNECTED; 1.192 + 1.193 + if (nsAccUtils::MustPrune(this)) 1.194 + return S_OK; 1.195 + 1.196 + *pcountChildren = ChildCount(); 1.197 + return S_OK; 1.198 + 1.199 + A11Y_TRYBLOCK_END 1.200 +} 1.201 + 1.202 +STDMETHODIMP 1.203 +AccessibleWrap::get_accChild( 1.204 + /* [in] */ VARIANT varChild, 1.205 + /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispChild) 1.206 +{ 1.207 + A11Y_TRYBLOCK_BEGIN 1.208 + 1.209 + if (!ppdispChild) 1.210 + return E_INVALIDARG; 1.211 + 1.212 + *ppdispChild = nullptr; 1.213 + if (IsDefunct()) 1.214 + return CO_E_OBJNOTCONNECTED; 1.215 + 1.216 + // IAccessible::accChild is used to return this accessible or child accessible 1.217 + // at the given index or to get an accessible by child ID in the case of 1.218 + // document accessible (it's handled by overriden GetXPAccessibleFor method 1.219 + // on the document accessible). The getting an accessible by child ID is used 1.220 + // by AccessibleObjectFromEvent() called by AT when AT handles our MSAA event. 1.221 + Accessible* child = GetXPAccessibleFor(varChild); 1.222 + if (!child) 1.223 + return E_INVALIDARG; 1.224 + 1.225 + if (child->IsDefunct()) 1.226 + return CO_E_OBJNOTCONNECTED; 1.227 + 1.228 + *ppdispChild = NativeAccessible(child); 1.229 + return S_OK; 1.230 + 1.231 + A11Y_TRYBLOCK_END 1.232 +} 1.233 + 1.234 +STDMETHODIMP 1.235 +AccessibleWrap::get_accName( 1.236 + /* [optional][in] */ VARIANT varChild, 1.237 + /* [retval][out] */ BSTR __RPC_FAR *pszName) 1.238 +{ 1.239 + A11Y_TRYBLOCK_BEGIN 1.240 + 1.241 + if (!pszName) 1.242 + return E_INVALIDARG; 1.243 + 1.244 + *pszName = nullptr; 1.245 + 1.246 + if (IsDefunct()) 1.247 + return CO_E_OBJNOTCONNECTED; 1.248 + 1.249 + Accessible* xpAccessible = GetXPAccessibleFor(varChild); 1.250 + if (!xpAccessible) 1.251 + return E_INVALIDARG; 1.252 + 1.253 + if (xpAccessible->IsDefunct()) 1.254 + return CO_E_OBJNOTCONNECTED; 1.255 + 1.256 + nsAutoString name; 1.257 + xpAccessible->Name(name); 1.258 + 1.259 + // The name was not provided, e.g. no alt attribute for an image. A screen 1.260 + // reader may choose to invent its own accessible name, e.g. from an image src 1.261 + // attribute. Refer to eNoNameOnPurpose return value. 1.262 + if (name.IsVoid()) 1.263 + return S_FALSE; 1.264 + 1.265 + *pszName = ::SysAllocStringLen(name.get(), name.Length()); 1.266 + if (!*pszName) 1.267 + return E_OUTOFMEMORY; 1.268 + return S_OK; 1.269 + 1.270 + A11Y_TRYBLOCK_END 1.271 +} 1.272 + 1.273 + 1.274 +STDMETHODIMP 1.275 +AccessibleWrap::get_accValue( 1.276 + /* [optional][in] */ VARIANT varChild, 1.277 + /* [retval][out] */ BSTR __RPC_FAR *pszValue) 1.278 +{ 1.279 + A11Y_TRYBLOCK_BEGIN 1.280 + 1.281 + if (!pszValue) 1.282 + return E_INVALIDARG; 1.283 + 1.284 + *pszValue = nullptr; 1.285 + 1.286 + if (IsDefunct()) 1.287 + return CO_E_OBJNOTCONNECTED; 1.288 + 1.289 + Accessible* xpAccessible = GetXPAccessibleFor(varChild); 1.290 + if (!xpAccessible) 1.291 + return E_INVALIDARG; 1.292 + 1.293 + if (xpAccessible->IsDefunct()) 1.294 + return CO_E_OBJNOTCONNECTED; 1.295 + 1.296 + if (xpAccessible->NativeRole() == roles::PASSWORD_TEXT) 1.297 + return E_ACCESSDENIED; 1.298 + 1.299 + nsAutoString value; 1.300 + xpAccessible->Value(value); 1.301 + 1.302 + // See bug 438784: need to expose URL on doc's value attribute. For this, 1.303 + // reverting part of fix for bug 425693 to make this MSAA method behave 1.304 + // IAccessible2-style. 1.305 + if (value.IsEmpty()) 1.306 + return S_FALSE; 1.307 + 1.308 + *pszValue = ::SysAllocStringLen(value.get(), value.Length()); 1.309 + if (!*pszValue) 1.310 + return E_OUTOFMEMORY; 1.311 + return S_OK; 1.312 + 1.313 + A11Y_TRYBLOCK_END 1.314 +} 1.315 + 1.316 +STDMETHODIMP 1.317 +AccessibleWrap::get_accDescription(VARIANT varChild, 1.318 + BSTR __RPC_FAR *pszDescription) 1.319 +{ 1.320 + A11Y_TRYBLOCK_BEGIN 1.321 + 1.322 + if (!pszDescription) 1.323 + return E_INVALIDARG; 1.324 + 1.325 + *pszDescription = nullptr; 1.326 + 1.327 + if (IsDefunct()) 1.328 + return CO_E_OBJNOTCONNECTED; 1.329 + 1.330 + Accessible* xpAccessible = GetXPAccessibleFor(varChild); 1.331 + if (!xpAccessible) 1.332 + return E_INVALIDARG; 1.333 + 1.334 + if (xpAccessible->IsDefunct()) 1.335 + return CO_E_OBJNOTCONNECTED; 1.336 + 1.337 + nsAutoString description; 1.338 + xpAccessible->Description(description); 1.339 + 1.340 + *pszDescription = ::SysAllocStringLen(description.get(), 1.341 + description.Length()); 1.342 + return *pszDescription ? S_OK : E_OUTOFMEMORY; 1.343 + 1.344 + A11Y_TRYBLOCK_END 1.345 +} 1.346 + 1.347 +STDMETHODIMP 1.348 +AccessibleWrap::get_accRole( 1.349 + /* [optional][in] */ VARIANT varChild, 1.350 + /* [retval][out] */ VARIANT __RPC_FAR *pvarRole) 1.351 +{ 1.352 + A11Y_TRYBLOCK_BEGIN 1.353 + 1.354 + if (!pvarRole) 1.355 + return E_INVALIDARG; 1.356 + 1.357 + VariantInit(pvarRole); 1.358 + 1.359 + if (IsDefunct()) 1.360 + return CO_E_OBJNOTCONNECTED; 1.361 + 1.362 + Accessible* xpAccessible = GetXPAccessibleFor(varChild); 1.363 + if (!xpAccessible) 1.364 + return E_INVALIDARG; 1.365 + 1.366 + if (xpAccessible->IsDefunct()) 1.367 + return CO_E_OBJNOTCONNECTED; 1.368 + 1.369 +#ifdef DEBUG 1.370 + NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(xpAccessible), 1.371 + "Does not support nsIAccessibleText when it should"); 1.372 +#endif 1.373 + 1.374 + a11y::role geckoRole = xpAccessible->Role(); 1.375 + uint32_t msaaRole = 0; 1.376 + 1.377 +#define ROLE(_geckoRole, stringRole, atkRole, macRole, \ 1.378 + _msaaRole, ia2Role, nameRule) \ 1.379 + case roles::_geckoRole: \ 1.380 + msaaRole = _msaaRole; \ 1.381 + break; 1.382 + 1.383 + switch (geckoRole) { 1.384 +#include "RoleMap.h" 1.385 + default: 1.386 + MOZ_CRASH("Unknown role."); 1.387 + }; 1.388 + 1.389 +#undef ROLE 1.390 + 1.391 + // Special case, if there is a ROLE_ROW inside of a ROLE_TREE_TABLE, then call the MSAA role 1.392 + // a ROLE_OUTLINEITEM for consistency and compatibility. 1.393 + // We need this because ARIA has a role of "row" for both grid and treegrid 1.394 + if (geckoRole == roles::ROW) { 1.395 + Accessible* xpParent = Parent(); 1.396 + if (xpParent && xpParent->Role() == roles::TREE_TABLE) 1.397 + msaaRole = ROLE_SYSTEM_OUTLINEITEM; 1.398 + } 1.399 + 1.400 + // -- Try enumerated role 1.401 + if (msaaRole != USE_ROLE_STRING) { 1.402 + pvarRole->vt = VT_I4; 1.403 + pvarRole->lVal = msaaRole; // Normal enumerated role 1.404 + return S_OK; 1.405 + } 1.406 + 1.407 + // -- Try BSTR role 1.408 + // Could not map to known enumerated MSAA role like ROLE_BUTTON 1.409 + // Use BSTR role to expose role attribute or tag name + namespace 1.410 + nsIContent *content = xpAccessible->GetContent(); 1.411 + if (!content) 1.412 + return E_FAIL; 1.413 + 1.414 + if (content->IsElement()) { 1.415 + nsAutoString roleString; 1.416 + if (msaaRole != ROLE_SYSTEM_CLIENT && 1.417 + !content->GetAttr(kNameSpaceID_None, nsGkAtoms::role, roleString)) { 1.418 + nsIDocument * document = content->GetCurrentDoc(); 1.419 + if (!document) 1.420 + return E_FAIL; 1.421 + 1.422 + nsINodeInfo *nodeInfo = content->NodeInfo(); 1.423 + nodeInfo->GetName(roleString); 1.424 + 1.425 + // Only append name space if different from that of current document. 1.426 + if (!nodeInfo->NamespaceEquals(document->GetDefaultNamespaceID())) { 1.427 + nsAutoString nameSpaceURI; 1.428 + nodeInfo->GetNamespaceURI(nameSpaceURI); 1.429 + roleString += NS_LITERAL_STRING(", ") + nameSpaceURI; 1.430 + } 1.431 + } 1.432 + 1.433 + if (!roleString.IsEmpty()) { 1.434 + pvarRole->vt = VT_BSTR; 1.435 + pvarRole->bstrVal = ::SysAllocString(roleString.get()); 1.436 + return S_OK; 1.437 + } 1.438 + } 1.439 + 1.440 + return E_FAIL; 1.441 + 1.442 + A11Y_TRYBLOCK_END 1.443 +} 1.444 + 1.445 +STDMETHODIMP 1.446 +AccessibleWrap::get_accState( 1.447 + /* [optional][in] */ VARIANT varChild, 1.448 + /* [retval][out] */ VARIANT __RPC_FAR *pvarState) 1.449 +{ 1.450 + A11Y_TRYBLOCK_BEGIN 1.451 + 1.452 + if (!pvarState) 1.453 + return E_INVALIDARG; 1.454 + 1.455 + VariantInit(pvarState); 1.456 + pvarState->vt = VT_I4; 1.457 + pvarState->lVal = 0; 1.458 + 1.459 + if (IsDefunct()) 1.460 + return CO_E_OBJNOTCONNECTED; 1.461 + 1.462 + Accessible* xpAccessible = GetXPAccessibleFor(varChild); 1.463 + if (!xpAccessible) 1.464 + return E_INVALIDARG; 1.465 + 1.466 + if (xpAccessible->IsDefunct()) 1.467 + return CO_E_OBJNOTCONNECTED; 1.468 + 1.469 + // MSAA only has 31 states and the lowest 31 bits of our state bit mask 1.470 + // are the same states as MSAA. 1.471 + // Note: we map the following Gecko states to different MSAA states: 1.472 + // REQUIRED -> ALERT_LOW 1.473 + // ALERT -> ALERT_MEDIUM 1.474 + // INVALID -> ALERT_HIGH 1.475 + // CHECKABLE -> MARQUEED 1.476 + 1.477 + uint32_t msaaState = 0; 1.478 + nsAccUtils::To32States(xpAccessible->State(), &msaaState, nullptr); 1.479 + pvarState->lVal = msaaState; 1.480 + return S_OK; 1.481 + 1.482 + A11Y_TRYBLOCK_END 1.483 +} 1.484 + 1.485 + 1.486 +STDMETHODIMP 1.487 +AccessibleWrap::get_accHelp( 1.488 + /* [optional][in] */ VARIANT varChild, 1.489 + /* [retval][out] */ BSTR __RPC_FAR *pszHelp) 1.490 +{ 1.491 + A11Y_TRYBLOCK_BEGIN 1.492 + 1.493 + if (!pszHelp) 1.494 + return E_INVALIDARG; 1.495 + 1.496 + *pszHelp = nullptr; 1.497 + return S_FALSE; 1.498 + 1.499 + A11Y_TRYBLOCK_END 1.500 +} 1.501 + 1.502 +STDMETHODIMP 1.503 +AccessibleWrap::get_accHelpTopic( 1.504 + /* [out] */ BSTR __RPC_FAR *pszHelpFile, 1.505 + /* [optional][in] */ VARIANT varChild, 1.506 + /* [retval][out] */ long __RPC_FAR *pidTopic) 1.507 +{ 1.508 + A11Y_TRYBLOCK_BEGIN 1.509 + 1.510 + if (!pszHelpFile || !pidTopic) 1.511 + return E_INVALIDARG; 1.512 + 1.513 + *pszHelpFile = nullptr; 1.514 + *pidTopic = 0; 1.515 + return S_FALSE; 1.516 + 1.517 + A11Y_TRYBLOCK_END 1.518 +} 1.519 + 1.520 +STDMETHODIMP 1.521 +AccessibleWrap::get_accKeyboardShortcut( 1.522 + /* [optional][in] */ VARIANT varChild, 1.523 + /* [retval][out] */ BSTR __RPC_FAR *pszKeyboardShortcut) 1.524 +{ 1.525 + A11Y_TRYBLOCK_BEGIN 1.526 + 1.527 + if (!pszKeyboardShortcut) 1.528 + return E_INVALIDARG; 1.529 + *pszKeyboardShortcut = nullptr; 1.530 + 1.531 + if (IsDefunct()) 1.532 + return CO_E_OBJNOTCONNECTED; 1.533 + 1.534 + Accessible* acc = GetXPAccessibleFor(varChild); 1.535 + if (!acc) 1.536 + return E_INVALIDARG; 1.537 + 1.538 + if (acc->IsDefunct()) 1.539 + return CO_E_OBJNOTCONNECTED; 1.540 + 1.541 + KeyBinding keyBinding = acc->AccessKey(); 1.542 + if (keyBinding.IsEmpty()) 1.543 + keyBinding = acc->KeyboardShortcut(); 1.544 + 1.545 + nsAutoString shortcut; 1.546 + keyBinding.ToString(shortcut); 1.547 + 1.548 + *pszKeyboardShortcut = ::SysAllocStringLen(shortcut.get(), 1.549 + shortcut.Length()); 1.550 + return *pszKeyboardShortcut ? S_OK : E_OUTOFMEMORY; 1.551 + 1.552 + A11Y_TRYBLOCK_END 1.553 +} 1.554 + 1.555 +STDMETHODIMP 1.556 +AccessibleWrap::get_accFocus( 1.557 + /* [retval][out] */ VARIANT __RPC_FAR *pvarChild) 1.558 +{ 1.559 + A11Y_TRYBLOCK_BEGIN 1.560 + 1.561 + if (!pvarChild) 1.562 + return E_INVALIDARG; 1.563 + 1.564 + VariantInit(pvarChild); 1.565 + 1.566 + // VT_EMPTY: None. This object does not have the keyboard focus itself 1.567 + // and does not contain a child that has the keyboard focus. 1.568 + // VT_I4: lVal is CHILDID_SELF. The object itself has the keyboard focus. 1.569 + // VT_I4: lVal contains the child ID of the child element with the keyboard focus. 1.570 + // VT_DISPATCH: pdispVal member is the address of the IDispatch interface 1.571 + // for the child object with the keyboard focus. 1.572 + if (IsDefunct()) 1.573 + return CO_E_OBJNOTCONNECTED; 1.574 + 1.575 + // Return the current IAccessible child that has focus 1.576 + Accessible* focusedAccessible = FocusedChild(); 1.577 + if (focusedAccessible == this) { 1.578 + pvarChild->vt = VT_I4; 1.579 + pvarChild->lVal = CHILDID_SELF; 1.580 + } 1.581 + else if (focusedAccessible) { 1.582 + pvarChild->vt = VT_DISPATCH; 1.583 + pvarChild->pdispVal = NativeAccessible(focusedAccessible); 1.584 + } 1.585 + else { 1.586 + pvarChild->vt = VT_EMPTY; // No focus or focus is not a child 1.587 + } 1.588 + 1.589 + return S_OK; 1.590 + 1.591 + A11Y_TRYBLOCK_END 1.592 +} 1.593 + 1.594 +// This helper class implements IEnumVARIANT for a nsIArray containing nsIAccessible objects. 1.595 + 1.596 +class AccessibleEnumerator MOZ_FINAL : public IEnumVARIANT 1.597 +{ 1.598 +public: 1.599 + AccessibleEnumerator(nsIArray* aArray) : mArray(aArray), mCurIndex(0) { } 1.600 + AccessibleEnumerator(const AccessibleEnumerator& toCopy) : 1.601 + mArray(toCopy.mArray), mCurIndex(toCopy.mCurIndex) { } 1.602 + ~AccessibleEnumerator() { } 1.603 + 1.604 + // IUnknown 1.605 + DECL_IUNKNOWN 1.606 + 1.607 + // IEnumVARIANT 1.608 + STDMETHODIMP Next(unsigned long celt, VARIANT FAR* rgvar, unsigned long FAR* pceltFetched); 1.609 + STDMETHODIMP Skip(unsigned long celt); 1.610 + STDMETHODIMP Reset() 1.611 + { 1.612 + mCurIndex = 0; 1.613 + return S_OK; 1.614 + } 1.615 + STDMETHODIMP Clone(IEnumVARIANT FAR* FAR* ppenum); 1.616 + 1.617 +private: 1.618 + nsCOMPtr<nsIArray> mArray; 1.619 + uint32_t mCurIndex; 1.620 +}; 1.621 + 1.622 +STDMETHODIMP 1.623 +AccessibleEnumerator::QueryInterface(REFIID iid, void ** ppvObject) 1.624 +{ 1.625 + A11Y_TRYBLOCK_BEGIN 1.626 + 1.627 + if (iid == IID_IEnumVARIANT) { 1.628 + *ppvObject = static_cast<IEnumVARIANT*>(this); 1.629 + AddRef(); 1.630 + return S_OK; 1.631 + } 1.632 + if (iid == IID_IUnknown) { 1.633 + *ppvObject = static_cast<IUnknown*>(this); 1.634 + AddRef(); 1.635 + return S_OK; 1.636 + } 1.637 + 1.638 + *ppvObject = nullptr; 1.639 + return E_NOINTERFACE; 1.640 + 1.641 + A11Y_TRYBLOCK_END 1.642 +} 1.643 + 1.644 +STDMETHODIMP 1.645 +AccessibleEnumerator::Next(unsigned long celt, VARIANT FAR* rgvar, unsigned long FAR* pceltFetched) 1.646 +{ 1.647 + A11Y_TRYBLOCK_BEGIN 1.648 + 1.649 + uint32_t length = 0; 1.650 + mArray->GetLength(&length); 1.651 + 1.652 + HRESULT hr = S_OK; 1.653 + 1.654 + // Can't get more elements than there are... 1.655 + if (celt > length - mCurIndex) { 1.656 + hr = S_FALSE; 1.657 + celt = length - mCurIndex; 1.658 + } 1.659 + 1.660 + for (uint32_t i = 0; i < celt; ++i, ++mCurIndex) { 1.661 + // Copy the elements of the array into rgvar 1.662 + nsCOMPtr<nsIAccessible> accel(do_QueryElementAt(mArray, mCurIndex)); 1.663 + NS_ASSERTION(accel, "Invalid pointer in mArray"); 1.664 + 1.665 + if (accel) { 1.666 + rgvar[i].vt = VT_DISPATCH; 1.667 + rgvar[i].pdispVal = AccessibleWrap::NativeAccessible(accel); 1.668 + } 1.669 + } 1.670 + 1.671 + if (pceltFetched) 1.672 + *pceltFetched = celt; 1.673 + 1.674 + return hr; 1.675 + 1.676 + A11Y_TRYBLOCK_END 1.677 +} 1.678 + 1.679 +STDMETHODIMP 1.680 +AccessibleEnumerator::Clone(IEnumVARIANT FAR* FAR* ppenum) 1.681 +{ 1.682 + A11Y_TRYBLOCK_BEGIN 1.683 + 1.684 + *ppenum = new AccessibleEnumerator(*this); 1.685 + if (!*ppenum) 1.686 + return E_OUTOFMEMORY; 1.687 + NS_ADDREF(*ppenum); 1.688 + return S_OK; 1.689 + 1.690 + A11Y_TRYBLOCK_END 1.691 +} 1.692 + 1.693 +STDMETHODIMP 1.694 +AccessibleEnumerator::Skip(unsigned long celt) 1.695 +{ 1.696 + A11Y_TRYBLOCK_BEGIN 1.697 + 1.698 + uint32_t length = 0; 1.699 + mArray->GetLength(&length); 1.700 + // Check if we can skip the requested number of elements 1.701 + if (celt > length - mCurIndex) { 1.702 + mCurIndex = length; 1.703 + return S_FALSE; 1.704 + } 1.705 + mCurIndex += celt; 1.706 + return S_OK; 1.707 + 1.708 + A11Y_TRYBLOCK_END 1.709 +} 1.710 + 1.711 +/** 1.712 + * This method is called when a client wants to know which children of a node 1.713 + * are selected. Note that this method can only find selected children for 1.714 + * nsIAccessible object which implement SelectAccessible. 1.715 + * 1.716 + * The VARIANT return value arguement is expected to either contain a single IAccessible 1.717 + * or an IEnumVARIANT of IAccessibles. We return the IEnumVARIANT regardless of the number 1.718 + * of children selected, unless there are none selected in which case we return an empty 1.719 + * VARIANT. 1.720 + * 1.721 + * We get the selected options from the select's accessible object and wrap 1.722 + * those in an AccessibleEnumerator which we then put in the return VARIANT. 1.723 + * 1.724 + * returns a VT_EMPTY VARIANT if: 1.725 + * - there are no selected children for this object 1.726 + * - the object is not the type that can have children selected 1.727 + */ 1.728 +STDMETHODIMP 1.729 +AccessibleWrap::get_accSelection(VARIANT __RPC_FAR *pvarChildren) 1.730 +{ 1.731 + A11Y_TRYBLOCK_BEGIN 1.732 + 1.733 + if (!pvarChildren) 1.734 + return E_INVALIDARG; 1.735 + 1.736 + VariantInit(pvarChildren); 1.737 + pvarChildren->vt = VT_EMPTY; 1.738 + 1.739 + if (IsDefunct()) 1.740 + return CO_E_OBJNOTCONNECTED; 1.741 + 1.742 + if (IsSelect()) { 1.743 + nsCOMPtr<nsIArray> selectedItems = SelectedItems(); 1.744 + if (selectedItems) { 1.745 + // 1) Create and initialize the enumeration 1.746 + nsRefPtr<AccessibleEnumerator> pEnum = 1.747 + new AccessibleEnumerator(selectedItems); 1.748 + 1.749 + // 2) Put the enumerator in the VARIANT 1.750 + if (!pEnum) 1.751 + return E_OUTOFMEMORY; 1.752 + pvarChildren->vt = VT_UNKNOWN; // this must be VT_UNKNOWN for an IEnumVARIANT 1.753 + NS_ADDREF(pvarChildren->punkVal = pEnum); 1.754 + } 1.755 + } 1.756 + return S_OK; 1.757 + 1.758 + A11Y_TRYBLOCK_END 1.759 +} 1.760 + 1.761 +STDMETHODIMP 1.762 +AccessibleWrap::get_accDefaultAction( 1.763 + /* [optional][in] */ VARIANT varChild, 1.764 + /* [retval][out] */ BSTR __RPC_FAR *pszDefaultAction) 1.765 +{ 1.766 + A11Y_TRYBLOCK_BEGIN 1.767 + 1.768 + if (!pszDefaultAction) 1.769 + return E_INVALIDARG; 1.770 + 1.771 + *pszDefaultAction = nullptr; 1.772 + 1.773 + if (IsDefunct()) 1.774 + return CO_E_OBJNOTCONNECTED; 1.775 + 1.776 + Accessible* xpAccessible = GetXPAccessibleFor(varChild); 1.777 + if (!xpAccessible) 1.778 + return E_INVALIDARG; 1.779 + 1.780 + if (xpAccessible->IsDefunct()) 1.781 + return CO_E_OBJNOTCONNECTED; 1.782 + 1.783 + nsAutoString defaultAction; 1.784 + if (NS_FAILED(xpAccessible->GetActionName(0, defaultAction))) 1.785 + return E_FAIL; 1.786 + 1.787 + *pszDefaultAction = ::SysAllocStringLen(defaultAction.get(), 1.788 + defaultAction.Length()); 1.789 + return *pszDefaultAction ? S_OK : E_OUTOFMEMORY; 1.790 + 1.791 + A11Y_TRYBLOCK_END 1.792 +} 1.793 + 1.794 +STDMETHODIMP 1.795 +AccessibleWrap::accSelect( 1.796 + /* [in] */ long flagsSelect, 1.797 + /* [optional][in] */ VARIANT varChild) 1.798 +{ 1.799 + A11Y_TRYBLOCK_BEGIN 1.800 + 1.801 + if (IsDefunct()) 1.802 + return CO_E_OBJNOTCONNECTED; 1.803 + 1.804 + // currently only handle focus and selection 1.805 + Accessible* xpAccessible = GetXPAccessibleFor(varChild); 1.806 + if (!xpAccessible) 1.807 + return E_INVALIDARG; 1.808 + 1.809 + if (xpAccessible->IsDefunct()) 1.810 + return CO_E_OBJNOTCONNECTED; 1.811 + 1.812 + if (flagsSelect & (SELFLAG_TAKEFOCUS|SELFLAG_TAKESELECTION|SELFLAG_REMOVESELECTION)) 1.813 + { 1.814 + if (flagsSelect & SELFLAG_TAKEFOCUS) 1.815 + xpAccessible->TakeFocus(); 1.816 + 1.817 + if (flagsSelect & SELFLAG_TAKESELECTION) 1.818 + xpAccessible->TakeSelection(); 1.819 + 1.820 + if (flagsSelect & SELFLAG_ADDSELECTION) 1.821 + xpAccessible->SetSelected(true); 1.822 + 1.823 + if (flagsSelect & SELFLAG_REMOVESELECTION) 1.824 + xpAccessible->SetSelected(false); 1.825 + 1.826 + if (flagsSelect & SELFLAG_EXTENDSELECTION) 1.827 + xpAccessible->ExtendSelection(); 1.828 + 1.829 + return S_OK; 1.830 + } 1.831 + 1.832 + return E_FAIL; 1.833 + 1.834 + A11Y_TRYBLOCK_END 1.835 +} 1.836 + 1.837 +STDMETHODIMP 1.838 +AccessibleWrap::accLocation( 1.839 + /* [out] */ long __RPC_FAR *pxLeft, 1.840 + /* [out] */ long __RPC_FAR *pyTop, 1.841 + /* [out] */ long __RPC_FAR *pcxWidth, 1.842 + /* [out] */ long __RPC_FAR *pcyHeight, 1.843 + /* [optional][in] */ VARIANT varChild) 1.844 +{ 1.845 + A11Y_TRYBLOCK_BEGIN 1.846 + 1.847 + if (!pxLeft || !pyTop || !pcxWidth || !pcyHeight) 1.848 + return E_INVALIDARG; 1.849 + 1.850 + *pxLeft = 0; 1.851 + *pyTop = 0; 1.852 + *pcxWidth = 0; 1.853 + *pcyHeight = 0; 1.854 + 1.855 + if (IsDefunct()) 1.856 + return CO_E_OBJNOTCONNECTED; 1.857 + 1.858 + Accessible* xpAccessible = GetXPAccessibleFor(varChild); 1.859 + if (!xpAccessible) 1.860 + return E_INVALIDARG; 1.861 + 1.862 + if (xpAccessible->IsDefunct()) 1.863 + return CO_E_OBJNOTCONNECTED; 1.864 + 1.865 + int32_t x, y, width, height; 1.866 + if (NS_FAILED(xpAccessible->GetBounds(&x, &y, &width, &height))) 1.867 + return E_FAIL; 1.868 + 1.869 + *pxLeft = x; 1.870 + *pyTop = y; 1.871 + *pcxWidth = width; 1.872 + *pcyHeight = height; 1.873 + return S_OK; 1.874 + 1.875 + A11Y_TRYBLOCK_END 1.876 +} 1.877 + 1.878 +STDMETHODIMP 1.879 +AccessibleWrap::accNavigate( 1.880 + /* [in] */ long navDir, 1.881 + /* [optional][in] */ VARIANT varStart, 1.882 + /* [retval][out] */ VARIANT __RPC_FAR *pvarEndUpAt) 1.883 +{ 1.884 + A11Y_TRYBLOCK_BEGIN 1.885 + 1.886 + if (!pvarEndUpAt) 1.887 + return E_INVALIDARG; 1.888 + 1.889 + VariantInit(pvarEndUpAt); 1.890 + 1.891 + if (IsDefunct()) 1.892 + return CO_E_OBJNOTCONNECTED; 1.893 + 1.894 + Accessible* accessible = GetXPAccessibleFor(varStart); 1.895 + if (!accessible) 1.896 + return E_INVALIDARG; 1.897 + 1.898 + if (accessible->IsDefunct()) 1.899 + return CO_E_OBJNOTCONNECTED; 1.900 + 1.901 + Accessible* navAccessible = nullptr; 1.902 + Maybe<RelationType> xpRelation; 1.903 + 1.904 +#define RELATIONTYPE(geckoType, stringType, atkType, msaaType, ia2Type) \ 1.905 + case msaaType: \ 1.906 + xpRelation.construct(RelationType::geckoType); \ 1.907 + break; 1.908 + 1.909 + switch(navDir) { 1.910 + case NAVDIR_FIRSTCHILD: 1.911 + if (!nsAccUtils::MustPrune(accessible)) 1.912 + navAccessible = accessible->FirstChild(); 1.913 + break; 1.914 + case NAVDIR_LASTCHILD: 1.915 + if (!nsAccUtils::MustPrune(accessible)) 1.916 + navAccessible = accessible->LastChild(); 1.917 + break; 1.918 + case NAVDIR_NEXT: 1.919 + navAccessible = accessible->NextSibling(); 1.920 + break; 1.921 + case NAVDIR_PREVIOUS: 1.922 + navAccessible = accessible->PrevSibling(); 1.923 + break; 1.924 + case NAVDIR_DOWN: 1.925 + case NAVDIR_LEFT: 1.926 + case NAVDIR_RIGHT: 1.927 + case NAVDIR_UP: 1.928 + return E_NOTIMPL; 1.929 + 1.930 + // MSAA relationship extensions to accNavigate 1.931 +#include "RelationTypeMap.h" 1.932 + 1.933 + default: 1.934 + return E_INVALIDARG; 1.935 + } 1.936 + 1.937 +#undef RELATIONTYPE 1.938 + 1.939 + pvarEndUpAt->vt = VT_EMPTY; 1.940 + 1.941 + if (!xpRelation.empty()) { 1.942 + Relation rel = RelationByType(xpRelation.ref()); 1.943 + navAccessible = rel.Next(); 1.944 + } 1.945 + 1.946 + if (!navAccessible) 1.947 + return E_FAIL; 1.948 + 1.949 + pvarEndUpAt->pdispVal = NativeAccessible(navAccessible); 1.950 + pvarEndUpAt->vt = VT_DISPATCH; 1.951 + return S_OK; 1.952 + 1.953 + A11Y_TRYBLOCK_END 1.954 +} 1.955 + 1.956 +STDMETHODIMP 1.957 +AccessibleWrap::accHitTest( 1.958 + /* [in] */ long xLeft, 1.959 + /* [in] */ long yTop, 1.960 + /* [retval][out] */ VARIANT __RPC_FAR *pvarChild) 1.961 +{ 1.962 + A11Y_TRYBLOCK_BEGIN 1.963 + 1.964 + if (!pvarChild) 1.965 + return E_INVALIDARG; 1.966 + 1.967 + VariantInit(pvarChild); 1.968 + 1.969 + if (IsDefunct()) 1.970 + return CO_E_OBJNOTCONNECTED; 1.971 + 1.972 + Accessible* accessible = ChildAtPoint(xLeft, yTop, eDirectChild); 1.973 + 1.974 + // if we got a child 1.975 + if (accessible) { 1.976 + // if the child is us 1.977 + if (accessible == this) { 1.978 + pvarChild->vt = VT_I4; 1.979 + pvarChild->lVal = CHILDID_SELF; 1.980 + } else { // its not create an Accessible for it. 1.981 + pvarChild->vt = VT_DISPATCH; 1.982 + pvarChild->pdispVal = NativeAccessible(accessible); 1.983 + } 1.984 + } else { 1.985 + // no child at that point 1.986 + pvarChild->vt = VT_EMPTY; 1.987 + return S_FALSE; 1.988 + } 1.989 + return S_OK; 1.990 + 1.991 + A11Y_TRYBLOCK_END 1.992 +} 1.993 + 1.994 +STDMETHODIMP 1.995 +AccessibleWrap::accDoDefaultAction( 1.996 + /* [optional][in] */ VARIANT varChild) 1.997 +{ 1.998 + A11Y_TRYBLOCK_BEGIN 1.999 + 1.1000 + if (IsDefunct()) 1.1001 + return CO_E_OBJNOTCONNECTED; 1.1002 + 1.1003 + Accessible* xpAccessible = GetXPAccessibleFor(varChild); 1.1004 + if (!xpAccessible) 1.1005 + return E_INVALIDARG; 1.1006 + 1.1007 + if (xpAccessible->IsDefunct()) 1.1008 + return CO_E_OBJNOTCONNECTED; 1.1009 + 1.1010 + return GetHRESULT(xpAccessible->DoAction(0)); 1.1011 + 1.1012 + A11Y_TRYBLOCK_END 1.1013 +} 1.1014 + 1.1015 +STDMETHODIMP 1.1016 +AccessibleWrap::put_accName( 1.1017 + /* [optional][in] */ VARIANT varChild, 1.1018 + /* [in] */ BSTR szName) 1.1019 +{ 1.1020 + return E_NOTIMPL; 1.1021 +} 1.1022 + 1.1023 +STDMETHODIMP 1.1024 +AccessibleWrap::put_accValue( 1.1025 + /* [optional][in] */ VARIANT varChild, 1.1026 + /* [in] */ BSTR szValue) 1.1027 +{ 1.1028 + return E_NOTIMPL; 1.1029 +} 1.1030 + 1.1031 +//////////////////////////////////////////////////////////////////////////////// 1.1032 +// IDispatch 1.1033 + 1.1034 +STDMETHODIMP 1.1035 +AccessibleWrap::GetTypeInfoCount(UINT *pctinfo) 1.1036 +{ 1.1037 + if (!pctinfo) 1.1038 + return E_INVALIDARG; 1.1039 + 1.1040 + *pctinfo = 1; 1.1041 + return S_OK; 1.1042 +} 1.1043 + 1.1044 +STDMETHODIMP 1.1045 +AccessibleWrap::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) 1.1046 +{ 1.1047 + if (!ppTInfo) 1.1048 + return E_INVALIDARG; 1.1049 + 1.1050 + *ppTInfo = nullptr; 1.1051 + 1.1052 + if (iTInfo != 0) 1.1053 + return DISP_E_BADINDEX; 1.1054 + 1.1055 + ITypeInfo * typeInfo = GetTI(lcid); 1.1056 + if (!typeInfo) 1.1057 + return E_FAIL; 1.1058 + 1.1059 + typeInfo->AddRef(); 1.1060 + *ppTInfo = typeInfo; 1.1061 + 1.1062 + return S_OK; 1.1063 +} 1.1064 + 1.1065 +STDMETHODIMP 1.1066 +AccessibleWrap::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, 1.1067 + UINT cNames, LCID lcid, DISPID *rgDispId) 1.1068 +{ 1.1069 + ITypeInfo *typeInfo = GetTI(lcid); 1.1070 + if (!typeInfo) 1.1071 + return E_FAIL; 1.1072 + 1.1073 + HRESULT hr = DispGetIDsOfNames(typeInfo, rgszNames, cNames, rgDispId); 1.1074 + return hr; 1.1075 +} 1.1076 + 1.1077 +STDMETHODIMP 1.1078 +AccessibleWrap::Invoke(DISPID dispIdMember, REFIID riid, 1.1079 + LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, 1.1080 + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, 1.1081 + UINT *puArgErr) 1.1082 +{ 1.1083 + ITypeInfo *typeInfo = GetTI(lcid); 1.1084 + if (!typeInfo) 1.1085 + return E_FAIL; 1.1086 + 1.1087 + return typeInfo->Invoke(static_cast<IAccessible*>(this), dispIdMember, 1.1088 + wFlags, pDispParams, pVarResult, pExcepInfo, 1.1089 + puArgErr); 1.1090 +} 1.1091 + 1.1092 + 1.1093 +// nsIAccessible method 1.1094 +NS_IMETHODIMP 1.1095 +AccessibleWrap::GetNativeInterface(void **aOutAccessible) 1.1096 +{ 1.1097 + *aOutAccessible = static_cast<IAccessible*>(this); 1.1098 + NS_ADDREF_THIS(); 1.1099 + return NS_OK; 1.1100 +} 1.1101 + 1.1102 +//////////////////////////////////////////////////////////////////////////////// 1.1103 +// Accessible 1.1104 + 1.1105 +nsresult 1.1106 +AccessibleWrap::HandleAccEvent(AccEvent* aEvent) 1.1107 +{ 1.1108 + nsresult rv = Accessible::HandleAccEvent(aEvent); 1.1109 + NS_ENSURE_SUCCESS(rv, rv); 1.1110 + 1.1111 + // Don't fire native MSAA events or mess with the system caret 1.1112 + // when running in metro mode. This confuses input focus tracking 1.1113 + // in metro's UIA implementation. 1.1114 + if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) { 1.1115 + return NS_OK; 1.1116 + } 1.1117 + 1.1118 + uint32_t eventType = aEvent->GetEventType(); 1.1119 + 1.1120 + static_assert(sizeof(gWinEventMap)/sizeof(gWinEventMap[0]) == nsIAccessibleEvent::EVENT_LAST_ENTRY, 1.1121 + "MSAA event map skewed"); 1.1122 + 1.1123 + NS_ENSURE_TRUE(eventType > 0 && eventType < ArrayLength(gWinEventMap), NS_ERROR_FAILURE); 1.1124 + 1.1125 + uint32_t winEvent = gWinEventMap[eventType]; 1.1126 + if (!winEvent) 1.1127 + return NS_OK; 1.1128 + 1.1129 + // Means we're not active. 1.1130 + NS_ENSURE_TRUE(!IsDefunct(), NS_ERROR_FAILURE); 1.1131 + 1.1132 + Accessible* accessible = aEvent->GetAccessible(); 1.1133 + if (!accessible) 1.1134 + return NS_OK; 1.1135 + 1.1136 + if (eventType == nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED || 1.1137 + eventType == nsIAccessibleEvent::EVENT_FOCUS) { 1.1138 + UpdateSystemCaretFor(accessible); 1.1139 + } 1.1140 + 1.1141 + int32_t childID = GetChildIDFor(accessible); // get the id for the accessible 1.1142 + if (!childID) 1.1143 + return NS_OK; // Can't fire an event without a child ID 1.1144 + 1.1145 + HWND hWnd = GetHWNDFor(accessible); 1.1146 + NS_ENSURE_TRUE(hWnd, NS_ERROR_FAILURE); 1.1147 + 1.1148 + nsAutoString tag; 1.1149 + nsAutoCString id; 1.1150 + nsIContent* cnt = accessible->GetContent(); 1.1151 + if (cnt) { 1.1152 + cnt->Tag()->ToString(tag); 1.1153 + nsIAtom* aid = cnt->GetID(); 1.1154 + if (aid) 1.1155 + aid->ToUTF8String(id); 1.1156 + } 1.1157 + 1.1158 +#ifdef A11Y_LOG 1.1159 + if (logging::IsEnabled(logging::ePlatforms)) { 1.1160 + printf("\n\nMSAA event: event: %d, target: %s@id='%s', childid: %d, hwnd: %d\n\n", 1.1161 + eventType, NS_ConvertUTF16toUTF8(tag).get(), id.get(), 1.1162 + childID, hWnd); 1.1163 + } 1.1164 +#endif 1.1165 + 1.1166 + // Fire MSAA event for client area window. 1.1167 + ::NotifyWinEvent(winEvent, hWnd, OBJID_CLIENT, childID); 1.1168 + 1.1169 + // JAWS announces collapsed combobox navigation based on focus events. 1.1170 + if (Compatibility::IsJAWS()) { 1.1171 + if (eventType == nsIAccessibleEvent::EVENT_SELECTION && 1.1172 + accessible->Role() == roles::COMBOBOX_OPTION) { 1.1173 + ::NotifyWinEvent(EVENT_OBJECT_FOCUS, hWnd, OBJID_CLIENT, childID); 1.1174 + } 1.1175 + } 1.1176 + 1.1177 + return NS_OK; 1.1178 +} 1.1179 + 1.1180 +//////////////////////////////////////////////////////////////////////////////// 1.1181 +// AccessibleWrap 1.1182 + 1.1183 +//------- Helper methods --------- 1.1184 + 1.1185 +int32_t 1.1186 +AccessibleWrap::GetChildIDFor(Accessible* aAccessible) 1.1187 +{ 1.1188 + // A child ID of the window is required, when we use NotifyWinEvent, 1.1189 + // so that the 3rd party application can call back and get the IAccessible 1.1190 + // the event occurred on. 1.1191 + 1.1192 + // Yes, this means we're only compatibible with 32 bit 1.1193 + // MSAA is only available for 32 bit windows, so it's okay 1.1194 + // XXX: bug 606080 1.1195 + return aAccessible ? - NS_PTR_TO_INT32(aAccessible->UniqueID()) : 0; 1.1196 +} 1.1197 + 1.1198 +HWND 1.1199 +AccessibleWrap::GetHWNDFor(Accessible* aAccessible) 1.1200 +{ 1.1201 + if (aAccessible) { 1.1202 + DocAccessible* document = aAccessible->Document(); 1.1203 + if(!document) 1.1204 + return nullptr; 1.1205 + 1.1206 + // Popup lives in own windows, use its HWND until the popup window is 1.1207 + // hidden to make old JAWS versions work with collapsed comboboxes (see 1.1208 + // discussion in bug 379678). 1.1209 + nsIFrame* frame = aAccessible->GetFrame(); 1.1210 + if (frame) { 1.1211 + nsIWidget* widget = frame->GetNearestWidget(); 1.1212 + if (widget && widget->IsVisible()) { 1.1213 + nsIPresShell* shell = document->PresShell(); 1.1214 + nsViewManager* vm = shell->GetViewManager(); 1.1215 + if (vm) { 1.1216 + nsCOMPtr<nsIWidget> rootWidget; 1.1217 + vm->GetRootWidget(getter_AddRefs(rootWidget)); 1.1218 + // Make sure the accessible belongs to popup. If not then use 1.1219 + // document HWND (which might be different from root widget in the 1.1220 + // case of window emulation). 1.1221 + if (rootWidget != widget) 1.1222 + return static_cast<HWND>(widget->GetNativeData(NS_NATIVE_WINDOW)); 1.1223 + } 1.1224 + } 1.1225 + } 1.1226 + 1.1227 + return static_cast<HWND>(document->GetNativeWindow()); 1.1228 + } 1.1229 + return nullptr; 1.1230 +} 1.1231 + 1.1232 +IDispatch* 1.1233 +AccessibleWrap::NativeAccessible(nsIAccessible* aAccessible) 1.1234 +{ 1.1235 + if (!aAccessible) { 1.1236 + NS_WARNING("Not passing in an aAccessible"); 1.1237 + return nullptr; 1.1238 + } 1.1239 + 1.1240 + IAccessible* msaaAccessible = nullptr; 1.1241 + aAccessible->GetNativeInterface(reinterpret_cast<void**>(&msaaAccessible)); 1.1242 + return static_cast<IDispatch*>(msaaAccessible); 1.1243 +} 1.1244 + 1.1245 +Accessible* 1.1246 +AccessibleWrap::GetXPAccessibleFor(const VARIANT& aVarChild) 1.1247 +{ 1.1248 + if (aVarChild.vt != VT_I4) 1.1249 + return nullptr; 1.1250 + 1.1251 + // if its us real easy - this seems to always be the case 1.1252 + if (aVarChild.lVal == CHILDID_SELF) 1.1253 + return this; 1.1254 + 1.1255 + if (nsAccUtils::MustPrune(this)) 1.1256 + return nullptr; 1.1257 + 1.1258 + // If lVal negative then it is treated as child ID and we should look for 1.1259 + // accessible through whole accessible subtree including subdocuments. 1.1260 + // Otherwise we treat lVal as index in parent. 1.1261 + 1.1262 + if (aVarChild.lVal < 0) { 1.1263 + // Convert child ID to unique ID. 1.1264 + void* uniqueID = reinterpret_cast<void*>(-aVarChild.lVal); 1.1265 + 1.1266 + DocAccessible* document = Document(); 1.1267 + Accessible* child = 1.1268 + document->GetAccessibleByUniqueIDInSubtree(uniqueID); 1.1269 + 1.1270 + // If it is a document then just return an accessible. 1.1271 + if (IsDoc()) 1.1272 + return child; 1.1273 + 1.1274 + // Otherwise check whether the accessible is a child (this path works for 1.1275 + // ARIA documents and popups). 1.1276 + Accessible* parent = child; 1.1277 + while (parent && parent != document) { 1.1278 + if (parent == this) 1.1279 + return child; 1.1280 + 1.1281 + parent = parent->Parent(); 1.1282 + } 1.1283 + 1.1284 + return nullptr; 1.1285 + } 1.1286 + 1.1287 + // Gecko child indices are 0-based in contrast to indices used in MSAA. 1.1288 + return GetChildAt(aVarChild.lVal - 1); 1.1289 +} 1.1290 + 1.1291 +void 1.1292 +AccessibleWrap::UpdateSystemCaretFor(Accessible* aAccessible) 1.1293 +{ 1.1294 + // Move the system caret so that Windows Tablet Edition and tradional ATs with 1.1295 + // off-screen model can follow the caret 1.1296 + ::DestroyCaret(); 1.1297 + 1.1298 + HyperTextAccessible* text = aAccessible->AsHyperText(); 1.1299 + if (!text) 1.1300 + return; 1.1301 + 1.1302 + nsIWidget* widget = nullptr; 1.1303 + nsIntRect caretRect = text->GetCaretRect(&widget); 1.1304 + HWND caretWnd; 1.1305 + if (caretRect.IsEmpty() || !(caretWnd = (HWND)widget->GetNativeData(NS_NATIVE_WINDOW))) { 1.1306 + return; 1.1307 + } 1.1308 + 1.1309 + // Create invisible bitmap for caret, otherwise its appearance interferes 1.1310 + // with Gecko caret 1.1311 + HBITMAP caretBitMap = CreateBitmap(1, caretRect.height, 1, 1, nullptr); 1.1312 + if (::CreateCaret(caretWnd, caretBitMap, 1, caretRect.height)) { // Also destroys the last caret 1.1313 + ::ShowCaret(caretWnd); 1.1314 + RECT windowRect; 1.1315 + ::GetWindowRect(caretWnd, &windowRect); 1.1316 + ::SetCaretPos(caretRect.x - windowRect.left, caretRect.y - windowRect.top); 1.1317 + ::DeleteObject(caretBitMap); 1.1318 + } 1.1319 +} 1.1320 + 1.1321 +ITypeInfo* 1.1322 +AccessibleWrap::GetTI(LCID lcid) 1.1323 +{ 1.1324 + if (gTypeInfo) 1.1325 + return gTypeInfo; 1.1326 + 1.1327 + ITypeLib *typeLib = nullptr; 1.1328 + HRESULT hr = LoadRegTypeLib(LIBID_Accessibility, 1, 0, lcid, &typeLib); 1.1329 + if (FAILED(hr)) 1.1330 + return nullptr; 1.1331 + 1.1332 + hr = typeLib->GetTypeInfoOfGuid(IID_IAccessible, &gTypeInfo); 1.1333 + typeLib->Release(); 1.1334 + 1.1335 + if (FAILED(hr)) 1.1336 + return nullptr; 1.1337 + 1.1338 + return gTypeInfo; 1.1339 +}