1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/accessible/src/windows/ia2/ia2Accessible.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,677 @@ 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 + 1.12 +#include "Accessible2_i.c" 1.13 +#include "Accessible2_2_i.c" 1.14 +#include "AccessibleRole.h" 1.15 +#include "AccessibleStates.h" 1.16 + 1.17 +#include "Compatibility.h" 1.18 +#include "ia2AccessibleRelation.h" 1.19 +#include "IUnknownImpl.h" 1.20 +#include "nsCoreUtils.h" 1.21 +#include "nsIAccessibleTypes.h" 1.22 +#include "Relation.h" 1.23 + 1.24 +#include "nsIPersistentProperties2.h" 1.25 +#include "nsISimpleEnumerator.h" 1.26 + 1.27 +using namespace mozilla; 1.28 +using namespace mozilla::a11y; 1.29 + 1.30 +//////////////////////////////////////////////////////////////////////////////// 1.31 +// ia2Accessible 1.32 +//////////////////////////////////////////////////////////////////////////////// 1.33 + 1.34 +STDMETHODIMP 1.35 +ia2Accessible::QueryInterface(REFIID iid, void** ppv) 1.36 +{ 1.37 + if (!ppv) 1.38 + return E_INVALIDARG; 1.39 + 1.40 + *ppv = nullptr; 1.41 + 1.42 + if (IID_IAccessible2_2 == iid) 1.43 + *ppv = static_cast<IAccessible2_2*>(this); 1.44 + else if (IID_IAccessible2 == iid && !Compatibility::IsIA2Off()) 1.45 + *ppv = static_cast<IAccessible2*>(this); 1.46 + 1.47 + if (*ppv) { 1.48 + (reinterpret_cast<IUnknown*>(*ppv))->AddRef(); 1.49 + return S_OK; 1.50 + } 1.51 + 1.52 + return E_NOINTERFACE; 1.53 +} 1.54 + 1.55 +//////////////////////////////////////////////////////////////////////////////// 1.56 +// IAccessible2 1.57 + 1.58 +STDMETHODIMP 1.59 +ia2Accessible::get_nRelations(long* aNRelations) 1.60 +{ 1.61 + A11Y_TRYBLOCK_BEGIN 1.62 + 1.63 + if (!aNRelations) 1.64 + return E_INVALIDARG; 1.65 + *aNRelations = 0; 1.66 + 1.67 + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); 1.68 + if (acc->IsDefunct()) 1.69 + return CO_E_OBJNOTCONNECTED; 1.70 + 1.71 + for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) { 1.72 + if (sRelationTypePairs[idx].second == IA2_RELATION_NULL) 1.73 + continue; 1.74 + 1.75 + Relation rel = acc->RelationByType(sRelationTypePairs[idx].first); 1.76 + if (rel.Next()) 1.77 + (*aNRelations)++; 1.78 + } 1.79 + return S_OK; 1.80 + 1.81 + A11Y_TRYBLOCK_END 1.82 +} 1.83 + 1.84 +STDMETHODIMP 1.85 +ia2Accessible::get_relation(long aRelationIndex, 1.86 + IAccessibleRelation** aRelation) 1.87 +{ 1.88 + A11Y_TRYBLOCK_BEGIN 1.89 + 1.90 + if (!aRelation) 1.91 + return E_INVALIDARG; 1.92 + *aRelation = nullptr; 1.93 + 1.94 + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); 1.95 + if (acc->IsDefunct()) 1.96 + return CO_E_OBJNOTCONNECTED; 1.97 + 1.98 + long relIdx = 0; 1.99 + for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) { 1.100 + if (sRelationTypePairs[idx].second == IA2_RELATION_NULL) 1.101 + continue; 1.102 + 1.103 + RelationType relationType = sRelationTypePairs[idx].first; 1.104 + Relation rel = acc->RelationByType(relationType); 1.105 + nsRefPtr<ia2AccessibleRelation> ia2Relation = 1.106 + new ia2AccessibleRelation(relationType, &rel); 1.107 + if (ia2Relation->HasTargets()) { 1.108 + if (relIdx == aRelationIndex) { 1.109 + ia2Relation.forget(aRelation); 1.110 + return S_OK; 1.111 + } 1.112 + 1.113 + relIdx++; 1.114 + } 1.115 + } 1.116 + 1.117 + return E_INVALIDARG; 1.118 + 1.119 + A11Y_TRYBLOCK_END 1.120 +} 1.121 + 1.122 +STDMETHODIMP 1.123 +ia2Accessible::get_relations(long aMaxRelations, 1.124 + IAccessibleRelation** aRelation, 1.125 + long *aNRelations) 1.126 +{ 1.127 + A11Y_TRYBLOCK_BEGIN 1.128 + 1.129 + if (!aRelation || !aNRelations) 1.130 + return E_INVALIDARG; 1.131 + *aNRelations = 0; 1.132 + 1.133 + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); 1.134 + if (acc->IsDefunct()) 1.135 + return CO_E_OBJNOTCONNECTED; 1.136 + 1.137 + for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs) && 1.138 + *aNRelations < aMaxRelations; idx++) { 1.139 + if (sRelationTypePairs[idx].second == IA2_RELATION_NULL) 1.140 + continue; 1.141 + 1.142 + RelationType relationType = sRelationTypePairs[idx].first; 1.143 + Relation rel = acc->RelationByType(relationType); 1.144 + nsRefPtr<ia2AccessibleRelation> ia2Rel = 1.145 + new ia2AccessibleRelation(relationType, &rel); 1.146 + if (ia2Rel->HasTargets()) { 1.147 + ia2Rel.forget(aRelation + (*aNRelations)); 1.148 + (*aNRelations)++; 1.149 + } 1.150 + } 1.151 + return S_OK; 1.152 + 1.153 + A11Y_TRYBLOCK_END 1.154 +} 1.155 + 1.156 +STDMETHODIMP 1.157 +ia2Accessible::role(long* aRole) 1.158 +{ 1.159 + A11Y_TRYBLOCK_BEGIN 1.160 + 1.161 + if (!aRole) 1.162 + return E_INVALIDARG; 1.163 + *aRole = 0; 1.164 + 1.165 + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); 1.166 + if (acc->IsDefunct()) 1.167 + return CO_E_OBJNOTCONNECTED; 1.168 + 1.169 +#define ROLE(_geckoRole, stringRole, atkRole, macRole, \ 1.170 + msaaRole, ia2Role, nameRule) \ 1.171 + case roles::_geckoRole: \ 1.172 + *aRole = ia2Role; \ 1.173 + break; 1.174 + 1.175 + a11y::role geckoRole = acc->Role(); 1.176 + switch (geckoRole) { 1.177 +#include "RoleMap.h" 1.178 + default: 1.179 + MOZ_CRASH("Unknown role."); 1.180 + }; 1.181 + 1.182 +#undef ROLE 1.183 + 1.184 + // Special case, if there is a ROLE_ROW inside of a ROLE_TREE_TABLE, then call 1.185 + // the IA2 role a ROLE_OUTLINEITEM. 1.186 + if (geckoRole == roles::ROW) { 1.187 + Accessible* xpParent = acc->Parent(); 1.188 + if (xpParent && xpParent->Role() == roles::TREE_TABLE) 1.189 + *aRole = ROLE_SYSTEM_OUTLINEITEM; 1.190 + } 1.191 + 1.192 + return S_OK; 1.193 + 1.194 + A11Y_TRYBLOCK_END 1.195 +} 1.196 + 1.197 +STDMETHODIMP 1.198 +ia2Accessible::scrollTo(enum IA2ScrollType aScrollType) 1.199 +{ 1.200 + A11Y_TRYBLOCK_BEGIN 1.201 + 1.202 + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); 1.203 + if (acc->IsDefunct()) 1.204 + return CO_E_OBJNOTCONNECTED; 1.205 + 1.206 + nsCoreUtils::ScrollTo(acc->Document()->PresShell(), 1.207 + acc->GetContent(), aScrollType); 1.208 + return S_OK; 1.209 + 1.210 + A11Y_TRYBLOCK_END 1.211 +} 1.212 + 1.213 +STDMETHODIMP 1.214 +ia2Accessible::scrollToPoint(enum IA2CoordinateType aCoordType, 1.215 + long aX, long aY) 1.216 +{ 1.217 + A11Y_TRYBLOCK_BEGIN 1.218 + 1.219 + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); 1.220 + if (acc->IsDefunct()) 1.221 + return CO_E_OBJNOTCONNECTED; 1.222 + 1.223 + uint32_t geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ? 1.224 + nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE : 1.225 + nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE; 1.226 + 1.227 + nsresult rv = acc->ScrollToPoint(geckoCoordType, aX, aY); 1.228 + return GetHRESULT(rv); 1.229 + 1.230 + A11Y_TRYBLOCK_END 1.231 +} 1.232 + 1.233 +STDMETHODIMP 1.234 +ia2Accessible::get_groupPosition(long* aGroupLevel, 1.235 + long* aSimilarItemsInGroup, 1.236 + long* aPositionInGroup) 1.237 +{ 1.238 + A11Y_TRYBLOCK_BEGIN 1.239 + 1.240 + if (!aGroupLevel || !aSimilarItemsInGroup || !aPositionInGroup) 1.241 + return E_INVALIDARG; 1.242 + 1.243 + *aGroupLevel = 0; 1.244 + *aSimilarItemsInGroup = 0; 1.245 + *aPositionInGroup = 0; 1.246 + 1.247 + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); 1.248 + if (acc->IsDefunct()) 1.249 + return CO_E_OBJNOTCONNECTED; 1.250 + 1.251 + GroupPos groupPos = acc->GroupPosition(); 1.252 + 1.253 + // Group information for accessibles having level only (like html headings 1.254 + // elements) isn't exposed by this method. AT should look for 'level' object 1.255 + // attribute. 1.256 + if (!groupPos.setSize && !groupPos.posInSet) 1.257 + return S_FALSE; 1.258 + 1.259 + *aGroupLevel = groupPos.level; 1.260 + *aSimilarItemsInGroup = groupPos.setSize; 1.261 + *aPositionInGroup = groupPos.posInSet; 1.262 + 1.263 + return S_OK; 1.264 + 1.265 + A11Y_TRYBLOCK_END 1.266 +} 1.267 + 1.268 +STDMETHODIMP 1.269 +ia2Accessible::get_states(AccessibleStates* aStates) 1.270 +{ 1.271 + A11Y_TRYBLOCK_BEGIN 1.272 + 1.273 + if (!aStates) 1.274 + return E_INVALIDARG; 1.275 + *aStates = 0; 1.276 + 1.277 + // XXX: bug 344674 should come with better approach that we have here. 1.278 + 1.279 + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); 1.280 + uint64_t state = acc->State(); 1.281 + 1.282 + if (state & states::INVALID) 1.283 + *aStates |= IA2_STATE_INVALID_ENTRY; 1.284 + if (state & states::REQUIRED) 1.285 + *aStates |= IA2_STATE_REQUIRED; 1.286 + 1.287 + // The following IA2 states are not supported by Gecko 1.288 + // IA2_STATE_ARMED 1.289 + // IA2_STATE_MANAGES_DESCENDANTS 1.290 + // IA2_STATE_ICONIFIED 1.291 + // IA2_STATE_INVALID // This is not a state, it is the absence of a state 1.292 + 1.293 + if (state & states::ACTIVE) 1.294 + *aStates |= IA2_STATE_ACTIVE; 1.295 + if (state & states::DEFUNCT) 1.296 + *aStates |= IA2_STATE_DEFUNCT; 1.297 + if (state & states::EDITABLE) 1.298 + *aStates |= IA2_STATE_EDITABLE; 1.299 + if (state & states::HORIZONTAL) 1.300 + *aStates |= IA2_STATE_HORIZONTAL; 1.301 + if (state & states::MODAL) 1.302 + *aStates |= IA2_STATE_MODAL; 1.303 + if (state & states::MULTI_LINE) 1.304 + *aStates |= IA2_STATE_MULTI_LINE; 1.305 + if (state & states::OPAQUE1) 1.306 + *aStates |= IA2_STATE_OPAQUE; 1.307 + if (state & states::SELECTABLE_TEXT) 1.308 + *aStates |= IA2_STATE_SELECTABLE_TEXT; 1.309 + if (state & states::SINGLE_LINE) 1.310 + *aStates |= IA2_STATE_SINGLE_LINE; 1.311 + if (state & states::STALE) 1.312 + *aStates |= IA2_STATE_STALE; 1.313 + if (state & states::SUPPORTS_AUTOCOMPLETION) 1.314 + *aStates |= IA2_STATE_SUPPORTS_AUTOCOMPLETION; 1.315 + if (state & states::TRANSIENT) 1.316 + *aStates |= IA2_STATE_TRANSIENT; 1.317 + if (state & states::VERTICAL) 1.318 + *aStates |= IA2_STATE_VERTICAL; 1.319 + if (state & states::CHECKED) 1.320 + *aStates |= IA2_STATE_CHECKABLE; 1.321 + if (state & states::PINNED) 1.322 + *aStates |= IA2_STATE_PINNED; 1.323 + 1.324 + return S_OK; 1.325 + 1.326 + A11Y_TRYBLOCK_END 1.327 +} 1.328 + 1.329 +STDMETHODIMP 1.330 +ia2Accessible::get_extendedRole(BSTR* aExtendedRole) 1.331 +{ 1.332 + A11Y_TRYBLOCK_BEGIN 1.333 + 1.334 + if (!aExtendedRole) 1.335 + return E_INVALIDARG; 1.336 + 1.337 + *aExtendedRole = nullptr; 1.338 + return E_NOTIMPL; 1.339 + 1.340 + A11Y_TRYBLOCK_END 1.341 +} 1.342 + 1.343 +STDMETHODIMP 1.344 +ia2Accessible::get_localizedExtendedRole(BSTR* aLocalizedExtendedRole) 1.345 +{ 1.346 + A11Y_TRYBLOCK_BEGIN 1.347 + 1.348 + if (!aLocalizedExtendedRole) 1.349 + return E_INVALIDARG; 1.350 + 1.351 + *aLocalizedExtendedRole = nullptr; 1.352 + return E_NOTIMPL; 1.353 + 1.354 + A11Y_TRYBLOCK_END 1.355 +} 1.356 + 1.357 +STDMETHODIMP 1.358 +ia2Accessible::get_nExtendedStates(long* aNExtendedStates) 1.359 +{ 1.360 + A11Y_TRYBLOCK_BEGIN 1.361 + 1.362 + if (!aNExtendedStates) 1.363 + return E_INVALIDARG; 1.364 + 1.365 + *aNExtendedStates = 0; 1.366 + return E_NOTIMPL; 1.367 + 1.368 + A11Y_TRYBLOCK_END 1.369 +} 1.370 + 1.371 +STDMETHODIMP 1.372 +ia2Accessible::get_extendedStates(long aMaxExtendedStates, 1.373 + BSTR** aExtendedStates, 1.374 + long* aNExtendedStates) 1.375 +{ 1.376 + A11Y_TRYBLOCK_BEGIN 1.377 + 1.378 + if (!aExtendedStates || !aNExtendedStates) 1.379 + return E_INVALIDARG; 1.380 + 1.381 + *aExtendedStates = nullptr; 1.382 + *aNExtendedStates = 0; 1.383 + return E_NOTIMPL; 1.384 + 1.385 + A11Y_TRYBLOCK_END 1.386 +} 1.387 + 1.388 +STDMETHODIMP 1.389 +ia2Accessible::get_localizedExtendedStates(long aMaxLocalizedExtendedStates, 1.390 + BSTR** aLocalizedExtendedStates, 1.391 + long* aNLocalizedExtendedStates) 1.392 +{ 1.393 + A11Y_TRYBLOCK_BEGIN 1.394 + 1.395 + if (!aLocalizedExtendedStates || !aNLocalizedExtendedStates) 1.396 + return E_INVALIDARG; 1.397 + 1.398 + *aLocalizedExtendedStates = nullptr; 1.399 + *aNLocalizedExtendedStates = 0; 1.400 + return E_NOTIMPL; 1.401 + 1.402 + A11Y_TRYBLOCK_END 1.403 +} 1.404 + 1.405 +STDMETHODIMP 1.406 +ia2Accessible::get_uniqueID(long* aUniqueID) 1.407 +{ 1.408 + A11Y_TRYBLOCK_BEGIN 1.409 + 1.410 + if (!aUniqueID) 1.411 + return E_INVALIDARG; 1.412 + 1.413 + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); 1.414 + *aUniqueID = - reinterpret_cast<intptr_t>(acc->UniqueID()); 1.415 + return S_OK; 1.416 + 1.417 + A11Y_TRYBLOCK_END 1.418 +} 1.419 + 1.420 +STDMETHODIMP 1.421 +ia2Accessible::get_windowHandle(HWND* aWindowHandle) 1.422 +{ 1.423 + A11Y_TRYBLOCK_BEGIN 1.424 + 1.425 + if (!aWindowHandle) 1.426 + return E_INVALIDARG; 1.427 + *aWindowHandle = 0; 1.428 + 1.429 + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); 1.430 + if (acc->IsDefunct()) 1.431 + return CO_E_OBJNOTCONNECTED; 1.432 + 1.433 + *aWindowHandle = AccessibleWrap::GetHWNDFor(acc); 1.434 + return S_OK; 1.435 + 1.436 + A11Y_TRYBLOCK_END 1.437 +} 1.438 + 1.439 +STDMETHODIMP 1.440 +ia2Accessible::get_indexInParent(long* aIndexInParent) 1.441 +{ 1.442 + A11Y_TRYBLOCK_BEGIN 1.443 + 1.444 + if (!aIndexInParent) 1.445 + return E_INVALIDARG; 1.446 + *aIndexInParent = -1; 1.447 + 1.448 + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); 1.449 + if (acc->IsDefunct()) 1.450 + return CO_E_OBJNOTCONNECTED; 1.451 + 1.452 + *aIndexInParent = acc->IndexInParent(); 1.453 + if (*aIndexInParent == -1) 1.454 + return S_FALSE; 1.455 + 1.456 + return S_OK; 1.457 + 1.458 + A11Y_TRYBLOCK_END 1.459 +} 1.460 + 1.461 +STDMETHODIMP 1.462 +ia2Accessible::get_locale(IA2Locale* aLocale) 1.463 +{ 1.464 + A11Y_TRYBLOCK_BEGIN 1.465 + 1.466 + if (!aLocale) 1.467 + return E_INVALIDARG; 1.468 + 1.469 + // Language codes consist of a primary code and a possibly empty series of 1.470 + // subcodes: language-code = primary-code ( "-" subcode )* 1.471 + // Two-letter primary codes are reserved for [ISO639] language abbreviations. 1.472 + // Any two-letter subcode is understood to be a [ISO3166] country code. 1.473 + 1.474 + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); 1.475 + if (acc->IsDefunct()) 1.476 + return CO_E_OBJNOTCONNECTED; 1.477 + 1.478 + nsAutoString lang; 1.479 + acc->Language(lang); 1.480 + 1.481 + // If primary code consists from two letters then expose it as language. 1.482 + int32_t offset = lang.FindChar('-', 0); 1.483 + if (offset == -1) { 1.484 + if (lang.Length() == 2) { 1.485 + aLocale->language = ::SysAllocString(lang.get()); 1.486 + return S_OK; 1.487 + } 1.488 + } else if (offset == 2) { 1.489 + aLocale->language = ::SysAllocStringLen(lang.get(), 2); 1.490 + 1.491 + // If the first subcode consists from two letters then expose it as 1.492 + // country. 1.493 + offset = lang.FindChar('-', 3); 1.494 + if (offset == -1) { 1.495 + if (lang.Length() == 5) { 1.496 + aLocale->country = ::SysAllocString(lang.get() + 3); 1.497 + return S_OK; 1.498 + } 1.499 + } else if (offset == 5) { 1.500 + aLocale->country = ::SysAllocStringLen(lang.get() + 3, 2); 1.501 + } 1.502 + } 1.503 + 1.504 + // Expose as a string if primary code or subcode cannot point to language or 1.505 + // country abbreviations or if there are more than one subcode. 1.506 + aLocale->variant = ::SysAllocString(lang.get()); 1.507 + return S_OK; 1.508 + 1.509 + A11Y_TRYBLOCK_END 1.510 +} 1.511 + 1.512 +STDMETHODIMP 1.513 +ia2Accessible::get_attributes(BSTR* aAttributes) 1.514 +{ 1.515 + A11Y_TRYBLOCK_BEGIN 1.516 + 1.517 + if (!aAttributes) 1.518 + return E_INVALIDARG; 1.519 + *aAttributes = nullptr; 1.520 + 1.521 + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); 1.522 + if (acc->IsDefunct()) 1.523 + return CO_E_OBJNOTCONNECTED; 1.524 + 1.525 + // The format is name:value;name:value; with \ for escaping these 1.526 + // characters ":;=,\". 1.527 + nsCOMPtr<nsIPersistentProperties> attributes = acc->Attributes(); 1.528 + return ConvertToIA2Attributes(attributes, aAttributes); 1.529 + 1.530 + A11Y_TRYBLOCK_END 1.531 +} 1.532 + 1.533 +//////////////////////////////////////////////////////////////////////////////// 1.534 +// IAccessible2_2 1.535 + 1.536 +STDMETHODIMP 1.537 +ia2Accessible::get_attribute(BSTR name, VARIANT* aAttribute) 1.538 +{ 1.539 + A11Y_TRYBLOCK_BEGIN 1.540 + 1.541 + if (!aAttribute) 1.542 + return E_INVALIDARG; 1.543 + 1.544 + return E_NOTIMPL; 1.545 + 1.546 + A11Y_TRYBLOCK_END 1.547 +} 1.548 + 1.549 +STDMETHODIMP 1.550 +ia2Accessible::get_accessibleWithCaret(IUnknown** aAccessible, 1.551 + long* aCaretOffset) 1.552 +{ 1.553 + A11Y_TRYBLOCK_BEGIN 1.554 + 1.555 + if (!aAccessible || !aCaretOffset) 1.556 + return E_INVALIDARG; 1.557 + 1.558 + *aAccessible = nullptr; 1.559 + *aCaretOffset = -1; 1.560 + return E_NOTIMPL; 1.561 + 1.562 + A11Y_TRYBLOCK_END 1.563 +} 1.564 + 1.565 +STDMETHODIMP 1.566 +ia2Accessible::get_relationTargetsOfType(BSTR aType, 1.567 + long aMaxTargets, 1.568 + IUnknown*** aTargets, 1.569 + long* aNTargets) 1.570 +{ 1.571 + A11Y_TRYBLOCK_BEGIN 1.572 + 1.573 + if (!aTargets || !aNTargets) 1.574 + return E_INVALIDARG; 1.575 + *aNTargets = 0; 1.576 + 1.577 + Maybe<RelationType> relationType; 1.578 + for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) { 1.579 + if (wcscmp(aType, sRelationTypePairs[idx].second) == 0) { 1.580 + relationType.construct(sRelationTypePairs[idx].first); 1.581 + break; 1.582 + } 1.583 + } 1.584 + if (relationType.empty()) 1.585 + return E_INVALIDARG; 1.586 + 1.587 + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); 1.588 + if (acc->IsDefunct()) 1.589 + return CO_E_OBJNOTCONNECTED; 1.590 + 1.591 + Relation rel = acc->RelationByType(relationType.ref()); 1.592 + 1.593 + nsTArray<Accessible*> targets; 1.594 + Accessible* target = nullptr; 1.595 + while ((target = rel.Next()) && 1.596 + static_cast<long>(targets.Length()) <= aMaxTargets) 1.597 + targets.AppendElement(target); 1.598 + 1.599 + *aNTargets = targets.Length(); 1.600 + *aTargets = static_cast<IUnknown**>( 1.601 + ::CoTaskMemAlloc(sizeof(IUnknown*) * *aNTargets)); 1.602 + if (!*aTargets) 1.603 + return E_OUTOFMEMORY; 1.604 + 1.605 + for (int32_t i = 0; i < *aNTargets; i++) { 1.606 + AccessibleWrap* target= static_cast<AccessibleWrap*>(targets[i]); 1.607 + (*aTargets)[i] = static_cast<IAccessible2*>(target); 1.608 + (*aTargets)[i]->AddRef(); 1.609 + } 1.610 + 1.611 + return S_OK; 1.612 + 1.613 + A11Y_TRYBLOCK_END 1.614 +} 1.615 + 1.616 +//////////////////////////////////////////////////////////////////////////////// 1.617 +// Helpers 1.618 + 1.619 +HRESULT 1.620 +ia2Accessible::ConvertToIA2Attributes(nsIPersistentProperties* aAttributes, 1.621 + BSTR* aIA2Attributes) 1.622 +{ 1.623 + *aIA2Attributes = nullptr; 1.624 + 1.625 + // The format is name:value;name:value; with \ for escaping these 1.626 + // characters ":;=,\". 1.627 + 1.628 + if (!aAttributes) 1.629 + return S_FALSE; 1.630 + 1.631 + nsCOMPtr<nsISimpleEnumerator> propEnum; 1.632 + aAttributes->Enumerate(getter_AddRefs(propEnum)); 1.633 + if (!propEnum) 1.634 + return E_FAIL; 1.635 + 1.636 + nsAutoString strAttrs; 1.637 + 1.638 + const char kCharsToEscape[] = ":;=,\\"; 1.639 + 1.640 + bool hasMore = false; 1.641 + while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) { 1.642 + nsCOMPtr<nsISupports> propSupports; 1.643 + propEnum->GetNext(getter_AddRefs(propSupports)); 1.644 + 1.645 + nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(propSupports)); 1.646 + if (!propElem) 1.647 + return E_FAIL; 1.648 + 1.649 + nsAutoCString name; 1.650 + if (NS_FAILED(propElem->GetKey(name))) 1.651 + return E_FAIL; 1.652 + 1.653 + int32_t offset = 0; 1.654 + while ((offset = name.FindCharInSet(kCharsToEscape, offset)) != kNotFound) { 1.655 + name.Insert('\\', offset); 1.656 + offset += 2; 1.657 + } 1.658 + 1.659 + nsAutoString value; 1.660 + if (NS_FAILED(propElem->GetValue(value))) 1.661 + return E_FAIL; 1.662 + 1.663 + offset = 0; 1.664 + while ((offset = value.FindCharInSet(kCharsToEscape, offset)) != kNotFound) { 1.665 + value.Insert('\\', offset); 1.666 + offset += 2; 1.667 + } 1.668 + 1.669 + AppendUTF8toUTF16(name, strAttrs); 1.670 + strAttrs.Append(':'); 1.671 + strAttrs.Append(value); 1.672 + strAttrs.Append(';'); 1.673 + } 1.674 + 1.675 + if (strAttrs.IsEmpty()) 1.676 + return S_FALSE; 1.677 + 1.678 + *aIA2Attributes = ::SysAllocStringLen(strAttrs.get(), strAttrs.Length()); 1.679 + return *aIA2Attributes ? S_OK : E_OUTOFMEMORY; 1.680 +}