1 /* 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. 3 * Copyright (C) 2009 Jan Michael Alonzo 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "config.h" 28 #include "AccessibilityUIElement.h" 29 30 #include "GOwnPtr.h" 31 #include "GRefPtr.h" 32 #include "WebCoreSupport/DumpRenderTreeSupportGtk.h" 33 #include <JavaScriptCore/JSStringRef.h> 34 #include <atk/atk.h> 35 #include <gtk/gtk.h> 36 #include <wtf/Assertions.h> 37 38 AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element) 39 : m_element(element) 40 { 41 } 42 43 AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other) 44 : m_element(other.m_element) 45 { 46 } 47 48 AccessibilityUIElement::~AccessibilityUIElement() 49 { 50 } 51 52 void AccessibilityUIElement::getLinkedUIElements(Vector<AccessibilityUIElement>& elements) 53 { 54 // FIXME: implement 55 } 56 57 void AccessibilityUIElement::getDocumentLinks(Vector<AccessibilityUIElement>&) 58 { 59 // FIXME: implement 60 } 61 62 void AccessibilityUIElement::getChildren(Vector<AccessibilityUIElement>& children) 63 { 64 int count = childrenCount(); 65 for (int i = 0; i < count; i++) { 66 AtkObject* child = atk_object_ref_accessible_child(ATK_OBJECT(m_element), i); 67 children.append(AccessibilityUIElement(child)); 68 } 69 } 70 71 void AccessibilityUIElement::getChildrenWithRange(Vector<AccessibilityUIElement>& elementVector, unsigned start, unsigned end) 72 { 73 for (unsigned i = start; i < end; i++) { 74 AtkObject* child = atk_object_ref_accessible_child(ATK_OBJECT(m_element), i); 75 elementVector.append(AccessibilityUIElement(child)); 76 } 77 } 78 79 int AccessibilityUIElement::rowCount() 80 { 81 if (!m_element) 82 return 0; 83 84 ASSERT(ATK_IS_TABLE(m_element)); 85 86 return atk_table_get_n_rows(ATK_TABLE(m_element)); 87 } 88 89 int AccessibilityUIElement::columnCount() 90 { 91 if (!m_element) 92 return 0; 93 94 ASSERT(ATK_IS_TABLE(m_element)); 95 96 return atk_table_get_n_columns(ATK_TABLE(m_element)); 97 } 98 99 int AccessibilityUIElement::childrenCount() 100 { 101 if (!m_element) 102 return 0; 103 104 ASSERT(ATK_IS_OBJECT(m_element)); 105 106 return atk_object_get_n_accessible_children(ATK_OBJECT(m_element)); 107 } 108 109 AccessibilityUIElement AccessibilityUIElement::elementAtPoint(int x, int y) 110 { 111 // FIXME: implement 112 return 0; 113 } 114 115 AccessibilityUIElement AccessibilityUIElement::linkedUIElementAtIndex(unsigned index) 116 { 117 // FIXME: implement 118 return 0; 119 } 120 121 AccessibilityUIElement AccessibilityUIElement::getChildAtIndex(unsigned index) 122 { 123 Vector<AccessibilityUIElement> children; 124 getChildrenWithRange(children, index, index + 1); 125 126 if (children.size() == 1) 127 return children.at(0); 128 129 return 0; 130 } 131 132 unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element) 133 { 134 // FIXME: implement 135 return 0; 136 } 137 138 gchar* attributeSetToString(AtkAttributeSet* attributeSet) 139 { 140 GString* str = g_string_new(0); 141 for (GSList* attributes = attributeSet; attributes; attributes = attributes->next) { 142 AtkAttribute* attribute = static_cast<AtkAttribute*>(attributes->data); 143 g_string_append(str, g_strconcat(attribute->name, ":", attribute->value, NULL)); 144 if (attributes->next) 145 g_string_append(str, ", "); 146 } 147 148 return g_string_free(str, FALSE); 149 } 150 151 JSStringRef AccessibilityUIElement::allAttributes() 152 { 153 if (!m_element) 154 return JSStringCreateWithCharacters(0, 0); 155 156 ASSERT(ATK_IS_OBJECT(m_element)); 157 return JSStringCreateWithUTF8CString(attributeSetToString(atk_object_get_attributes(ATK_OBJECT(m_element)))); 158 } 159 160 JSStringRef AccessibilityUIElement::attributesOfLinkedUIElements() 161 { 162 // FIXME: implement 163 return JSStringCreateWithCharacters(0, 0); 164 } 165 166 JSStringRef AccessibilityUIElement::attributesOfDocumentLinks() 167 { 168 // FIXME: implement 169 return JSStringCreateWithCharacters(0, 0); 170 } 171 172 AccessibilityUIElement AccessibilityUIElement::titleUIElement() 173 { 174 // FIXME: implement 175 return 0; 176 } 177 178 AccessibilityUIElement AccessibilityUIElement::parentElement() 179 { 180 if (!m_element) 181 return 0; 182 183 ASSERT(ATK_IS_OBJECT(m_element)); 184 185 AtkObject* parent = atk_object_get_parent(ATK_OBJECT(m_element)); 186 return parent ? AccessibilityUIElement(parent) : 0; 187 } 188 189 JSStringRef AccessibilityUIElement::attributesOfChildren() 190 { 191 // FIXME: implement 192 return JSStringCreateWithCharacters(0, 0); 193 } 194 195 JSStringRef AccessibilityUIElement::parameterizedAttributeNames() 196 { 197 // FIXME: implement 198 return JSStringCreateWithCharacters(0, 0); 199 } 200 201 JSStringRef AccessibilityUIElement::role() 202 { 203 AtkRole role = atk_object_get_role(ATK_OBJECT(m_element)); 204 205 if (!role) 206 return JSStringCreateWithCharacters(0, 0); 207 208 const gchar* roleName = atk_role_get_name(role); 209 GOwnPtr<gchar> axRole(g_strdup_printf("AXRole: %s", roleName)); 210 211 return JSStringCreateWithUTF8CString(axRole.get()); 212 } 213 214 JSStringRef AccessibilityUIElement::subrole() 215 { 216 return 0; 217 } 218 219 JSStringRef AccessibilityUIElement::roleDescription() 220 { 221 return 0; 222 } 223 224 JSStringRef AccessibilityUIElement::title() 225 { 226 const gchar* name = atk_object_get_name(ATK_OBJECT(m_element)); 227 228 if (!name) 229 return JSStringCreateWithCharacters(0, 0); 230 231 GOwnPtr<gchar> axTitle(g_strdup_printf("AXTitle: %s", name)); 232 233 return JSStringCreateWithUTF8CString(axTitle.get()); 234 } 235 236 JSStringRef AccessibilityUIElement::description() 237 { 238 const gchar* description = atk_object_get_description(ATK_OBJECT(m_element)); 239 240 if (!description) 241 return JSStringCreateWithCharacters(0, 0); 242 243 GOwnPtr<gchar> axDesc(g_strdup_printf("AXDescription: %s", description)); 244 245 return JSStringCreateWithUTF8CString(axDesc.get()); 246 } 247 248 JSStringRef AccessibilityUIElement::stringValue() 249 { 250 // FIXME: implement 251 return JSStringCreateWithCharacters(0, 0); 252 } 253 254 JSStringRef AccessibilityUIElement::language() 255 { 256 // FIXME: implement 257 return JSStringCreateWithCharacters(0, 0); 258 } 259 260 JSStringRef AccessibilityUIElement::helpText() const 261 { 262 return 0; 263 } 264 265 double AccessibilityUIElement::x() 266 { 267 int x, y; 268 269 atk_component_get_position(ATK_COMPONENT(m_element), &x, &y, ATK_XY_SCREEN); 270 271 return x; 272 } 273 274 double AccessibilityUIElement::y() 275 { 276 int x, y; 277 278 atk_component_get_position(ATK_COMPONENT(m_element), &x, &y, ATK_XY_SCREEN); 279 280 return y; 281 } 282 283 double AccessibilityUIElement::width() 284 { 285 int width, height; 286 287 atk_component_get_size(ATK_COMPONENT(m_element), &width, &height); 288 289 return width; 290 } 291 292 double AccessibilityUIElement::height() 293 { 294 int width, height; 295 296 atk_component_get_size(ATK_COMPONENT(m_element), &width, &height); 297 298 return height; 299 } 300 301 double AccessibilityUIElement::clickPointX() 302 { 303 return 0.f; 304 } 305 306 double AccessibilityUIElement::clickPointY() 307 { 308 return 0.f; 309 } 310 311 JSStringRef AccessibilityUIElement::orientation() const 312 { 313 return 0; 314 } 315 316 double AccessibilityUIElement::intValue() const 317 { 318 GValue value = { 0, { { 0 } } }; 319 320 if (!ATK_IS_VALUE(m_element)) 321 return 0.0f; 322 323 atk_value_get_current_value(ATK_VALUE(m_element), &value); 324 325 if (G_VALUE_HOLDS_DOUBLE(&value)) 326 return g_value_get_double(&value); 327 else if (G_VALUE_HOLDS_INT(&value)) 328 return static_cast<double>(g_value_get_int(&value)); 329 else 330 return 0.0f; 331 } 332 333 double AccessibilityUIElement::minValue() 334 { 335 GValue value = { 0, { { 0 } } }; 336 337 if (!ATK_IS_VALUE(m_element)) 338 return 0.0f; 339 340 atk_value_get_minimum_value(ATK_VALUE(m_element), &value); 341 342 if (G_VALUE_HOLDS_DOUBLE(&value)) 343 return g_value_get_double(&value); 344 else if (G_VALUE_HOLDS_INT(&value)) 345 return static_cast<double>(g_value_get_int(&value)); 346 else 347 return 0.0f; 348 } 349 350 double AccessibilityUIElement::maxValue() 351 { 352 GValue value = { 0, { { 0 } } }; 353 354 if (!ATK_IS_VALUE(m_element)) 355 return 0.0f; 356 357 atk_value_get_maximum_value(ATK_VALUE(m_element), &value); 358 359 if (G_VALUE_HOLDS_DOUBLE(&value)) 360 return g_value_get_double(&value); 361 else if (G_VALUE_HOLDS_INT(&value)) 362 return static_cast<double>(g_value_get_int(&value)); 363 else 364 return 0.0f; 365 } 366 367 JSStringRef AccessibilityUIElement::valueDescription() 368 { 369 // FIXME: implement 370 return JSStringCreateWithCharacters(0, 0); 371 } 372 373 static bool checkElementState(PlatformUIElement element, AtkStateType stateType) 374 { 375 if (!ATK_IS_OBJECT(element)) 376 return false; 377 378 GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(element))); 379 return atk_state_set_contains_state(stateSet.get(), stateType); 380 } 381 382 bool AccessibilityUIElement::isEnabled() 383 { 384 return checkElementState(m_element, ATK_STATE_ENABLED); 385 } 386 387 int AccessibilityUIElement::insertionPointLineNumber() 388 { 389 // FIXME: implement 390 return 0; 391 } 392 393 bool AccessibilityUIElement::isActionSupported(JSStringRef action) 394 { 395 // FIXME: implement 396 return false; 397 } 398 399 bool AccessibilityUIElement::isRequired() const 400 { 401 // FIXME: implement 402 return false; 403 } 404 405 bool AccessibilityUIElement::isFocused() const 406 { 407 if (!ATK_IS_OBJECT(m_element)) 408 return false; 409 410 GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(m_element))); 411 gboolean isFocused = atk_state_set_contains_state(stateSet.get(), ATK_STATE_FOCUSED); 412 413 return isFocused; 414 } 415 416 bool AccessibilityUIElement::isSelected() const 417 { 418 return checkElementState(m_element, ATK_STATE_SELECTED); 419 } 420 421 int AccessibilityUIElement::hierarchicalLevel() const 422 { 423 // FIXME: implement 424 return 0; 425 } 426 427 bool AccessibilityUIElement::ariaIsGrabbed() const 428 { 429 return false; 430 } 431 432 JSStringRef AccessibilityUIElement::ariaDropEffects() const 433 { 434 return 0; 435 } 436 437 bool AccessibilityUIElement::isExpanded() const 438 { 439 // FIXME: implement 440 return false; 441 } 442 443 bool AccessibilityUIElement::isChecked() const 444 { 445 return intValue(); 446 } 447 448 JSStringRef AccessibilityUIElement::attributesOfColumnHeaders() 449 { 450 // FIXME: implement 451 return JSStringCreateWithCharacters(0, 0); 452 } 453 454 JSStringRef AccessibilityUIElement::attributesOfRowHeaders() 455 { 456 // FIXME: implement 457 return JSStringCreateWithCharacters(0, 0); 458 } 459 460 JSStringRef AccessibilityUIElement::attributesOfColumns() 461 { 462 // FIXME: implement 463 return JSStringCreateWithCharacters(0, 0); 464 } 465 466 JSStringRef AccessibilityUIElement::attributesOfRows() 467 { 468 // FIXME: implement 469 return JSStringCreateWithCharacters(0, 0); 470 } 471 472 JSStringRef AccessibilityUIElement::attributesOfVisibleCells() 473 { 474 // FIXME: implement 475 return JSStringCreateWithCharacters(0, 0); 476 } 477 478 JSStringRef AccessibilityUIElement::attributesOfHeader() 479 { 480 // FIXME: implement 481 return JSStringCreateWithCharacters(0, 0); 482 } 483 484 int AccessibilityUIElement::indexInTable() 485 { 486 // FIXME: implement 487 return 0; 488 } 489 490 static JSStringRef indexRangeInTable(PlatformUIElement element, bool isRowRange) 491 { 492 GOwnPtr<gchar> rangeString(g_strdup("{0, 0}")); 493 494 if (!element) 495 return JSStringCreateWithUTF8CString(rangeString.get()); 496 497 ASSERT(ATK_IS_OBJECT(element)); 498 499 AtkObject* axTable = atk_object_get_parent(ATK_OBJECT(element)); 500 if (!axTable || !ATK_IS_TABLE(axTable)) 501 return JSStringCreateWithUTF8CString(rangeString.get()); 502 503 // Look for the cell in the table. 504 gint indexInParent = atk_object_get_index_in_parent(ATK_OBJECT(element)); 505 if (indexInParent == -1) 506 return JSStringCreateWithUTF8CString(rangeString.get()); 507 508 int row = -1; 509 int column = -1; 510 row = atk_table_get_row_at_index(ATK_TABLE(axTable), indexInParent); 511 column = atk_table_get_column_at_index(ATK_TABLE(axTable), indexInParent); 512 513 // Get the actual values, if row and columns are valid values. 514 if (row != -1 && column != -1) { 515 int base = 0; 516 int length = 0; 517 if (isRowRange) { 518 base = row; 519 length = atk_table_get_row_extent_at(ATK_TABLE(axTable), row, column); 520 } else { 521 base = column; 522 length = atk_table_get_column_extent_at(ATK_TABLE(axTable), row, column); 523 } 524 rangeString.set(g_strdup_printf("{%d, %d}", base, length)); 525 } 526 527 return JSStringCreateWithUTF8CString(rangeString.get()); 528 } 529 530 JSStringRef AccessibilityUIElement::rowIndexRange() 531 { 532 // Range in table for rows. 533 return indexRangeInTable(m_element, true); 534 } 535 536 JSStringRef AccessibilityUIElement::columnIndexRange() 537 { 538 // Range in table for columns. 539 return indexRangeInTable(m_element, false); 540 } 541 542 int AccessibilityUIElement::lineForIndex(int) 543 { 544 // FIXME: implement 545 return 0; 546 } 547 548 JSStringRef AccessibilityUIElement::boundsForRange(unsigned location, unsigned length) 549 { 550 // FIXME: implement 551 return JSStringCreateWithCharacters(0, 0); 552 } 553 554 JSStringRef AccessibilityUIElement::stringForRange(unsigned, unsigned) 555 { 556 // FIXME: implement 557 return JSStringCreateWithCharacters(0, 0); 558 } 559 560 JSStringRef AccessibilityUIElement::attributedStringForRange(unsigned, unsigned) 561 { 562 // FIXME: implement 563 return JSStringCreateWithCharacters(0, 0); 564 } 565 566 bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location, unsigned length) 567 { 568 // FIXME: implement 569 return false; 570 } 571 572 AccessibilityUIElement AccessibilityUIElement::cellForColumnAndRow(unsigned column, unsigned row) 573 { 574 if (!m_element) 575 return 0; 576 577 ASSERT(ATK_IS_TABLE(m_element)); 578 579 AtkObject* foundCell = atk_table_ref_at(ATK_TABLE(m_element), row, column); 580 return foundCell ? AccessibilityUIElement(foundCell) : 0; 581 } 582 583 JSStringRef AccessibilityUIElement::selectedTextRange() 584 { 585 // FIXME: implement 586 return JSStringCreateWithCharacters(0, 0); 587 } 588 589 void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length) 590 { 591 // FIXME: implement 592 } 593 594 JSStringRef AccessibilityUIElement::stringAttributeValue(JSStringRef attribute) 595 { 596 // FIXME: implement 597 return JSStringCreateWithCharacters(0, 0); 598 } 599 600 bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute) 601 { 602 // FIXME: implement 603 return false; 604 } 605 606 bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute) 607 { 608 // FIXME: implement 609 return false; 610 } 611 612 bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute) 613 { 614 return false; 615 } 616 617 void AccessibilityUIElement::increment() 618 { 619 if (!m_element) 620 return; 621 622 ASSERT(ATK_IS_OBJECT(m_element)); 623 DumpRenderTreeSupportGtk::incrementAccessibilityValue(ATK_OBJECT(m_element)); 624 } 625 626 void AccessibilityUIElement::decrement() 627 { 628 if (!m_element) 629 return; 630 631 ASSERT(ATK_IS_OBJECT(m_element)); 632 DumpRenderTreeSupportGtk::decrementAccessibilityValue(ATK_OBJECT(m_element)); 633 } 634 635 void AccessibilityUIElement::press() 636 { 637 if (!m_element) 638 return; 639 640 ASSERT(ATK_IS_OBJECT(m_element)); 641 642 if (!ATK_IS_ACTION(m_element)) 643 return; 644 645 // Only one action per object is supported so far. 646 atk_action_do_action(ATK_ACTION(m_element), 0); 647 } 648 649 void AccessibilityUIElement::showMenu() 650 { 651 // FIXME: implement 652 } 653 654 AccessibilityUIElement AccessibilityUIElement::disclosedRowAtIndex(unsigned index) 655 { 656 return 0; 657 } 658 659 AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index) 660 { 661 return 0; 662 } 663 664 AccessibilityUIElement AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index) 665 { 666 return 0; 667 } 668 669 AccessibilityUIElement AccessibilityUIElement::selectedRowAtIndex(unsigned index) 670 { 671 return 0; 672 } 673 674 AccessibilityUIElement AccessibilityUIElement::disclosedByRow() 675 { 676 return 0; 677 } 678 679 JSStringRef AccessibilityUIElement::accessibilityValue() const 680 { 681 // FIXME: implement 682 return JSStringCreateWithCharacters(0, 0); 683 } 684 685 JSStringRef AccessibilityUIElement::documentEncoding() 686 { 687 AtkRole role = atk_object_get_role(ATK_OBJECT(m_element)); 688 if (role != ATK_ROLE_DOCUMENT_FRAME) 689 return JSStringCreateWithCharacters(0, 0); 690 691 return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element), "Encoding")); 692 } 693 694 JSStringRef AccessibilityUIElement::documentURI() 695 { 696 AtkRole role = atk_object_get_role(ATK_OBJECT(m_element)); 697 if (role != ATK_ROLE_DOCUMENT_FRAME) 698 return JSStringCreateWithCharacters(0, 0); 699 700 return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element), "URI")); 701 } 702 703 JSStringRef AccessibilityUIElement::url() 704 { 705 // FIXME: implement 706 return JSStringCreateWithCharacters(0, 0); 707 } 708 709 bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallback) 710 { 711 // FIXME: implement 712 return false; 713 } 714 715 void AccessibilityUIElement::removeNotificationListener() 716 { 717 // FIXME: implement 718 } 719 720 bool AccessibilityUIElement::isFocusable() const 721 { 722 if (!ATK_IS_OBJECT(m_element)) 723 return false; 724 725 GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(m_element))); 726 gboolean isFocusable = atk_state_set_contains_state(stateSet.get(), ATK_STATE_FOCUSABLE); 727 728 return isFocusable; 729 } 730 731 bool AccessibilityUIElement::isSelectable() const 732 { 733 // FIXME: implement 734 return false; 735 } 736 737 bool AccessibilityUIElement::isMultiSelectable() const 738 { 739 // FIXME: implement 740 return false; 741 } 742 743 bool AccessibilityUIElement::isVisible() const 744 { 745 // FIXME: implement 746 return false; 747 } 748 749 bool AccessibilityUIElement::isOffScreen() const 750 { 751 // FIXME: implement 752 return false; 753 } 754 755 bool AccessibilityUIElement::isCollapsed() const 756 { 757 // FIXME: implement 758 return false; 759 } 760 761 bool AccessibilityUIElement::isIgnored() const 762 { 763 // FIXME: implement 764 return false; 765 } 766 767 bool AccessibilityUIElement::hasPopup() const 768 { 769 // FIXME: implement 770 return false; 771 } 772 773 void AccessibilityUIElement::takeFocus() 774 { 775 // FIXME: implement 776 } 777 778 void AccessibilityUIElement::takeSelection() 779 { 780 // FIXME: implement 781 } 782 783 void AccessibilityUIElement::addSelection() 784 { 785 // FIXME: implement 786 } 787 788 void AccessibilityUIElement::removeSelection() 789 { 790 // FIXME: implement 791 } 792