1 /* 2 * Copyright (C) 2010 Google 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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "AccessibilityUIElement.h" 33 34 #include "WebAccessibilityObject.h" 35 #include "WebCString.h" 36 #include "WebString.h" 37 #include <wtf/Assertions.h> 38 39 using namespace WebKit; 40 using namespace std; 41 42 // Map role value to string, matching Safari/Mac platform implementation to 43 // avoid rebaselining layout tests. 44 static string roleToString(WebAccessibilityRole role) 45 { 46 string result = "AXRole: AX"; 47 switch (role) { 48 case WebAccessibilityRoleButton: 49 return result.append("Button"); 50 case WebAccessibilityRoleRadioButton: 51 return result.append("RadioButton"); 52 case WebAccessibilityRoleCheckBox: 53 return result.append("CheckBox"); 54 case WebAccessibilityRoleSlider: 55 return result.append("Slider"); 56 case WebAccessibilityRoleTabGroup: 57 return result.append("TabGroup"); 58 case WebAccessibilityRoleTextField: 59 return result.append("TextField"); 60 case WebAccessibilityRoleStaticText: 61 return result.append("StaticText"); 62 case WebAccessibilityRoleTextArea: 63 return result.append("TextArea"); 64 case WebAccessibilityRoleScrollArea: 65 return result.append("ScrollArea"); 66 case WebAccessibilityRolePopUpButton: 67 return result.append("PopUpButton"); 68 case WebAccessibilityRoleMenuButton: 69 return result.append("MenuButton"); 70 case WebAccessibilityRoleTable: 71 return result.append("Table"); 72 case WebAccessibilityRoleApplication: 73 return result.append("Application"); 74 case WebAccessibilityRoleGroup: 75 return result.append("Group"); 76 case WebAccessibilityRoleRadioGroup: 77 return result.append("RadioGroup"); 78 case WebAccessibilityRoleList: 79 return result.append("List"); 80 case WebAccessibilityRoleScrollBar: 81 return result.append("ScrollBar"); 82 case WebAccessibilityRoleValueIndicator: 83 return result.append("ValueIndicator"); 84 case WebAccessibilityRoleImage: 85 return result.append("Image"); 86 case WebAccessibilityRoleMenuBar: 87 return result.append("MenuBar"); 88 case WebAccessibilityRoleMenu: 89 return result.append("Menu"); 90 case WebAccessibilityRoleMenuItem: 91 return result.append("MenuItem"); 92 case WebAccessibilityRoleColumn: 93 return result.append("Column"); 94 case WebAccessibilityRoleRow: 95 return result.append("Row"); 96 case WebAccessibilityRoleToolbar: 97 return result.append("Toolbar"); 98 case WebAccessibilityRoleBusyIndicator: 99 return result.append("BusyIndicator"); 100 case WebAccessibilityRoleProgressIndicator: 101 return result.append("ProgressIndicator"); 102 case WebAccessibilityRoleWindow: 103 return result.append("Window"); 104 case WebAccessibilityRoleDrawer: 105 return result.append("Drawer"); 106 case WebAccessibilityRoleSystemWide: 107 return result.append("SystemWide"); 108 case WebAccessibilityRoleOutline: 109 return result.append("Outline"); 110 case WebAccessibilityRoleIncrementor: 111 return result.append("Incrementor"); 112 case WebAccessibilityRoleBrowser: 113 return result.append("Browser"); 114 case WebAccessibilityRoleComboBox: 115 return result.append("ComboBox"); 116 case WebAccessibilityRoleSplitGroup: 117 return result.append("SplitGroup"); 118 case WebAccessibilityRoleSplitter: 119 return result.append("Splitter"); 120 case WebAccessibilityRoleColorWell: 121 return result.append("ColorWell"); 122 case WebAccessibilityRoleGrowArea: 123 return result.append("GrowArea"); 124 case WebAccessibilityRoleSheet: 125 return result.append("Sheet"); 126 case WebAccessibilityRoleHelpTag: 127 return result.append("HelpTag"); 128 case WebAccessibilityRoleMatte: 129 return result.append("Matte"); 130 case WebAccessibilityRoleRuler: 131 return result.append("Ruler"); 132 case WebAccessibilityRoleRulerMarker: 133 return result.append("RulerMarker"); 134 case WebAccessibilityRoleLink: 135 return result.append("Link"); 136 case WebAccessibilityRoleDisclosureTriangle: 137 return result.append("DisclosureTriangle"); 138 case WebAccessibilityRoleGrid: 139 return result.append("Grid"); 140 case WebAccessibilityRoleCell: 141 return result.append("Cell"); 142 case WebAccessibilityRoleColumnHeader: 143 return result.append("ColumnHeader"); 144 case WebAccessibilityRoleRowHeader: 145 return result.append("RowHeader"); 146 case WebAccessibilityRoleWebCoreLink: 147 // Maps to Link role. 148 return result.append("Link"); 149 case WebAccessibilityRoleImageMapLink: 150 return result.append("ImageMapLink"); 151 case WebAccessibilityRoleImageMap: 152 return result.append("ImageMap"); 153 case WebAccessibilityRoleListMarker: 154 return result.append("ListMarker"); 155 case WebAccessibilityRoleWebArea: 156 return result.append("WebArea"); 157 case WebAccessibilityRoleHeading: 158 return result.append("Heading"); 159 case WebAccessibilityRoleListBox: 160 return result.append("ListBox"); 161 case WebAccessibilityRoleListBoxOption: 162 return result.append("ListBoxOption"); 163 case WebAccessibilityRoleTableHeaderContainer: 164 return result.append("TableHeaderContainer"); 165 case WebAccessibilityRoleDefinitionListTerm: 166 return result.append("DefinitionListTerm"); 167 case WebAccessibilityRoleDefinitionListDefinition: 168 return result.append("DefinitionListDefinition"); 169 case WebAccessibilityRoleAnnotation: 170 return result.append("Annotation"); 171 case WebAccessibilityRoleSliderThumb: 172 return result.append("SliderThumb"); 173 case WebAccessibilityRoleLandmarkApplication: 174 return result.append("LandmarkApplication"); 175 case WebAccessibilityRoleLandmarkBanner: 176 return result.append("LandmarkBanner"); 177 case WebAccessibilityRoleLandmarkComplementary: 178 return result.append("LandmarkComplementary"); 179 case WebAccessibilityRoleLandmarkContentInfo: 180 return result.append("LandmarkContentInfo"); 181 case WebAccessibilityRoleLandmarkMain: 182 return result.append("LandmarkMain"); 183 case WebAccessibilityRoleLandmarkNavigation: 184 return result.append("LandmarkNavigation"); 185 case WebAccessibilityRoleLandmarkSearch: 186 return result.append("LandmarkSearch"); 187 case WebAccessibilityRoleApplicationLog: 188 return result.append("ApplicationLog"); 189 case WebAccessibilityRoleApplicationMarquee: 190 return result.append("ApplicationMarquee"); 191 case WebAccessibilityRoleApplicationStatus: 192 return result.append("ApplicationStatus"); 193 case WebAccessibilityRoleApplicationTimer: 194 return result.append("ApplicationTimer"); 195 case WebAccessibilityRoleDocument: 196 return result.append("Document"); 197 case WebAccessibilityRoleDocumentArticle: 198 return result.append("DocumentArticle"); 199 case WebAccessibilityRoleDocumentNote: 200 return result.append("DocumentNote"); 201 case WebAccessibilityRoleDocumentRegion: 202 return result.append("DocumentRegion"); 203 case WebAccessibilityRoleUserInterfaceTooltip: 204 return result.append("UserInterfaceTooltip"); 205 default: 206 // Also matches WebAccessibilityRoleUnknown. 207 return result.append("Unknown"); 208 } 209 } 210 211 string getDescription(const WebAccessibilityObject& object) 212 { 213 string description = object.accessibilityDescription().utf8(); 214 return description.insert(0, "AXDescription: "); 215 } 216 217 string getRole(const WebAccessibilityObject& object) 218 { 219 return roleToString(object.roleValue()); 220 } 221 222 string getTitle(const WebAccessibilityObject& object) 223 { 224 string title = object.title().utf8(); 225 return title.insert(0, "AXTitle: "); 226 } 227 228 string getAttributes(const WebAccessibilityObject& object) 229 { 230 // FIXME: Concatenate all attributes of the AccessibilityObject. 231 string attributes(getTitle(object)); 232 attributes.append("\n"); 233 attributes.append(getRole(object)); 234 attributes.append("\n"); 235 attributes.append(getDescription(object)); 236 return attributes; 237 } 238 239 240 // Collects attributes into a string, delimited by dashes. Used by all methods 241 // that output lists of attributes: attributesOfLinkedUIElementsCallback, 242 // AttributesOfChildrenCallback, etc. 243 class AttributesCollector { 244 public: 245 void collectAttributes(const WebAccessibilityObject& object) 246 { 247 m_attributes.append("\n------------\n"); 248 m_attributes.append(getAttributes(object)); 249 } 250 251 string attributes() const { return m_attributes; } 252 253 private: 254 string m_attributes; 255 }; 256 257 AccessibilityUIElement::AccessibilityUIElement(const WebAccessibilityObject& object, Factory* factory) 258 : m_accessibilityObject(object) 259 , m_factory(factory) 260 { 261 262 ASSERT(factory); 263 264 bindMethod("allAttributes", &AccessibilityUIElement::allAttributesCallback); 265 bindMethod("attributesOfLinkedUIElements", 266 &AccessibilityUIElement::attributesOfLinkedUIElementsCallback); 267 bindMethod("attributesOfDocumentLinks", 268 &AccessibilityUIElement::attributesOfDocumentLinksCallback); 269 bindMethod("attributesOfChildren", 270 &AccessibilityUIElement::attributesOfChildrenCallback); 271 bindMethod("parameterizedAttributeNames", 272 &AccessibilityUIElement::parametrizedAttributeNamesCallback); 273 bindMethod("lineForIndex", &AccessibilityUIElement::lineForIndexCallback); 274 bindMethod("boundsForRange", &AccessibilityUIElement::boundsForRangeCallback); 275 bindMethod("stringForRange", &AccessibilityUIElement::stringForRangeCallback); 276 bindMethod("childAtIndex", &AccessibilityUIElement::childAtIndexCallback); 277 bindMethod("elementAtPoint", &AccessibilityUIElement::elementAtPointCallback); 278 bindMethod("attributesOfColumnHeaders", 279 &AccessibilityUIElement::attributesOfColumnHeadersCallback); 280 bindMethod("attributesOfRowHeaders", 281 &AccessibilityUIElement::attributesOfRowHeadersCallback); 282 bindMethod("attributesOfColumns", 283 &AccessibilityUIElement::attributesOfColumnsCallback); 284 bindMethod("attributesOfRows", 285 &AccessibilityUIElement::attributesOfRowsCallback); 286 bindMethod("attributesOfVisibleCells", 287 &AccessibilityUIElement::attributesOfVisibleCellsCallback); 288 bindMethod("attributesOfHeader", 289 &AccessibilityUIElement::attributesOfHeaderCallback); 290 bindMethod("indexInTable", &AccessibilityUIElement::indexInTableCallback); 291 bindMethod("rowIndexRange", &AccessibilityUIElement::rowIndexRangeCallback); 292 bindMethod("columnIndexRange", 293 &AccessibilityUIElement::columnIndexRangeCallback); 294 bindMethod("cellForColumnAndRow", 295 &AccessibilityUIElement::cellForColumnAndRowCallback); 296 bindMethod("titleUIElement", &AccessibilityUIElement::titleUIElementCallback); 297 bindMethod("setSelectedTextRange", 298 &AccessibilityUIElement::setSelectedTextRangeCallback); 299 bindMethod("attributeValue", &AccessibilityUIElement::attributeValueCallback); 300 bindMethod("isAttributeSettable", 301 &AccessibilityUIElement::isAttributeSettableCallback); 302 bindMethod("isActionSupported", 303 &AccessibilityUIElement::isActionSupportedCallback); 304 bindMethod("parentElement", &AccessibilityUIElement::parentElementCallback); 305 bindMethod("increment", &AccessibilityUIElement::incrementCallback); 306 bindMethod("decrement", &AccessibilityUIElement::decrementCallback); 307 308 bindProperty("role", &AccessibilityUIElement::roleGetterCallback); 309 bindProperty("subrole", &m_subrole); 310 bindProperty("title", &AccessibilityUIElement::titleGetterCallback); 311 bindProperty("description", 312 &AccessibilityUIElement::descriptionGetterCallback); 313 bindProperty("language", &m_language); 314 bindProperty("x", &m_x); 315 bindProperty("y", &m_y); 316 bindProperty("width", &m_width); 317 bindProperty("height", &m_height); 318 bindProperty("clickPointX", &m_clickPointX); 319 bindProperty("clickPointY", &m_clickPointY); 320 bindProperty("intValue", &m_intValue); 321 bindProperty("minValue", &m_minValue); 322 bindProperty("maxValue", &m_maxValue); 323 bindProperty("childrenCount", 324 &AccessibilityUIElement::childrenCountGetterCallback); 325 bindProperty("insertionPointLineNumber", &m_insertionPointLineNumber); 326 bindProperty("selectedTextRange", &m_selectedTextRange); 327 bindProperty("isEnabled", &AccessibilityUIElement::isEnabledGetterCallback); 328 bindProperty("isRequired", &m_isRequired); 329 bindProperty("isSelected", &AccessibilityUIElement::isSelectedGetterCallback); 330 bindProperty("valueDescription", &m_valueDescription); 331 332 bindFallbackMethod(&AccessibilityUIElement::fallbackCallback); 333 } 334 335 AccessibilityUIElement* AccessibilityUIElement::getChildAtIndex(unsigned index) 336 { 337 return m_factory->create(accessibilityObject().childAt(index)); 338 } 339 340 void AccessibilityUIElement::allAttributesCallback(const CppArgumentList&, CppVariant* result) 341 { 342 result->set(getAttributes(accessibilityObject())); 343 } 344 345 void AccessibilityUIElement::attributesOfLinkedUIElementsCallback(const CppArgumentList&, CppVariant* result) 346 { 347 result->setNull(); 348 } 349 350 void AccessibilityUIElement::attributesOfDocumentLinksCallback(const CppArgumentList&, CppVariant* result) 351 { 352 result->setNull(); 353 } 354 355 void AccessibilityUIElement::attributesOfChildrenCallback(const CppArgumentList& arguments, CppVariant* result) 356 { 357 AttributesCollector collector; 358 unsigned size = accessibilityObject().childCount(); 359 for (unsigned i = 0; i < size; ++i) 360 collector.collectAttributes(accessibilityObject().childAt(i)); 361 result->set(collector.attributes()); 362 } 363 364 void AccessibilityUIElement::parametrizedAttributeNamesCallback(const CppArgumentList&, CppVariant* result) 365 { 366 result->setNull(); 367 } 368 369 void AccessibilityUIElement::lineForIndexCallback(const CppArgumentList&, CppVariant* result) 370 { 371 result->setNull(); 372 } 373 374 void AccessibilityUIElement::boundsForRangeCallback(const CppArgumentList&, CppVariant* result) 375 { 376 result->setNull(); 377 } 378 379 void AccessibilityUIElement::stringForRangeCallback(const CppArgumentList&, CppVariant* result) 380 { 381 result->setNull(); 382 } 383 384 void AccessibilityUIElement::childAtIndexCallback(const CppArgumentList& arguments, CppVariant* result) 385 { 386 if (!arguments.size() || !arguments[0].isNumber()) { 387 result->setNull(); 388 return; 389 } 390 391 AccessibilityUIElement* child = getChildAtIndex(arguments[0].toInt32()); 392 if (!child) { 393 result->setNull(); 394 return; 395 } 396 397 result->set(*(child->getAsCppVariant())); 398 } 399 400 void AccessibilityUIElement::elementAtPointCallback(const CppArgumentList&, CppVariant* result) 401 { 402 result->setNull(); 403 } 404 405 void AccessibilityUIElement::attributesOfColumnHeadersCallback(const CppArgumentList&, CppVariant* result) 406 { 407 result->setNull(); 408 } 409 410 void AccessibilityUIElement::attributesOfRowHeadersCallback(const CppArgumentList&, CppVariant* result) 411 { 412 result->setNull(); 413 } 414 415 void AccessibilityUIElement::attributesOfColumnsCallback(const CppArgumentList&, CppVariant* result) 416 { 417 result->setNull(); 418 } 419 420 void AccessibilityUIElement::attributesOfRowsCallback(const CppArgumentList&, CppVariant* result) 421 { 422 result->setNull(); 423 } 424 425 void AccessibilityUIElement::attributesOfVisibleCellsCallback(const CppArgumentList&, CppVariant* result) 426 { 427 result->setNull(); 428 } 429 430 void AccessibilityUIElement::attributesOfHeaderCallback(const CppArgumentList&, CppVariant* result) 431 { 432 result->setNull(); 433 } 434 435 void AccessibilityUIElement::indexInTableCallback(const CppArgumentList&, CppVariant* result) 436 { 437 result->setNull(); 438 } 439 440 void AccessibilityUIElement::rowIndexRangeCallback(const CppArgumentList&, CppVariant* result) 441 { 442 result->setNull(); 443 } 444 445 void AccessibilityUIElement::columnIndexRangeCallback(const CppArgumentList&, CppVariant* result) 446 { 447 result->setNull(); 448 } 449 450 void AccessibilityUIElement::cellForColumnAndRowCallback(const CppArgumentList&, CppVariant* result) 451 { 452 result->setNull(); 453 } 454 455 void AccessibilityUIElement::titleUIElementCallback(const CppArgumentList&, CppVariant* result) 456 { 457 result->setNull(); 458 } 459 460 void AccessibilityUIElement::setSelectedTextRangeCallback(const CppArgumentList&, CppVariant* result) 461 { 462 result->setNull(); 463 } 464 465 void AccessibilityUIElement::attributeValueCallback(const CppArgumentList&, CppVariant* result) 466 { 467 result->setNull(); 468 } 469 470 void AccessibilityUIElement::isAttributeSettableCallback(const CppArgumentList& arguments, CppVariant* result) 471 { 472 if (arguments.size() < 1 && !arguments[0].isString()) { 473 result->setNull(); 474 return; 475 } 476 477 string attribute = arguments[0].toString(); 478 bool settable = false; 479 if (attribute == "AXValue") 480 settable = accessibilityObject().canSetValueAttribute(); 481 result->set(settable); 482 } 483 484 void AccessibilityUIElement::isActionSupportedCallback(const CppArgumentList&, CppVariant* result) 485 { 486 // This one may be really hard to implement. 487 // Not exposed by AccessibilityObject. 488 result->setNull(); 489 } 490 491 void AccessibilityUIElement::parentElementCallback(const CppArgumentList&, CppVariant* result) 492 { 493 result->setNull(); 494 } 495 496 void AccessibilityUIElement::incrementCallback(const CppArgumentList&, CppVariant* result) 497 { 498 result->setNull(); 499 } 500 501 void AccessibilityUIElement::decrementCallback(const CppArgumentList&, CppVariant* result) 502 { 503 result->setNull(); 504 } 505 506 void AccessibilityUIElement::fallbackCallback(const CppArgumentList &, CppVariant* result) 507 { 508 // FIXME: Implement this. 509 result->setNull(); 510 } 511 512 void AccessibilityUIElement::childrenCountGetterCallback(CppVariant* result) 513 { 514 int count = 1; // Root object always has only one child, the WebView. 515 if (!isRoot()) 516 count = accessibilityObject().childCount(); 517 result->set(count); 518 } 519 520 void AccessibilityUIElement::descriptionGetterCallback(CppVariant* result) 521 { 522 result->set(getDescription(accessibilityObject())); 523 } 524 525 void AccessibilityUIElement::isEnabledGetterCallback(CppVariant* result) 526 { 527 result->set(accessibilityObject().isEnabled()); 528 } 529 530 void AccessibilityUIElement::isSelectedGetterCallback(CppVariant* result) 531 { 532 result->setNull(); 533 } 534 535 void AccessibilityUIElement::roleGetterCallback(CppVariant* result) 536 { 537 result->set(getRole(accessibilityObject())); 538 } 539 540 void AccessibilityUIElement::titleGetterCallback(CppVariant* result) 541 { 542 result->set(getTitle(accessibilityObject())); 543 } 544 545 546 RootAccessibilityUIElement::RootAccessibilityUIElement(const WebAccessibilityObject &object, Factory *factory) 547 : AccessibilityUIElement(object, factory) { } 548 549 AccessibilityUIElement* RootAccessibilityUIElement::getChildAtIndex(unsigned index) 550 { 551 if (index) 552 return 0; 553 554 return factory()->create(accessibilityObject()); 555 } 556 557 558 AccessibilityUIElementList ::~AccessibilityUIElementList() 559 { 560 clear(); 561 } 562 563 void AccessibilityUIElementList::clear() 564 { 565 for (ElementList::iterator i = m_elements.begin(); i != m_elements.end(); ++i) 566 delete (*i); 567 m_elements.clear(); 568 } 569 570 AccessibilityUIElement* AccessibilityUIElementList::create(const WebAccessibilityObject& object) 571 { 572 if (object.isNull()) 573 return 0; 574 575 AccessibilityUIElement* element = new AccessibilityUIElement(object, this); 576 m_elements.append(element); 577 return element; 578 } 579 580 AccessibilityUIElement* AccessibilityUIElementList::createRoot(const WebAccessibilityObject& object) 581 { 582 AccessibilityUIElement* element = new RootAccessibilityUIElement(object, this); 583 m_elements.append(element); 584 return element; 585 } 586