1 /* 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "AccessibilityUIElement.h" 28 29 #include "AccessibilityController.h" 30 #include "DumpRenderTree.h" 31 #include "FrameLoadDelegate.h" 32 #include <JavaScriptCore/JSStringRef.h> 33 #include <tchar.h> 34 #include <string> 35 36 using std::wstring; 37 38 static COMPtr<IAccessibleComparable> comparableObject(IAccessible* accessible) 39 { 40 COMPtr<IServiceProvider> serviceProvider(Query, accessible); 41 if (!serviceProvider) 42 return 0; 43 COMPtr<IAccessibleComparable> comparable; 44 serviceProvider->QueryService(SID_AccessibleComparable, __uuidof(IAccessibleComparable), reinterpret_cast<void**>(&comparable)); 45 return comparable; 46 } 47 48 AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element) 49 : m_element(element) 50 { 51 } 52 53 AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other) 54 : m_element(other.m_element) 55 { 56 } 57 58 AccessibilityUIElement::~AccessibilityUIElement() 59 { 60 } 61 62 bool AccessibilityUIElement::isEqual(AccessibilityUIElement* otherElement) 63 { 64 COMPtr<IAccessibleComparable> comparable = comparableObject(m_element.get()); 65 COMPtr<IAccessibleComparable> otherComparable = comparableObject(otherElement->m_element.get()); 66 if (!comparable || !otherComparable) 67 return false; 68 BOOL isSame = FALSE; 69 if (FAILED(comparable->isSameObject(otherComparable.get(), &isSame))) 70 return false; 71 return isSame; 72 } 73 74 void AccessibilityUIElement::getLinkedUIElements(Vector<AccessibilityUIElement>&) 75 { 76 } 77 78 void AccessibilityUIElement::getDocumentLinks(Vector<AccessibilityUIElement>&) 79 { 80 } 81 82 void AccessibilityUIElement::getChildren(Vector<AccessibilityUIElement>& children) 83 { 84 long childCount; 85 if (FAILED(m_element->get_accChildCount(&childCount))) 86 return; 87 for (long i = 0; i < childCount; ++i) 88 children.append(getChildAtIndex(i)); 89 } 90 91 void AccessibilityUIElement::getChildrenWithRange(Vector<AccessibilityUIElement>& elementVector, unsigned location, unsigned length) 92 { 93 long childCount; 94 unsigned appendedCount = 0; 95 if (FAILED(m_element->get_accChildCount(&childCount))) 96 return; 97 for (long i = location; i < childCount && appendedCount < length; ++i, ++appendedCount) 98 elementVector.append(getChildAtIndex(i)); 99 } 100 101 int AccessibilityUIElement::childrenCount() 102 { 103 long childCount; 104 m_element->get_accChildCount(&childCount); 105 return childCount; 106 } 107 108 int AccessibilityUIElement::rowCount() 109 { 110 // FIXME: implement 111 return 0; 112 } 113 114 int AccessibilityUIElement::columnCount() 115 { 116 // FIXME: implement 117 return 0; 118 } 119 120 AccessibilityUIElement AccessibilityUIElement::elementAtPoint(int x, int y) 121 { 122 return 0; 123 } 124 125 AccessibilityUIElement AccessibilityUIElement::linkedUIElementAtIndex(unsigned index) 126 { 127 // FIXME: implement 128 return 0; 129 } 130 131 AccessibilityUIElement AccessibilityUIElement::getChildAtIndex(unsigned index) 132 { 133 COMPtr<IDispatch> child; 134 VARIANT vChild; 135 ::VariantInit(&vChild); 136 V_VT(&vChild) = VT_I4; 137 // In MSAA, index 0 is the object itself. 138 V_I4(&vChild) = index + 1; 139 if (FAILED(m_element->get_accChild(vChild, &child))) 140 return 0; 141 return COMPtr<IAccessible>(Query, child); 142 } 143 144 unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element) 145 { 146 // FIXME: implement 147 return 0; 148 } 149 150 JSStringRef AccessibilityUIElement::allAttributes() 151 { 152 return JSStringCreateWithCharacters(0, 0); 153 } 154 155 JSStringRef AccessibilityUIElement::attributesOfLinkedUIElements() 156 { 157 return JSStringCreateWithCharacters(0, 0); 158 } 159 160 JSStringRef AccessibilityUIElement::attributesOfDocumentLinks() 161 { 162 return JSStringCreateWithCharacters(0, 0); 163 } 164 165 AccessibilityUIElement AccessibilityUIElement::titleUIElement() 166 { 167 return 0; 168 } 169 170 AccessibilityUIElement AccessibilityUIElement::parentElement() 171 { 172 COMPtr<IDispatch> parent; 173 m_element->get_accParent(&parent); 174 175 COMPtr<IAccessible> parentAccessible(Query, parent); 176 return parentAccessible; 177 } 178 179 JSStringRef AccessibilityUIElement::attributesOfChildren() 180 { 181 return JSStringCreateWithCharacters(0, 0); 182 } 183 184 JSStringRef AccessibilityUIElement::parameterizedAttributeNames() 185 { 186 return JSStringCreateWithCharacters(0, 0); 187 } 188 189 static VARIANT& self() 190 { 191 static VARIANT vSelf; 192 static bool haveInitialized; 193 194 if (!haveInitialized) { 195 ::VariantInit(&vSelf); 196 V_VT(&vSelf) = VT_I4; 197 V_I4(&vSelf) = CHILDID_SELF; 198 } 199 return vSelf; 200 } 201 202 JSStringRef AccessibilityUIElement::role() 203 { 204 VARIANT vRole; 205 if (FAILED(m_element->get_accRole(self(), &vRole))) 206 return JSStringCreateWithCharacters(0, 0); 207 208 ASSERT(V_VT(&vRole) == VT_I4 || V_VT(&vRole) == VT_BSTR); 209 210 wstring result; 211 if (V_VT(&vRole) == VT_I4) { 212 unsigned roleTextLength = ::GetRoleText(V_I4(&vRole), 0, 0) + 1; 213 214 Vector<TCHAR> roleText(roleTextLength); 215 216 ::GetRoleText(V_I4(&vRole), roleText.data(), roleTextLength); 217 218 result = roleText.data(); 219 } else if (V_VT(&vRole) == VT_BSTR) 220 result = wstring(V_BSTR(&vRole), ::SysStringLen(V_BSTR(&vRole))); 221 222 ::VariantClear(&vRole); 223 224 return JSStringCreateWithCharacters(result.data(), result.length()); 225 } 226 227 JSStringRef AccessibilityUIElement::subrole() 228 { 229 return 0; 230 } 231 232 JSStringRef AccessibilityUIElement::roleDescription() 233 { 234 return 0; 235 } 236 237 JSStringRef AccessibilityUIElement::title() 238 { 239 BSTR titleBSTR; 240 if (FAILED(m_element->get_accName(self(), &titleBSTR)) || !titleBSTR) 241 return JSStringCreateWithCharacters(0, 0); 242 wstring title(titleBSTR, SysStringLen(titleBSTR)); 243 ::SysFreeString(titleBSTR); 244 return JSStringCreateWithCharacters(title.data(), title.length()); 245 } 246 247 JSStringRef AccessibilityUIElement::description() 248 { 249 BSTR descriptionBSTR; 250 if (FAILED(m_element->get_accDescription(self(), &descriptionBSTR)) || !descriptionBSTR) 251 return JSStringCreateWithCharacters(0, 0); 252 wstring description(descriptionBSTR, SysStringLen(descriptionBSTR)); 253 ::SysFreeString(descriptionBSTR); 254 return JSStringCreateWithCharacters(description.data(), description.length()); 255 } 256 257 JSStringRef AccessibilityUIElement::stringValue() 258 { 259 return JSStringCreateWithCharacters(0, 0); 260 } 261 262 JSStringRef AccessibilityUIElement::language() 263 { 264 return JSStringCreateWithCharacters(0, 0); 265 } 266 267 JSStringRef AccessibilityUIElement::helpText() const 268 { 269 return 0; 270 } 271 272 double AccessibilityUIElement::x() 273 { 274 long x, y, width, height; 275 if (FAILED(m_element->accLocation(&x, &y, &width, &height, self()))) 276 return 0; 277 return x; 278 } 279 280 double AccessibilityUIElement::y() 281 { 282 long x, y, width, height; 283 if (FAILED(m_element->accLocation(&x, &y, &width, &height, self()))) 284 return 0; 285 return y; 286 } 287 288 double AccessibilityUIElement::width() 289 { 290 long x, y, width, height; 291 if (FAILED(m_element->accLocation(&x, &y, &width, &height, self()))) 292 return 0; 293 return width; 294 } 295 296 double AccessibilityUIElement::height() 297 { 298 long x, y, width, height; 299 if (FAILED(m_element->accLocation(&x, &y, &width, &height, self()))) 300 return 0; 301 return height; 302 } 303 304 double AccessibilityUIElement::clickPointX() 305 { 306 return 0; 307 } 308 309 double AccessibilityUIElement::clickPointY() 310 { 311 return 0; 312 } 313 314 JSStringRef AccessibilityUIElement::valueDescription() 315 { 316 return 0; 317 } 318 319 static DWORD accessibilityState(COMPtr<IAccessible> element) 320 { 321 VARIANT state; 322 element->get_accState(self(), &state); 323 324 ASSERT(V_VT(&state) == VT_I4); 325 326 DWORD result = state.lVal; 327 VariantClear(&state); 328 329 return result; 330 } 331 332 bool AccessibilityUIElement::isFocused() const 333 { 334 // FIXME: implement 335 return false; 336 } 337 338 bool AccessibilityUIElement::isSelected() const 339 { 340 DWORD state = accessibilityState(m_element); 341 return (state & STATE_SYSTEM_SELECTED) == STATE_SYSTEM_SELECTED; 342 } 343 344 int AccessibilityUIElement::hierarchicalLevel() const 345 { 346 return 0; 347 } 348 349 bool AccessibilityUIElement::ariaIsGrabbed() const 350 { 351 return false; 352 } 353 354 JSStringRef AccessibilityUIElement::ariaDropEffects() const 355 { 356 return 0; 357 } 358 359 bool AccessibilityUIElement::isExpanded() const 360 { 361 return false; 362 } 363 364 bool AccessibilityUIElement::isChecked() const 365 { 366 VARIANT vState; 367 if (FAILED(m_element->get_accState(self(), &vState))) 368 return false; 369 370 return vState.lVal & STATE_SYSTEM_CHECKED; 371 } 372 373 JSStringRef AccessibilityUIElement::orientation() const 374 { 375 return 0; 376 } 377 378 double AccessibilityUIElement::intValue() const 379 { 380 BSTR valueBSTR; 381 if (FAILED(m_element->get_accValue(self(), &valueBSTR)) || !valueBSTR) 382 return 0; 383 wstring value(valueBSTR, SysStringLen(valueBSTR)); 384 ::SysFreeString(valueBSTR); 385 TCHAR* ignored; 386 return _tcstod(value.data(), &ignored); 387 } 388 389 double AccessibilityUIElement::minValue() 390 { 391 return 0; 392 } 393 394 double AccessibilityUIElement::maxValue() 395 { 396 return 0; 397 } 398 399 bool AccessibilityUIElement::isActionSupported(JSStringRef action) 400 { 401 return false; 402 } 403 404 bool AccessibilityUIElement::isEnabled() 405 { 406 DWORD state = accessibilityState(m_element); 407 return (state & STATE_SYSTEM_UNAVAILABLE) != STATE_SYSTEM_UNAVAILABLE; 408 } 409 410 bool AccessibilityUIElement::isRequired() const 411 { 412 return false; 413 } 414 415 416 int AccessibilityUIElement::insertionPointLineNumber() 417 { 418 return 0; 419 } 420 421 JSStringRef AccessibilityUIElement::attributesOfColumnHeaders() 422 { 423 return JSStringCreateWithCharacters(0, 0); 424 } 425 426 JSStringRef AccessibilityUIElement::attributesOfRowHeaders() 427 { 428 return JSStringCreateWithCharacters(0, 0); 429 } 430 431 JSStringRef AccessibilityUIElement::attributesOfColumns() 432 { 433 return JSStringCreateWithCharacters(0, 0); 434 } 435 436 JSStringRef AccessibilityUIElement::attributesOfRows() 437 { 438 return JSStringCreateWithCharacters(0, 0); 439 } 440 441 JSStringRef AccessibilityUIElement::attributesOfVisibleCells() 442 { 443 return JSStringCreateWithCharacters(0, 0); 444 } 445 446 JSStringRef AccessibilityUIElement::attributesOfHeader() 447 { 448 return JSStringCreateWithCharacters(0, 0); 449 } 450 451 int AccessibilityUIElement::indexInTable() 452 { 453 return 0; 454 } 455 456 JSStringRef AccessibilityUIElement::rowIndexRange() 457 { 458 return JSStringCreateWithCharacters(0, 0); 459 } 460 461 JSStringRef AccessibilityUIElement::columnIndexRange() 462 { 463 return JSStringCreateWithCharacters(0, 0); 464 } 465 466 int AccessibilityUIElement::lineForIndex(int) 467 { 468 return 0; 469 } 470 471 JSStringRef AccessibilityUIElement::boundsForRange(unsigned location, unsigned length) 472 { 473 return JSStringCreateWithCharacters(0, 0); 474 } 475 476 JSStringRef AccessibilityUIElement::stringForRange(unsigned, unsigned) 477 { 478 return JSStringCreateWithCharacters(0, 0); 479 } 480 481 JSStringRef AccessibilityUIElement::attributedStringForRange(unsigned, unsigned) 482 { 483 return JSStringCreateWithCharacters(0, 0); 484 } 485 486 bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned, unsigned) 487 { 488 return false; 489 } 490 491 AccessibilityUIElement AccessibilityUIElement::cellForColumnAndRow(unsigned column, unsigned row) 492 { 493 return 0; 494 } 495 496 JSStringRef AccessibilityUIElement::selectedTextRange() 497 { 498 return JSStringCreateWithCharacters(0, 0); 499 } 500 501 void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length) 502 { 503 } 504 505 JSStringRef AccessibilityUIElement::stringAttributeValue(JSStringRef attribute) 506 { 507 // FIXME: implement 508 return JSStringCreateWithCharacters(0, 0); 509 } 510 511 bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute) 512 { 513 // FIXME: implement 514 return false; 515 } 516 517 bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute) 518 { 519 return false; 520 } 521 522 bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute) 523 { 524 return false; 525 } 526 527 void AccessibilityUIElement::increment() 528 { 529 } 530 531 void AccessibilityUIElement::decrement() 532 { 533 } 534 535 void AccessibilityUIElement::showMenu() 536 { 537 ASSERT(hasPopup()); 538 m_element->accDoDefaultAction(self()); 539 } 540 541 void AccessibilityUIElement::press() 542 { 543 // FIXME: implement 544 } 545 546 AccessibilityUIElement AccessibilityUIElement::disclosedRowAtIndex(unsigned index) 547 { 548 return 0; 549 } 550 551 AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index) 552 { 553 return 0; 554 } 555 556 AccessibilityUIElement AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index) 557 { 558 return 0; 559 } 560 561 AccessibilityUIElement AccessibilityUIElement::selectedRowAtIndex(unsigned index) 562 { 563 return 0; 564 } 565 566 AccessibilityUIElement AccessibilityUIElement::disclosedByRow() 567 { 568 return 0; 569 } 570 571 JSStringRef AccessibilityUIElement::accessibilityValue() const 572 { 573 BSTR valueBSTR; 574 if (FAILED(m_element->get_accValue(self(), &valueBSTR)) || !valueBSTR) 575 return JSStringCreateWithCharacters(0, 0); 576 577 wstring value(valueBSTR, SysStringLen(valueBSTR)); 578 ::SysFreeString(valueBSTR); 579 580 return JSStringCreateWithCharacters(value.data(), value.length()); 581 } 582 583 584 JSStringRef AccessibilityUIElement::documentEncoding() 585 { 586 return JSStringCreateWithCharacters(0, 0); 587 } 588 589 JSStringRef AccessibilityUIElement::documentURI() 590 { 591 return JSStringCreateWithCharacters(0, 0); 592 } 593 594 JSStringRef AccessibilityUIElement::url() 595 { 596 // FIXME: implement 597 return JSStringCreateWithCharacters(0, 0); 598 } 599 600 bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallback) 601 { 602 if (!functionCallback) 603 return false; 604 605 sharedFrameLoadDelegate->accessibilityController()->addNotificationListener(m_element, functionCallback); 606 return true; 607 } 608 609 void AccessibilityUIElement::removeNotificationListener() 610 { 611 // FIXME: implement 612 } 613 614 bool AccessibilityUIElement::isFocusable() const 615 { 616 // FIXME: implement 617 return false; 618 } 619 620 bool AccessibilityUIElement::isSelectable() const 621 { 622 DWORD state = accessibilityState(m_element); 623 return (state & STATE_SYSTEM_SELECTABLE) == STATE_SYSTEM_SELECTABLE; 624 } 625 626 bool AccessibilityUIElement::isMultiSelectable() const 627 { 628 DWORD multiSelectable = STATE_SYSTEM_EXTSELECTABLE | STATE_SYSTEM_MULTISELECTABLE; 629 DWORD state = accessibilityState(m_element); 630 return (state & multiSelectable) == multiSelectable; 631 } 632 633 bool AccessibilityUIElement::isVisible() const 634 { 635 DWORD state = accessibilityState(m_element); 636 return (state & STATE_SYSTEM_INVISIBLE) != STATE_SYSTEM_INVISIBLE; 637 } 638 639 bool AccessibilityUIElement::isOffScreen() const 640 { 641 DWORD state = accessibilityState(m_element); 642 return (state & STATE_SYSTEM_OFFSCREEN) == STATE_SYSTEM_OFFSCREEN; 643 } 644 645 bool AccessibilityUIElement::isCollapsed() const 646 { 647 DWORD state = accessibilityState(m_element); 648 return (state & STATE_SYSTEM_COLLAPSED) == STATE_SYSTEM_COLLAPSED; 649 } 650 651 bool AccessibilityUIElement::isIgnored() const 652 { 653 // FIXME: implement 654 return false; 655 } 656 657 bool AccessibilityUIElement::hasPopup() const 658 { 659 DWORD state = accessibilityState(m_element); 660 return (state & STATE_SYSTEM_HASPOPUP) == STATE_SYSTEM_HASPOPUP; 661 } 662 663 void AccessibilityUIElement::takeFocus() 664 { 665 m_element->accSelect(SELFLAG_TAKEFOCUS, self()); 666 } 667 668 void AccessibilityUIElement::takeSelection() 669 { 670 m_element->accSelect(SELFLAG_TAKESELECTION, self()); 671 } 672 673 void AccessibilityUIElement::addSelection() 674 { 675 m_element->accSelect(SELFLAG_ADDSELECTION, self()); 676 } 677 678 void AccessibilityUIElement::removeSelection() 679 { 680 m_element->accSelect(SELFLAG_REMOVESELECTION, self()); 681 } 682