accessible/src/windows/ia2/ia2Accessible.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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
michael@0 9 #include "Accessible2_i.c"
michael@0 10 #include "Accessible2_2_i.c"
michael@0 11 #include "AccessibleRole.h"
michael@0 12 #include "AccessibleStates.h"
michael@0 13
michael@0 14 #include "Compatibility.h"
michael@0 15 #include "ia2AccessibleRelation.h"
michael@0 16 #include "IUnknownImpl.h"
michael@0 17 #include "nsCoreUtils.h"
michael@0 18 #include "nsIAccessibleTypes.h"
michael@0 19 #include "Relation.h"
michael@0 20
michael@0 21 #include "nsIPersistentProperties2.h"
michael@0 22 #include "nsISimpleEnumerator.h"
michael@0 23
michael@0 24 using namespace mozilla;
michael@0 25 using namespace mozilla::a11y;
michael@0 26
michael@0 27 ////////////////////////////////////////////////////////////////////////////////
michael@0 28 // ia2Accessible
michael@0 29 ////////////////////////////////////////////////////////////////////////////////
michael@0 30
michael@0 31 STDMETHODIMP
michael@0 32 ia2Accessible::QueryInterface(REFIID iid, void** ppv)
michael@0 33 {
michael@0 34 if (!ppv)
michael@0 35 return E_INVALIDARG;
michael@0 36
michael@0 37 *ppv = nullptr;
michael@0 38
michael@0 39 if (IID_IAccessible2_2 == iid)
michael@0 40 *ppv = static_cast<IAccessible2_2*>(this);
michael@0 41 else if (IID_IAccessible2 == iid && !Compatibility::IsIA2Off())
michael@0 42 *ppv = static_cast<IAccessible2*>(this);
michael@0 43
michael@0 44 if (*ppv) {
michael@0 45 (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
michael@0 46 return S_OK;
michael@0 47 }
michael@0 48
michael@0 49 return E_NOINTERFACE;
michael@0 50 }
michael@0 51
michael@0 52 ////////////////////////////////////////////////////////////////////////////////
michael@0 53 // IAccessible2
michael@0 54
michael@0 55 STDMETHODIMP
michael@0 56 ia2Accessible::get_nRelations(long* aNRelations)
michael@0 57 {
michael@0 58 A11Y_TRYBLOCK_BEGIN
michael@0 59
michael@0 60 if (!aNRelations)
michael@0 61 return E_INVALIDARG;
michael@0 62 *aNRelations = 0;
michael@0 63
michael@0 64 AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
michael@0 65 if (acc->IsDefunct())
michael@0 66 return CO_E_OBJNOTCONNECTED;
michael@0 67
michael@0 68 for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) {
michael@0 69 if (sRelationTypePairs[idx].second == IA2_RELATION_NULL)
michael@0 70 continue;
michael@0 71
michael@0 72 Relation rel = acc->RelationByType(sRelationTypePairs[idx].first);
michael@0 73 if (rel.Next())
michael@0 74 (*aNRelations)++;
michael@0 75 }
michael@0 76 return S_OK;
michael@0 77
michael@0 78 A11Y_TRYBLOCK_END
michael@0 79 }
michael@0 80
michael@0 81 STDMETHODIMP
michael@0 82 ia2Accessible::get_relation(long aRelationIndex,
michael@0 83 IAccessibleRelation** aRelation)
michael@0 84 {
michael@0 85 A11Y_TRYBLOCK_BEGIN
michael@0 86
michael@0 87 if (!aRelation)
michael@0 88 return E_INVALIDARG;
michael@0 89 *aRelation = nullptr;
michael@0 90
michael@0 91 AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
michael@0 92 if (acc->IsDefunct())
michael@0 93 return CO_E_OBJNOTCONNECTED;
michael@0 94
michael@0 95 long relIdx = 0;
michael@0 96 for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) {
michael@0 97 if (sRelationTypePairs[idx].second == IA2_RELATION_NULL)
michael@0 98 continue;
michael@0 99
michael@0 100 RelationType relationType = sRelationTypePairs[idx].first;
michael@0 101 Relation rel = acc->RelationByType(relationType);
michael@0 102 nsRefPtr<ia2AccessibleRelation> ia2Relation =
michael@0 103 new ia2AccessibleRelation(relationType, &rel);
michael@0 104 if (ia2Relation->HasTargets()) {
michael@0 105 if (relIdx == aRelationIndex) {
michael@0 106 ia2Relation.forget(aRelation);
michael@0 107 return S_OK;
michael@0 108 }
michael@0 109
michael@0 110 relIdx++;
michael@0 111 }
michael@0 112 }
michael@0 113
michael@0 114 return E_INVALIDARG;
michael@0 115
michael@0 116 A11Y_TRYBLOCK_END
michael@0 117 }
michael@0 118
michael@0 119 STDMETHODIMP
michael@0 120 ia2Accessible::get_relations(long aMaxRelations,
michael@0 121 IAccessibleRelation** aRelation,
michael@0 122 long *aNRelations)
michael@0 123 {
michael@0 124 A11Y_TRYBLOCK_BEGIN
michael@0 125
michael@0 126 if (!aRelation || !aNRelations)
michael@0 127 return E_INVALIDARG;
michael@0 128 *aNRelations = 0;
michael@0 129
michael@0 130 AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
michael@0 131 if (acc->IsDefunct())
michael@0 132 return CO_E_OBJNOTCONNECTED;
michael@0 133
michael@0 134 for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs) &&
michael@0 135 *aNRelations < aMaxRelations; idx++) {
michael@0 136 if (sRelationTypePairs[idx].second == IA2_RELATION_NULL)
michael@0 137 continue;
michael@0 138
michael@0 139 RelationType relationType = sRelationTypePairs[idx].first;
michael@0 140 Relation rel = acc->RelationByType(relationType);
michael@0 141 nsRefPtr<ia2AccessibleRelation> ia2Rel =
michael@0 142 new ia2AccessibleRelation(relationType, &rel);
michael@0 143 if (ia2Rel->HasTargets()) {
michael@0 144 ia2Rel.forget(aRelation + (*aNRelations));
michael@0 145 (*aNRelations)++;
michael@0 146 }
michael@0 147 }
michael@0 148 return S_OK;
michael@0 149
michael@0 150 A11Y_TRYBLOCK_END
michael@0 151 }
michael@0 152
michael@0 153 STDMETHODIMP
michael@0 154 ia2Accessible::role(long* aRole)
michael@0 155 {
michael@0 156 A11Y_TRYBLOCK_BEGIN
michael@0 157
michael@0 158 if (!aRole)
michael@0 159 return E_INVALIDARG;
michael@0 160 *aRole = 0;
michael@0 161
michael@0 162 AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
michael@0 163 if (acc->IsDefunct())
michael@0 164 return CO_E_OBJNOTCONNECTED;
michael@0 165
michael@0 166 #define ROLE(_geckoRole, stringRole, atkRole, macRole, \
michael@0 167 msaaRole, ia2Role, nameRule) \
michael@0 168 case roles::_geckoRole: \
michael@0 169 *aRole = ia2Role; \
michael@0 170 break;
michael@0 171
michael@0 172 a11y::role geckoRole = acc->Role();
michael@0 173 switch (geckoRole) {
michael@0 174 #include "RoleMap.h"
michael@0 175 default:
michael@0 176 MOZ_CRASH("Unknown role.");
michael@0 177 };
michael@0 178
michael@0 179 #undef ROLE
michael@0 180
michael@0 181 // Special case, if there is a ROLE_ROW inside of a ROLE_TREE_TABLE, then call
michael@0 182 // the IA2 role a ROLE_OUTLINEITEM.
michael@0 183 if (geckoRole == roles::ROW) {
michael@0 184 Accessible* xpParent = acc->Parent();
michael@0 185 if (xpParent && xpParent->Role() == roles::TREE_TABLE)
michael@0 186 *aRole = ROLE_SYSTEM_OUTLINEITEM;
michael@0 187 }
michael@0 188
michael@0 189 return S_OK;
michael@0 190
michael@0 191 A11Y_TRYBLOCK_END
michael@0 192 }
michael@0 193
michael@0 194 STDMETHODIMP
michael@0 195 ia2Accessible::scrollTo(enum IA2ScrollType aScrollType)
michael@0 196 {
michael@0 197 A11Y_TRYBLOCK_BEGIN
michael@0 198
michael@0 199 AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
michael@0 200 if (acc->IsDefunct())
michael@0 201 return CO_E_OBJNOTCONNECTED;
michael@0 202
michael@0 203 nsCoreUtils::ScrollTo(acc->Document()->PresShell(),
michael@0 204 acc->GetContent(), aScrollType);
michael@0 205 return S_OK;
michael@0 206
michael@0 207 A11Y_TRYBLOCK_END
michael@0 208 }
michael@0 209
michael@0 210 STDMETHODIMP
michael@0 211 ia2Accessible::scrollToPoint(enum IA2CoordinateType aCoordType,
michael@0 212 long aX, long aY)
michael@0 213 {
michael@0 214 A11Y_TRYBLOCK_BEGIN
michael@0 215
michael@0 216 AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
michael@0 217 if (acc->IsDefunct())
michael@0 218 return CO_E_OBJNOTCONNECTED;
michael@0 219
michael@0 220 uint32_t geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ?
michael@0 221 nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE :
michael@0 222 nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
michael@0 223
michael@0 224 nsresult rv = acc->ScrollToPoint(geckoCoordType, aX, aY);
michael@0 225 return GetHRESULT(rv);
michael@0 226
michael@0 227 A11Y_TRYBLOCK_END
michael@0 228 }
michael@0 229
michael@0 230 STDMETHODIMP
michael@0 231 ia2Accessible::get_groupPosition(long* aGroupLevel,
michael@0 232 long* aSimilarItemsInGroup,
michael@0 233 long* aPositionInGroup)
michael@0 234 {
michael@0 235 A11Y_TRYBLOCK_BEGIN
michael@0 236
michael@0 237 if (!aGroupLevel || !aSimilarItemsInGroup || !aPositionInGroup)
michael@0 238 return E_INVALIDARG;
michael@0 239
michael@0 240 *aGroupLevel = 0;
michael@0 241 *aSimilarItemsInGroup = 0;
michael@0 242 *aPositionInGroup = 0;
michael@0 243
michael@0 244 AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
michael@0 245 if (acc->IsDefunct())
michael@0 246 return CO_E_OBJNOTCONNECTED;
michael@0 247
michael@0 248 GroupPos groupPos = acc->GroupPosition();
michael@0 249
michael@0 250 // Group information for accessibles having level only (like html headings
michael@0 251 // elements) isn't exposed by this method. AT should look for 'level' object
michael@0 252 // attribute.
michael@0 253 if (!groupPos.setSize && !groupPos.posInSet)
michael@0 254 return S_FALSE;
michael@0 255
michael@0 256 *aGroupLevel = groupPos.level;
michael@0 257 *aSimilarItemsInGroup = groupPos.setSize;
michael@0 258 *aPositionInGroup = groupPos.posInSet;
michael@0 259
michael@0 260 return S_OK;
michael@0 261
michael@0 262 A11Y_TRYBLOCK_END
michael@0 263 }
michael@0 264
michael@0 265 STDMETHODIMP
michael@0 266 ia2Accessible::get_states(AccessibleStates* aStates)
michael@0 267 {
michael@0 268 A11Y_TRYBLOCK_BEGIN
michael@0 269
michael@0 270 if (!aStates)
michael@0 271 return E_INVALIDARG;
michael@0 272 *aStates = 0;
michael@0 273
michael@0 274 // XXX: bug 344674 should come with better approach that we have here.
michael@0 275
michael@0 276 AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
michael@0 277 uint64_t state = acc->State();
michael@0 278
michael@0 279 if (state & states::INVALID)
michael@0 280 *aStates |= IA2_STATE_INVALID_ENTRY;
michael@0 281 if (state & states::REQUIRED)
michael@0 282 *aStates |= IA2_STATE_REQUIRED;
michael@0 283
michael@0 284 // The following IA2 states are not supported by Gecko
michael@0 285 // IA2_STATE_ARMED
michael@0 286 // IA2_STATE_MANAGES_DESCENDANTS
michael@0 287 // IA2_STATE_ICONIFIED
michael@0 288 // IA2_STATE_INVALID // This is not a state, it is the absence of a state
michael@0 289
michael@0 290 if (state & states::ACTIVE)
michael@0 291 *aStates |= IA2_STATE_ACTIVE;
michael@0 292 if (state & states::DEFUNCT)
michael@0 293 *aStates |= IA2_STATE_DEFUNCT;
michael@0 294 if (state & states::EDITABLE)
michael@0 295 *aStates |= IA2_STATE_EDITABLE;
michael@0 296 if (state & states::HORIZONTAL)
michael@0 297 *aStates |= IA2_STATE_HORIZONTAL;
michael@0 298 if (state & states::MODAL)
michael@0 299 *aStates |= IA2_STATE_MODAL;
michael@0 300 if (state & states::MULTI_LINE)
michael@0 301 *aStates |= IA2_STATE_MULTI_LINE;
michael@0 302 if (state & states::OPAQUE1)
michael@0 303 *aStates |= IA2_STATE_OPAQUE;
michael@0 304 if (state & states::SELECTABLE_TEXT)
michael@0 305 *aStates |= IA2_STATE_SELECTABLE_TEXT;
michael@0 306 if (state & states::SINGLE_LINE)
michael@0 307 *aStates |= IA2_STATE_SINGLE_LINE;
michael@0 308 if (state & states::STALE)
michael@0 309 *aStates |= IA2_STATE_STALE;
michael@0 310 if (state & states::SUPPORTS_AUTOCOMPLETION)
michael@0 311 *aStates |= IA2_STATE_SUPPORTS_AUTOCOMPLETION;
michael@0 312 if (state & states::TRANSIENT)
michael@0 313 *aStates |= IA2_STATE_TRANSIENT;
michael@0 314 if (state & states::VERTICAL)
michael@0 315 *aStates |= IA2_STATE_VERTICAL;
michael@0 316 if (state & states::CHECKED)
michael@0 317 *aStates |= IA2_STATE_CHECKABLE;
michael@0 318 if (state & states::PINNED)
michael@0 319 *aStates |= IA2_STATE_PINNED;
michael@0 320
michael@0 321 return S_OK;
michael@0 322
michael@0 323 A11Y_TRYBLOCK_END
michael@0 324 }
michael@0 325
michael@0 326 STDMETHODIMP
michael@0 327 ia2Accessible::get_extendedRole(BSTR* aExtendedRole)
michael@0 328 {
michael@0 329 A11Y_TRYBLOCK_BEGIN
michael@0 330
michael@0 331 if (!aExtendedRole)
michael@0 332 return E_INVALIDARG;
michael@0 333
michael@0 334 *aExtendedRole = nullptr;
michael@0 335 return E_NOTIMPL;
michael@0 336
michael@0 337 A11Y_TRYBLOCK_END
michael@0 338 }
michael@0 339
michael@0 340 STDMETHODIMP
michael@0 341 ia2Accessible::get_localizedExtendedRole(BSTR* aLocalizedExtendedRole)
michael@0 342 {
michael@0 343 A11Y_TRYBLOCK_BEGIN
michael@0 344
michael@0 345 if (!aLocalizedExtendedRole)
michael@0 346 return E_INVALIDARG;
michael@0 347
michael@0 348 *aLocalizedExtendedRole = nullptr;
michael@0 349 return E_NOTIMPL;
michael@0 350
michael@0 351 A11Y_TRYBLOCK_END
michael@0 352 }
michael@0 353
michael@0 354 STDMETHODIMP
michael@0 355 ia2Accessible::get_nExtendedStates(long* aNExtendedStates)
michael@0 356 {
michael@0 357 A11Y_TRYBLOCK_BEGIN
michael@0 358
michael@0 359 if (!aNExtendedStates)
michael@0 360 return E_INVALIDARG;
michael@0 361
michael@0 362 *aNExtendedStates = 0;
michael@0 363 return E_NOTIMPL;
michael@0 364
michael@0 365 A11Y_TRYBLOCK_END
michael@0 366 }
michael@0 367
michael@0 368 STDMETHODIMP
michael@0 369 ia2Accessible::get_extendedStates(long aMaxExtendedStates,
michael@0 370 BSTR** aExtendedStates,
michael@0 371 long* aNExtendedStates)
michael@0 372 {
michael@0 373 A11Y_TRYBLOCK_BEGIN
michael@0 374
michael@0 375 if (!aExtendedStates || !aNExtendedStates)
michael@0 376 return E_INVALIDARG;
michael@0 377
michael@0 378 *aExtendedStates = nullptr;
michael@0 379 *aNExtendedStates = 0;
michael@0 380 return E_NOTIMPL;
michael@0 381
michael@0 382 A11Y_TRYBLOCK_END
michael@0 383 }
michael@0 384
michael@0 385 STDMETHODIMP
michael@0 386 ia2Accessible::get_localizedExtendedStates(long aMaxLocalizedExtendedStates,
michael@0 387 BSTR** aLocalizedExtendedStates,
michael@0 388 long* aNLocalizedExtendedStates)
michael@0 389 {
michael@0 390 A11Y_TRYBLOCK_BEGIN
michael@0 391
michael@0 392 if (!aLocalizedExtendedStates || !aNLocalizedExtendedStates)
michael@0 393 return E_INVALIDARG;
michael@0 394
michael@0 395 *aLocalizedExtendedStates = nullptr;
michael@0 396 *aNLocalizedExtendedStates = 0;
michael@0 397 return E_NOTIMPL;
michael@0 398
michael@0 399 A11Y_TRYBLOCK_END
michael@0 400 }
michael@0 401
michael@0 402 STDMETHODIMP
michael@0 403 ia2Accessible::get_uniqueID(long* aUniqueID)
michael@0 404 {
michael@0 405 A11Y_TRYBLOCK_BEGIN
michael@0 406
michael@0 407 if (!aUniqueID)
michael@0 408 return E_INVALIDARG;
michael@0 409
michael@0 410 AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
michael@0 411 *aUniqueID = - reinterpret_cast<intptr_t>(acc->UniqueID());
michael@0 412 return S_OK;
michael@0 413
michael@0 414 A11Y_TRYBLOCK_END
michael@0 415 }
michael@0 416
michael@0 417 STDMETHODIMP
michael@0 418 ia2Accessible::get_windowHandle(HWND* aWindowHandle)
michael@0 419 {
michael@0 420 A11Y_TRYBLOCK_BEGIN
michael@0 421
michael@0 422 if (!aWindowHandle)
michael@0 423 return E_INVALIDARG;
michael@0 424 *aWindowHandle = 0;
michael@0 425
michael@0 426 AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
michael@0 427 if (acc->IsDefunct())
michael@0 428 return CO_E_OBJNOTCONNECTED;
michael@0 429
michael@0 430 *aWindowHandle = AccessibleWrap::GetHWNDFor(acc);
michael@0 431 return S_OK;
michael@0 432
michael@0 433 A11Y_TRYBLOCK_END
michael@0 434 }
michael@0 435
michael@0 436 STDMETHODIMP
michael@0 437 ia2Accessible::get_indexInParent(long* aIndexInParent)
michael@0 438 {
michael@0 439 A11Y_TRYBLOCK_BEGIN
michael@0 440
michael@0 441 if (!aIndexInParent)
michael@0 442 return E_INVALIDARG;
michael@0 443 *aIndexInParent = -1;
michael@0 444
michael@0 445 AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
michael@0 446 if (acc->IsDefunct())
michael@0 447 return CO_E_OBJNOTCONNECTED;
michael@0 448
michael@0 449 *aIndexInParent = acc->IndexInParent();
michael@0 450 if (*aIndexInParent == -1)
michael@0 451 return S_FALSE;
michael@0 452
michael@0 453 return S_OK;
michael@0 454
michael@0 455 A11Y_TRYBLOCK_END
michael@0 456 }
michael@0 457
michael@0 458 STDMETHODIMP
michael@0 459 ia2Accessible::get_locale(IA2Locale* aLocale)
michael@0 460 {
michael@0 461 A11Y_TRYBLOCK_BEGIN
michael@0 462
michael@0 463 if (!aLocale)
michael@0 464 return E_INVALIDARG;
michael@0 465
michael@0 466 // Language codes consist of a primary code and a possibly empty series of
michael@0 467 // subcodes: language-code = primary-code ( "-" subcode )*
michael@0 468 // Two-letter primary codes are reserved for [ISO639] language abbreviations.
michael@0 469 // Any two-letter subcode is understood to be a [ISO3166] country code.
michael@0 470
michael@0 471 AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
michael@0 472 if (acc->IsDefunct())
michael@0 473 return CO_E_OBJNOTCONNECTED;
michael@0 474
michael@0 475 nsAutoString lang;
michael@0 476 acc->Language(lang);
michael@0 477
michael@0 478 // If primary code consists from two letters then expose it as language.
michael@0 479 int32_t offset = lang.FindChar('-', 0);
michael@0 480 if (offset == -1) {
michael@0 481 if (lang.Length() == 2) {
michael@0 482 aLocale->language = ::SysAllocString(lang.get());
michael@0 483 return S_OK;
michael@0 484 }
michael@0 485 } else if (offset == 2) {
michael@0 486 aLocale->language = ::SysAllocStringLen(lang.get(), 2);
michael@0 487
michael@0 488 // If the first subcode consists from two letters then expose it as
michael@0 489 // country.
michael@0 490 offset = lang.FindChar('-', 3);
michael@0 491 if (offset == -1) {
michael@0 492 if (lang.Length() == 5) {
michael@0 493 aLocale->country = ::SysAllocString(lang.get() + 3);
michael@0 494 return S_OK;
michael@0 495 }
michael@0 496 } else if (offset == 5) {
michael@0 497 aLocale->country = ::SysAllocStringLen(lang.get() + 3, 2);
michael@0 498 }
michael@0 499 }
michael@0 500
michael@0 501 // Expose as a string if primary code or subcode cannot point to language or
michael@0 502 // country abbreviations or if there are more than one subcode.
michael@0 503 aLocale->variant = ::SysAllocString(lang.get());
michael@0 504 return S_OK;
michael@0 505
michael@0 506 A11Y_TRYBLOCK_END
michael@0 507 }
michael@0 508
michael@0 509 STDMETHODIMP
michael@0 510 ia2Accessible::get_attributes(BSTR* aAttributes)
michael@0 511 {
michael@0 512 A11Y_TRYBLOCK_BEGIN
michael@0 513
michael@0 514 if (!aAttributes)
michael@0 515 return E_INVALIDARG;
michael@0 516 *aAttributes = nullptr;
michael@0 517
michael@0 518 AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
michael@0 519 if (acc->IsDefunct())
michael@0 520 return CO_E_OBJNOTCONNECTED;
michael@0 521
michael@0 522 // The format is name:value;name:value; with \ for escaping these
michael@0 523 // characters ":;=,\".
michael@0 524 nsCOMPtr<nsIPersistentProperties> attributes = acc->Attributes();
michael@0 525 return ConvertToIA2Attributes(attributes, aAttributes);
michael@0 526
michael@0 527 A11Y_TRYBLOCK_END
michael@0 528 }
michael@0 529
michael@0 530 ////////////////////////////////////////////////////////////////////////////////
michael@0 531 // IAccessible2_2
michael@0 532
michael@0 533 STDMETHODIMP
michael@0 534 ia2Accessible::get_attribute(BSTR name, VARIANT* aAttribute)
michael@0 535 {
michael@0 536 A11Y_TRYBLOCK_BEGIN
michael@0 537
michael@0 538 if (!aAttribute)
michael@0 539 return E_INVALIDARG;
michael@0 540
michael@0 541 return E_NOTIMPL;
michael@0 542
michael@0 543 A11Y_TRYBLOCK_END
michael@0 544 }
michael@0 545
michael@0 546 STDMETHODIMP
michael@0 547 ia2Accessible::get_accessibleWithCaret(IUnknown** aAccessible,
michael@0 548 long* aCaretOffset)
michael@0 549 {
michael@0 550 A11Y_TRYBLOCK_BEGIN
michael@0 551
michael@0 552 if (!aAccessible || !aCaretOffset)
michael@0 553 return E_INVALIDARG;
michael@0 554
michael@0 555 *aAccessible = nullptr;
michael@0 556 *aCaretOffset = -1;
michael@0 557 return E_NOTIMPL;
michael@0 558
michael@0 559 A11Y_TRYBLOCK_END
michael@0 560 }
michael@0 561
michael@0 562 STDMETHODIMP
michael@0 563 ia2Accessible::get_relationTargetsOfType(BSTR aType,
michael@0 564 long aMaxTargets,
michael@0 565 IUnknown*** aTargets,
michael@0 566 long* aNTargets)
michael@0 567 {
michael@0 568 A11Y_TRYBLOCK_BEGIN
michael@0 569
michael@0 570 if (!aTargets || !aNTargets)
michael@0 571 return E_INVALIDARG;
michael@0 572 *aNTargets = 0;
michael@0 573
michael@0 574 Maybe<RelationType> relationType;
michael@0 575 for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) {
michael@0 576 if (wcscmp(aType, sRelationTypePairs[idx].second) == 0) {
michael@0 577 relationType.construct(sRelationTypePairs[idx].first);
michael@0 578 break;
michael@0 579 }
michael@0 580 }
michael@0 581 if (relationType.empty())
michael@0 582 return E_INVALIDARG;
michael@0 583
michael@0 584 AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
michael@0 585 if (acc->IsDefunct())
michael@0 586 return CO_E_OBJNOTCONNECTED;
michael@0 587
michael@0 588 Relation rel = acc->RelationByType(relationType.ref());
michael@0 589
michael@0 590 nsTArray<Accessible*> targets;
michael@0 591 Accessible* target = nullptr;
michael@0 592 while ((target = rel.Next()) &&
michael@0 593 static_cast<long>(targets.Length()) <= aMaxTargets)
michael@0 594 targets.AppendElement(target);
michael@0 595
michael@0 596 *aNTargets = targets.Length();
michael@0 597 *aTargets = static_cast<IUnknown**>(
michael@0 598 ::CoTaskMemAlloc(sizeof(IUnknown*) * *aNTargets));
michael@0 599 if (!*aTargets)
michael@0 600 return E_OUTOFMEMORY;
michael@0 601
michael@0 602 for (int32_t i = 0; i < *aNTargets; i++) {
michael@0 603 AccessibleWrap* target= static_cast<AccessibleWrap*>(targets[i]);
michael@0 604 (*aTargets)[i] = static_cast<IAccessible2*>(target);
michael@0 605 (*aTargets)[i]->AddRef();
michael@0 606 }
michael@0 607
michael@0 608 return S_OK;
michael@0 609
michael@0 610 A11Y_TRYBLOCK_END
michael@0 611 }
michael@0 612
michael@0 613 ////////////////////////////////////////////////////////////////////////////////
michael@0 614 // Helpers
michael@0 615
michael@0 616 HRESULT
michael@0 617 ia2Accessible::ConvertToIA2Attributes(nsIPersistentProperties* aAttributes,
michael@0 618 BSTR* aIA2Attributes)
michael@0 619 {
michael@0 620 *aIA2Attributes = nullptr;
michael@0 621
michael@0 622 // The format is name:value;name:value; with \ for escaping these
michael@0 623 // characters ":;=,\".
michael@0 624
michael@0 625 if (!aAttributes)
michael@0 626 return S_FALSE;
michael@0 627
michael@0 628 nsCOMPtr<nsISimpleEnumerator> propEnum;
michael@0 629 aAttributes->Enumerate(getter_AddRefs(propEnum));
michael@0 630 if (!propEnum)
michael@0 631 return E_FAIL;
michael@0 632
michael@0 633 nsAutoString strAttrs;
michael@0 634
michael@0 635 const char kCharsToEscape[] = ":;=,\\";
michael@0 636
michael@0 637 bool hasMore = false;
michael@0 638 while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
michael@0 639 nsCOMPtr<nsISupports> propSupports;
michael@0 640 propEnum->GetNext(getter_AddRefs(propSupports));
michael@0 641
michael@0 642 nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(propSupports));
michael@0 643 if (!propElem)
michael@0 644 return E_FAIL;
michael@0 645
michael@0 646 nsAutoCString name;
michael@0 647 if (NS_FAILED(propElem->GetKey(name)))
michael@0 648 return E_FAIL;
michael@0 649
michael@0 650 int32_t offset = 0;
michael@0 651 while ((offset = name.FindCharInSet(kCharsToEscape, offset)) != kNotFound) {
michael@0 652 name.Insert('\\', offset);
michael@0 653 offset += 2;
michael@0 654 }
michael@0 655
michael@0 656 nsAutoString value;
michael@0 657 if (NS_FAILED(propElem->GetValue(value)))
michael@0 658 return E_FAIL;
michael@0 659
michael@0 660 offset = 0;
michael@0 661 while ((offset = value.FindCharInSet(kCharsToEscape, offset)) != kNotFound) {
michael@0 662 value.Insert('\\', offset);
michael@0 663 offset += 2;
michael@0 664 }
michael@0 665
michael@0 666 AppendUTF8toUTF16(name, strAttrs);
michael@0 667 strAttrs.Append(':');
michael@0 668 strAttrs.Append(value);
michael@0 669 strAttrs.Append(';');
michael@0 670 }
michael@0 671
michael@0 672 if (strAttrs.IsEmpty())
michael@0 673 return S_FALSE;
michael@0 674
michael@0 675 *aIA2Attributes = ::SysAllocStringLen(strAttrs.get(), strAttrs.Length());
michael@0 676 return *aIA2Attributes ? S_OK : E_OUTOFMEMORY;
michael@0 677 }

mercurial