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 "WebAXObjectProxy.h" 32 33 #include "TestCommon.h" 34 #include "public/platform/WebCString.h" 35 #include "public/platform/WebPoint.h" 36 #include "public/platform/WebRect.h" 37 #include "public/platform/WebString.h" 38 39 using namespace blink; 40 using namespace std; 41 42 namespace WebTestRunner { 43 44 namespace { 45 46 // Map role value to string, matching Safari/Mac platform implementation to 47 // avoid rebaselining layout tests. 48 string roleToString(WebAXRole role) 49 { 50 string result = "AXRole: AX"; 51 switch (role) { 52 case WebAXRoleAlertDialog: 53 return result.append("AlertDialog"); 54 case WebAXRoleAlert: 55 return result.append("Alert"); 56 case WebAXRoleAnnotation: 57 return result.append("Annotation"); 58 case WebAXRoleApplication: 59 return result.append("Application"); 60 case WebAXRoleArticle: 61 return result.append("Article"); 62 case WebAXRoleBanner: 63 return result.append("Banner"); 64 case WebAXRoleBrowser: 65 return result.append("Browser"); 66 case WebAXRoleBusyIndicator: 67 return result.append("BusyIndicator"); 68 case WebAXRoleButton: 69 return result.append("Button"); 70 case WebAXRoleCanvas: 71 return result.append("Canvas"); 72 case WebAXRoleCell: 73 return result.append("Cell"); 74 case WebAXRoleCheckBox: 75 return result.append("CheckBox"); 76 case WebAXRoleColorWell: 77 return result.append("ColorWell"); 78 case WebAXRoleColumnHeader: 79 return result.append("ColumnHeader"); 80 case WebAXRoleColumn: 81 return result.append("Column"); 82 case WebAXRoleComboBox: 83 return result.append("ComboBox"); 84 case WebAXRoleComplementary: 85 return result.append("Complementary"); 86 case WebAXRoleContentInfo: 87 return result.append("ContentInfo"); 88 case WebAXRoleDefinition: 89 return result.append("Definition"); 90 case WebAXRoleDescriptionListDetail: 91 return result.append("DescriptionListDetail"); 92 case WebAXRoleDescriptionListTerm: 93 return result.append("DescriptionListTerm"); 94 case WebAXRoleDialog: 95 return result.append("Dialog"); 96 case WebAXRoleDirectory: 97 return result.append("Directory"); 98 case WebAXRoleDisclosureTriangle: 99 return result.append("DisclosureTriangle"); 100 case WebAXRoleDiv: 101 return result.append("Div"); 102 case WebAXRoleDocument: 103 return result.append("Document"); 104 case WebAXRoleDrawer: 105 return result.append("Drawer"); 106 case WebAXRoleEditableText: 107 return result.append("EditableText"); 108 case WebAXRoleFooter: 109 return result.append("Footer"); 110 case WebAXRoleForm: 111 return result.append("Form"); 112 case WebAXRoleGrid: 113 return result.append("Grid"); 114 case WebAXRoleGroup: 115 return result.append("Group"); 116 case WebAXRoleGrowArea: 117 return result.append("GrowArea"); 118 case WebAXRoleHeading: 119 return result.append("Heading"); 120 case WebAXRoleHelpTag: 121 return result.append("HelpTag"); 122 case WebAXRoleHorizontalRule: 123 return result.append("HorizontalRule"); 124 case WebAXRoleIgnored: 125 return result.append("Ignored"); 126 case WebAXRoleImageMapLink: 127 return result.append("ImageMapLink"); 128 case WebAXRoleImageMap: 129 return result.append("ImageMap"); 130 case WebAXRoleImage: 131 return result.append("Image"); 132 case WebAXRoleIncrementor: 133 return result.append("Incrementor"); 134 case WebAXRoleInlineTextBox: 135 return result.append("InlineTextBox"); 136 case WebAXRoleLabel: 137 return result.append("Label"); 138 case WebAXRoleLegend: 139 return result.append("Legend"); 140 case WebAXRoleLink: 141 return result.append("Link"); 142 case WebAXRoleListBoxOption: 143 return result.append("ListBoxOption"); 144 case WebAXRoleListBox: 145 return result.append("ListBox"); 146 case WebAXRoleListItem: 147 return result.append("ListItem"); 148 case WebAXRoleListMarker: 149 return result.append("ListMarker"); 150 case WebAXRoleList: 151 return result.append("List"); 152 case WebAXRoleLog: 153 return result.append("Log"); 154 case WebAXRoleMain: 155 return result.append("Main"); 156 case WebAXRoleMarquee: 157 return result.append("Marquee"); 158 case WebAXRoleMathElement: 159 return result.append("MathElement"); 160 case WebAXRoleMath: 161 return result.append("Math"); 162 case WebAXRoleMatte: 163 return result.append("Matte"); 164 case WebAXRoleMenuBar: 165 return result.append("MenuBar"); 166 case WebAXRoleMenuButton: 167 return result.append("MenuButton"); 168 case WebAXRoleMenuItem: 169 return result.append("MenuItem"); 170 case WebAXRoleMenuListOption: 171 return result.append("MenuListOption"); 172 case WebAXRoleMenuListPopup: 173 return result.append("MenuListPopup"); 174 case WebAXRoleMenu: 175 return result.append("Menu"); 176 case WebAXRoleNavigation: 177 return result.append("Navigation"); 178 case WebAXRoleNote: 179 return result.append("Note"); 180 case WebAXRoleOutline: 181 return result.append("Outline"); 182 case WebAXRoleParagraph: 183 return result.append("Paragraph"); 184 case WebAXRolePopUpButton: 185 return result.append("PopUpButton"); 186 case WebAXRolePresentational: 187 return result.append("Presentational"); 188 case WebAXRoleProgressIndicator: 189 return result.append("ProgressIndicator"); 190 case WebAXRoleRadioButton: 191 return result.append("RadioButton"); 192 case WebAXRoleRadioGroup: 193 return result.append("RadioGroup"); 194 case WebAXRoleRegion: 195 return result.append("Region"); 196 case WebAXRoleRootWebArea: 197 return result.append("RootWebArea"); 198 case WebAXRoleRowHeader: 199 return result.append("RowHeader"); 200 case WebAXRoleRow: 201 return result.append("Row"); 202 case WebAXRoleRulerMarker: 203 return result.append("RulerMarker"); 204 case WebAXRoleRuler: 205 return result.append("Ruler"); 206 case WebAXRoleSVGRoot: 207 return result.append("SVGRoot"); 208 case WebAXRoleScrollArea: 209 return result.append("ScrollArea"); 210 case WebAXRoleScrollBar: 211 return result.append("ScrollBar"); 212 case WebAXRoleSeamlessWebArea: 213 return result.append("SeamlessWebArea"); 214 case WebAXRoleSearch: 215 return result.append("Search"); 216 case WebAXRoleSheet: 217 return result.append("Sheet"); 218 case WebAXRoleSlider: 219 return result.append("Slider"); 220 case WebAXRoleSliderThumb: 221 return result.append("SliderThumb"); 222 case WebAXRoleSpinButtonPart: 223 return result.append("SpinButtonPart"); 224 case WebAXRoleSpinButton: 225 return result.append("SpinButton"); 226 case WebAXRoleSplitGroup: 227 return result.append("SplitGroup"); 228 case WebAXRoleSplitter: 229 return result.append("Splitter"); 230 case WebAXRoleStaticText: 231 return result.append("StaticText"); 232 case WebAXRoleStatus: 233 return result.append("Status"); 234 case WebAXRoleSystemWide: 235 return result.append("SystemWide"); 236 case WebAXRoleTabGroup: 237 return result.append("TabGroup"); 238 case WebAXRoleTabList: 239 return result.append("TabList"); 240 case WebAXRoleTabPanel: 241 return result.append("TabPanel"); 242 case WebAXRoleTab: 243 return result.append("Tab"); 244 case WebAXRoleTableHeaderContainer: 245 return result.append("TableHeaderContainer"); 246 case WebAXRoleTable: 247 return result.append("Table"); 248 case WebAXRoleTextArea: 249 return result.append("TextArea"); 250 case WebAXRoleTextField: 251 return result.append("TextField"); 252 case WebAXRoleTimer: 253 return result.append("Timer"); 254 case WebAXRoleToggleButton: 255 return result.append("ToggleButton"); 256 case WebAXRoleToolbar: 257 return result.append("Toolbar"); 258 case WebAXRoleTreeGrid: 259 return result.append("TreeGrid"); 260 case WebAXRoleTreeItem: 261 return result.append("TreeItem"); 262 case WebAXRoleTree: 263 return result.append("Tree"); 264 case WebAXRoleUnknown: 265 return result.append("Unknown"); 266 case WebAXRoleUserInterfaceTooltip: 267 return result.append("UserInterfaceTooltip"); 268 case WebAXRoleValueIndicator: 269 return result.append("ValueIndicator"); 270 case WebAXRoleWebArea: 271 return result.append("WebArea"); 272 case WebAXRoleWindow: 273 return result.append("Window"); 274 default: 275 return result.append("Unknown"); 276 } 277 } 278 279 string getDescription(const WebAXObject& object) 280 { 281 string description = object.accessibilityDescription().utf8(); 282 return description.insert(0, "AXDescription: "); 283 } 284 285 string getHelpText(const WebAXObject& object) 286 { 287 string helpText = object.helpText().utf8(); 288 return helpText.insert(0, "AXHelp: "); 289 } 290 291 string getStringValue(const WebAXObject& object) 292 { 293 string value; 294 if (object.role() == WebAXRoleColorWell) { 295 int r, g, b; 296 char buffer[100]; 297 object.colorValue(r, g, b); 298 snprintf(buffer, sizeof(buffer), "rgb %7.5f %7.5f %7.5f 1", r / 255., g / 255., b / 255.); 299 value = buffer; 300 } else { 301 value = object.stringValue().utf8(); 302 } 303 return value.insert(0, "AXValue: "); 304 } 305 306 string getRole(const WebAXObject& object) 307 { 308 string roleString = roleToString(object.role()); 309 310 // Special-case canvas with fallback content because Chromium wants to 311 // treat this as essentially a separate role that it can map differently depending 312 // on the platform. 313 if (object.role() == WebAXRoleCanvas && object.canvasHasFallbackContent()) 314 roleString += "WithFallbackContent"; 315 316 return roleString; 317 } 318 319 string getTitle(const WebAXObject& object) 320 { 321 string title = object.title().utf8(); 322 return title.insert(0, "AXTitle: "); 323 } 324 325 string getOrientation(const WebAXObject& object) 326 { 327 if (object.isVertical()) 328 return "AXOrientation: AXVerticalOrientation"; 329 330 return "AXOrientation: AXHorizontalOrientation"; 331 } 332 333 string getValueDescription(const WebAXObject& object) 334 { 335 string valueDescription = object.valueDescription().utf8(); 336 return valueDescription.insert(0, "AXValueDescription: "); 337 } 338 339 string getAttributes(const WebAXObject& object) 340 { 341 // FIXME: Concatenate all attributes of the AXObject. 342 string attributes(getTitle(object)); 343 attributes.append("\n"); 344 attributes.append(getRole(object)); 345 attributes.append("\n"); 346 attributes.append(getDescription(object)); 347 return attributes; 348 } 349 350 WebRect boundsForCharacter(const WebAXObject& object, int characterIndex) 351 { 352 BLINK_ASSERT(object.role() == WebAXRoleStaticText); 353 int end = 0; 354 for (unsigned i = 0; i < object.childCount(); i++) { 355 WebAXObject inlineTextBox = object.childAt(i); 356 BLINK_ASSERT(inlineTextBox.role() == WebAXRoleInlineTextBox); 357 int start = end; 358 end += inlineTextBox.stringValue().length(); 359 if (end <= characterIndex) 360 continue; 361 WebRect inlineTextBoxRect = inlineTextBox.boundingBoxRect(); 362 int localIndex = characterIndex - start; 363 WebVector<int> characterOffsets; 364 inlineTextBox.characterOffsets(characterOffsets); 365 BLINK_ASSERT(characterOffsets.size() > 0 && characterOffsets.size() == inlineTextBox.stringValue().length()); 366 switch (inlineTextBox.textDirection()) { 367 case WebAXTextDirectionLR: { 368 if (localIndex) { 369 int left = inlineTextBoxRect.x + characterOffsets[localIndex - 1]; 370 int width = characterOffsets[localIndex] - characterOffsets[localIndex - 1]; 371 return WebRect(left, inlineTextBoxRect.y, width, inlineTextBoxRect.height); 372 } 373 return WebRect(inlineTextBoxRect.x, inlineTextBoxRect.y, characterOffsets[0], inlineTextBoxRect.height); 374 } 375 case WebAXTextDirectionRL: { 376 int right = inlineTextBoxRect.x + inlineTextBoxRect.width; 377 378 if (localIndex) { 379 int left = right - characterOffsets[localIndex]; 380 int width = characterOffsets[localIndex] - characterOffsets[localIndex - 1]; 381 return WebRect(left, inlineTextBoxRect.y, width, inlineTextBoxRect.height); 382 } 383 int left = right - characterOffsets[0]; 384 return WebRect(left, inlineTextBoxRect.y, characterOffsets[0], inlineTextBoxRect.height); 385 } 386 case WebAXTextDirectionTB: { 387 if (localIndex) { 388 int top = inlineTextBoxRect.y + characterOffsets[localIndex - 1]; 389 int height = characterOffsets[localIndex] - characterOffsets[localIndex - 1]; 390 return WebRect(inlineTextBoxRect.x, top, inlineTextBoxRect.width, height); 391 } 392 return WebRect(inlineTextBoxRect.x, inlineTextBoxRect.y, inlineTextBoxRect.width, characterOffsets[0]); 393 } 394 case WebAXTextDirectionBT: { 395 int bottom = inlineTextBoxRect.y + inlineTextBoxRect.height; 396 397 if (localIndex) { 398 int top = bottom - characterOffsets[localIndex]; 399 int height = characterOffsets[localIndex] - characterOffsets[localIndex - 1]; 400 return WebRect(inlineTextBoxRect.x, top, inlineTextBoxRect.width, height); 401 } 402 int top = bottom - characterOffsets[0]; 403 return WebRect(inlineTextBoxRect.x, top, inlineTextBoxRect.width, characterOffsets[0]); 404 } 405 } 406 } 407 408 BLINK_ASSERT(false); 409 return WebRect(); 410 } 411 412 void getBoundariesForOneWord(const WebAXObject& object, int characterIndex, int& wordStart, int& wordEnd) 413 { 414 int end = 0; 415 for (unsigned i = 0; i < object.childCount(); i++) { 416 WebAXObject inlineTextBox = object.childAt(i); 417 BLINK_ASSERT(inlineTextBox.role() == WebAXRoleInlineTextBox); 418 int start = end; 419 end += inlineTextBox.stringValue().length(); 420 if (end <= characterIndex) 421 continue; 422 int localIndex = characterIndex - start; 423 424 WebVector<int> starts; 425 WebVector<int> ends; 426 inlineTextBox.wordBoundaries(starts, ends); 427 size_t wordCount = starts.size(); 428 BLINK_ASSERT(ends.size() == wordCount); 429 430 // If there are no words, use the InlineTextBox boundaries. 431 if (!wordCount) { 432 wordStart = start; 433 wordEnd = end; 434 return; 435 } 436 437 // Look for a character within any word other than the last. 438 for (size_t j = 0; j < wordCount - 1; j++) { 439 if (localIndex <= ends[j]) { 440 wordStart = start + starts[j]; 441 wordEnd = start + ends[j]; 442 return; 443 } 444 } 445 446 // Return the last word by default. 447 wordStart = start + starts[wordCount - 1]; 448 wordEnd = start + ends[wordCount - 1]; 449 return; 450 } 451 } 452 453 // Collects attributes into a string, delimited by dashes. Used by all methods 454 // that output lists of attributes: attributesOfLinkedUIElementsCallback, 455 // AttributesOfChildrenCallback, etc. 456 class AttributesCollector { 457 public: 458 void collectAttributes(const WebAXObject& object) 459 { 460 m_attributes.append("\n------------\n"); 461 m_attributes.append(getAttributes(object)); 462 } 463 464 string attributes() const { return m_attributes; } 465 466 private: 467 string m_attributes; 468 }; 469 470 } 471 472 WebAXObjectProxy::WebAXObjectProxy(const WebAXObject& object, Factory* factory) 473 : m_accessibilityObject(object) 474 , m_factory(factory) 475 { 476 477 BLINK_ASSERT(factory); 478 479 // 480 // Properties 481 // 482 483 bindProperty("role", &WebAXObjectProxy::roleGetterCallback); 484 bindProperty("title", &WebAXObjectProxy::titleGetterCallback); 485 bindProperty("description", &WebAXObjectProxy::descriptionGetterCallback); 486 bindProperty("helpText", &WebAXObjectProxy::helpTextGetterCallback); 487 bindProperty("stringValue", &WebAXObjectProxy::stringValueGetterCallback); 488 bindProperty("x", &WebAXObjectProxy::xGetterCallback); 489 bindProperty("y", &WebAXObjectProxy::yGetterCallback); 490 bindProperty("width", &WebAXObjectProxy::widthGetterCallback); 491 bindProperty("height", &WebAXObjectProxy::heightGetterCallback); 492 bindProperty("intValue", &WebAXObjectProxy::intValueGetterCallback); 493 bindProperty("minValue", &WebAXObjectProxy::minValueGetterCallback); 494 bindProperty("maxValue", &WebAXObjectProxy::maxValueGetterCallback); 495 bindProperty("valueDescription", &WebAXObjectProxy::valueDescriptionGetterCallback); 496 bindProperty("childrenCount", &WebAXObjectProxy::childrenCountGetterCallback); 497 bindProperty("insertionPointLineNumber", &WebAXObjectProxy::insertionPointLineNumberGetterCallback); 498 bindProperty("selectedTextRange", &WebAXObjectProxy::selectedTextRangeGetterCallback); 499 bindProperty("isEnabled", &WebAXObjectProxy::isEnabledGetterCallback); 500 bindProperty("isRequired", &WebAXObjectProxy::isRequiredGetterCallback); 501 bindProperty("isFocused", &WebAXObjectProxy::isFocusedGetterCallback); 502 bindProperty("isFocusable", &WebAXObjectProxy::isFocusableGetterCallback); 503 bindProperty("isSelected", &WebAXObjectProxy::isSelectedGetterCallback); 504 bindProperty("isSelectable", &WebAXObjectProxy::isSelectableGetterCallback); 505 bindProperty("isMultiSelectable", &WebAXObjectProxy::isMultiSelectableGetterCallback); 506 bindProperty("isSelectedOptionActive", &WebAXObjectProxy::isSelectedOptionActiveGetterCallback); 507 bindProperty("isExpanded", &WebAXObjectProxy::isExpandedGetterCallback); 508 bindProperty("isChecked", &WebAXObjectProxy::isCheckedGetterCallback); 509 bindProperty("isVisible", &WebAXObjectProxy::isVisibleGetterCallback); 510 bindProperty("isOffScreen", &WebAXObjectProxy::isOffScreenGetterCallback); 511 bindProperty("isCollapsed", &WebAXObjectProxy::isCollapsedGetterCallback); 512 bindProperty("hasPopup", &WebAXObjectProxy::hasPopupGetterCallback); 513 bindProperty("isValid", &WebAXObjectProxy::isValidGetterCallback); 514 bindProperty("isReadOnly", &WebAXObjectProxy::isReadOnlyGetterCallback); 515 bindProperty("orientation", &WebAXObjectProxy::orientationGetterCallback); 516 bindProperty("clickPointX", &WebAXObjectProxy::clickPointXGetterCallback); 517 bindProperty("clickPointY", &WebAXObjectProxy::clickPointYGetterCallback); 518 bindProperty("rowCount", &WebAXObjectProxy::rowCountGetterCallback); 519 bindProperty("columnCount", &WebAXObjectProxy::columnCountGetterCallback); 520 bindProperty("isClickable", &WebAXObjectProxy::isClickableGetterCallback); 521 522 // 523 // Methods 524 // 525 526 bindMethod("allAttributes", &WebAXObjectProxy::allAttributesCallback); 527 bindMethod("attributesOfChildren", &WebAXObjectProxy::attributesOfChildrenCallback); 528 bindMethod("lineForIndex", &WebAXObjectProxy::lineForIndexCallback); 529 bindMethod("boundsForRange", &WebAXObjectProxy::boundsForRangeCallback); 530 bindMethod("childAtIndex", &WebAXObjectProxy::childAtIndexCallback); 531 bindMethod("elementAtPoint", &WebAXObjectProxy::elementAtPointCallback); 532 bindMethod("tableHeader", &WebAXObjectProxy::tableHeaderCallback); 533 bindMethod("rowIndexRange", &WebAXObjectProxy::rowIndexRangeCallback); 534 bindMethod("columnIndexRange", &WebAXObjectProxy::columnIndexRangeCallback); 535 bindMethod("cellForColumnAndRow", &WebAXObjectProxy::cellForColumnAndRowCallback); 536 bindMethod("titleUIElement", &WebAXObjectProxy::titleUIElementCallback); 537 bindMethod("setSelectedTextRange", &WebAXObjectProxy::setSelectedTextRangeCallback); 538 bindMethod("isAttributeSettable", &WebAXObjectProxy::isAttributeSettableCallback); 539 bindMethod("isPressActionSupported", &WebAXObjectProxy::isPressActionSupportedCallback); 540 bindMethod("isIncrementActionSupported", &WebAXObjectProxy::isIncrementActionSupportedCallback); 541 bindMethod("isDecrementActionSupported", &WebAXObjectProxy::isDecrementActionSupportedCallback); 542 bindMethod("parentElement", &WebAXObjectProxy::parentElementCallback); 543 bindMethod("increment", &WebAXObjectProxy::incrementCallback); 544 bindMethod("decrement", &WebAXObjectProxy::decrementCallback); 545 bindMethod("showMenu", &WebAXObjectProxy::showMenuCallback); 546 bindMethod("press", &WebAXObjectProxy::pressCallback); 547 bindMethod("isEqual", &WebAXObjectProxy::isEqualCallback); 548 bindMethod("addNotificationListener", &WebAXObjectProxy::addNotificationListenerCallback); 549 bindMethod("removeNotificationListener", &WebAXObjectProxy::removeNotificationListenerCallback); 550 bindMethod("takeFocus", &WebAXObjectProxy::takeFocusCallback); 551 bindMethod("scrollToMakeVisible", &WebAXObjectProxy::scrollToMakeVisibleCallback); 552 bindMethod("scrollToMakeVisibleWithSubFocus", &WebAXObjectProxy::scrollToMakeVisibleWithSubFocusCallback); 553 bindMethod("scrollToGlobalPoint", &WebAXObjectProxy::scrollToGlobalPointCallback); 554 bindMethod("wordStart", &WebAXObjectProxy::wordStartCallback); 555 bindMethod("wordEnd", &WebAXObjectProxy::wordEndCallback); 556 557 bindFallbackMethod(&WebAXObjectProxy::fallbackCallback); 558 } 559 560 WebAXObjectProxy* WebAXObjectProxy::getChildAtIndex(unsigned index) 561 { 562 return m_factory->getOrCreate(accessibilityObject().childAt(index)); 563 } 564 565 bool WebAXObjectProxy::isEqual(const blink::WebAXObject& other) 566 { 567 return accessibilityObject().equals(other); 568 } 569 570 void WebAXObjectProxy::notificationReceived(const char* notificationName) 571 { 572 size_t callbackCount = m_notificationCallbacks.size(); 573 for (size_t i = 0; i < callbackCount; i++) { 574 CppVariant notificationNameArgument; 575 notificationNameArgument.set(notificationName); 576 CppVariant invokeResult; 577 m_notificationCallbacks[i].invokeDefault(¬ificationNameArgument, 1, invokeResult); 578 } 579 } 580 581 // 582 // Properties 583 // 584 585 void WebAXObjectProxy::roleGetterCallback(CppVariant* result) 586 { 587 result->set(getRole(accessibilityObject())); 588 } 589 590 void WebAXObjectProxy::titleGetterCallback(CppVariant* result) 591 { 592 result->set(getTitle(accessibilityObject())); 593 } 594 595 void WebAXObjectProxy::descriptionGetterCallback(CppVariant* result) 596 { 597 result->set(getDescription(accessibilityObject())); 598 } 599 600 void WebAXObjectProxy::helpTextGetterCallback(CppVariant* result) 601 { 602 result->set(getHelpText(accessibilityObject())); 603 } 604 605 void WebAXObjectProxy::stringValueGetterCallback(CppVariant* result) 606 { 607 result->set(getStringValue(accessibilityObject())); 608 } 609 610 void WebAXObjectProxy::xGetterCallback(CppVariant* result) 611 { 612 result->set(accessibilityObject().boundingBoxRect().x); 613 } 614 615 void WebAXObjectProxy::yGetterCallback(CppVariant* result) 616 { 617 result->set(accessibilityObject().boundingBoxRect().y); 618 } 619 620 void WebAXObjectProxy::widthGetterCallback(CppVariant* result) 621 { 622 result->set(accessibilityObject().boundingBoxRect().width); 623 } 624 625 void WebAXObjectProxy::heightGetterCallback(CppVariant* result) 626 { 627 result->set(accessibilityObject().boundingBoxRect().height); 628 } 629 630 void WebAXObjectProxy::intValueGetterCallback(CppVariant* result) 631 { 632 if (accessibilityObject().supportsRangeValue()) 633 result->set(accessibilityObject().valueForRange()); 634 else if (accessibilityObject().role() == WebAXRoleHeading) 635 result->set(accessibilityObject().headingLevel()); 636 else 637 result->set(atoi(accessibilityObject().stringValue().utf8().data())); 638 } 639 640 void WebAXObjectProxy::minValueGetterCallback(CppVariant* result) 641 { 642 result->set(accessibilityObject().minValueForRange()); 643 } 644 645 void WebAXObjectProxy::maxValueGetterCallback(CppVariant* result) 646 { 647 result->set(accessibilityObject().maxValueForRange()); 648 } 649 650 void WebAXObjectProxy::valueDescriptionGetterCallback(CppVariant* result) 651 { 652 result->set(getValueDescription(accessibilityObject())); 653 } 654 655 void WebAXObjectProxy::childrenCountGetterCallback(CppVariant* result) 656 { 657 int count = 1; // Root object always has only one child, the WebView. 658 if (!isRoot()) 659 count = accessibilityObject().childCount(); 660 result->set(count); 661 } 662 663 void WebAXObjectProxy::insertionPointLineNumberGetterCallback(CppVariant* result) 664 { 665 if (!accessibilityObject().isFocused()) { 666 result->set(-1); 667 return; 668 } 669 670 int lineNumber = accessibilityObject().selectionEndLineNumber(); 671 result->set(lineNumber); 672 } 673 674 void WebAXObjectProxy::selectedTextRangeGetterCallback(CppVariant* result) 675 { 676 unsigned selectionStart = accessibilityObject().selectionStart(); 677 unsigned selectionEnd = accessibilityObject().selectionEnd(); 678 char buffer[100]; 679 snprintf(buffer, sizeof(buffer), "{%d, %d}", selectionStart, selectionEnd - selectionStart); 680 681 result->set(std::string(buffer)); 682 } 683 684 void WebAXObjectProxy::isEnabledGetterCallback(CppVariant* result) 685 { 686 result->set(accessibilityObject().isEnabled()); 687 } 688 689 void WebAXObjectProxy::isRequiredGetterCallback(CppVariant* result) 690 { 691 result->set(accessibilityObject().isRequired()); 692 } 693 694 void WebAXObjectProxy::isFocusedGetterCallback(CppVariant* result) 695 { 696 result->set(accessibilityObject().isFocused()); 697 } 698 699 void WebAXObjectProxy::isFocusableGetterCallback(CppVariant* result) 700 { 701 result->set(accessibilityObject().canSetFocusAttribute()); 702 } 703 704 void WebAXObjectProxy::isSelectedGetterCallback(CppVariant* result) 705 { 706 result->set(accessibilityObject().isSelected()); 707 } 708 709 void WebAXObjectProxy::isSelectableGetterCallback(CppVariant* result) 710 { 711 result->set(accessibilityObject().canSetSelectedAttribute()); 712 } 713 714 void WebAXObjectProxy::isMultiSelectableGetterCallback(CppVariant* result) 715 { 716 result->set(accessibilityObject().isMultiSelectable()); 717 } 718 719 void WebAXObjectProxy::isSelectedOptionActiveGetterCallback(CppVariant* result) 720 { 721 result->set(accessibilityObject().isSelectedOptionActive()); 722 } 723 724 void WebAXObjectProxy::isExpandedGetterCallback(CppVariant* result) 725 { 726 result->set(!accessibilityObject().isCollapsed()); 727 } 728 729 void WebAXObjectProxy::isCheckedGetterCallback(CppVariant* result) 730 { 731 result->set(accessibilityObject().isChecked()); 732 } 733 734 void WebAXObjectProxy::isVisibleGetterCallback(CppVariant* result) 735 { 736 result->set(accessibilityObject().isVisible()); 737 } 738 739 void WebAXObjectProxy::isOffScreenGetterCallback(CppVariant* result) 740 { 741 result->set(accessibilityObject().isOffScreen()); 742 } 743 744 void WebAXObjectProxy::isCollapsedGetterCallback(CppVariant* result) 745 { 746 result->set(accessibilityObject().isCollapsed()); 747 } 748 749 void WebAXObjectProxy::hasPopupGetterCallback(CppVariant* result) 750 { 751 result->set(accessibilityObject().ariaHasPopup()); 752 } 753 754 void WebAXObjectProxy::isValidGetterCallback(CppVariant* result) 755 { 756 result->set(!accessibilityObject().isDetached()); 757 } 758 759 void WebAXObjectProxy::isReadOnlyGetterCallback(CppVariant* result) 760 { 761 result->set(accessibilityObject().isReadOnly()); 762 } 763 764 void WebAXObjectProxy::orientationGetterCallback(CppVariant* result) 765 { 766 result->set(getOrientation(accessibilityObject())); 767 } 768 769 void WebAXObjectProxy::clickPointXGetterCallback(CppVariant* result) 770 { 771 result->set(accessibilityObject().clickPoint().x); 772 } 773 774 void WebAXObjectProxy::clickPointYGetterCallback(CppVariant* result) 775 { 776 result->set(accessibilityObject().clickPoint().y); 777 } 778 779 void WebAXObjectProxy::rowCountGetterCallback(CppVariant* result) 780 { 781 result->set(static_cast<int32_t>(accessibilityObject().rowCount())); 782 } 783 784 void WebAXObjectProxy::columnCountGetterCallback(CppVariant* result) 785 { 786 result->set(static_cast<int32_t>(accessibilityObject().columnCount())); 787 } 788 789 void WebAXObjectProxy::isClickableGetterCallback(CppVariant* result) 790 { 791 result->set(accessibilityObject().isClickable()); 792 } 793 794 // 795 // Methods 796 // 797 798 void WebAXObjectProxy::allAttributesCallback(const CppArgumentList&, CppVariant* result) 799 { 800 result->set(getAttributes(accessibilityObject())); 801 } 802 803 void WebAXObjectProxy::attributesOfChildrenCallback(const CppArgumentList& arguments, CppVariant* result) 804 { 805 AttributesCollector collector; 806 unsigned size = accessibilityObject().childCount(); 807 for (unsigned i = 0; i < size; ++i) 808 collector.collectAttributes(accessibilityObject().childAt(i)); 809 result->set(collector.attributes()); 810 } 811 812 void WebAXObjectProxy::lineForIndexCallback(const CppArgumentList& arguments, CppVariant* result) 813 { 814 if (!arguments.size() || !arguments[0].isNumber()) { 815 result->setNull(); 816 return; 817 } 818 819 int index = arguments[0].toInt32(); 820 821 WebVector<int> lineBreaks; 822 accessibilityObject().lineBreaks(lineBreaks); 823 int line = 0; 824 int vectorSize = static_cast<int>(lineBreaks.size()); 825 while (line < vectorSize && lineBreaks[line] <= index) 826 line++; 827 result->set(line); 828 } 829 830 void WebAXObjectProxy::boundsForRangeCallback(const CppArgumentList& arguments, CppVariant* result) 831 { 832 result->setNull(); 833 834 if (arguments.size() != 2 || !arguments[0].isNumber() || !arguments[1].isNumber()) 835 return; 836 837 if (accessibilityObject().role() != WebAXRoleStaticText) 838 return; 839 840 int start = arguments[0].toInt32(); 841 int end = arguments[1].toInt32(); 842 int len = end - start; 843 844 // Get the bounds for each character and union them into one large rectangle. 845 // This is just for testing so it doesn't need to be efficient. 846 WebRect bounds = boundsForCharacter(accessibilityObject(), start); 847 for (int i = 1; i < len; i++) { 848 WebRect next = boundsForCharacter(accessibilityObject(), start + i); 849 int right = std::max(bounds.x + bounds.width, next.x + next.width); 850 int bottom = std::max(bounds.y + bounds.height, next.y + next.height); 851 bounds.x = std::min(bounds.x, next.x); 852 bounds.y = std::min(bounds.y, next.y); 853 bounds.width = right - bounds.x; 854 bounds.height = bottom - bounds.y; 855 } 856 857 char buffer[100]; 858 snprintf(buffer, sizeof(buffer), "{x: %d, y: %d, width: %d, height: %d}", bounds.x, bounds.y, bounds.width, bounds.height); 859 result->set(string(buffer)); 860 } 861 862 void WebAXObjectProxy::childAtIndexCallback(const CppArgumentList& arguments, CppVariant* result) 863 { 864 if (!arguments.size() || !arguments[0].isNumber()) { 865 result->setNull(); 866 return; 867 } 868 869 WebAXObjectProxy* child = getChildAtIndex(arguments[0].toInt32()); 870 if (!child) { 871 result->setNull(); 872 return; 873 } 874 875 result->set(*(child->getAsCppVariant())); 876 } 877 878 void WebAXObjectProxy::elementAtPointCallback(const CppArgumentList& arguments, CppVariant* result) 879 { 880 result->setNull(); 881 882 if (arguments.size() != 2 || !arguments[0].isNumber() || !arguments[1].isNumber()) 883 return; 884 885 int x = arguments[0].toInt32(); 886 int y = arguments[1].toInt32(); 887 WebPoint point(x, y); 888 WebAXObject obj = accessibilityObject().hitTest(point); 889 if (obj.isNull()) 890 return; 891 892 result->set(*(m_factory->getOrCreate(obj)->getAsCppVariant())); 893 } 894 895 void WebAXObjectProxy::tableHeaderCallback(const CppArgumentList&, CppVariant* result) 896 { 897 WebAXObject obj = accessibilityObject().headerContainerObject(); 898 if (obj.isNull()) { 899 result->setNull(); 900 return; 901 } 902 903 result->set(*(m_factory->getOrCreate(obj)->getAsCppVariant())); 904 } 905 906 void WebAXObjectProxy::rowIndexRangeCallback(const CppArgumentList&, CppVariant* result) 907 { 908 unsigned rowIndex = accessibilityObject().cellRowIndex(); 909 unsigned rowSpan = accessibilityObject().cellRowSpan(); 910 char buffer[100]; 911 snprintf(buffer, sizeof(buffer), "{%d, %d}", rowIndex, rowSpan); 912 string value = buffer; 913 result->set(std::string(buffer)); 914 } 915 916 void WebAXObjectProxy::columnIndexRangeCallback(const CppArgumentList&, CppVariant* result) 917 { 918 unsigned columnIndex = accessibilityObject().cellColumnIndex(); 919 unsigned columnSpan = accessibilityObject().cellColumnSpan(); 920 char buffer[100]; 921 snprintf(buffer, sizeof(buffer), "{%d, %d}", columnIndex, columnSpan); 922 result->set(std::string(buffer)); 923 } 924 925 void WebAXObjectProxy::cellForColumnAndRowCallback(const CppArgumentList& arguments, CppVariant* result) 926 { 927 if (arguments.size() != 2 || !arguments[0].isNumber() || !arguments[1].isNumber()) 928 return; 929 930 int column = arguments[0].toInt32(); 931 int row = arguments[1].toInt32(); 932 WebAXObject obj = accessibilityObject().cellForColumnAndRow(column, row); 933 if (obj.isNull()) { 934 result->setNull(); 935 return; 936 } 937 938 result->set(*(m_factory->getOrCreate(obj)->getAsCppVariant())); 939 } 940 941 void WebAXObjectProxy::titleUIElementCallback(const CppArgumentList&, CppVariant* result) 942 { 943 WebAXObject obj = accessibilityObject().titleUIElement(); 944 if (obj.isNull()) { 945 result->setNull(); 946 return; 947 } 948 949 result->set(*(m_factory->getOrCreate(obj)->getAsCppVariant())); 950 } 951 952 void WebAXObjectProxy::setSelectedTextRangeCallback(const CppArgumentList&arguments, CppVariant* result) 953 { 954 result->setNull(); 955 if (arguments.size() != 2 || !arguments[0].isNumber() || !arguments[1].isNumber()) 956 return; 957 958 int selectionStart = arguments[0].toInt32(); 959 int selectionEnd = selectionStart + arguments[1].toInt32(); 960 accessibilityObject().setSelectedTextRange(selectionStart, selectionEnd); 961 } 962 963 void WebAXObjectProxy::isAttributeSettableCallback(const CppArgumentList& arguments, CppVariant* result) 964 { 965 if (arguments.size() < 1 && !arguments[0].isString()) { 966 result->setNull(); 967 return; 968 } 969 970 string attribute = arguments[0].toString(); 971 bool settable = false; 972 if (attribute == "AXValue") 973 settable = accessibilityObject().canSetValueAttribute(); 974 result->set(settable); 975 } 976 977 void WebAXObjectProxy::isPressActionSupportedCallback(const CppArgumentList&, CppVariant* result) 978 { 979 result->set(accessibilityObject().canPress()); 980 } 981 982 void WebAXObjectProxy::isIncrementActionSupportedCallback(const CppArgumentList&, CppVariant* result) 983 { 984 result->set(accessibilityObject().canIncrement()); 985 } 986 987 void WebAXObjectProxy::isDecrementActionSupportedCallback(const CppArgumentList&, CppVariant* result) 988 { 989 result->set(accessibilityObject().canDecrement()); 990 } 991 992 void WebAXObjectProxy::parentElementCallback(const CppArgumentList&, CppVariant* result) 993 { 994 WebAXObject parentObject = accessibilityObject().parentObject(); 995 while (parentObject.accessibilityIsIgnored()) 996 parentObject = parentObject.parentObject(); 997 WebAXObjectProxy* parent = m_factory->getOrCreate(parentObject); 998 if (!parent) { 999 result->setNull(); 1000 return; 1001 } 1002 1003 result->set(*(parent->getAsCppVariant())); 1004 } 1005 1006 void WebAXObjectProxy::incrementCallback(const CppArgumentList&, CppVariant* result) 1007 { 1008 accessibilityObject().increment(); 1009 result->setNull(); 1010 } 1011 1012 void WebAXObjectProxy::decrementCallback(const CppArgumentList&, CppVariant* result) 1013 { 1014 accessibilityObject().decrement(); 1015 result->setNull(); 1016 } 1017 1018 void WebAXObjectProxy::showMenuCallback(const CppArgumentList&, CppVariant* result) 1019 { 1020 result->setNull(); 1021 } 1022 1023 void WebAXObjectProxy::pressCallback(const CppArgumentList&, CppVariant* result) 1024 { 1025 accessibilityObject().press(); 1026 result->setNull(); 1027 } 1028 1029 void WebAXObjectProxy::isEqualCallback(const CppArgumentList& arguments, CppVariant* result) 1030 { 1031 if (arguments.size() < 1 || !arguments[0].isObject()) { 1032 result->setNull(); 1033 return; 1034 } 1035 1036 result->set(arguments[0].isEqual(*getAsCppVariant())); 1037 } 1038 1039 void WebAXObjectProxy::addNotificationListenerCallback(const CppArgumentList& arguments, CppVariant* result) 1040 { 1041 if (arguments.size() < 1 || !arguments[0].isObject()) { 1042 result->setNull(); 1043 return; 1044 } 1045 1046 m_notificationCallbacks.push_back(arguments[0]); 1047 result->setNull(); 1048 } 1049 1050 void WebAXObjectProxy::removeNotificationListenerCallback(const CppArgumentList&, CppVariant* result) 1051 { 1052 // FIXME: Implement this. 1053 result->setNull(); 1054 } 1055 1056 void WebAXObjectProxy::takeFocusCallback(const CppArgumentList&, CppVariant* result) 1057 { 1058 accessibilityObject().setFocused(true); 1059 result->setNull(); 1060 } 1061 1062 void WebAXObjectProxy::scrollToMakeVisibleCallback(const CppArgumentList&, CppVariant* result) 1063 { 1064 accessibilityObject().scrollToMakeVisible(); 1065 result->setNull(); 1066 } 1067 1068 void WebAXObjectProxy::scrollToMakeVisibleWithSubFocusCallback(const CppArgumentList& arguments, CppVariant* result) 1069 { 1070 result->setNull(); 1071 1072 if (arguments.size() != 4 1073 || !arguments[0].isNumber() 1074 || !arguments[1].isNumber() 1075 || !arguments[2].isNumber() 1076 || !arguments[3].isNumber()) 1077 return; 1078 1079 int x = arguments[0].toInt32(); 1080 int y = arguments[1].toInt32(); 1081 int width = arguments[2].toInt32(); 1082 int height = arguments[3].toInt32(); 1083 accessibilityObject().scrollToMakeVisibleWithSubFocus(WebRect(x, y, width, height)); 1084 result->setNull(); 1085 } 1086 1087 void WebAXObjectProxy::scrollToGlobalPointCallback(const CppArgumentList& arguments, CppVariant* result) 1088 { 1089 result->setNull(); 1090 1091 if (arguments.size() != 2 1092 || !arguments[0].isNumber() 1093 || !arguments[1].isNumber()) 1094 return; 1095 1096 int x = arguments[0].toInt32(); 1097 int y = arguments[1].toInt32(); 1098 1099 accessibilityObject().scrollToGlobalPoint(WebPoint(x, y)); 1100 result->setNull(); 1101 } 1102 1103 void WebAXObjectProxy::wordStartCallback(const CppArgumentList& arguments, CppVariant* result) 1104 { 1105 result->setNull(); 1106 1107 if (arguments.size() != 1 || !arguments[0].isNumber()) 1108 return; 1109 1110 if (accessibilityObject().role() != WebAXRoleStaticText) 1111 return; 1112 1113 int characterIndex = arguments[0].toInt32(); 1114 int wordStart, wordEnd; 1115 getBoundariesForOneWord(accessibilityObject(), characterIndex, wordStart, wordEnd); 1116 result->set(wordStart); 1117 } 1118 1119 void WebAXObjectProxy::wordEndCallback(const CppArgumentList& arguments, CppVariant* result) 1120 { 1121 result->setNull(); 1122 1123 if (arguments.size() != 1 || !arguments[0].isNumber()) 1124 return; 1125 1126 if (accessibilityObject().role() != WebAXRoleStaticText) 1127 return; 1128 1129 int characterIndex = arguments[0].toInt32(); 1130 int wordStart, wordEnd; 1131 getBoundariesForOneWord(accessibilityObject(), characterIndex, wordStart, wordEnd); 1132 result->set(wordEnd); 1133 } 1134 1135 void WebAXObjectProxy::fallbackCallback(const CppArgumentList &, CppVariant* result) 1136 { 1137 result->setNull(); 1138 } 1139 1140 RootWebAXObjectProxy::RootWebAXObjectProxy(const WebAXObject &object, Factory *factory) 1141 : WebAXObjectProxy(object, factory) { } 1142 1143 WebAXObjectProxy* RootWebAXObjectProxy::getChildAtIndex(unsigned index) 1144 { 1145 if (index) 1146 return 0; 1147 1148 return factory()->getOrCreate(accessibilityObject()); 1149 } 1150 1151 1152 WebAXObjectProxyList ::~WebAXObjectProxyList() 1153 { 1154 clear(); 1155 } 1156 1157 void WebAXObjectProxyList::clear() 1158 { 1159 for (ElementList::iterator i = m_elements.begin(); i != m_elements.end(); ++i) 1160 delete (*i); 1161 m_elements.clear(); 1162 } 1163 1164 WebAXObjectProxy* WebAXObjectProxyList::getOrCreate(const WebAXObject& object) 1165 { 1166 if (object.isNull()) 1167 return 0; 1168 1169 size_t elementCount = m_elements.size(); 1170 for (size_t i = 0; i < elementCount; i++) { 1171 if (m_elements[i]->isEqual(object)) 1172 return m_elements[i]; 1173 } 1174 1175 WebAXObjectProxy* element = new WebAXObjectProxy(object, this); 1176 m_elements.push_back(element); 1177 return element; 1178 } 1179 1180 WebAXObjectProxy* WebAXObjectProxyList::createRoot(const WebAXObject& object) 1181 { 1182 WebAXObjectProxy* element = new RootWebAXObjectProxy(object, this); 1183 m_elements.push_back(element); 1184 return element; 1185 } 1186 1187 } 1188