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 38AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element) 39 : m_element(element) 40{ 41} 42 43AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other) 44 : m_element(other.m_element) 45{ 46} 47 48AccessibilityUIElement::~AccessibilityUIElement() 49{ 50} 51 52void AccessibilityUIElement::getLinkedUIElements(Vector<AccessibilityUIElement>& elements) 53{ 54 // FIXME: implement 55} 56 57void AccessibilityUIElement::getDocumentLinks(Vector<AccessibilityUIElement>&) 58{ 59 // FIXME: implement 60} 61 62void 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 71void 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 79int 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 89int 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 99int 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 109AccessibilityUIElement AccessibilityUIElement::elementAtPoint(int x, int y) 110{ 111 // FIXME: implement 112 return 0; 113} 114 115AccessibilityUIElement AccessibilityUIElement::linkedUIElementAtIndex(unsigned index) 116{ 117 // FIXME: implement 118 return 0; 119} 120 121AccessibilityUIElement 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 132unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element) 133{ 134 // FIXME: implement 135 return 0; 136} 137 138gchar* 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 151JSStringRef 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 160JSStringRef AccessibilityUIElement::attributesOfLinkedUIElements() 161{ 162 // FIXME: implement 163 return JSStringCreateWithCharacters(0, 0); 164} 165 166JSStringRef AccessibilityUIElement::attributesOfDocumentLinks() 167{ 168 // FIXME: implement 169 return JSStringCreateWithCharacters(0, 0); 170} 171 172AccessibilityUIElement AccessibilityUIElement::titleUIElement() 173{ 174 // FIXME: implement 175 return 0; 176} 177 178AccessibilityUIElement 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 189JSStringRef AccessibilityUIElement::attributesOfChildren() 190{ 191 // FIXME: implement 192 return JSStringCreateWithCharacters(0, 0); 193} 194 195JSStringRef AccessibilityUIElement::parameterizedAttributeNames() 196{ 197 // FIXME: implement 198 return JSStringCreateWithCharacters(0, 0); 199} 200 201JSStringRef 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 214JSStringRef AccessibilityUIElement::subrole() 215{ 216 return 0; 217} 218 219JSStringRef AccessibilityUIElement::roleDescription() 220{ 221 return 0; 222} 223 224JSStringRef 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 236JSStringRef 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 248JSStringRef AccessibilityUIElement::stringValue() 249{ 250 // FIXME: implement 251 return JSStringCreateWithCharacters(0, 0); 252} 253 254JSStringRef AccessibilityUIElement::language() 255{ 256 // FIXME: implement 257 return JSStringCreateWithCharacters(0, 0); 258} 259 260JSStringRef AccessibilityUIElement::helpText() const 261{ 262 return 0; 263} 264 265double 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 274double 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 283double 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 292double 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 301double AccessibilityUIElement::clickPointX() 302{ 303 return 0.f; 304} 305 306double AccessibilityUIElement::clickPointY() 307{ 308 return 0.f; 309} 310 311JSStringRef AccessibilityUIElement::orientation() const 312{ 313 return 0; 314} 315 316double 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 333double 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 350double 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 367JSStringRef AccessibilityUIElement::valueDescription() 368{ 369 // FIXME: implement 370 return JSStringCreateWithCharacters(0, 0); 371} 372 373static 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 382bool AccessibilityUIElement::isEnabled() 383{ 384 return checkElementState(m_element, ATK_STATE_ENABLED); 385} 386 387int AccessibilityUIElement::insertionPointLineNumber() 388{ 389 // FIXME: implement 390 return 0; 391} 392 393bool AccessibilityUIElement::isActionSupported(JSStringRef action) 394{ 395 // FIXME: implement 396 return false; 397} 398 399bool AccessibilityUIElement::isRequired() const 400{ 401 // FIXME: implement 402 return false; 403} 404 405bool 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 416bool AccessibilityUIElement::isSelected() const 417{ 418 return checkElementState(m_element, ATK_STATE_SELECTED); 419} 420 421int AccessibilityUIElement::hierarchicalLevel() const 422{ 423 // FIXME: implement 424 return 0; 425} 426 427bool AccessibilityUIElement::ariaIsGrabbed() const 428{ 429 return false; 430} 431 432JSStringRef AccessibilityUIElement::ariaDropEffects() const 433{ 434 return 0; 435} 436 437bool AccessibilityUIElement::isExpanded() const 438{ 439 // FIXME: implement 440 return false; 441} 442 443bool AccessibilityUIElement::isChecked() const 444{ 445 return intValue(); 446} 447 448JSStringRef AccessibilityUIElement::attributesOfColumnHeaders() 449{ 450 // FIXME: implement 451 return JSStringCreateWithCharacters(0, 0); 452} 453 454JSStringRef AccessibilityUIElement::attributesOfRowHeaders() 455{ 456 // FIXME: implement 457 return JSStringCreateWithCharacters(0, 0); 458} 459 460JSStringRef AccessibilityUIElement::attributesOfColumns() 461{ 462 // FIXME: implement 463 return JSStringCreateWithCharacters(0, 0); 464} 465 466JSStringRef AccessibilityUIElement::attributesOfRows() 467{ 468 // FIXME: implement 469 return JSStringCreateWithCharacters(0, 0); 470} 471 472JSStringRef AccessibilityUIElement::attributesOfVisibleCells() 473{ 474 // FIXME: implement 475 return JSStringCreateWithCharacters(0, 0); 476} 477 478JSStringRef AccessibilityUIElement::attributesOfHeader() 479{ 480 // FIXME: implement 481 return JSStringCreateWithCharacters(0, 0); 482} 483 484int AccessibilityUIElement::indexInTable() 485{ 486 // FIXME: implement 487 return 0; 488} 489 490static 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 530JSStringRef AccessibilityUIElement::rowIndexRange() 531{ 532 // Range in table for rows. 533 return indexRangeInTable(m_element, true); 534} 535 536JSStringRef AccessibilityUIElement::columnIndexRange() 537{ 538 // Range in table for columns. 539 return indexRangeInTable(m_element, false); 540} 541 542int AccessibilityUIElement::lineForIndex(int) 543{ 544 // FIXME: implement 545 return 0; 546} 547 548JSStringRef AccessibilityUIElement::boundsForRange(unsigned location, unsigned length) 549{ 550 // FIXME: implement 551 return JSStringCreateWithCharacters(0, 0); 552} 553 554JSStringRef AccessibilityUIElement::stringForRange(unsigned, unsigned) 555{ 556 // FIXME: implement 557 return JSStringCreateWithCharacters(0, 0); 558} 559 560JSStringRef AccessibilityUIElement::attributedStringForRange(unsigned, unsigned) 561{ 562 // FIXME: implement 563 return JSStringCreateWithCharacters(0, 0); 564} 565 566bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location, unsigned length) 567{ 568 // FIXME: implement 569 return false; 570} 571 572AccessibilityUIElement 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 583JSStringRef AccessibilityUIElement::selectedTextRange() 584{ 585 // FIXME: implement 586 return JSStringCreateWithCharacters(0, 0); 587} 588 589void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length) 590{ 591 // FIXME: implement 592} 593 594JSStringRef AccessibilityUIElement::stringAttributeValue(JSStringRef attribute) 595{ 596 // FIXME: implement 597 return JSStringCreateWithCharacters(0, 0); 598} 599 600bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute) 601{ 602 // FIXME: implement 603 return false; 604} 605 606bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute) 607{ 608 // FIXME: implement 609 return false; 610} 611 612bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute) 613{ 614 return false; 615} 616 617void 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 626void 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 635void 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 649void AccessibilityUIElement::showMenu() 650{ 651 // FIXME: implement 652} 653 654AccessibilityUIElement AccessibilityUIElement::disclosedRowAtIndex(unsigned index) 655{ 656 return 0; 657} 658 659AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index) 660{ 661 return 0; 662} 663 664AccessibilityUIElement AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index) 665{ 666 return 0; 667} 668 669AccessibilityUIElement AccessibilityUIElement::selectedRowAtIndex(unsigned index) 670{ 671 return 0; 672} 673 674AccessibilityUIElement AccessibilityUIElement::disclosedByRow() 675{ 676 return 0; 677} 678 679JSStringRef AccessibilityUIElement::accessibilityValue() const 680{ 681 // FIXME: implement 682 return JSStringCreateWithCharacters(0, 0); 683} 684 685JSStringRef 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 694JSStringRef 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 703JSStringRef AccessibilityUIElement::url() 704{ 705 // FIXME: implement 706 return JSStringCreateWithCharacters(0, 0); 707} 708 709bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallback) 710{ 711 // FIXME: implement 712 return false; 713} 714 715void AccessibilityUIElement::removeNotificationListener() 716{ 717 // FIXME: implement 718} 719 720bool 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 731bool AccessibilityUIElement::isSelectable() const 732{ 733 // FIXME: implement 734 return false; 735} 736 737bool AccessibilityUIElement::isMultiSelectable() const 738{ 739 // FIXME: implement 740 return false; 741} 742 743bool AccessibilityUIElement::isVisible() const 744{ 745 // FIXME: implement 746 return false; 747} 748 749bool AccessibilityUIElement::isOffScreen() const 750{ 751 // FIXME: implement 752 return false; 753} 754 755bool AccessibilityUIElement::isCollapsed() const 756{ 757 // FIXME: implement 758 return false; 759} 760 761bool AccessibilityUIElement::isIgnored() const 762{ 763 // FIXME: implement 764 return false; 765} 766 767bool AccessibilityUIElement::hasPopup() const 768{ 769 // FIXME: implement 770 return false; 771} 772 773void AccessibilityUIElement::takeFocus() 774{ 775 // FIXME: implement 776} 777 778void AccessibilityUIElement::takeSelection() 779{ 780 // FIXME: implement 781} 782 783void AccessibilityUIElement::addSelection() 784{ 785 // FIXME: implement 786} 787 788void AccessibilityUIElement::removeSelection() 789{ 790 // FIXME: implement 791} 792