Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* vim: set ts=2 et sw=2 tw=80: */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #include "AccessibleWrap.h" |
michael@0 | 8 | #include "Accessible-inl.h" |
michael@0 | 9 | |
michael@0 | 10 | #include "Compatibility.h" |
michael@0 | 11 | #include "DocAccessible-inl.h" |
michael@0 | 12 | #include "EnumVariant.h" |
michael@0 | 13 | #include "nsAccUtils.h" |
michael@0 | 14 | #include "nsCoreUtils.h" |
michael@0 | 15 | #include "nsIAccessibleEvent.h" |
michael@0 | 16 | #include "nsIAccessibleRelation.h" |
michael@0 | 17 | #include "nsWinUtils.h" |
michael@0 | 18 | #include "ServiceProvider.h" |
michael@0 | 19 | #include "Relation.h" |
michael@0 | 20 | #include "Role.h" |
michael@0 | 21 | #include "RootAccessible.h" |
michael@0 | 22 | #include "sdnAccessible.h" |
michael@0 | 23 | #include "States.h" |
michael@0 | 24 | |
michael@0 | 25 | #ifdef A11Y_LOG |
michael@0 | 26 | #include "Logging.h" |
michael@0 | 27 | #endif |
michael@0 | 28 | |
michael@0 | 29 | #include "nsIMutableArray.h" |
michael@0 | 30 | #include "nsIFrame.h" |
michael@0 | 31 | #include "nsIScrollableFrame.h" |
michael@0 | 32 | #include "nsINodeInfo.h" |
michael@0 | 33 | #include "nsIServiceManager.h" |
michael@0 | 34 | #include "nsNameSpaceManager.h" |
michael@0 | 35 | #include "nsTextFormatter.h" |
michael@0 | 36 | #include "nsView.h" |
michael@0 | 37 | #include "nsViewManager.h" |
michael@0 | 38 | #include "nsEventMap.h" |
michael@0 | 39 | #include "nsArrayUtils.h" |
michael@0 | 40 | #include "mozilla/Preferences.h" |
michael@0 | 41 | |
michael@0 | 42 | #include "oleacc.h" |
michael@0 | 43 | |
michael@0 | 44 | using namespace mozilla; |
michael@0 | 45 | using namespace mozilla::a11y; |
michael@0 | 46 | |
michael@0 | 47 | const uint32_t USE_ROLE_STRING = 0; |
michael@0 | 48 | |
michael@0 | 49 | /* For documentation of the accessibility architecture, |
michael@0 | 50 | * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html |
michael@0 | 51 | */ |
michael@0 | 52 | |
michael@0 | 53 | //#define DEBUG_LEAKS |
michael@0 | 54 | |
michael@0 | 55 | #ifdef DEBUG_LEAKS |
michael@0 | 56 | static gAccessibles = 0; |
michael@0 | 57 | #endif |
michael@0 | 58 | |
michael@0 | 59 | static const int32_t kIEnumVariantDisconnected = -1; |
michael@0 | 60 | |
michael@0 | 61 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 62 | // AccessibleWrap |
michael@0 | 63 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 64 | |
michael@0 | 65 | ITypeInfo* AccessibleWrap::gTypeInfo = nullptr; |
michael@0 | 66 | |
michael@0 | 67 | NS_IMPL_ISUPPORTS_INHERITED0(AccessibleWrap, Accessible) |
michael@0 | 68 | |
michael@0 | 69 | //----------------------------------------------------- |
michael@0 | 70 | // IUnknown interface methods - see iunknown.h for documentation |
michael@0 | 71 | //----------------------------------------------------- |
michael@0 | 72 | |
michael@0 | 73 | // Microsoft COM QueryInterface |
michael@0 | 74 | STDMETHODIMP |
michael@0 | 75 | AccessibleWrap::QueryInterface(REFIID iid, void** ppv) |
michael@0 | 76 | { |
michael@0 | 77 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 78 | |
michael@0 | 79 | if (!ppv) |
michael@0 | 80 | return E_INVALIDARG; |
michael@0 | 81 | |
michael@0 | 82 | *ppv = nullptr; |
michael@0 | 83 | |
michael@0 | 84 | if (IID_IUnknown == iid || IID_IDispatch == iid || IID_IAccessible == iid) |
michael@0 | 85 | *ppv = static_cast<IAccessible*>(this); |
michael@0 | 86 | else if (IID_IEnumVARIANT == iid) { |
michael@0 | 87 | // Don't support this interface for leaf elements. |
michael@0 | 88 | if (!HasChildren() || nsAccUtils::MustPrune(this)) |
michael@0 | 89 | return E_NOINTERFACE; |
michael@0 | 90 | |
michael@0 | 91 | *ppv = static_cast<IEnumVARIANT*>(new ChildrenEnumVariant(this)); |
michael@0 | 92 | } else if (IID_IServiceProvider == iid) |
michael@0 | 93 | *ppv = new ServiceProvider(this); |
michael@0 | 94 | else if (IID_ISimpleDOMNode == iid) { |
michael@0 | 95 | if (IsDefunct() || (!HasOwnContent() && !IsDoc())) |
michael@0 | 96 | return E_NOINTERFACE; |
michael@0 | 97 | |
michael@0 | 98 | *ppv = static_cast<ISimpleDOMNode*>(new sdnAccessible(GetNode())); |
michael@0 | 99 | } |
michael@0 | 100 | |
michael@0 | 101 | if (nullptr == *ppv) { |
michael@0 | 102 | HRESULT hr = ia2Accessible::QueryInterface(iid, ppv); |
michael@0 | 103 | if (SUCCEEDED(hr)) |
michael@0 | 104 | return hr; |
michael@0 | 105 | } |
michael@0 | 106 | |
michael@0 | 107 | if (nullptr == *ppv) { |
michael@0 | 108 | HRESULT hr = ia2AccessibleComponent::QueryInterface(iid, ppv); |
michael@0 | 109 | if (SUCCEEDED(hr)) |
michael@0 | 110 | return hr; |
michael@0 | 111 | } |
michael@0 | 112 | |
michael@0 | 113 | if (nullptr == *ppv) { |
michael@0 | 114 | HRESULT hr = ia2AccessibleHyperlink::QueryInterface(iid, ppv); |
michael@0 | 115 | if (SUCCEEDED(hr)) |
michael@0 | 116 | return hr; |
michael@0 | 117 | } |
michael@0 | 118 | |
michael@0 | 119 | if (nullptr == *ppv) { |
michael@0 | 120 | HRESULT hr = ia2AccessibleValue::QueryInterface(iid, ppv); |
michael@0 | 121 | if (SUCCEEDED(hr)) |
michael@0 | 122 | return hr; |
michael@0 | 123 | } |
michael@0 | 124 | |
michael@0 | 125 | if (nullptr == *ppv) |
michael@0 | 126 | return E_NOINTERFACE; |
michael@0 | 127 | |
michael@0 | 128 | (reinterpret_cast<IUnknown*>(*ppv))->AddRef(); |
michael@0 | 129 | return S_OK; |
michael@0 | 130 | |
michael@0 | 131 | A11Y_TRYBLOCK_END |
michael@0 | 132 | } |
michael@0 | 133 | |
michael@0 | 134 | //----------------------------------------------------- |
michael@0 | 135 | // IAccessible methods |
michael@0 | 136 | //----------------------------------------------------- |
michael@0 | 137 | |
michael@0 | 138 | STDMETHODIMP |
michael@0 | 139 | AccessibleWrap::get_accParent( IDispatch __RPC_FAR *__RPC_FAR *ppdispParent) |
michael@0 | 140 | { |
michael@0 | 141 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 142 | |
michael@0 | 143 | if (!ppdispParent) |
michael@0 | 144 | return E_INVALIDARG; |
michael@0 | 145 | |
michael@0 | 146 | *ppdispParent = nullptr; |
michael@0 | 147 | |
michael@0 | 148 | if (IsDefunct()) |
michael@0 | 149 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 150 | |
michael@0 | 151 | DocAccessible* doc = AsDoc(); |
michael@0 | 152 | if (doc) { |
michael@0 | 153 | // Return window system accessible object for root document and tab document |
michael@0 | 154 | // accessibles. |
michael@0 | 155 | if (!doc->ParentDocument() || |
michael@0 | 156 | (nsWinUtils::IsWindowEmulationStarted() && |
michael@0 | 157 | nsCoreUtils::IsTabDocument(doc->DocumentNode()))) { |
michael@0 | 158 | HWND hwnd = static_cast<HWND>(doc->GetNativeWindow()); |
michael@0 | 159 | if (hwnd && SUCCEEDED(::AccessibleObjectFromWindow(hwnd, OBJID_WINDOW, |
michael@0 | 160 | IID_IAccessible, |
michael@0 | 161 | (void**)ppdispParent))) { |
michael@0 | 162 | return S_OK; |
michael@0 | 163 | } |
michael@0 | 164 | } |
michael@0 | 165 | } |
michael@0 | 166 | |
michael@0 | 167 | Accessible* xpParentAcc = Parent(); |
michael@0 | 168 | if (!xpParentAcc) |
michael@0 | 169 | return S_FALSE; |
michael@0 | 170 | |
michael@0 | 171 | *ppdispParent = NativeAccessible(xpParentAcc); |
michael@0 | 172 | return S_OK; |
michael@0 | 173 | |
michael@0 | 174 | A11Y_TRYBLOCK_END |
michael@0 | 175 | } |
michael@0 | 176 | |
michael@0 | 177 | STDMETHODIMP |
michael@0 | 178 | AccessibleWrap::get_accChildCount( long __RPC_FAR *pcountChildren) |
michael@0 | 179 | { |
michael@0 | 180 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 181 | |
michael@0 | 182 | if (!pcountChildren) |
michael@0 | 183 | return E_INVALIDARG; |
michael@0 | 184 | |
michael@0 | 185 | *pcountChildren = 0; |
michael@0 | 186 | |
michael@0 | 187 | if (IsDefunct()) |
michael@0 | 188 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 189 | |
michael@0 | 190 | if (nsAccUtils::MustPrune(this)) |
michael@0 | 191 | return S_OK; |
michael@0 | 192 | |
michael@0 | 193 | *pcountChildren = ChildCount(); |
michael@0 | 194 | return S_OK; |
michael@0 | 195 | |
michael@0 | 196 | A11Y_TRYBLOCK_END |
michael@0 | 197 | } |
michael@0 | 198 | |
michael@0 | 199 | STDMETHODIMP |
michael@0 | 200 | AccessibleWrap::get_accChild( |
michael@0 | 201 | /* [in] */ VARIANT varChild, |
michael@0 | 202 | /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispChild) |
michael@0 | 203 | { |
michael@0 | 204 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 205 | |
michael@0 | 206 | if (!ppdispChild) |
michael@0 | 207 | return E_INVALIDARG; |
michael@0 | 208 | |
michael@0 | 209 | *ppdispChild = nullptr; |
michael@0 | 210 | if (IsDefunct()) |
michael@0 | 211 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 212 | |
michael@0 | 213 | // IAccessible::accChild is used to return this accessible or child accessible |
michael@0 | 214 | // at the given index or to get an accessible by child ID in the case of |
michael@0 | 215 | // document accessible (it's handled by overriden GetXPAccessibleFor method |
michael@0 | 216 | // on the document accessible). The getting an accessible by child ID is used |
michael@0 | 217 | // by AccessibleObjectFromEvent() called by AT when AT handles our MSAA event. |
michael@0 | 218 | Accessible* child = GetXPAccessibleFor(varChild); |
michael@0 | 219 | if (!child) |
michael@0 | 220 | return E_INVALIDARG; |
michael@0 | 221 | |
michael@0 | 222 | if (child->IsDefunct()) |
michael@0 | 223 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 224 | |
michael@0 | 225 | *ppdispChild = NativeAccessible(child); |
michael@0 | 226 | return S_OK; |
michael@0 | 227 | |
michael@0 | 228 | A11Y_TRYBLOCK_END |
michael@0 | 229 | } |
michael@0 | 230 | |
michael@0 | 231 | STDMETHODIMP |
michael@0 | 232 | AccessibleWrap::get_accName( |
michael@0 | 233 | /* [optional][in] */ VARIANT varChild, |
michael@0 | 234 | /* [retval][out] */ BSTR __RPC_FAR *pszName) |
michael@0 | 235 | { |
michael@0 | 236 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 237 | |
michael@0 | 238 | if (!pszName) |
michael@0 | 239 | return E_INVALIDARG; |
michael@0 | 240 | |
michael@0 | 241 | *pszName = nullptr; |
michael@0 | 242 | |
michael@0 | 243 | if (IsDefunct()) |
michael@0 | 244 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 245 | |
michael@0 | 246 | Accessible* xpAccessible = GetXPAccessibleFor(varChild); |
michael@0 | 247 | if (!xpAccessible) |
michael@0 | 248 | return E_INVALIDARG; |
michael@0 | 249 | |
michael@0 | 250 | if (xpAccessible->IsDefunct()) |
michael@0 | 251 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 252 | |
michael@0 | 253 | nsAutoString name; |
michael@0 | 254 | xpAccessible->Name(name); |
michael@0 | 255 | |
michael@0 | 256 | // The name was not provided, e.g. no alt attribute for an image. A screen |
michael@0 | 257 | // reader may choose to invent its own accessible name, e.g. from an image src |
michael@0 | 258 | // attribute. Refer to eNoNameOnPurpose return value. |
michael@0 | 259 | if (name.IsVoid()) |
michael@0 | 260 | return S_FALSE; |
michael@0 | 261 | |
michael@0 | 262 | *pszName = ::SysAllocStringLen(name.get(), name.Length()); |
michael@0 | 263 | if (!*pszName) |
michael@0 | 264 | return E_OUTOFMEMORY; |
michael@0 | 265 | return S_OK; |
michael@0 | 266 | |
michael@0 | 267 | A11Y_TRYBLOCK_END |
michael@0 | 268 | } |
michael@0 | 269 | |
michael@0 | 270 | |
michael@0 | 271 | STDMETHODIMP |
michael@0 | 272 | AccessibleWrap::get_accValue( |
michael@0 | 273 | /* [optional][in] */ VARIANT varChild, |
michael@0 | 274 | /* [retval][out] */ BSTR __RPC_FAR *pszValue) |
michael@0 | 275 | { |
michael@0 | 276 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 277 | |
michael@0 | 278 | if (!pszValue) |
michael@0 | 279 | return E_INVALIDARG; |
michael@0 | 280 | |
michael@0 | 281 | *pszValue = nullptr; |
michael@0 | 282 | |
michael@0 | 283 | if (IsDefunct()) |
michael@0 | 284 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 285 | |
michael@0 | 286 | Accessible* xpAccessible = GetXPAccessibleFor(varChild); |
michael@0 | 287 | if (!xpAccessible) |
michael@0 | 288 | return E_INVALIDARG; |
michael@0 | 289 | |
michael@0 | 290 | if (xpAccessible->IsDefunct()) |
michael@0 | 291 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 292 | |
michael@0 | 293 | if (xpAccessible->NativeRole() == roles::PASSWORD_TEXT) |
michael@0 | 294 | return E_ACCESSDENIED; |
michael@0 | 295 | |
michael@0 | 296 | nsAutoString value; |
michael@0 | 297 | xpAccessible->Value(value); |
michael@0 | 298 | |
michael@0 | 299 | // See bug 438784: need to expose URL on doc's value attribute. For this, |
michael@0 | 300 | // reverting part of fix for bug 425693 to make this MSAA method behave |
michael@0 | 301 | // IAccessible2-style. |
michael@0 | 302 | if (value.IsEmpty()) |
michael@0 | 303 | return S_FALSE; |
michael@0 | 304 | |
michael@0 | 305 | *pszValue = ::SysAllocStringLen(value.get(), value.Length()); |
michael@0 | 306 | if (!*pszValue) |
michael@0 | 307 | return E_OUTOFMEMORY; |
michael@0 | 308 | return S_OK; |
michael@0 | 309 | |
michael@0 | 310 | A11Y_TRYBLOCK_END |
michael@0 | 311 | } |
michael@0 | 312 | |
michael@0 | 313 | STDMETHODIMP |
michael@0 | 314 | AccessibleWrap::get_accDescription(VARIANT varChild, |
michael@0 | 315 | BSTR __RPC_FAR *pszDescription) |
michael@0 | 316 | { |
michael@0 | 317 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 318 | |
michael@0 | 319 | if (!pszDescription) |
michael@0 | 320 | return E_INVALIDARG; |
michael@0 | 321 | |
michael@0 | 322 | *pszDescription = nullptr; |
michael@0 | 323 | |
michael@0 | 324 | if (IsDefunct()) |
michael@0 | 325 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 326 | |
michael@0 | 327 | Accessible* xpAccessible = GetXPAccessibleFor(varChild); |
michael@0 | 328 | if (!xpAccessible) |
michael@0 | 329 | return E_INVALIDARG; |
michael@0 | 330 | |
michael@0 | 331 | if (xpAccessible->IsDefunct()) |
michael@0 | 332 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 333 | |
michael@0 | 334 | nsAutoString description; |
michael@0 | 335 | xpAccessible->Description(description); |
michael@0 | 336 | |
michael@0 | 337 | *pszDescription = ::SysAllocStringLen(description.get(), |
michael@0 | 338 | description.Length()); |
michael@0 | 339 | return *pszDescription ? S_OK : E_OUTOFMEMORY; |
michael@0 | 340 | |
michael@0 | 341 | A11Y_TRYBLOCK_END |
michael@0 | 342 | } |
michael@0 | 343 | |
michael@0 | 344 | STDMETHODIMP |
michael@0 | 345 | AccessibleWrap::get_accRole( |
michael@0 | 346 | /* [optional][in] */ VARIANT varChild, |
michael@0 | 347 | /* [retval][out] */ VARIANT __RPC_FAR *pvarRole) |
michael@0 | 348 | { |
michael@0 | 349 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 350 | |
michael@0 | 351 | if (!pvarRole) |
michael@0 | 352 | return E_INVALIDARG; |
michael@0 | 353 | |
michael@0 | 354 | VariantInit(pvarRole); |
michael@0 | 355 | |
michael@0 | 356 | if (IsDefunct()) |
michael@0 | 357 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 358 | |
michael@0 | 359 | Accessible* xpAccessible = GetXPAccessibleFor(varChild); |
michael@0 | 360 | if (!xpAccessible) |
michael@0 | 361 | return E_INVALIDARG; |
michael@0 | 362 | |
michael@0 | 363 | if (xpAccessible->IsDefunct()) |
michael@0 | 364 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 365 | |
michael@0 | 366 | #ifdef DEBUG |
michael@0 | 367 | NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(xpAccessible), |
michael@0 | 368 | "Does not support nsIAccessibleText when it should"); |
michael@0 | 369 | #endif |
michael@0 | 370 | |
michael@0 | 371 | a11y::role geckoRole = xpAccessible->Role(); |
michael@0 | 372 | uint32_t msaaRole = 0; |
michael@0 | 373 | |
michael@0 | 374 | #define ROLE(_geckoRole, stringRole, atkRole, macRole, \ |
michael@0 | 375 | _msaaRole, ia2Role, nameRule) \ |
michael@0 | 376 | case roles::_geckoRole: \ |
michael@0 | 377 | msaaRole = _msaaRole; \ |
michael@0 | 378 | break; |
michael@0 | 379 | |
michael@0 | 380 | switch (geckoRole) { |
michael@0 | 381 | #include "RoleMap.h" |
michael@0 | 382 | default: |
michael@0 | 383 | MOZ_CRASH("Unknown role."); |
michael@0 | 384 | }; |
michael@0 | 385 | |
michael@0 | 386 | #undef ROLE |
michael@0 | 387 | |
michael@0 | 388 | // Special case, if there is a ROLE_ROW inside of a ROLE_TREE_TABLE, then call the MSAA role |
michael@0 | 389 | // a ROLE_OUTLINEITEM for consistency and compatibility. |
michael@0 | 390 | // We need this because ARIA has a role of "row" for both grid and treegrid |
michael@0 | 391 | if (geckoRole == roles::ROW) { |
michael@0 | 392 | Accessible* xpParent = Parent(); |
michael@0 | 393 | if (xpParent && xpParent->Role() == roles::TREE_TABLE) |
michael@0 | 394 | msaaRole = ROLE_SYSTEM_OUTLINEITEM; |
michael@0 | 395 | } |
michael@0 | 396 | |
michael@0 | 397 | // -- Try enumerated role |
michael@0 | 398 | if (msaaRole != USE_ROLE_STRING) { |
michael@0 | 399 | pvarRole->vt = VT_I4; |
michael@0 | 400 | pvarRole->lVal = msaaRole; // Normal enumerated role |
michael@0 | 401 | return S_OK; |
michael@0 | 402 | } |
michael@0 | 403 | |
michael@0 | 404 | // -- Try BSTR role |
michael@0 | 405 | // Could not map to known enumerated MSAA role like ROLE_BUTTON |
michael@0 | 406 | // Use BSTR role to expose role attribute or tag name + namespace |
michael@0 | 407 | nsIContent *content = xpAccessible->GetContent(); |
michael@0 | 408 | if (!content) |
michael@0 | 409 | return E_FAIL; |
michael@0 | 410 | |
michael@0 | 411 | if (content->IsElement()) { |
michael@0 | 412 | nsAutoString roleString; |
michael@0 | 413 | if (msaaRole != ROLE_SYSTEM_CLIENT && |
michael@0 | 414 | !content->GetAttr(kNameSpaceID_None, nsGkAtoms::role, roleString)) { |
michael@0 | 415 | nsIDocument * document = content->GetCurrentDoc(); |
michael@0 | 416 | if (!document) |
michael@0 | 417 | return E_FAIL; |
michael@0 | 418 | |
michael@0 | 419 | nsINodeInfo *nodeInfo = content->NodeInfo(); |
michael@0 | 420 | nodeInfo->GetName(roleString); |
michael@0 | 421 | |
michael@0 | 422 | // Only append name space if different from that of current document. |
michael@0 | 423 | if (!nodeInfo->NamespaceEquals(document->GetDefaultNamespaceID())) { |
michael@0 | 424 | nsAutoString nameSpaceURI; |
michael@0 | 425 | nodeInfo->GetNamespaceURI(nameSpaceURI); |
michael@0 | 426 | roleString += NS_LITERAL_STRING(", ") + nameSpaceURI; |
michael@0 | 427 | } |
michael@0 | 428 | } |
michael@0 | 429 | |
michael@0 | 430 | if (!roleString.IsEmpty()) { |
michael@0 | 431 | pvarRole->vt = VT_BSTR; |
michael@0 | 432 | pvarRole->bstrVal = ::SysAllocString(roleString.get()); |
michael@0 | 433 | return S_OK; |
michael@0 | 434 | } |
michael@0 | 435 | } |
michael@0 | 436 | |
michael@0 | 437 | return E_FAIL; |
michael@0 | 438 | |
michael@0 | 439 | A11Y_TRYBLOCK_END |
michael@0 | 440 | } |
michael@0 | 441 | |
michael@0 | 442 | STDMETHODIMP |
michael@0 | 443 | AccessibleWrap::get_accState( |
michael@0 | 444 | /* [optional][in] */ VARIANT varChild, |
michael@0 | 445 | /* [retval][out] */ VARIANT __RPC_FAR *pvarState) |
michael@0 | 446 | { |
michael@0 | 447 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 448 | |
michael@0 | 449 | if (!pvarState) |
michael@0 | 450 | return E_INVALIDARG; |
michael@0 | 451 | |
michael@0 | 452 | VariantInit(pvarState); |
michael@0 | 453 | pvarState->vt = VT_I4; |
michael@0 | 454 | pvarState->lVal = 0; |
michael@0 | 455 | |
michael@0 | 456 | if (IsDefunct()) |
michael@0 | 457 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 458 | |
michael@0 | 459 | Accessible* xpAccessible = GetXPAccessibleFor(varChild); |
michael@0 | 460 | if (!xpAccessible) |
michael@0 | 461 | return E_INVALIDARG; |
michael@0 | 462 | |
michael@0 | 463 | if (xpAccessible->IsDefunct()) |
michael@0 | 464 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 465 | |
michael@0 | 466 | // MSAA only has 31 states and the lowest 31 bits of our state bit mask |
michael@0 | 467 | // are the same states as MSAA. |
michael@0 | 468 | // Note: we map the following Gecko states to different MSAA states: |
michael@0 | 469 | // REQUIRED -> ALERT_LOW |
michael@0 | 470 | // ALERT -> ALERT_MEDIUM |
michael@0 | 471 | // INVALID -> ALERT_HIGH |
michael@0 | 472 | // CHECKABLE -> MARQUEED |
michael@0 | 473 | |
michael@0 | 474 | uint32_t msaaState = 0; |
michael@0 | 475 | nsAccUtils::To32States(xpAccessible->State(), &msaaState, nullptr); |
michael@0 | 476 | pvarState->lVal = msaaState; |
michael@0 | 477 | return S_OK; |
michael@0 | 478 | |
michael@0 | 479 | A11Y_TRYBLOCK_END |
michael@0 | 480 | } |
michael@0 | 481 | |
michael@0 | 482 | |
michael@0 | 483 | STDMETHODIMP |
michael@0 | 484 | AccessibleWrap::get_accHelp( |
michael@0 | 485 | /* [optional][in] */ VARIANT varChild, |
michael@0 | 486 | /* [retval][out] */ BSTR __RPC_FAR *pszHelp) |
michael@0 | 487 | { |
michael@0 | 488 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 489 | |
michael@0 | 490 | if (!pszHelp) |
michael@0 | 491 | return E_INVALIDARG; |
michael@0 | 492 | |
michael@0 | 493 | *pszHelp = nullptr; |
michael@0 | 494 | return S_FALSE; |
michael@0 | 495 | |
michael@0 | 496 | A11Y_TRYBLOCK_END |
michael@0 | 497 | } |
michael@0 | 498 | |
michael@0 | 499 | STDMETHODIMP |
michael@0 | 500 | AccessibleWrap::get_accHelpTopic( |
michael@0 | 501 | /* [out] */ BSTR __RPC_FAR *pszHelpFile, |
michael@0 | 502 | /* [optional][in] */ VARIANT varChild, |
michael@0 | 503 | /* [retval][out] */ long __RPC_FAR *pidTopic) |
michael@0 | 504 | { |
michael@0 | 505 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 506 | |
michael@0 | 507 | if (!pszHelpFile || !pidTopic) |
michael@0 | 508 | return E_INVALIDARG; |
michael@0 | 509 | |
michael@0 | 510 | *pszHelpFile = nullptr; |
michael@0 | 511 | *pidTopic = 0; |
michael@0 | 512 | return S_FALSE; |
michael@0 | 513 | |
michael@0 | 514 | A11Y_TRYBLOCK_END |
michael@0 | 515 | } |
michael@0 | 516 | |
michael@0 | 517 | STDMETHODIMP |
michael@0 | 518 | AccessibleWrap::get_accKeyboardShortcut( |
michael@0 | 519 | /* [optional][in] */ VARIANT varChild, |
michael@0 | 520 | /* [retval][out] */ BSTR __RPC_FAR *pszKeyboardShortcut) |
michael@0 | 521 | { |
michael@0 | 522 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 523 | |
michael@0 | 524 | if (!pszKeyboardShortcut) |
michael@0 | 525 | return E_INVALIDARG; |
michael@0 | 526 | *pszKeyboardShortcut = nullptr; |
michael@0 | 527 | |
michael@0 | 528 | if (IsDefunct()) |
michael@0 | 529 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 530 | |
michael@0 | 531 | Accessible* acc = GetXPAccessibleFor(varChild); |
michael@0 | 532 | if (!acc) |
michael@0 | 533 | return E_INVALIDARG; |
michael@0 | 534 | |
michael@0 | 535 | if (acc->IsDefunct()) |
michael@0 | 536 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 537 | |
michael@0 | 538 | KeyBinding keyBinding = acc->AccessKey(); |
michael@0 | 539 | if (keyBinding.IsEmpty()) |
michael@0 | 540 | keyBinding = acc->KeyboardShortcut(); |
michael@0 | 541 | |
michael@0 | 542 | nsAutoString shortcut; |
michael@0 | 543 | keyBinding.ToString(shortcut); |
michael@0 | 544 | |
michael@0 | 545 | *pszKeyboardShortcut = ::SysAllocStringLen(shortcut.get(), |
michael@0 | 546 | shortcut.Length()); |
michael@0 | 547 | return *pszKeyboardShortcut ? S_OK : E_OUTOFMEMORY; |
michael@0 | 548 | |
michael@0 | 549 | A11Y_TRYBLOCK_END |
michael@0 | 550 | } |
michael@0 | 551 | |
michael@0 | 552 | STDMETHODIMP |
michael@0 | 553 | AccessibleWrap::get_accFocus( |
michael@0 | 554 | /* [retval][out] */ VARIANT __RPC_FAR *pvarChild) |
michael@0 | 555 | { |
michael@0 | 556 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 557 | |
michael@0 | 558 | if (!pvarChild) |
michael@0 | 559 | return E_INVALIDARG; |
michael@0 | 560 | |
michael@0 | 561 | VariantInit(pvarChild); |
michael@0 | 562 | |
michael@0 | 563 | // VT_EMPTY: None. This object does not have the keyboard focus itself |
michael@0 | 564 | // and does not contain a child that has the keyboard focus. |
michael@0 | 565 | // VT_I4: lVal is CHILDID_SELF. The object itself has the keyboard focus. |
michael@0 | 566 | // VT_I4: lVal contains the child ID of the child element with the keyboard focus. |
michael@0 | 567 | // VT_DISPATCH: pdispVal member is the address of the IDispatch interface |
michael@0 | 568 | // for the child object with the keyboard focus. |
michael@0 | 569 | if (IsDefunct()) |
michael@0 | 570 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 571 | |
michael@0 | 572 | // Return the current IAccessible child that has focus |
michael@0 | 573 | Accessible* focusedAccessible = FocusedChild(); |
michael@0 | 574 | if (focusedAccessible == this) { |
michael@0 | 575 | pvarChild->vt = VT_I4; |
michael@0 | 576 | pvarChild->lVal = CHILDID_SELF; |
michael@0 | 577 | } |
michael@0 | 578 | else if (focusedAccessible) { |
michael@0 | 579 | pvarChild->vt = VT_DISPATCH; |
michael@0 | 580 | pvarChild->pdispVal = NativeAccessible(focusedAccessible); |
michael@0 | 581 | } |
michael@0 | 582 | else { |
michael@0 | 583 | pvarChild->vt = VT_EMPTY; // No focus or focus is not a child |
michael@0 | 584 | } |
michael@0 | 585 | |
michael@0 | 586 | return S_OK; |
michael@0 | 587 | |
michael@0 | 588 | A11Y_TRYBLOCK_END |
michael@0 | 589 | } |
michael@0 | 590 | |
michael@0 | 591 | // This helper class implements IEnumVARIANT for a nsIArray containing nsIAccessible objects. |
michael@0 | 592 | |
michael@0 | 593 | class AccessibleEnumerator MOZ_FINAL : public IEnumVARIANT |
michael@0 | 594 | { |
michael@0 | 595 | public: |
michael@0 | 596 | AccessibleEnumerator(nsIArray* aArray) : mArray(aArray), mCurIndex(0) { } |
michael@0 | 597 | AccessibleEnumerator(const AccessibleEnumerator& toCopy) : |
michael@0 | 598 | mArray(toCopy.mArray), mCurIndex(toCopy.mCurIndex) { } |
michael@0 | 599 | ~AccessibleEnumerator() { } |
michael@0 | 600 | |
michael@0 | 601 | // IUnknown |
michael@0 | 602 | DECL_IUNKNOWN |
michael@0 | 603 | |
michael@0 | 604 | // IEnumVARIANT |
michael@0 | 605 | STDMETHODIMP Next(unsigned long celt, VARIANT FAR* rgvar, unsigned long FAR* pceltFetched); |
michael@0 | 606 | STDMETHODIMP Skip(unsigned long celt); |
michael@0 | 607 | STDMETHODIMP Reset() |
michael@0 | 608 | { |
michael@0 | 609 | mCurIndex = 0; |
michael@0 | 610 | return S_OK; |
michael@0 | 611 | } |
michael@0 | 612 | STDMETHODIMP Clone(IEnumVARIANT FAR* FAR* ppenum); |
michael@0 | 613 | |
michael@0 | 614 | private: |
michael@0 | 615 | nsCOMPtr<nsIArray> mArray; |
michael@0 | 616 | uint32_t mCurIndex; |
michael@0 | 617 | }; |
michael@0 | 618 | |
michael@0 | 619 | STDMETHODIMP |
michael@0 | 620 | AccessibleEnumerator::QueryInterface(REFIID iid, void ** ppvObject) |
michael@0 | 621 | { |
michael@0 | 622 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 623 | |
michael@0 | 624 | if (iid == IID_IEnumVARIANT) { |
michael@0 | 625 | *ppvObject = static_cast<IEnumVARIANT*>(this); |
michael@0 | 626 | AddRef(); |
michael@0 | 627 | return S_OK; |
michael@0 | 628 | } |
michael@0 | 629 | if (iid == IID_IUnknown) { |
michael@0 | 630 | *ppvObject = static_cast<IUnknown*>(this); |
michael@0 | 631 | AddRef(); |
michael@0 | 632 | return S_OK; |
michael@0 | 633 | } |
michael@0 | 634 | |
michael@0 | 635 | *ppvObject = nullptr; |
michael@0 | 636 | return E_NOINTERFACE; |
michael@0 | 637 | |
michael@0 | 638 | A11Y_TRYBLOCK_END |
michael@0 | 639 | } |
michael@0 | 640 | |
michael@0 | 641 | STDMETHODIMP |
michael@0 | 642 | AccessibleEnumerator::Next(unsigned long celt, VARIANT FAR* rgvar, unsigned long FAR* pceltFetched) |
michael@0 | 643 | { |
michael@0 | 644 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 645 | |
michael@0 | 646 | uint32_t length = 0; |
michael@0 | 647 | mArray->GetLength(&length); |
michael@0 | 648 | |
michael@0 | 649 | HRESULT hr = S_OK; |
michael@0 | 650 | |
michael@0 | 651 | // Can't get more elements than there are... |
michael@0 | 652 | if (celt > length - mCurIndex) { |
michael@0 | 653 | hr = S_FALSE; |
michael@0 | 654 | celt = length - mCurIndex; |
michael@0 | 655 | } |
michael@0 | 656 | |
michael@0 | 657 | for (uint32_t i = 0; i < celt; ++i, ++mCurIndex) { |
michael@0 | 658 | // Copy the elements of the array into rgvar |
michael@0 | 659 | nsCOMPtr<nsIAccessible> accel(do_QueryElementAt(mArray, mCurIndex)); |
michael@0 | 660 | NS_ASSERTION(accel, "Invalid pointer in mArray"); |
michael@0 | 661 | |
michael@0 | 662 | if (accel) { |
michael@0 | 663 | rgvar[i].vt = VT_DISPATCH; |
michael@0 | 664 | rgvar[i].pdispVal = AccessibleWrap::NativeAccessible(accel); |
michael@0 | 665 | } |
michael@0 | 666 | } |
michael@0 | 667 | |
michael@0 | 668 | if (pceltFetched) |
michael@0 | 669 | *pceltFetched = celt; |
michael@0 | 670 | |
michael@0 | 671 | return hr; |
michael@0 | 672 | |
michael@0 | 673 | A11Y_TRYBLOCK_END |
michael@0 | 674 | } |
michael@0 | 675 | |
michael@0 | 676 | STDMETHODIMP |
michael@0 | 677 | AccessibleEnumerator::Clone(IEnumVARIANT FAR* FAR* ppenum) |
michael@0 | 678 | { |
michael@0 | 679 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 680 | |
michael@0 | 681 | *ppenum = new AccessibleEnumerator(*this); |
michael@0 | 682 | if (!*ppenum) |
michael@0 | 683 | return E_OUTOFMEMORY; |
michael@0 | 684 | NS_ADDREF(*ppenum); |
michael@0 | 685 | return S_OK; |
michael@0 | 686 | |
michael@0 | 687 | A11Y_TRYBLOCK_END |
michael@0 | 688 | } |
michael@0 | 689 | |
michael@0 | 690 | STDMETHODIMP |
michael@0 | 691 | AccessibleEnumerator::Skip(unsigned long celt) |
michael@0 | 692 | { |
michael@0 | 693 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 694 | |
michael@0 | 695 | uint32_t length = 0; |
michael@0 | 696 | mArray->GetLength(&length); |
michael@0 | 697 | // Check if we can skip the requested number of elements |
michael@0 | 698 | if (celt > length - mCurIndex) { |
michael@0 | 699 | mCurIndex = length; |
michael@0 | 700 | return S_FALSE; |
michael@0 | 701 | } |
michael@0 | 702 | mCurIndex += celt; |
michael@0 | 703 | return S_OK; |
michael@0 | 704 | |
michael@0 | 705 | A11Y_TRYBLOCK_END |
michael@0 | 706 | } |
michael@0 | 707 | |
michael@0 | 708 | /** |
michael@0 | 709 | * This method is called when a client wants to know which children of a node |
michael@0 | 710 | * are selected. Note that this method can only find selected children for |
michael@0 | 711 | * nsIAccessible object which implement SelectAccessible. |
michael@0 | 712 | * |
michael@0 | 713 | * The VARIANT return value arguement is expected to either contain a single IAccessible |
michael@0 | 714 | * or an IEnumVARIANT of IAccessibles. We return the IEnumVARIANT regardless of the number |
michael@0 | 715 | * of children selected, unless there are none selected in which case we return an empty |
michael@0 | 716 | * VARIANT. |
michael@0 | 717 | * |
michael@0 | 718 | * We get the selected options from the select's accessible object and wrap |
michael@0 | 719 | * those in an AccessibleEnumerator which we then put in the return VARIANT. |
michael@0 | 720 | * |
michael@0 | 721 | * returns a VT_EMPTY VARIANT if: |
michael@0 | 722 | * - there are no selected children for this object |
michael@0 | 723 | * - the object is not the type that can have children selected |
michael@0 | 724 | */ |
michael@0 | 725 | STDMETHODIMP |
michael@0 | 726 | AccessibleWrap::get_accSelection(VARIANT __RPC_FAR *pvarChildren) |
michael@0 | 727 | { |
michael@0 | 728 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 729 | |
michael@0 | 730 | if (!pvarChildren) |
michael@0 | 731 | return E_INVALIDARG; |
michael@0 | 732 | |
michael@0 | 733 | VariantInit(pvarChildren); |
michael@0 | 734 | pvarChildren->vt = VT_EMPTY; |
michael@0 | 735 | |
michael@0 | 736 | if (IsDefunct()) |
michael@0 | 737 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 738 | |
michael@0 | 739 | if (IsSelect()) { |
michael@0 | 740 | nsCOMPtr<nsIArray> selectedItems = SelectedItems(); |
michael@0 | 741 | if (selectedItems) { |
michael@0 | 742 | // 1) Create and initialize the enumeration |
michael@0 | 743 | nsRefPtr<AccessibleEnumerator> pEnum = |
michael@0 | 744 | new AccessibleEnumerator(selectedItems); |
michael@0 | 745 | |
michael@0 | 746 | // 2) Put the enumerator in the VARIANT |
michael@0 | 747 | if (!pEnum) |
michael@0 | 748 | return E_OUTOFMEMORY; |
michael@0 | 749 | pvarChildren->vt = VT_UNKNOWN; // this must be VT_UNKNOWN for an IEnumVARIANT |
michael@0 | 750 | NS_ADDREF(pvarChildren->punkVal = pEnum); |
michael@0 | 751 | } |
michael@0 | 752 | } |
michael@0 | 753 | return S_OK; |
michael@0 | 754 | |
michael@0 | 755 | A11Y_TRYBLOCK_END |
michael@0 | 756 | } |
michael@0 | 757 | |
michael@0 | 758 | STDMETHODIMP |
michael@0 | 759 | AccessibleWrap::get_accDefaultAction( |
michael@0 | 760 | /* [optional][in] */ VARIANT varChild, |
michael@0 | 761 | /* [retval][out] */ BSTR __RPC_FAR *pszDefaultAction) |
michael@0 | 762 | { |
michael@0 | 763 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 764 | |
michael@0 | 765 | if (!pszDefaultAction) |
michael@0 | 766 | return E_INVALIDARG; |
michael@0 | 767 | |
michael@0 | 768 | *pszDefaultAction = nullptr; |
michael@0 | 769 | |
michael@0 | 770 | if (IsDefunct()) |
michael@0 | 771 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 772 | |
michael@0 | 773 | Accessible* xpAccessible = GetXPAccessibleFor(varChild); |
michael@0 | 774 | if (!xpAccessible) |
michael@0 | 775 | return E_INVALIDARG; |
michael@0 | 776 | |
michael@0 | 777 | if (xpAccessible->IsDefunct()) |
michael@0 | 778 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 779 | |
michael@0 | 780 | nsAutoString defaultAction; |
michael@0 | 781 | if (NS_FAILED(xpAccessible->GetActionName(0, defaultAction))) |
michael@0 | 782 | return E_FAIL; |
michael@0 | 783 | |
michael@0 | 784 | *pszDefaultAction = ::SysAllocStringLen(defaultAction.get(), |
michael@0 | 785 | defaultAction.Length()); |
michael@0 | 786 | return *pszDefaultAction ? S_OK : E_OUTOFMEMORY; |
michael@0 | 787 | |
michael@0 | 788 | A11Y_TRYBLOCK_END |
michael@0 | 789 | } |
michael@0 | 790 | |
michael@0 | 791 | STDMETHODIMP |
michael@0 | 792 | AccessibleWrap::accSelect( |
michael@0 | 793 | /* [in] */ long flagsSelect, |
michael@0 | 794 | /* [optional][in] */ VARIANT varChild) |
michael@0 | 795 | { |
michael@0 | 796 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 797 | |
michael@0 | 798 | if (IsDefunct()) |
michael@0 | 799 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 800 | |
michael@0 | 801 | // currently only handle focus and selection |
michael@0 | 802 | Accessible* xpAccessible = GetXPAccessibleFor(varChild); |
michael@0 | 803 | if (!xpAccessible) |
michael@0 | 804 | return E_INVALIDARG; |
michael@0 | 805 | |
michael@0 | 806 | if (xpAccessible->IsDefunct()) |
michael@0 | 807 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 808 | |
michael@0 | 809 | if (flagsSelect & (SELFLAG_TAKEFOCUS|SELFLAG_TAKESELECTION|SELFLAG_REMOVESELECTION)) |
michael@0 | 810 | { |
michael@0 | 811 | if (flagsSelect & SELFLAG_TAKEFOCUS) |
michael@0 | 812 | xpAccessible->TakeFocus(); |
michael@0 | 813 | |
michael@0 | 814 | if (flagsSelect & SELFLAG_TAKESELECTION) |
michael@0 | 815 | xpAccessible->TakeSelection(); |
michael@0 | 816 | |
michael@0 | 817 | if (flagsSelect & SELFLAG_ADDSELECTION) |
michael@0 | 818 | xpAccessible->SetSelected(true); |
michael@0 | 819 | |
michael@0 | 820 | if (flagsSelect & SELFLAG_REMOVESELECTION) |
michael@0 | 821 | xpAccessible->SetSelected(false); |
michael@0 | 822 | |
michael@0 | 823 | if (flagsSelect & SELFLAG_EXTENDSELECTION) |
michael@0 | 824 | xpAccessible->ExtendSelection(); |
michael@0 | 825 | |
michael@0 | 826 | return S_OK; |
michael@0 | 827 | } |
michael@0 | 828 | |
michael@0 | 829 | return E_FAIL; |
michael@0 | 830 | |
michael@0 | 831 | A11Y_TRYBLOCK_END |
michael@0 | 832 | } |
michael@0 | 833 | |
michael@0 | 834 | STDMETHODIMP |
michael@0 | 835 | AccessibleWrap::accLocation( |
michael@0 | 836 | /* [out] */ long __RPC_FAR *pxLeft, |
michael@0 | 837 | /* [out] */ long __RPC_FAR *pyTop, |
michael@0 | 838 | /* [out] */ long __RPC_FAR *pcxWidth, |
michael@0 | 839 | /* [out] */ long __RPC_FAR *pcyHeight, |
michael@0 | 840 | /* [optional][in] */ VARIANT varChild) |
michael@0 | 841 | { |
michael@0 | 842 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 843 | |
michael@0 | 844 | if (!pxLeft || !pyTop || !pcxWidth || !pcyHeight) |
michael@0 | 845 | return E_INVALIDARG; |
michael@0 | 846 | |
michael@0 | 847 | *pxLeft = 0; |
michael@0 | 848 | *pyTop = 0; |
michael@0 | 849 | *pcxWidth = 0; |
michael@0 | 850 | *pcyHeight = 0; |
michael@0 | 851 | |
michael@0 | 852 | if (IsDefunct()) |
michael@0 | 853 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 854 | |
michael@0 | 855 | Accessible* xpAccessible = GetXPAccessibleFor(varChild); |
michael@0 | 856 | if (!xpAccessible) |
michael@0 | 857 | return E_INVALIDARG; |
michael@0 | 858 | |
michael@0 | 859 | if (xpAccessible->IsDefunct()) |
michael@0 | 860 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 861 | |
michael@0 | 862 | int32_t x, y, width, height; |
michael@0 | 863 | if (NS_FAILED(xpAccessible->GetBounds(&x, &y, &width, &height))) |
michael@0 | 864 | return E_FAIL; |
michael@0 | 865 | |
michael@0 | 866 | *pxLeft = x; |
michael@0 | 867 | *pyTop = y; |
michael@0 | 868 | *pcxWidth = width; |
michael@0 | 869 | *pcyHeight = height; |
michael@0 | 870 | return S_OK; |
michael@0 | 871 | |
michael@0 | 872 | A11Y_TRYBLOCK_END |
michael@0 | 873 | } |
michael@0 | 874 | |
michael@0 | 875 | STDMETHODIMP |
michael@0 | 876 | AccessibleWrap::accNavigate( |
michael@0 | 877 | /* [in] */ long navDir, |
michael@0 | 878 | /* [optional][in] */ VARIANT varStart, |
michael@0 | 879 | /* [retval][out] */ VARIANT __RPC_FAR *pvarEndUpAt) |
michael@0 | 880 | { |
michael@0 | 881 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 882 | |
michael@0 | 883 | if (!pvarEndUpAt) |
michael@0 | 884 | return E_INVALIDARG; |
michael@0 | 885 | |
michael@0 | 886 | VariantInit(pvarEndUpAt); |
michael@0 | 887 | |
michael@0 | 888 | if (IsDefunct()) |
michael@0 | 889 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 890 | |
michael@0 | 891 | Accessible* accessible = GetXPAccessibleFor(varStart); |
michael@0 | 892 | if (!accessible) |
michael@0 | 893 | return E_INVALIDARG; |
michael@0 | 894 | |
michael@0 | 895 | if (accessible->IsDefunct()) |
michael@0 | 896 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 897 | |
michael@0 | 898 | Accessible* navAccessible = nullptr; |
michael@0 | 899 | Maybe<RelationType> xpRelation; |
michael@0 | 900 | |
michael@0 | 901 | #define RELATIONTYPE(geckoType, stringType, atkType, msaaType, ia2Type) \ |
michael@0 | 902 | case msaaType: \ |
michael@0 | 903 | xpRelation.construct(RelationType::geckoType); \ |
michael@0 | 904 | break; |
michael@0 | 905 | |
michael@0 | 906 | switch(navDir) { |
michael@0 | 907 | case NAVDIR_FIRSTCHILD: |
michael@0 | 908 | if (!nsAccUtils::MustPrune(accessible)) |
michael@0 | 909 | navAccessible = accessible->FirstChild(); |
michael@0 | 910 | break; |
michael@0 | 911 | case NAVDIR_LASTCHILD: |
michael@0 | 912 | if (!nsAccUtils::MustPrune(accessible)) |
michael@0 | 913 | navAccessible = accessible->LastChild(); |
michael@0 | 914 | break; |
michael@0 | 915 | case NAVDIR_NEXT: |
michael@0 | 916 | navAccessible = accessible->NextSibling(); |
michael@0 | 917 | break; |
michael@0 | 918 | case NAVDIR_PREVIOUS: |
michael@0 | 919 | navAccessible = accessible->PrevSibling(); |
michael@0 | 920 | break; |
michael@0 | 921 | case NAVDIR_DOWN: |
michael@0 | 922 | case NAVDIR_LEFT: |
michael@0 | 923 | case NAVDIR_RIGHT: |
michael@0 | 924 | case NAVDIR_UP: |
michael@0 | 925 | return E_NOTIMPL; |
michael@0 | 926 | |
michael@0 | 927 | // MSAA relationship extensions to accNavigate |
michael@0 | 928 | #include "RelationTypeMap.h" |
michael@0 | 929 | |
michael@0 | 930 | default: |
michael@0 | 931 | return E_INVALIDARG; |
michael@0 | 932 | } |
michael@0 | 933 | |
michael@0 | 934 | #undef RELATIONTYPE |
michael@0 | 935 | |
michael@0 | 936 | pvarEndUpAt->vt = VT_EMPTY; |
michael@0 | 937 | |
michael@0 | 938 | if (!xpRelation.empty()) { |
michael@0 | 939 | Relation rel = RelationByType(xpRelation.ref()); |
michael@0 | 940 | navAccessible = rel.Next(); |
michael@0 | 941 | } |
michael@0 | 942 | |
michael@0 | 943 | if (!navAccessible) |
michael@0 | 944 | return E_FAIL; |
michael@0 | 945 | |
michael@0 | 946 | pvarEndUpAt->pdispVal = NativeAccessible(navAccessible); |
michael@0 | 947 | pvarEndUpAt->vt = VT_DISPATCH; |
michael@0 | 948 | return S_OK; |
michael@0 | 949 | |
michael@0 | 950 | A11Y_TRYBLOCK_END |
michael@0 | 951 | } |
michael@0 | 952 | |
michael@0 | 953 | STDMETHODIMP |
michael@0 | 954 | AccessibleWrap::accHitTest( |
michael@0 | 955 | /* [in] */ long xLeft, |
michael@0 | 956 | /* [in] */ long yTop, |
michael@0 | 957 | /* [retval][out] */ VARIANT __RPC_FAR *pvarChild) |
michael@0 | 958 | { |
michael@0 | 959 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 960 | |
michael@0 | 961 | if (!pvarChild) |
michael@0 | 962 | return E_INVALIDARG; |
michael@0 | 963 | |
michael@0 | 964 | VariantInit(pvarChild); |
michael@0 | 965 | |
michael@0 | 966 | if (IsDefunct()) |
michael@0 | 967 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 968 | |
michael@0 | 969 | Accessible* accessible = ChildAtPoint(xLeft, yTop, eDirectChild); |
michael@0 | 970 | |
michael@0 | 971 | // if we got a child |
michael@0 | 972 | if (accessible) { |
michael@0 | 973 | // if the child is us |
michael@0 | 974 | if (accessible == this) { |
michael@0 | 975 | pvarChild->vt = VT_I4; |
michael@0 | 976 | pvarChild->lVal = CHILDID_SELF; |
michael@0 | 977 | } else { // its not create an Accessible for it. |
michael@0 | 978 | pvarChild->vt = VT_DISPATCH; |
michael@0 | 979 | pvarChild->pdispVal = NativeAccessible(accessible); |
michael@0 | 980 | } |
michael@0 | 981 | } else { |
michael@0 | 982 | // no child at that point |
michael@0 | 983 | pvarChild->vt = VT_EMPTY; |
michael@0 | 984 | return S_FALSE; |
michael@0 | 985 | } |
michael@0 | 986 | return S_OK; |
michael@0 | 987 | |
michael@0 | 988 | A11Y_TRYBLOCK_END |
michael@0 | 989 | } |
michael@0 | 990 | |
michael@0 | 991 | STDMETHODIMP |
michael@0 | 992 | AccessibleWrap::accDoDefaultAction( |
michael@0 | 993 | /* [optional][in] */ VARIANT varChild) |
michael@0 | 994 | { |
michael@0 | 995 | A11Y_TRYBLOCK_BEGIN |
michael@0 | 996 | |
michael@0 | 997 | if (IsDefunct()) |
michael@0 | 998 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 999 | |
michael@0 | 1000 | Accessible* xpAccessible = GetXPAccessibleFor(varChild); |
michael@0 | 1001 | if (!xpAccessible) |
michael@0 | 1002 | return E_INVALIDARG; |
michael@0 | 1003 | |
michael@0 | 1004 | if (xpAccessible->IsDefunct()) |
michael@0 | 1005 | return CO_E_OBJNOTCONNECTED; |
michael@0 | 1006 | |
michael@0 | 1007 | return GetHRESULT(xpAccessible->DoAction(0)); |
michael@0 | 1008 | |
michael@0 | 1009 | A11Y_TRYBLOCK_END |
michael@0 | 1010 | } |
michael@0 | 1011 | |
michael@0 | 1012 | STDMETHODIMP |
michael@0 | 1013 | AccessibleWrap::put_accName( |
michael@0 | 1014 | /* [optional][in] */ VARIANT varChild, |
michael@0 | 1015 | /* [in] */ BSTR szName) |
michael@0 | 1016 | { |
michael@0 | 1017 | return E_NOTIMPL; |
michael@0 | 1018 | } |
michael@0 | 1019 | |
michael@0 | 1020 | STDMETHODIMP |
michael@0 | 1021 | AccessibleWrap::put_accValue( |
michael@0 | 1022 | /* [optional][in] */ VARIANT varChild, |
michael@0 | 1023 | /* [in] */ BSTR szValue) |
michael@0 | 1024 | { |
michael@0 | 1025 | return E_NOTIMPL; |
michael@0 | 1026 | } |
michael@0 | 1027 | |
michael@0 | 1028 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 1029 | // IDispatch |
michael@0 | 1030 | |
michael@0 | 1031 | STDMETHODIMP |
michael@0 | 1032 | AccessibleWrap::GetTypeInfoCount(UINT *pctinfo) |
michael@0 | 1033 | { |
michael@0 | 1034 | if (!pctinfo) |
michael@0 | 1035 | return E_INVALIDARG; |
michael@0 | 1036 | |
michael@0 | 1037 | *pctinfo = 1; |
michael@0 | 1038 | return S_OK; |
michael@0 | 1039 | } |
michael@0 | 1040 | |
michael@0 | 1041 | STDMETHODIMP |
michael@0 | 1042 | AccessibleWrap::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) |
michael@0 | 1043 | { |
michael@0 | 1044 | if (!ppTInfo) |
michael@0 | 1045 | return E_INVALIDARG; |
michael@0 | 1046 | |
michael@0 | 1047 | *ppTInfo = nullptr; |
michael@0 | 1048 | |
michael@0 | 1049 | if (iTInfo != 0) |
michael@0 | 1050 | return DISP_E_BADINDEX; |
michael@0 | 1051 | |
michael@0 | 1052 | ITypeInfo * typeInfo = GetTI(lcid); |
michael@0 | 1053 | if (!typeInfo) |
michael@0 | 1054 | return E_FAIL; |
michael@0 | 1055 | |
michael@0 | 1056 | typeInfo->AddRef(); |
michael@0 | 1057 | *ppTInfo = typeInfo; |
michael@0 | 1058 | |
michael@0 | 1059 | return S_OK; |
michael@0 | 1060 | } |
michael@0 | 1061 | |
michael@0 | 1062 | STDMETHODIMP |
michael@0 | 1063 | AccessibleWrap::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, |
michael@0 | 1064 | UINT cNames, LCID lcid, DISPID *rgDispId) |
michael@0 | 1065 | { |
michael@0 | 1066 | ITypeInfo *typeInfo = GetTI(lcid); |
michael@0 | 1067 | if (!typeInfo) |
michael@0 | 1068 | return E_FAIL; |
michael@0 | 1069 | |
michael@0 | 1070 | HRESULT hr = DispGetIDsOfNames(typeInfo, rgszNames, cNames, rgDispId); |
michael@0 | 1071 | return hr; |
michael@0 | 1072 | } |
michael@0 | 1073 | |
michael@0 | 1074 | STDMETHODIMP |
michael@0 | 1075 | AccessibleWrap::Invoke(DISPID dispIdMember, REFIID riid, |
michael@0 | 1076 | LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, |
michael@0 | 1077 | VARIANT *pVarResult, EXCEPINFO *pExcepInfo, |
michael@0 | 1078 | UINT *puArgErr) |
michael@0 | 1079 | { |
michael@0 | 1080 | ITypeInfo *typeInfo = GetTI(lcid); |
michael@0 | 1081 | if (!typeInfo) |
michael@0 | 1082 | return E_FAIL; |
michael@0 | 1083 | |
michael@0 | 1084 | return typeInfo->Invoke(static_cast<IAccessible*>(this), dispIdMember, |
michael@0 | 1085 | wFlags, pDispParams, pVarResult, pExcepInfo, |
michael@0 | 1086 | puArgErr); |
michael@0 | 1087 | } |
michael@0 | 1088 | |
michael@0 | 1089 | |
michael@0 | 1090 | // nsIAccessible method |
michael@0 | 1091 | NS_IMETHODIMP |
michael@0 | 1092 | AccessibleWrap::GetNativeInterface(void **aOutAccessible) |
michael@0 | 1093 | { |
michael@0 | 1094 | *aOutAccessible = static_cast<IAccessible*>(this); |
michael@0 | 1095 | NS_ADDREF_THIS(); |
michael@0 | 1096 | return NS_OK; |
michael@0 | 1097 | } |
michael@0 | 1098 | |
michael@0 | 1099 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 1100 | // Accessible |
michael@0 | 1101 | |
michael@0 | 1102 | nsresult |
michael@0 | 1103 | AccessibleWrap::HandleAccEvent(AccEvent* aEvent) |
michael@0 | 1104 | { |
michael@0 | 1105 | nsresult rv = Accessible::HandleAccEvent(aEvent); |
michael@0 | 1106 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1107 | |
michael@0 | 1108 | // Don't fire native MSAA events or mess with the system caret |
michael@0 | 1109 | // when running in metro mode. This confuses input focus tracking |
michael@0 | 1110 | // in metro's UIA implementation. |
michael@0 | 1111 | if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) { |
michael@0 | 1112 | return NS_OK; |
michael@0 | 1113 | } |
michael@0 | 1114 | |
michael@0 | 1115 | uint32_t eventType = aEvent->GetEventType(); |
michael@0 | 1116 | |
michael@0 | 1117 | static_assert(sizeof(gWinEventMap)/sizeof(gWinEventMap[0]) == nsIAccessibleEvent::EVENT_LAST_ENTRY, |
michael@0 | 1118 | "MSAA event map skewed"); |
michael@0 | 1119 | |
michael@0 | 1120 | NS_ENSURE_TRUE(eventType > 0 && eventType < ArrayLength(gWinEventMap), NS_ERROR_FAILURE); |
michael@0 | 1121 | |
michael@0 | 1122 | uint32_t winEvent = gWinEventMap[eventType]; |
michael@0 | 1123 | if (!winEvent) |
michael@0 | 1124 | return NS_OK; |
michael@0 | 1125 | |
michael@0 | 1126 | // Means we're not active. |
michael@0 | 1127 | NS_ENSURE_TRUE(!IsDefunct(), NS_ERROR_FAILURE); |
michael@0 | 1128 | |
michael@0 | 1129 | Accessible* accessible = aEvent->GetAccessible(); |
michael@0 | 1130 | if (!accessible) |
michael@0 | 1131 | return NS_OK; |
michael@0 | 1132 | |
michael@0 | 1133 | if (eventType == nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED || |
michael@0 | 1134 | eventType == nsIAccessibleEvent::EVENT_FOCUS) { |
michael@0 | 1135 | UpdateSystemCaretFor(accessible); |
michael@0 | 1136 | } |
michael@0 | 1137 | |
michael@0 | 1138 | int32_t childID = GetChildIDFor(accessible); // get the id for the accessible |
michael@0 | 1139 | if (!childID) |
michael@0 | 1140 | return NS_OK; // Can't fire an event without a child ID |
michael@0 | 1141 | |
michael@0 | 1142 | HWND hWnd = GetHWNDFor(accessible); |
michael@0 | 1143 | NS_ENSURE_TRUE(hWnd, NS_ERROR_FAILURE); |
michael@0 | 1144 | |
michael@0 | 1145 | nsAutoString tag; |
michael@0 | 1146 | nsAutoCString id; |
michael@0 | 1147 | nsIContent* cnt = accessible->GetContent(); |
michael@0 | 1148 | if (cnt) { |
michael@0 | 1149 | cnt->Tag()->ToString(tag); |
michael@0 | 1150 | nsIAtom* aid = cnt->GetID(); |
michael@0 | 1151 | if (aid) |
michael@0 | 1152 | aid->ToUTF8String(id); |
michael@0 | 1153 | } |
michael@0 | 1154 | |
michael@0 | 1155 | #ifdef A11Y_LOG |
michael@0 | 1156 | if (logging::IsEnabled(logging::ePlatforms)) { |
michael@0 | 1157 | printf("\n\nMSAA event: event: %d, target: %s@id='%s', childid: %d, hwnd: %d\n\n", |
michael@0 | 1158 | eventType, NS_ConvertUTF16toUTF8(tag).get(), id.get(), |
michael@0 | 1159 | childID, hWnd); |
michael@0 | 1160 | } |
michael@0 | 1161 | #endif |
michael@0 | 1162 | |
michael@0 | 1163 | // Fire MSAA event for client area window. |
michael@0 | 1164 | ::NotifyWinEvent(winEvent, hWnd, OBJID_CLIENT, childID); |
michael@0 | 1165 | |
michael@0 | 1166 | // JAWS announces collapsed combobox navigation based on focus events. |
michael@0 | 1167 | if (Compatibility::IsJAWS()) { |
michael@0 | 1168 | if (eventType == nsIAccessibleEvent::EVENT_SELECTION && |
michael@0 | 1169 | accessible->Role() == roles::COMBOBOX_OPTION) { |
michael@0 | 1170 | ::NotifyWinEvent(EVENT_OBJECT_FOCUS, hWnd, OBJID_CLIENT, childID); |
michael@0 | 1171 | } |
michael@0 | 1172 | } |
michael@0 | 1173 | |
michael@0 | 1174 | return NS_OK; |
michael@0 | 1175 | } |
michael@0 | 1176 | |
michael@0 | 1177 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 1178 | // AccessibleWrap |
michael@0 | 1179 | |
michael@0 | 1180 | //------- Helper methods --------- |
michael@0 | 1181 | |
michael@0 | 1182 | int32_t |
michael@0 | 1183 | AccessibleWrap::GetChildIDFor(Accessible* aAccessible) |
michael@0 | 1184 | { |
michael@0 | 1185 | // A child ID of the window is required, when we use NotifyWinEvent, |
michael@0 | 1186 | // so that the 3rd party application can call back and get the IAccessible |
michael@0 | 1187 | // the event occurred on. |
michael@0 | 1188 | |
michael@0 | 1189 | // Yes, this means we're only compatibible with 32 bit |
michael@0 | 1190 | // MSAA is only available for 32 bit windows, so it's okay |
michael@0 | 1191 | // XXX: bug 606080 |
michael@0 | 1192 | return aAccessible ? - NS_PTR_TO_INT32(aAccessible->UniqueID()) : 0; |
michael@0 | 1193 | } |
michael@0 | 1194 | |
michael@0 | 1195 | HWND |
michael@0 | 1196 | AccessibleWrap::GetHWNDFor(Accessible* aAccessible) |
michael@0 | 1197 | { |
michael@0 | 1198 | if (aAccessible) { |
michael@0 | 1199 | DocAccessible* document = aAccessible->Document(); |
michael@0 | 1200 | if(!document) |
michael@0 | 1201 | return nullptr; |
michael@0 | 1202 | |
michael@0 | 1203 | // Popup lives in own windows, use its HWND until the popup window is |
michael@0 | 1204 | // hidden to make old JAWS versions work with collapsed comboboxes (see |
michael@0 | 1205 | // discussion in bug 379678). |
michael@0 | 1206 | nsIFrame* frame = aAccessible->GetFrame(); |
michael@0 | 1207 | if (frame) { |
michael@0 | 1208 | nsIWidget* widget = frame->GetNearestWidget(); |
michael@0 | 1209 | if (widget && widget->IsVisible()) { |
michael@0 | 1210 | nsIPresShell* shell = document->PresShell(); |
michael@0 | 1211 | nsViewManager* vm = shell->GetViewManager(); |
michael@0 | 1212 | if (vm) { |
michael@0 | 1213 | nsCOMPtr<nsIWidget> rootWidget; |
michael@0 | 1214 | vm->GetRootWidget(getter_AddRefs(rootWidget)); |
michael@0 | 1215 | // Make sure the accessible belongs to popup. If not then use |
michael@0 | 1216 | // document HWND (which might be different from root widget in the |
michael@0 | 1217 | // case of window emulation). |
michael@0 | 1218 | if (rootWidget != widget) |
michael@0 | 1219 | return static_cast<HWND>(widget->GetNativeData(NS_NATIVE_WINDOW)); |
michael@0 | 1220 | } |
michael@0 | 1221 | } |
michael@0 | 1222 | } |
michael@0 | 1223 | |
michael@0 | 1224 | return static_cast<HWND>(document->GetNativeWindow()); |
michael@0 | 1225 | } |
michael@0 | 1226 | return nullptr; |
michael@0 | 1227 | } |
michael@0 | 1228 | |
michael@0 | 1229 | IDispatch* |
michael@0 | 1230 | AccessibleWrap::NativeAccessible(nsIAccessible* aAccessible) |
michael@0 | 1231 | { |
michael@0 | 1232 | if (!aAccessible) { |
michael@0 | 1233 | NS_WARNING("Not passing in an aAccessible"); |
michael@0 | 1234 | return nullptr; |
michael@0 | 1235 | } |
michael@0 | 1236 | |
michael@0 | 1237 | IAccessible* msaaAccessible = nullptr; |
michael@0 | 1238 | aAccessible->GetNativeInterface(reinterpret_cast<void**>(&msaaAccessible)); |
michael@0 | 1239 | return static_cast<IDispatch*>(msaaAccessible); |
michael@0 | 1240 | } |
michael@0 | 1241 | |
michael@0 | 1242 | Accessible* |
michael@0 | 1243 | AccessibleWrap::GetXPAccessibleFor(const VARIANT& aVarChild) |
michael@0 | 1244 | { |
michael@0 | 1245 | if (aVarChild.vt != VT_I4) |
michael@0 | 1246 | return nullptr; |
michael@0 | 1247 | |
michael@0 | 1248 | // if its us real easy - this seems to always be the case |
michael@0 | 1249 | if (aVarChild.lVal == CHILDID_SELF) |
michael@0 | 1250 | return this; |
michael@0 | 1251 | |
michael@0 | 1252 | if (nsAccUtils::MustPrune(this)) |
michael@0 | 1253 | return nullptr; |
michael@0 | 1254 | |
michael@0 | 1255 | // If lVal negative then it is treated as child ID and we should look for |
michael@0 | 1256 | // accessible through whole accessible subtree including subdocuments. |
michael@0 | 1257 | // Otherwise we treat lVal as index in parent. |
michael@0 | 1258 | |
michael@0 | 1259 | if (aVarChild.lVal < 0) { |
michael@0 | 1260 | // Convert child ID to unique ID. |
michael@0 | 1261 | void* uniqueID = reinterpret_cast<void*>(-aVarChild.lVal); |
michael@0 | 1262 | |
michael@0 | 1263 | DocAccessible* document = Document(); |
michael@0 | 1264 | Accessible* child = |
michael@0 | 1265 | document->GetAccessibleByUniqueIDInSubtree(uniqueID); |
michael@0 | 1266 | |
michael@0 | 1267 | // If it is a document then just return an accessible. |
michael@0 | 1268 | if (IsDoc()) |
michael@0 | 1269 | return child; |
michael@0 | 1270 | |
michael@0 | 1271 | // Otherwise check whether the accessible is a child (this path works for |
michael@0 | 1272 | // ARIA documents and popups). |
michael@0 | 1273 | Accessible* parent = child; |
michael@0 | 1274 | while (parent && parent != document) { |
michael@0 | 1275 | if (parent == this) |
michael@0 | 1276 | return child; |
michael@0 | 1277 | |
michael@0 | 1278 | parent = parent->Parent(); |
michael@0 | 1279 | } |
michael@0 | 1280 | |
michael@0 | 1281 | return nullptr; |
michael@0 | 1282 | } |
michael@0 | 1283 | |
michael@0 | 1284 | // Gecko child indices are 0-based in contrast to indices used in MSAA. |
michael@0 | 1285 | return GetChildAt(aVarChild.lVal - 1); |
michael@0 | 1286 | } |
michael@0 | 1287 | |
michael@0 | 1288 | void |
michael@0 | 1289 | AccessibleWrap::UpdateSystemCaretFor(Accessible* aAccessible) |
michael@0 | 1290 | { |
michael@0 | 1291 | // Move the system caret so that Windows Tablet Edition and tradional ATs with |
michael@0 | 1292 | // off-screen model can follow the caret |
michael@0 | 1293 | ::DestroyCaret(); |
michael@0 | 1294 | |
michael@0 | 1295 | HyperTextAccessible* text = aAccessible->AsHyperText(); |
michael@0 | 1296 | if (!text) |
michael@0 | 1297 | return; |
michael@0 | 1298 | |
michael@0 | 1299 | nsIWidget* widget = nullptr; |
michael@0 | 1300 | nsIntRect caretRect = text->GetCaretRect(&widget); |
michael@0 | 1301 | HWND caretWnd; |
michael@0 | 1302 | if (caretRect.IsEmpty() || !(caretWnd = (HWND)widget->GetNativeData(NS_NATIVE_WINDOW))) { |
michael@0 | 1303 | return; |
michael@0 | 1304 | } |
michael@0 | 1305 | |
michael@0 | 1306 | // Create invisible bitmap for caret, otherwise its appearance interferes |
michael@0 | 1307 | // with Gecko caret |
michael@0 | 1308 | HBITMAP caretBitMap = CreateBitmap(1, caretRect.height, 1, 1, nullptr); |
michael@0 | 1309 | if (::CreateCaret(caretWnd, caretBitMap, 1, caretRect.height)) { // Also destroys the last caret |
michael@0 | 1310 | ::ShowCaret(caretWnd); |
michael@0 | 1311 | RECT windowRect; |
michael@0 | 1312 | ::GetWindowRect(caretWnd, &windowRect); |
michael@0 | 1313 | ::SetCaretPos(caretRect.x - windowRect.left, caretRect.y - windowRect.top); |
michael@0 | 1314 | ::DeleteObject(caretBitMap); |
michael@0 | 1315 | } |
michael@0 | 1316 | } |
michael@0 | 1317 | |
michael@0 | 1318 | ITypeInfo* |
michael@0 | 1319 | AccessibleWrap::GetTI(LCID lcid) |
michael@0 | 1320 | { |
michael@0 | 1321 | if (gTypeInfo) |
michael@0 | 1322 | return gTypeInfo; |
michael@0 | 1323 | |
michael@0 | 1324 | ITypeLib *typeLib = nullptr; |
michael@0 | 1325 | HRESULT hr = LoadRegTypeLib(LIBID_Accessibility, 1, 0, lcid, &typeLib); |
michael@0 | 1326 | if (FAILED(hr)) |
michael@0 | 1327 | return nullptr; |
michael@0 | 1328 | |
michael@0 | 1329 | hr = typeLib->GetTypeInfoOfGuid(IID_IAccessible, &gTypeInfo); |
michael@0 | 1330 | typeLib->Release(); |
michael@0 | 1331 | |
michael@0 | 1332 | if (FAILED(hr)) |
michael@0 | 1333 | return nullptr; |
michael@0 | 1334 | |
michael@0 | 1335 | return gTypeInfo; |
michael@0 | 1336 | } |