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 36using std::wstring; 37 38static 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 48AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element) 49 : m_element(element) 50{ 51} 52 53AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other) 54 : m_element(other.m_element) 55{ 56} 57 58AccessibilityUIElement::~AccessibilityUIElement() 59{ 60} 61 62bool 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 74void AccessibilityUIElement::getLinkedUIElements(Vector<AccessibilityUIElement>&) 75{ 76} 77 78void AccessibilityUIElement::getDocumentLinks(Vector<AccessibilityUIElement>&) 79{ 80} 81 82void 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 91void 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 101int AccessibilityUIElement::childrenCount() 102{ 103 long childCount; 104 m_element->get_accChildCount(&childCount); 105 return childCount; 106} 107 108int AccessibilityUIElement::rowCount() 109{ 110 // FIXME: implement 111 return 0; 112} 113 114int AccessibilityUIElement::columnCount() 115{ 116 // FIXME: implement 117 return 0; 118} 119 120AccessibilityUIElement AccessibilityUIElement::elementAtPoint(int x, int y) 121{ 122 return 0; 123} 124 125AccessibilityUIElement AccessibilityUIElement::linkedUIElementAtIndex(unsigned index) 126{ 127 // FIXME: implement 128 return 0; 129} 130 131AccessibilityUIElement 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 144unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element) 145{ 146 // FIXME: implement 147 return 0; 148} 149 150JSStringRef AccessibilityUIElement::allAttributes() 151{ 152 return JSStringCreateWithCharacters(0, 0); 153} 154 155JSStringRef AccessibilityUIElement::attributesOfLinkedUIElements() 156{ 157 return JSStringCreateWithCharacters(0, 0); 158} 159 160JSStringRef AccessibilityUIElement::attributesOfDocumentLinks() 161{ 162 return JSStringCreateWithCharacters(0, 0); 163} 164 165AccessibilityUIElement AccessibilityUIElement::titleUIElement() 166{ 167 return 0; 168} 169 170AccessibilityUIElement 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 179JSStringRef AccessibilityUIElement::attributesOfChildren() 180{ 181 return JSStringCreateWithCharacters(0, 0); 182} 183 184JSStringRef AccessibilityUIElement::parameterizedAttributeNames() 185{ 186 return JSStringCreateWithCharacters(0, 0); 187} 188 189static 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 202JSStringRef 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 227JSStringRef AccessibilityUIElement::subrole() 228{ 229 return 0; 230} 231 232JSStringRef AccessibilityUIElement::roleDescription() 233{ 234 return 0; 235} 236 237JSStringRef 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 247JSStringRef 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 257JSStringRef AccessibilityUIElement::stringValue() 258{ 259 return JSStringCreateWithCharacters(0, 0); 260} 261 262JSStringRef AccessibilityUIElement::language() 263{ 264 return JSStringCreateWithCharacters(0, 0); 265} 266 267JSStringRef AccessibilityUIElement::helpText() const 268{ 269 return 0; 270} 271 272double 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 280double 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 288double 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 296double 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 304double AccessibilityUIElement::clickPointX() 305{ 306 return 0; 307} 308 309double AccessibilityUIElement::clickPointY() 310{ 311 return 0; 312} 313 314JSStringRef AccessibilityUIElement::valueDescription() 315{ 316 return 0; 317} 318 319static 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 332bool AccessibilityUIElement::isFocused() const 333{ 334 // FIXME: implement 335 return false; 336} 337 338bool AccessibilityUIElement::isSelected() const 339{ 340 DWORD state = accessibilityState(m_element); 341 return (state & STATE_SYSTEM_SELECTED) == STATE_SYSTEM_SELECTED; 342} 343 344int AccessibilityUIElement::hierarchicalLevel() const 345{ 346 return 0; 347} 348 349bool AccessibilityUIElement::ariaIsGrabbed() const 350{ 351 return false; 352} 353 354JSStringRef AccessibilityUIElement::ariaDropEffects() const 355{ 356 return 0; 357} 358 359bool AccessibilityUIElement::isExpanded() const 360{ 361 return false; 362} 363 364bool 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 373JSStringRef AccessibilityUIElement::orientation() const 374{ 375 return 0; 376} 377 378double 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 389double AccessibilityUIElement::minValue() 390{ 391 return 0; 392} 393 394double AccessibilityUIElement::maxValue() 395{ 396 return 0; 397} 398 399bool AccessibilityUIElement::isActionSupported(JSStringRef action) 400{ 401 return false; 402} 403 404bool AccessibilityUIElement::isEnabled() 405{ 406 DWORD state = accessibilityState(m_element); 407 return (state & STATE_SYSTEM_UNAVAILABLE) != STATE_SYSTEM_UNAVAILABLE; 408} 409 410bool AccessibilityUIElement::isRequired() const 411{ 412 return false; 413} 414 415 416int AccessibilityUIElement::insertionPointLineNumber() 417{ 418 return 0; 419} 420 421JSStringRef AccessibilityUIElement::attributesOfColumnHeaders() 422{ 423 return JSStringCreateWithCharacters(0, 0); 424} 425 426JSStringRef AccessibilityUIElement::attributesOfRowHeaders() 427{ 428 return JSStringCreateWithCharacters(0, 0); 429} 430 431JSStringRef AccessibilityUIElement::attributesOfColumns() 432{ 433 return JSStringCreateWithCharacters(0, 0); 434} 435 436JSStringRef AccessibilityUIElement::attributesOfRows() 437{ 438 return JSStringCreateWithCharacters(0, 0); 439} 440 441JSStringRef AccessibilityUIElement::attributesOfVisibleCells() 442{ 443 return JSStringCreateWithCharacters(0, 0); 444} 445 446JSStringRef AccessibilityUIElement::attributesOfHeader() 447{ 448 return JSStringCreateWithCharacters(0, 0); 449} 450 451int AccessibilityUIElement::indexInTable() 452{ 453 return 0; 454} 455 456JSStringRef AccessibilityUIElement::rowIndexRange() 457{ 458 return JSStringCreateWithCharacters(0, 0); 459} 460 461JSStringRef AccessibilityUIElement::columnIndexRange() 462{ 463 return JSStringCreateWithCharacters(0, 0); 464} 465 466int AccessibilityUIElement::lineForIndex(int) 467{ 468 return 0; 469} 470 471JSStringRef AccessibilityUIElement::boundsForRange(unsigned location, unsigned length) 472{ 473 return JSStringCreateWithCharacters(0, 0); 474} 475 476JSStringRef AccessibilityUIElement::stringForRange(unsigned, unsigned) 477{ 478 return JSStringCreateWithCharacters(0, 0); 479} 480 481JSStringRef AccessibilityUIElement::attributedStringForRange(unsigned, unsigned) 482{ 483 return JSStringCreateWithCharacters(0, 0); 484} 485 486bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned, unsigned) 487{ 488 return false; 489} 490 491AccessibilityUIElement AccessibilityUIElement::cellForColumnAndRow(unsigned column, unsigned row) 492{ 493 return 0; 494} 495 496JSStringRef AccessibilityUIElement::selectedTextRange() 497{ 498 return JSStringCreateWithCharacters(0, 0); 499} 500 501void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length) 502{ 503} 504 505JSStringRef AccessibilityUIElement::stringAttributeValue(JSStringRef attribute) 506{ 507 // FIXME: implement 508 return JSStringCreateWithCharacters(0, 0); 509} 510 511bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute) 512{ 513 // FIXME: implement 514 return false; 515} 516 517bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute) 518{ 519 return false; 520} 521 522bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute) 523{ 524 return false; 525} 526 527void AccessibilityUIElement::increment() 528{ 529} 530 531void AccessibilityUIElement::decrement() 532{ 533} 534 535void AccessibilityUIElement::showMenu() 536{ 537 ASSERT(hasPopup()); 538 m_element->accDoDefaultAction(self()); 539} 540 541void AccessibilityUIElement::press() 542{ 543 // FIXME: implement 544} 545 546AccessibilityUIElement AccessibilityUIElement::disclosedRowAtIndex(unsigned index) 547{ 548 return 0; 549} 550 551AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index) 552{ 553 return 0; 554} 555 556AccessibilityUIElement AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index) 557{ 558 return 0; 559} 560 561AccessibilityUIElement AccessibilityUIElement::selectedRowAtIndex(unsigned index) 562{ 563 return 0; 564} 565 566AccessibilityUIElement AccessibilityUIElement::disclosedByRow() 567{ 568 return 0; 569} 570 571JSStringRef 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 584JSStringRef AccessibilityUIElement::documentEncoding() 585{ 586 return JSStringCreateWithCharacters(0, 0); 587} 588 589JSStringRef AccessibilityUIElement::documentURI() 590{ 591 return JSStringCreateWithCharacters(0, 0); 592} 593 594JSStringRef AccessibilityUIElement::url() 595{ 596 // FIXME: implement 597 return JSStringCreateWithCharacters(0, 0); 598} 599 600bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallback) 601{ 602 if (!functionCallback) 603 return false; 604 605 sharedFrameLoadDelegate->accessibilityController()->addNotificationListener(m_element, functionCallback); 606 return true; 607} 608 609void AccessibilityUIElement::removeNotificationListener() 610{ 611 // FIXME: implement 612} 613 614bool AccessibilityUIElement::isFocusable() const 615{ 616 // FIXME: implement 617 return false; 618} 619 620bool AccessibilityUIElement::isSelectable() const 621{ 622 DWORD state = accessibilityState(m_element); 623 return (state & STATE_SYSTEM_SELECTABLE) == STATE_SYSTEM_SELECTABLE; 624} 625 626bool 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 633bool AccessibilityUIElement::isVisible() const 634{ 635 DWORD state = accessibilityState(m_element); 636 return (state & STATE_SYSTEM_INVISIBLE) != STATE_SYSTEM_INVISIBLE; 637} 638 639bool AccessibilityUIElement::isOffScreen() const 640{ 641 DWORD state = accessibilityState(m_element); 642 return (state & STATE_SYSTEM_OFFSCREEN) == STATE_SYSTEM_OFFSCREEN; 643} 644 645bool AccessibilityUIElement::isCollapsed() const 646{ 647 DWORD state = accessibilityState(m_element); 648 return (state & STATE_SYSTEM_COLLAPSED) == STATE_SYSTEM_COLLAPSED; 649} 650 651bool AccessibilityUIElement::isIgnored() const 652{ 653 // FIXME: implement 654 return false; 655} 656 657bool AccessibilityUIElement::hasPopup() const 658{ 659 DWORD state = accessibilityState(m_element); 660 return (state & STATE_SYSTEM_HASPOPUP) == STATE_SYSTEM_HASPOPUP; 661} 662 663void AccessibilityUIElement::takeFocus() 664{ 665 m_element->accSelect(SELFLAG_TAKEFOCUS, self()); 666} 667 668void AccessibilityUIElement::takeSelection() 669{ 670 m_element->accSelect(SELFLAG_TAKESELECTION, self()); 671} 672 673void AccessibilityUIElement::addSelection() 674{ 675 m_element->accSelect(SELFLAG_ADDSELECTION, self()); 676} 677 678void AccessibilityUIElement::removeSelection() 679{ 680 m_element->accSelect(SELFLAG_REMOVESELECTION, self()); 681} 682