browser_accessibility_win.cc revision 731df977c0511bca2206b5f333555b1205ff1f43
1// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/accessibility/browser_accessibility_win.h" 6 7#include "base/string_number_conversions.h" 8#include "base/string_util.h" 9#include "base/utf_string_conversions.h" 10#include "chrome/browser/accessibility/browser_accessibility_manager_win.h" 11#include "net/base/escape.h" 12 13using webkit_glue::WebAccessibility; 14 15// static 16BrowserAccessibility* BrowserAccessibility::Create() { 17 CComObject<BrowserAccessibilityWin>* instance; 18 HRESULT hr = CComObject<BrowserAccessibilityWin>::CreateInstance(&instance); 19 DCHECK(SUCCEEDED(hr)); 20 return instance->NewReference(); 21} 22 23BrowserAccessibilityWin* BrowserAccessibility::toBrowserAccessibilityWin() { 24 return static_cast<BrowserAccessibilityWin*>(this); 25} 26 27BrowserAccessibilityWin::BrowserAccessibilityWin() 28 : instance_active_(false) { 29} 30 31BrowserAccessibilityWin::~BrowserAccessibilityWin() { 32 ReleaseTree(); 33} 34 35// 36// IAccessible methods. 37// 38// Conventions: 39// * Always test for instance_active_ first and return E_FAIL if it's false. 40// * Always check for invalid arguments first, even if they're unused. 41// * Return S_FALSE if the only output is a string argument and it's empty. 42// 43 44HRESULT BrowserAccessibilityWin::accDoDefaultAction(VARIANT var_id) { 45 if (!instance_active_) 46 return E_FAIL; 47 48 BrowserAccessibilityWin* target = GetTargetFromChildID(var_id); 49 if (!target) 50 return E_INVALIDARG; 51 52 manager_->DoDefaultAction(*target); 53 return S_OK; 54} 55 56STDMETHODIMP BrowserAccessibilityWin::accHitTest(LONG x_left, LONG y_top, 57 VARIANT* child) { 58 if (!instance_active_) 59 return E_FAIL; 60 61 if (!child) 62 return E_INVALIDARG; 63 64 return E_NOTIMPL; 65} 66 67STDMETHODIMP BrowserAccessibilityWin::accLocation(LONG* x_left, LONG* y_top, 68 LONG* width, LONG* height, 69 VARIANT var_id) { 70 if (!instance_active_) 71 return E_FAIL; 72 73 if (!x_left || !y_top || !width || !height) 74 return E_INVALIDARG; 75 76 BrowserAccessibilityWin* target = GetTargetFromChildID(var_id); 77 if (!target) 78 return E_INVALIDARG; 79 80 // Find the top left corner of the containing window in screen coords, and 81 // adjust the output position by this amount. 82 HWND parent_hwnd = manager_->GetParentView(); 83 POINT top_left = {0, 0}; 84 ::ClientToScreen(parent_hwnd, &top_left); 85 86 *x_left = target->location_.x + top_left.x; 87 *y_top = target->location_.y + top_left.y; 88 *width = target->location_.width; 89 *height = target->location_.height; 90 91 return S_OK; 92} 93 94STDMETHODIMP BrowserAccessibilityWin::accNavigate( 95 LONG nav_dir, VARIANT start, VARIANT* end) { 96 BrowserAccessibilityWin* target = GetTargetFromChildID(start); 97 if (!target) 98 return E_INVALIDARG; 99 100 if ((nav_dir == NAVDIR_LASTCHILD || nav_dir == NAVDIR_FIRSTCHILD) && 101 start.lVal != CHILDID_SELF) { 102 // MSAA states that navigating to first/last child can only be from self. 103 return E_INVALIDARG; 104 } 105 106 BrowserAccessibility* result = NULL; 107 switch (nav_dir) { 108 case NAVDIR_DOWN: 109 case NAVDIR_UP: 110 case NAVDIR_LEFT: 111 case NAVDIR_RIGHT: 112 // These directions are not implemented, matching Mozilla and IE. 113 return E_NOTIMPL; 114 case NAVDIR_FIRSTCHILD: 115 if (target->children_.size() > 0) 116 result = target->children_[0]; 117 break; 118 case NAVDIR_LASTCHILD: 119 if (target->children_.size() > 0) 120 result = target->children_[target->children_.size() - 1]; 121 break; 122 case NAVDIR_NEXT: 123 result = target->GetNextSibling(); 124 break; 125 case NAVDIR_PREVIOUS: 126 result = target->GetPreviousSibling(); 127 break; 128 } 129 130 if (!result) { 131 end->vt = VT_EMPTY; 132 return S_FALSE; 133 } 134 135 end->vt = VT_DISPATCH; 136 end->pdispVal = result->toBrowserAccessibilityWin()->NewReference(); 137 return S_OK; 138} 139 140STDMETHODIMP BrowserAccessibilityWin::get_accChild(VARIANT var_child, 141 IDispatch** disp_child) { 142 if (!instance_active_) 143 return E_FAIL; 144 145 if (!disp_child) 146 return E_INVALIDARG; 147 148 *disp_child = NULL; 149 150 BrowserAccessibilityWin* target = GetTargetFromChildID(var_child); 151 if (!target) 152 return E_INVALIDARG; 153 154 (*disp_child) = target->NewReference(); 155 return S_OK; 156} 157 158STDMETHODIMP BrowserAccessibilityWin::get_accChildCount(LONG* child_count) { 159 if (!instance_active_) 160 return E_FAIL; 161 162 if (!child_count) 163 return E_INVALIDARG; 164 165 *child_count = children_.size(); 166 return S_OK; 167} 168 169STDMETHODIMP BrowserAccessibilityWin::get_accDefaultAction(VARIANT var_id, 170 BSTR* def_action) { 171 if (!instance_active_) 172 return E_FAIL; 173 174 if (!def_action) 175 return E_INVALIDARG; 176 177 BrowserAccessibilityWin* target = GetTargetFromChildID(var_id); 178 if (!target) 179 return E_INVALIDARG; 180 181 return target->GetAttributeAsBstr( 182 WebAccessibility::ATTR_SHORTCUT, def_action); 183} 184 185STDMETHODIMP BrowserAccessibilityWin::get_accDescription(VARIANT var_id, 186 BSTR* desc) { 187 if (!instance_active_) 188 return E_FAIL; 189 190 if (!desc) 191 return E_INVALIDARG; 192 193 BrowserAccessibilityWin* target = GetTargetFromChildID(var_id); 194 if (!target) 195 return E_INVALIDARG; 196 197 return target->GetAttributeAsBstr(WebAccessibility::ATTR_DESCRIPTION, desc); 198} 199 200STDMETHODIMP BrowserAccessibilityWin::get_accFocus(VARIANT* focus_child) { 201 if (!instance_active_) 202 return E_FAIL; 203 204 if (!focus_child) 205 return E_INVALIDARG; 206 207 BrowserAccessibilityWin* focus = static_cast<BrowserAccessibilityWin*>( 208 manager_->GetFocus(this)); 209 if (focus == this) { 210 focus_child->vt = VT_I4; 211 focus_child->lVal = CHILDID_SELF; 212 } else if (focus == NULL) { 213 focus_child->vt = VT_EMPTY; 214 } else { 215 focus_child->vt = VT_DISPATCH; 216 focus_child->pdispVal = focus->NewReference(); 217 } 218 219 return S_OK; 220} 221 222STDMETHODIMP BrowserAccessibilityWin::get_accHelp(VARIANT var_id, BSTR* help) { 223 if (!instance_active_) 224 return E_FAIL; 225 226 if (!help) 227 return E_INVALIDARG; 228 229 BrowserAccessibilityWin* target = GetTargetFromChildID(var_id); 230 if (!target) 231 return E_INVALIDARG; 232 233 return target->GetAttributeAsBstr(WebAccessibility::ATTR_HELP, help); 234} 235 236STDMETHODIMP BrowserAccessibilityWin::get_accKeyboardShortcut(VARIANT var_id, 237 BSTR* acc_key) { 238 if (!instance_active_) 239 return E_FAIL; 240 241 if (!acc_key) 242 return E_INVALIDARG; 243 244 BrowserAccessibilityWin* target = GetTargetFromChildID(var_id); 245 if (!target) 246 return E_INVALIDARG; 247 248 return target->GetAttributeAsBstr(WebAccessibility::ATTR_SHORTCUT, acc_key); 249} 250 251STDMETHODIMP BrowserAccessibilityWin::get_accName(VARIANT var_id, BSTR* name) { 252 if (!instance_active_) 253 return E_FAIL; 254 255 if (!name) 256 return E_INVALIDARG; 257 258 BrowserAccessibilityWin* target = GetTargetFromChildID(var_id); 259 if (!target) 260 return E_INVALIDARG; 261 262 if (target->name_.empty()) 263 return S_FALSE; 264 265 *name = SysAllocString(target->name_.c_str()); 266 267 DCHECK(*name); 268 return S_OK; 269} 270 271STDMETHODIMP BrowserAccessibilityWin::get_accParent(IDispatch** disp_parent) { 272 if (!instance_active_) 273 return E_FAIL; 274 275 if (!disp_parent) 276 return E_INVALIDARG; 277 278 IAccessible* parent = parent_->toBrowserAccessibilityWin(); 279 if (parent == NULL) { 280 // This happens if we're the root of the tree; 281 // return the IAccessible for the window. 282 parent = manager_->toBrowserAccessibilityManagerWin()-> 283 GetParentWindowIAccessible(); 284 } 285 286 parent->AddRef(); 287 *disp_parent = parent; 288 return S_OK; 289} 290 291STDMETHODIMP BrowserAccessibilityWin::get_accRole( 292 VARIANT var_id, VARIANT* role) { 293 if (!instance_active_) 294 return E_FAIL; 295 296 if (!role) 297 return E_INVALIDARG; 298 299 BrowserAccessibilityWin* target = GetTargetFromChildID(var_id); 300 if (!target) 301 return E_INVALIDARG; 302 303 if (!target->role_name_.empty()) { 304 role->vt = VT_BSTR; 305 role->bstrVal = SysAllocString(target->role_name_.c_str()); 306 } else { 307 role->vt = VT_I4; 308 role->lVal = target->ia_role_; 309 } 310 return S_OK; 311} 312 313STDMETHODIMP BrowserAccessibilityWin::get_accState(VARIANT var_id, 314 VARIANT* state) { 315 if (!instance_active_) 316 return E_FAIL; 317 318 if (!state) 319 return E_INVALIDARG; 320 321 BrowserAccessibilityWin* target = GetTargetFromChildID(var_id); 322 if (!target) 323 return E_INVALIDARG; 324 325 state->vt = VT_I4; 326 state->lVal = target->ia_state_; 327 if (manager_->GetFocus(NULL) == this) 328 state->lVal |= STATE_SYSTEM_FOCUSED; 329 330 return S_OK; 331} 332 333STDMETHODIMP BrowserAccessibilityWin::get_accValue( 334 VARIANT var_id, BSTR* value) { 335 if (!instance_active_) 336 return E_FAIL; 337 338 if (!value) 339 return E_INVALIDARG; 340 341 BrowserAccessibilityWin* target = GetTargetFromChildID(var_id); 342 if (!target) 343 return E_INVALIDARG; 344 345 *value = SysAllocString(target->value_.c_str()); 346 347 DCHECK(*value); 348 return S_OK; 349} 350 351STDMETHODIMP BrowserAccessibilityWin::get_accHelpTopic( 352 BSTR* help_file, VARIANT var_id, LONG* topic_id) { 353 return E_NOTIMPL; 354} 355 356STDMETHODIMP BrowserAccessibilityWin::get_accSelection(VARIANT* selected) { 357 if (!instance_active_) 358 return E_FAIL; 359 360 return E_NOTIMPL; 361} 362 363STDMETHODIMP BrowserAccessibilityWin::accSelect( 364 LONG flags_sel, VARIANT var_id) { 365 if (!instance_active_) 366 return E_FAIL; 367 368 if (flags_sel & SELFLAG_TAKEFOCUS) { 369 manager_->SetFocus(*this); 370 return S_OK; 371 } 372 373 return S_FALSE; 374} 375 376// 377// IAccessible2 methods. 378// 379 380STDMETHODIMP BrowserAccessibilityWin::role(LONG* role) { 381 if (!instance_active_) 382 return E_FAIL; 383 384 if (!role) 385 return E_INVALIDARG; 386 387 *role = ia2_role_; 388 389 return S_OK; 390} 391 392STDMETHODIMP BrowserAccessibilityWin::get_attributes(BSTR* attributes) { 393 if (!instance_active_) 394 return E_FAIL; 395 396 if (!attributes) 397 return E_INVALIDARG; 398 399 // Follow Firefox's convention, which is to return a set of key-value pairs 400 // separated by semicolons, with a colon between the key and the value. 401 string16 str; 402 for (unsigned int i = 0; i < html_attributes_.size(); i++) { 403 if (i != 0) 404 str += L';'; 405 str += Escape(html_attributes_[i].first); 406 str += L':'; 407 str += Escape(html_attributes_[i].second); 408 } 409 410 if (str.empty()) 411 return S_FALSE; 412 413 *attributes = SysAllocString(str.c_str()); 414 DCHECK(*attributes); 415 return S_OK; 416} 417 418STDMETHODIMP BrowserAccessibilityWin::get_states(AccessibleStates* states) { 419 if (!instance_active_) 420 return E_FAIL; 421 422 if (!states) 423 return E_INVALIDARG; 424 425 *states = ia2_state_; 426 427 return S_OK; 428} 429 430STDMETHODIMP BrowserAccessibilityWin::get_uniqueID(LONG* unique_id) { 431 if (!instance_active_) 432 return E_FAIL; 433 434 if (!unique_id) 435 return E_INVALIDARG; 436 437 *unique_id = child_id_; 438 return S_OK; 439} 440 441STDMETHODIMP BrowserAccessibilityWin::get_windowHandle(HWND* window_handle) { 442 if (!instance_active_) 443 return E_FAIL; 444 445 if (!window_handle) 446 return E_INVALIDARG; 447 448 *window_handle = manager_->GetParentView(); 449 return S_OK; 450} 451 452STDMETHODIMP BrowserAccessibilityWin::get_indexInParent(LONG* index_in_parent) { 453 if (!instance_active_) 454 return E_FAIL; 455 456 if (!index_in_parent) 457 return E_INVALIDARG; 458 459 *index_in_parent = index_in_parent_; 460 return S_OK; 461} 462 463// 464// IAccessibleImage methods. 465// 466 467STDMETHODIMP BrowserAccessibilityWin::get_description(BSTR* desc) { 468 if (!instance_active_) 469 return E_FAIL; 470 471 if (!desc) 472 return E_INVALIDARG; 473 474 return GetAttributeAsBstr(WebAccessibility::ATTR_DESCRIPTION, desc); 475} 476 477STDMETHODIMP BrowserAccessibilityWin::get_imagePosition( 478 enum IA2CoordinateType coordinate_type, LONG* x, LONG* y) { 479 if (!instance_active_) 480 return E_FAIL; 481 482 if (!x || !y) 483 return E_INVALIDARG; 484 485 if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) { 486 HWND parent_hwnd = manager_->GetParentView(); 487 POINT top_left = {0, 0}; 488 ::ClientToScreen(parent_hwnd, &top_left); 489 *x = location_.x + top_left.x; 490 *y = location_.y + top_left.y; 491 } else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) { 492 *x = location_.x; 493 *y = location_.y; 494 if (parent_) { 495 *x -= parent_->location().x; 496 *y -= parent_->location().y; 497 } 498 } else { 499 return E_INVALIDARG; 500 } 501 502 return S_OK; 503} 504 505STDMETHODIMP BrowserAccessibilityWin::get_imageSize(LONG* height, LONG* width) { 506 if (!instance_active_) 507 return E_FAIL; 508 509 if (!height || !width) 510 return E_INVALIDARG; 511 512 *height = location_.height; 513 *width = location_.width; 514 return S_OK; 515} 516 517// 518// IAccessibleText methods. 519// 520 521STDMETHODIMP BrowserAccessibilityWin::get_nCharacters(LONG* n_characters) { 522 if (!instance_active_) 523 return E_FAIL; 524 525 if (!n_characters) 526 return E_INVALIDARG; 527 528 if (role_ == WebAccessibility::ROLE_TEXT_FIELD) { 529 *n_characters = value_.length(); 530 } else { 531 *n_characters = name_.length(); 532 } 533 534 return S_OK; 535} 536 537STDMETHODIMP BrowserAccessibilityWin::get_caretOffset(LONG* offset) { 538 if (!instance_active_) 539 return E_FAIL; 540 541 if (!offset) 542 return E_INVALIDARG; 543 544 if (role_ == WebAccessibility::ROLE_TEXT_FIELD) { 545 int sel_start = 0; 546 if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start)) { 547 *offset = sel_start; 548 } else { 549 *offset = 0; 550 } 551 } else { 552 *offset = 0; 553 } 554 555 return S_OK; 556} 557 558STDMETHODIMP BrowserAccessibilityWin::get_nSelections(LONG* n_selections) { 559 if (!instance_active_) 560 return E_FAIL; 561 562 if (!n_selections) 563 return E_INVALIDARG; 564 565 if (role_ == WebAccessibility::ROLE_TEXT_FIELD) { 566 int sel_start = 0; 567 int sel_end = 0; 568 if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start) && 569 GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_END, &sel_end) && 570 sel_start != sel_end) { 571 *n_selections = 1; 572 } else { 573 *n_selections = 0; 574 } 575 } else { 576 *n_selections = 0; 577 } 578 579 return S_OK; 580} 581 582STDMETHODIMP BrowserAccessibilityWin::get_selection(LONG selection_index, 583 LONG* start_offset, 584 LONG* end_offset) { 585 if (!instance_active_) 586 return E_FAIL; 587 588 if (!start_offset || !end_offset || selection_index != 0) 589 return E_INVALIDARG; 590 591 if (role_ == WebAccessibility::ROLE_TEXT_FIELD) { 592 int sel_start = 0; 593 int sel_end = 0; 594 if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start) && 595 GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_END, &sel_end)) { 596 *start_offset = sel_start; 597 *end_offset = sel_end; 598 } else { 599 *start_offset = 0; 600 *end_offset = 0; 601 } 602 } else { 603 *start_offset = 0; 604 *end_offset = 0; 605 } 606 607 return S_OK; 608} 609 610STDMETHODIMP BrowserAccessibilityWin::get_text( 611 LONG start_offset, LONG end_offset, BSTR* text) { 612 if (!instance_active_) 613 return E_FAIL; 614 615 if (!text) 616 return E_INVALIDARG; 617 618 const string16& text_str = TextForIAccessibleText(); 619 620 // The spec allows the arguments to be reversed. 621 if (start_offset > end_offset) { 622 LONG tmp = start_offset; 623 start_offset = end_offset; 624 end_offset = tmp; 625 } 626 627 // The spec does not allow the start or end offsets to be out or range; 628 // we must return an error if so. 629 LONG len = text_str.length(); 630 if (start_offset < 0) 631 return E_INVALIDARG; 632 if (end_offset > len) 633 return E_INVALIDARG; 634 635 string16 substr = text_str.substr(start_offset, end_offset - start_offset); 636 if (substr.empty()) 637 return S_FALSE; 638 639 *text = SysAllocString(substr.c_str()); 640 DCHECK(*text); 641 return S_OK; 642} 643 644STDMETHODIMP BrowserAccessibilityWin::get_textAtOffset( 645 LONG offset, 646 enum IA2TextBoundaryType boundary_type, 647 LONG* start_offset, LONG* end_offset, 648 BSTR* text) { 649 if (!instance_active_) 650 return E_FAIL; 651 652 if (!start_offset || !end_offset || !text) 653 return E_INVALIDARG; 654 655 // The IAccessible2 spec says we don't have to implement the "sentence" 656 // boundary type, we can just let the screenreader handle it. 657 if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) { 658 *start_offset = 0; 659 *end_offset = 0; 660 *text = NULL; 661 return S_FALSE; 662 } 663 664 const string16& text_str = TextForIAccessibleText(); 665 666 *start_offset = FindBoundary(text_str, boundary_type, offset, -1); 667 *end_offset = FindBoundary(text_str, boundary_type, offset, 1); 668 return get_text(*start_offset, *end_offset, text); 669} 670 671STDMETHODIMP BrowserAccessibilityWin::get_textBeforeOffset( 672 LONG offset, 673 enum IA2TextBoundaryType boundary_type, 674 LONG* start_offset, LONG* end_offset, 675 BSTR* text) { 676 if (!instance_active_) 677 return E_FAIL; 678 679 if (!start_offset || !end_offset || !text) 680 return E_INVALIDARG; 681 682 // The IAccessible2 spec says we don't have to implement the "sentence" 683 // boundary type, we can just let the screenreader handle it. 684 if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) { 685 *start_offset = 0; 686 *end_offset = 0; 687 *text = NULL; 688 return S_FALSE; 689 } 690 691 const string16& text_str = TextForIAccessibleText(); 692 693 *start_offset = FindBoundary(text_str, boundary_type, offset, -1); 694 *end_offset = offset; 695 return get_text(*start_offset, *end_offset, text); 696} 697 698STDMETHODIMP BrowserAccessibilityWin::get_textAfterOffset( 699 LONG offset, 700 enum IA2TextBoundaryType boundary_type, 701 LONG* start_offset, LONG* end_offset, 702 BSTR* text) { 703 if (!instance_active_) 704 return E_FAIL; 705 706 if (!start_offset || !end_offset || !text) 707 return E_INVALIDARG; 708 709 // The IAccessible2 spec says we don't have to implement the "sentence" 710 // boundary type, we can just let the screenreader handle it. 711 if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) { 712 *start_offset = 0; 713 *end_offset = 0; 714 *text = NULL; 715 return S_FALSE; 716 } 717 718 const string16& text_str = TextForIAccessibleText(); 719 720 *start_offset = offset; 721 *end_offset = FindBoundary(text_str, boundary_type, offset, 1); 722 return get_text(*start_offset, *end_offset, text); 723} 724 725// 726// ISimpleDOMDocument methods. 727// 728 729STDMETHODIMP BrowserAccessibilityWin::get_URL(BSTR* url) { 730 if (!instance_active_) 731 return E_FAIL; 732 733 if (!url) 734 return E_INVALIDARG; 735 736 return GetAttributeAsBstr(WebAccessibility::ATTR_DOC_URL, url); 737} 738 739STDMETHODIMP BrowserAccessibilityWin::get_title(BSTR* title) { 740 if (!instance_active_) 741 return E_FAIL; 742 743 if (!title) 744 return E_INVALIDARG; 745 746 return GetAttributeAsBstr(WebAccessibility::ATTR_DOC_TITLE, title); 747} 748 749STDMETHODIMP BrowserAccessibilityWin::get_mimeType(BSTR* mime_type) { 750 if (!instance_active_) 751 return E_FAIL; 752 753 if (!mime_type) 754 return E_INVALIDARG; 755 756 return GetAttributeAsBstr(WebAccessibility::ATTR_DOC_MIMETYPE, mime_type); 757} 758 759STDMETHODIMP BrowserAccessibilityWin::get_docType(BSTR* doc_type) { 760 if (!instance_active_) 761 return E_FAIL; 762 763 if (!doc_type) 764 return E_INVALIDARG; 765 766 return GetAttributeAsBstr(WebAccessibility::ATTR_DOC_DOCTYPE, doc_type); 767} 768 769// 770// ISimpleDOMNode methods. 771// 772 773STDMETHODIMP BrowserAccessibilityWin::get_nodeInfo( 774 BSTR* node_name, 775 short* name_space_id, 776 BSTR* node_value, 777 unsigned int* num_children, 778 unsigned int* unique_id, 779 unsigned short* node_type) { 780 if (!instance_active_) 781 return E_FAIL; 782 783 if (!node_name || !name_space_id || !node_value || !num_children || 784 !unique_id || !node_type) { 785 return E_INVALIDARG; 786 } 787 788 string16 tag; 789 if (GetAttribute(WebAccessibility::ATTR_HTML_TAG, &tag)) 790 *node_name = SysAllocString(tag.c_str()); 791 else 792 *node_name = NULL; 793 794 *name_space_id = 0; 795 *node_value = SysAllocString(value_.c_str()); 796 *num_children = children_.size(); 797 *unique_id = child_id_; 798 799 if (ia_role_ == ROLE_SYSTEM_DOCUMENT) { 800 *node_type = NODETYPE_DOCUMENT; 801 } else if (ia_role_ == ROLE_SYSTEM_TEXT && 802 ((ia2_state_ & IA2_STATE_EDITABLE) == 0)) { 803 *node_type = NODETYPE_TEXT; 804 } else { 805 *node_type = NODETYPE_ELEMENT; 806 } 807 808 return S_OK; 809} 810 811STDMETHODIMP BrowserAccessibilityWin::get_attributes( 812 unsigned short max_attribs, 813 BSTR* attrib_names, 814 short* name_space_id, 815 BSTR* attrib_values, 816 unsigned short* num_attribs) { 817 if (!instance_active_) 818 return E_FAIL; 819 820 if (!attrib_names || !name_space_id || !attrib_values || !num_attribs) 821 return E_INVALIDARG; 822 823 *num_attribs = max_attribs; 824 if (*num_attribs > html_attributes_.size()) 825 *num_attribs = html_attributes_.size(); 826 827 for (unsigned short i = 0; i < *num_attribs; ++i) { 828 attrib_names[i] = SysAllocString(html_attributes_[i].first.c_str()); 829 name_space_id[i] = 0; 830 attrib_values[i] = SysAllocString(html_attributes_[i].second.c_str()); 831 } 832 return S_OK; 833} 834 835STDMETHODIMP BrowserAccessibilityWin::get_attributesForNames( 836 unsigned short num_attribs, 837 BSTR* attrib_names, 838 short* name_space_id, 839 BSTR* attrib_values) { 840 if (!instance_active_) 841 return E_FAIL; 842 843 if (!attrib_names || !name_space_id || !attrib_values) 844 return E_INVALIDARG; 845 846 for (unsigned short i = 0; i < num_attribs; ++i) { 847 name_space_id[i] = 0; 848 bool found = false; 849 string16 name = (LPCWSTR)attrib_names[i]; 850 for (unsigned int j = 0; j < html_attributes_.size(); ++j) { 851 if (html_attributes_[j].first == name) { 852 attrib_values[i] = SysAllocString(html_attributes_[j].second.c_str()); 853 found = true; 854 break; 855 } 856 } 857 if (!found) { 858 attrib_values[i] = NULL; 859 } 860 } 861 return S_OK; 862} 863 864STDMETHODIMP BrowserAccessibilityWin::get_computedStyle( 865 unsigned short max_style_properties, 866 boolean use_alternate_view, 867 BSTR *style_properties, 868 BSTR *style_values, 869 unsigned short *num_style_properties) { 870 if (!instance_active_) 871 return E_FAIL; 872 873 if (!style_properties || !style_values) 874 return E_INVALIDARG; 875 876 // We only cache a single style property for now: DISPLAY 877 878 if (max_style_properties == 0 || 879 !HasAttribute(WebAccessibility::ATTR_DISPLAY)) { 880 *num_style_properties = 0; 881 return S_OK; 882 } 883 884 string16 display; 885 GetAttribute(WebAccessibility::ATTR_DISPLAY, &display); 886 *num_style_properties = 1; 887 style_properties[0] = SysAllocString(L"display"); 888 style_values[0] = SysAllocString(display.c_str()); 889 890 return S_OK; 891} 892 893STDMETHODIMP BrowserAccessibilityWin::get_computedStyleForProperties( 894 unsigned short num_style_properties, 895 boolean use_alternate_view, 896 BSTR* style_properties, 897 BSTR* style_values) { 898 if (!instance_active_) 899 return E_FAIL; 900 901 if (!style_properties || !style_values) 902 return E_INVALIDARG; 903 904 // We only cache a single style property for now: DISPLAY 905 906 for (unsigned short i = 0; i < num_style_properties; i++) { 907 string16 name = (LPCWSTR)style_properties[i]; 908 StringToLowerASCII(&name); 909 if (name == L"display") { 910 string16 display; 911 GetAttribute(WebAccessibility::ATTR_DISPLAY, &display); 912 style_values[i] = SysAllocString(display.c_str()); 913 } else { 914 style_values[i] = NULL; 915 } 916 } 917 918 return S_OK; 919} 920 921STDMETHODIMP BrowserAccessibilityWin::scrollTo(boolean placeTopLeft) { 922 return E_NOTIMPL; 923} 924 925STDMETHODIMP BrowserAccessibilityWin::get_parentNode(ISimpleDOMNode** node) { 926 if (!instance_active_) 927 return E_FAIL; 928 929 if (!node) 930 return E_INVALIDARG; 931 932 *node = parent_->toBrowserAccessibilityWin()->NewReference(); 933 return S_OK; 934} 935 936STDMETHODIMP BrowserAccessibilityWin::get_firstChild(ISimpleDOMNode** node) { 937 if (!instance_active_) 938 return E_FAIL; 939 940 if (!node) 941 return E_INVALIDARG; 942 943 if (children_.size()) { 944 *node = children_[0]->toBrowserAccessibilityWin()->NewReference(); 945 return S_OK; 946 } else { 947 *node = NULL; 948 return S_FALSE; 949 } 950} 951 952STDMETHODIMP BrowserAccessibilityWin::get_lastChild(ISimpleDOMNode** node) { 953 if (!instance_active_) 954 return E_FAIL; 955 956 if (!node) 957 return E_INVALIDARG; 958 959 if (children_.size()) { 960 *node = children_[children_.size() - 1]->toBrowserAccessibilityWin()-> 961 NewReference(); 962 return S_OK; 963 } else { 964 *node = NULL; 965 return S_FALSE; 966 } 967} 968 969STDMETHODIMP BrowserAccessibilityWin::get_previousSibling( 970 ISimpleDOMNode** node) { 971 if (!instance_active_) 972 return E_FAIL; 973 974 if (!node) 975 return E_INVALIDARG; 976 977 if (parent_ && index_in_parent_ > 0) { 978 *node = parent_->children()[index_in_parent_ - 1]-> 979 toBrowserAccessibilityWin()->NewReference(); 980 return S_OK; 981 } else { 982 *node = NULL; 983 return S_FALSE; 984 } 985} 986 987STDMETHODIMP BrowserAccessibilityWin::get_nextSibling(ISimpleDOMNode** node) { 988 if (!instance_active_) 989 return E_FAIL; 990 991 if (!node) 992 return E_INVALIDARG; 993 994 if (parent_ && 995 index_in_parent_ >= 0 && 996 index_in_parent_ < static_cast<int>(parent_->children().size()) - 1) { 997 *node = parent_->children()[index_in_parent_ + 1]-> 998 toBrowserAccessibilityWin()->NewReference(); 999 return S_OK; 1000 } else { 1001 *node = NULL; 1002 return S_FALSE; 1003 } 1004} 1005 1006STDMETHODIMP BrowserAccessibilityWin::get_childAt( 1007 unsigned int child_index, 1008 ISimpleDOMNode** node) { 1009 if (!instance_active_) 1010 return E_FAIL; 1011 1012 if (!node) 1013 return E_INVALIDARG; 1014 1015 if (child_index < children_.size()) { 1016 *node = children_[child_index]->toBrowserAccessibilityWin()->NewReference(); 1017 return S_OK; 1018 } else { 1019 *node = NULL; 1020 return S_FALSE; 1021 } 1022} 1023 1024// 1025// ISimpleDOMText methods. 1026// 1027 1028STDMETHODIMP BrowserAccessibilityWin::get_domText(BSTR* dom_text) { 1029 if (!instance_active_) 1030 return E_FAIL; 1031 1032 if (!dom_text) 1033 return E_INVALIDARG; 1034 1035 if (name_.empty()) 1036 return S_FALSE; 1037 1038 *dom_text = SysAllocString(name_.c_str()); 1039 DCHECK(*dom_text); 1040 return S_OK; 1041} 1042 1043// 1044// IServiceProvider methods. 1045// 1046 1047STDMETHODIMP BrowserAccessibilityWin::QueryService( 1048 REFGUID guidService, REFIID riid, void** object) { 1049 if (!instance_active_) 1050 return E_FAIL; 1051 1052 if (guidService == IID_IAccessible || 1053 guidService == IID_IAccessible2 || 1054 guidService == IID_IAccessibleImage || 1055 guidService == IID_IAccessibleText || 1056 guidService == IID_ISimpleDOMDocument || 1057 guidService == IID_ISimpleDOMNode || 1058 guidService == IID_ISimpleDOMText) { 1059 return QueryInterface(riid, object); 1060 } 1061 1062 *object = NULL; 1063 return E_FAIL; 1064} 1065 1066// 1067// CComObjectRootEx methods. 1068// 1069 1070HRESULT WINAPI BrowserAccessibilityWin::InternalQueryInterface( 1071 void* this_ptr, 1072 const _ATL_INTMAP_ENTRY* entries, 1073 REFIID iid, 1074 void** object) { 1075 if (iid == IID_IAccessibleText) { 1076 if (ia_role_ != ROLE_SYSTEM_LINK && ia_role_ != ROLE_SYSTEM_TEXT) { 1077 *object = NULL; 1078 return E_NOINTERFACE; 1079 } 1080 } else if (iid == IID_IAccessibleImage) { 1081 if (ia_role_ != ROLE_SYSTEM_GRAPHIC) { 1082 *object = NULL; 1083 return E_NOINTERFACE; 1084 } 1085 } else if (iid == IID_ISimpleDOMDocument) { 1086 if (ia_role_ != ROLE_SYSTEM_DOCUMENT) { 1087 *object = NULL; 1088 return E_NOINTERFACE; 1089 } 1090 } 1091 1092 return CComObjectRootBase::InternalQueryInterface( 1093 this_ptr, entries, iid, object); 1094} 1095 1096// 1097// Private methods. 1098// 1099 1100// Initialize this object and mark it as active. 1101void BrowserAccessibilityWin::Initialize() { 1102 InitRoleAndState(); 1103 1104 // Expose headings levels to NVDA with the "level" object attribute. 1105 if (role_ == WebAccessibility::ROLE_HEADING && role_name_.size() == 2 && 1106 IsAsciiDigit(role_name_[1])) { 1107 html_attributes_.push_back(std::make_pair(L"level", role_name_.substr(1))); 1108 } 1109 1110 // If this object doesn't have a name but it does have a description, 1111 // use the description as its name - because some screen readers only 1112 // announce the name. 1113 if (name_.empty() && HasAttribute(WebAccessibility::ATTR_DESCRIPTION)) { 1114 GetAttribute(WebAccessibility::ATTR_DESCRIPTION, &name_); 1115 } 1116 1117 instance_active_ = true; 1118} 1119 1120// Mark this object as inactive, and remove references to all children. 1121// When no other clients hold any references to this object it will be 1122// deleted, and in the meantime, calls to any methods will return E_FAIL. 1123void BrowserAccessibilityWin::ReleaseTree() { 1124 if (!instance_active_) 1125 return; 1126 1127 // Mark this object as inactive, so calls to all COM methods will return 1128 // failure. 1129 instance_active_ = false; 1130 1131 BrowserAccessibility::ReleaseTree(); 1132} 1133 1134void BrowserAccessibilityWin::ReleaseReference() { 1135 Release(); 1136} 1137 1138 1139BrowserAccessibilityWin* BrowserAccessibilityWin::NewReference() { 1140 AddRef(); 1141 return this; 1142} 1143 1144BrowserAccessibilityWin* BrowserAccessibilityWin::GetTargetFromChildID( 1145 const VARIANT& var_id) { 1146 if (var_id.vt != VT_I4) 1147 return NULL; 1148 1149 LONG child_id = var_id.lVal; 1150 if (child_id == CHILDID_SELF) 1151 return this; 1152 1153 if (child_id >= 1 && child_id <= static_cast<LONG>(children_.size())) 1154 return children_[child_id - 1]->toBrowserAccessibilityWin(); 1155 1156 return manager_->GetFromChildID(child_id)->toBrowserAccessibilityWin(); 1157} 1158 1159bool BrowserAccessibilityWin::HasAttribute( 1160 WebAccessibility::Attribute attribute) { 1161 return (attributes_.find(attribute) != attributes_.end()); 1162} 1163 1164bool BrowserAccessibilityWin::GetAttribute( 1165 WebAccessibility::Attribute attribute, string16* value) { 1166 std::map<int32, string16>::iterator iter = attributes_.find(attribute); 1167 if (iter != attributes_.end()) { 1168 *value = iter->second; 1169 return true; 1170 } 1171 1172 return false; 1173} 1174 1175HRESULT BrowserAccessibilityWin::GetAttributeAsBstr( 1176 WebAccessibility::Attribute attribute, BSTR* value_bstr) { 1177 string16 str; 1178 1179 if (!GetAttribute(attribute, &str)) 1180 return S_FALSE; 1181 1182 if (str.empty()) 1183 return S_FALSE; 1184 1185 *value_bstr = SysAllocString(str.c_str()); 1186 DCHECK(*value_bstr); 1187 1188 return S_OK; 1189} 1190 1191bool BrowserAccessibilityWin::GetAttributeAsInt( 1192 WebAccessibility::Attribute attribute, int* value_int) { 1193 string16 value_str; 1194 1195 if (!GetAttribute(attribute, &value_str)) 1196 return false; 1197 1198 if (!base::StringToInt(value_str, value_int)) 1199 return false; 1200 1201 return true; 1202} 1203 1204string16 BrowserAccessibilityWin::Escape(string16 str) { 1205 return EscapeQueryParamValueUTF8(str, false); 1206} 1207 1208const string16& BrowserAccessibilityWin::TextForIAccessibleText() { 1209 if (role_ == WebAccessibility::ROLE_TEXT_FIELD) { 1210 return value_; 1211 } else { 1212 return name_; 1213 } 1214} 1215 1216LONG BrowserAccessibilityWin::FindBoundary( 1217 const string16& text, 1218 IA2TextBoundaryType boundary, 1219 LONG start_offset, 1220 LONG direction) { 1221 LONG text_size = static_cast<LONG>(text.size()); 1222 DCHECK(start_offset >= 0 && start_offset <= text_size); 1223 DCHECK(direction == 1 || direction == -1); 1224 1225 if (boundary == IA2_TEXT_BOUNDARY_CHAR) { 1226 if (direction == 1 && start_offset < text_size) 1227 return start_offset + 1; 1228 else 1229 return start_offset; 1230 } 1231 1232 LONG result = start_offset; 1233 for (;;) { 1234 LONG pos; 1235 if (direction == 1) { 1236 if (result >= text_size) 1237 return text_size; 1238 pos = result; 1239 } else { 1240 if (result <= 0) 1241 return 0; 1242 pos = result - 1; 1243 } 1244 1245 switch (boundary) { 1246 case IA2_TEXT_BOUNDARY_WORD: 1247 if (IsWhitespace(text[pos])) 1248 return result; 1249 break; 1250 case IA2_TEXT_BOUNDARY_LINE: 1251 case IA2_TEXT_BOUNDARY_PARAGRAPH: 1252 if (text[pos] == '\n') 1253 return result; 1254 case IA2_TEXT_BOUNDARY_SENTENCE: 1255 // Note that we don't actually have to implement sentence support; 1256 // currently IAccessibleText functions return S_FALSE so that 1257 // screenreaders will handle it on their own. 1258 if ((text[pos] == '.' || text[pos] == '!' || text[pos] == '?') && 1259 (pos == text_size - 1 || IsWhitespace(text[pos + 1]))) { 1260 return result; 1261 } 1262 case IA2_TEXT_BOUNDARY_ALL: 1263 default: 1264 break; 1265 } 1266 1267 if (direction > 0) { 1268 result++; 1269 } else if (direction < 0) { 1270 result--; 1271 } else { 1272 NOTREACHED(); 1273 return result; 1274 } 1275 } 1276} 1277 1278void BrowserAccessibilityWin::InitRoleAndState() { 1279 ia_state_ = 0; 1280 ia2_state_ = IA2_STATE_OPAQUE; 1281 1282 if ((state_ >> WebAccessibility::STATE_CHECKED) & 1) 1283 ia_state_ |= STATE_SYSTEM_CHECKED; 1284 if ((state_ >> WebAccessibility::STATE_COLLAPSED) & 1) 1285 ia_state_|= STATE_SYSTEM_COLLAPSED; 1286 if ((state_ >> WebAccessibility::STATE_EXPANDED) & 1) 1287 ia_state_|= STATE_SYSTEM_EXPANDED; 1288 if ((state_ >> WebAccessibility::STATE_FOCUSABLE) & 1) 1289 ia_state_|= STATE_SYSTEM_FOCUSABLE; 1290 if ((state_ >> WebAccessibility::STATE_HASPOPUP) & 1) 1291 ia_state_|= STATE_SYSTEM_HASPOPUP; 1292 if ((state_ >> WebAccessibility::STATE_HOTTRACKED) & 1) 1293 ia_state_|= STATE_SYSTEM_HOTTRACKED; 1294 if ((state_ >> WebAccessibility::STATE_INDETERMINATE) & 1) 1295 ia_state_|= STATE_SYSTEM_INDETERMINATE; 1296 if ((state_ >> WebAccessibility::STATE_INVISIBLE) & 1) 1297 ia_state_|= STATE_SYSTEM_INVISIBLE; 1298 if ((state_ >> WebAccessibility::STATE_LINKED) & 1) 1299 ia_state_|= STATE_SYSTEM_LINKED; 1300 if ((state_ >> WebAccessibility::STATE_MULTISELECTABLE) & 1) 1301 ia_state_|= STATE_SYSTEM_MULTISELECTABLE; 1302 // TODO(ctguil): Support STATE_SYSTEM_EXTSELECTABLE/accSelect. 1303 if ((state_ >> WebAccessibility::STATE_OFFSCREEN) & 1) 1304 ia_state_|= STATE_SYSTEM_OFFSCREEN; 1305 if ((state_ >> WebAccessibility::STATE_PRESSED) & 1) 1306 ia_state_|= STATE_SYSTEM_PRESSED; 1307 if ((state_ >> WebAccessibility::STATE_PROTECTED) & 1) 1308 ia_state_|= STATE_SYSTEM_PROTECTED; 1309 if ((state_ >> WebAccessibility::STATE_SELECTABLE) & 1) 1310 ia_state_|= STATE_SYSTEM_SELECTABLE; 1311 if ((state_ >> WebAccessibility::STATE_SELECTED) & 1) 1312 ia_state_|= STATE_SYSTEM_SELECTED; 1313 if ((state_ >> WebAccessibility::STATE_READONLY) & 1) 1314 ia_state_|= STATE_SYSTEM_READONLY; 1315 if ((state_ >> WebAccessibility::STATE_TRAVERSED) & 1) 1316 ia_state_|= STATE_SYSTEM_TRAVERSED; 1317 if ((state_ >> WebAccessibility::STATE_BUSY) & 1) 1318 ia_state_|= STATE_SYSTEM_BUSY; 1319 if ((state_ >> WebAccessibility::STATE_UNAVAILABLE) & 1) 1320 ia_state_|= STATE_SYSTEM_UNAVAILABLE; 1321 1322 ia_role_ = 0; 1323 ia2_role_ = 0; 1324 switch (role_) { 1325 case WebAccessibility::ROLE_ALERT: 1326 case WebAccessibility::ROLE_ALERT_DIALOG: 1327 ia_role_ = ROLE_SYSTEM_ALERT; 1328 break; 1329 case WebAccessibility::ROLE_APPLICATION: 1330 ia_role_ = ROLE_SYSTEM_APPLICATION; 1331 break; 1332 case WebAccessibility::ROLE_ARTICLE: 1333 ia_role_ = ROLE_SYSTEM_GROUPING; 1334 ia2_role_ = IA2_ROLE_SECTION; 1335 break; 1336 case WebAccessibility::ROLE_BUTTON: 1337 ia_role_ = ROLE_SYSTEM_PUSHBUTTON; 1338 break; 1339 case WebAccessibility::ROLE_CELL: 1340 ia_role_ = ROLE_SYSTEM_CELL; 1341 break; 1342 case WebAccessibility::ROLE_CHECKBOX: 1343 ia_role_ = ROLE_SYSTEM_CHECKBUTTON; 1344 break; 1345 case WebAccessibility::ROLE_COLOR_WELL: 1346 ia_role_ = ROLE_SYSTEM_CLIENT; 1347 ia2_role_ = IA2_ROLE_COLOR_CHOOSER; 1348 break; 1349 case WebAccessibility::ROLE_COLUMN: 1350 ia_role_ = ROLE_SYSTEM_COLUMN; 1351 break; 1352 case WebAccessibility::ROLE_COLUMN_HEADER: 1353 ia_role_ = ROLE_SYSTEM_COLUMNHEADER; 1354 break; 1355 case WebAccessibility::ROLE_COMBO_BOX: 1356 ia_role_ = ROLE_SYSTEM_COMBOBOX; 1357 break; 1358 case WebAccessibility::ROLE_DEFINITION_LIST_DEFINITION: 1359 GetAttribute(WebAccessibility::ATTR_HTML_TAG, &role_name_); 1360 ia2_role_ = IA2_ROLE_PARAGRAPH; 1361 break; 1362 case WebAccessibility::ROLE_DEFINITION_LIST_TERM: 1363 ia_role_ = ROLE_SYSTEM_LISTITEM; 1364 break; 1365 case WebAccessibility::ROLE_DIALOG: 1366 ia_role_ = ROLE_SYSTEM_DIALOG; 1367 break; 1368 case WebAccessibility::ROLE_DOCUMENT: 1369 case WebAccessibility::ROLE_WEB_AREA: 1370 ia_role_ = ROLE_SYSTEM_DOCUMENT; 1371 ia_state_|= STATE_SYSTEM_READONLY; 1372 ia_state_|= STATE_SYSTEM_FOCUSABLE; 1373 break; 1374 case WebAccessibility::ROLE_EDITABLE_TEXT: 1375 ia_role_ = ROLE_SYSTEM_TEXT; 1376 ia2_state_ |= IA2_STATE_SINGLE_LINE; 1377 ia2_state_ |= IA2_STATE_EDITABLE; 1378 break; 1379 case WebAccessibility::ROLE_GRID: 1380 ia_role_ = ROLE_SYSTEM_TABLE; 1381 break; 1382 case WebAccessibility::ROLE_GROUP: 1383 GetAttribute(WebAccessibility::ATTR_HTML_TAG, &role_name_); 1384 if (role_name_.empty()) 1385 role_name_ = L"div"; 1386 ia2_role_ = IA2_ROLE_SECTION; 1387 break; 1388 case WebAccessibility::ROLE_HEADING: 1389 GetAttribute(WebAccessibility::ATTR_HTML_TAG, &role_name_); 1390 ia2_role_ = IA2_ROLE_HEADING; 1391 break; 1392 case WebAccessibility::ROLE_IMAGE: 1393 ia_role_ = ROLE_SYSTEM_GRAPHIC; 1394 break; 1395 case WebAccessibility::ROLE_IMAGE_MAP: 1396 GetAttribute(WebAccessibility::ATTR_HTML_TAG, &role_name_); 1397 ia2_role_ = IA2_ROLE_IMAGE_MAP; 1398 break; 1399 case WebAccessibility::ROLE_IMAGE_MAP_LINK: 1400 ia_role_ = ROLE_SYSTEM_LINK; 1401 ia_state_|= STATE_SYSTEM_LINKED; 1402 break; 1403 case WebAccessibility::ROLE_LANDMARK_APPLICATION: 1404 case WebAccessibility::ROLE_LANDMARK_BANNER: 1405 case WebAccessibility::ROLE_LANDMARK_COMPLEMENTARY: 1406 case WebAccessibility::ROLE_LANDMARK_CONTENTINFO: 1407 case WebAccessibility::ROLE_LANDMARK_MAIN: 1408 case WebAccessibility::ROLE_LANDMARK_NAVIGATION: 1409 case WebAccessibility::ROLE_LANDMARK_SEARCH: 1410 ia_role_ = ROLE_SYSTEM_GROUPING; 1411 ia2_role_ = IA2_ROLE_SECTION; 1412 break; 1413 case WebAccessibility::ROLE_LINK: 1414 case WebAccessibility::ROLE_WEBCORE_LINK: 1415 ia_role_ = ROLE_SYSTEM_LINK; 1416 ia_state_|= STATE_SYSTEM_LINKED; 1417 break; 1418 case WebAccessibility::ROLE_LIST: 1419 ia_role_ = ROLE_SYSTEM_LIST; 1420 break; 1421 case WebAccessibility::ROLE_LISTBOX: 1422 ia_role_ = ROLE_SYSTEM_LIST; 1423 break; 1424 case WebAccessibility::ROLE_LISTBOX_OPTION: 1425 case WebAccessibility::ROLE_LIST_ITEM: 1426 case WebAccessibility::ROLE_LIST_MARKER: 1427 ia_role_ = ROLE_SYSTEM_LISTITEM; 1428 break; 1429 case WebAccessibility::ROLE_MENU: 1430 case WebAccessibility::ROLE_MENU_BUTTON: 1431 ia_role_ = ROLE_SYSTEM_MENUPOPUP; 1432 break; 1433 case WebAccessibility::ROLE_MENU_BAR: 1434 ia_role_ = ROLE_SYSTEM_MENUBAR; 1435 break; 1436 case WebAccessibility::ROLE_MENU_ITEM: 1437 case WebAccessibility::ROLE_MENU_LIST_OPTION: 1438 ia_role_ = ROLE_SYSTEM_MENUITEM; 1439 break; 1440 case WebAccessibility::ROLE_MENU_LIST_POPUP: 1441 ia_role_ = ROLE_SYSTEM_MENUPOPUP; 1442 break; 1443 case WebAccessibility::ROLE_NOTE: 1444 ia_role_ = ROLE_SYSTEM_GROUPING; 1445 ia2_role_ = IA2_ROLE_NOTE; 1446 break; 1447 case WebAccessibility::ROLE_OUTLINE: 1448 ia_role_ = ROLE_SYSTEM_OUTLINE; 1449 break; 1450 case WebAccessibility::ROLE_POPUP_BUTTON: 1451 ia_role_ = ROLE_SYSTEM_COMBOBOX; 1452 break; 1453 case WebAccessibility::ROLE_PROGRESS_INDICATOR: 1454 ia_role_ = ROLE_SYSTEM_PROGRESSBAR; 1455 break; 1456 case WebAccessibility::ROLE_RADIO_BUTTON: 1457 ia_role_ = ROLE_SYSTEM_RADIOBUTTON; 1458 break; 1459 case WebAccessibility::ROLE_RADIO_GROUP: 1460 ia_role_ = ROLE_SYSTEM_GROUPING; 1461 ia2_role_ = IA2_ROLE_SECTION; 1462 break; 1463 case WebAccessibility::ROLE_REGION: 1464 ia_role_ = ROLE_SYSTEM_GROUPING; 1465 ia2_role_ = IA2_ROLE_SECTION; 1466 break; 1467 case WebAccessibility::ROLE_ROW: 1468 ia_role_ = ROLE_SYSTEM_ROW; 1469 break; 1470 case WebAccessibility::ROLE_ROW_HEADER: 1471 ia_role_ = ROLE_SYSTEM_ROWHEADER; 1472 break; 1473 case WebAccessibility::ROLE_RULER: 1474 ia_role_ = ROLE_SYSTEM_CLIENT; 1475 ia2_role_ = IA2_ROLE_RULER; 1476 break; 1477 case WebAccessibility::ROLE_SCROLLAREA: 1478 ia_role_ = ROLE_SYSTEM_CLIENT; 1479 ia2_role_ = IA2_ROLE_SCROLL_PANE; 1480 break; 1481 case WebAccessibility::ROLE_SCROLLBAR: 1482 ia_role_ = ROLE_SYSTEM_SCROLLBAR; 1483 break; 1484 case WebAccessibility::ROLE_SLIDER: 1485 ia_role_ = ROLE_SYSTEM_SLIDER; 1486 break; 1487 case WebAccessibility::ROLE_SPLIT_GROUP: 1488 ia_role_ = ROLE_SYSTEM_CLIENT; 1489 ia2_role_ = IA2_ROLE_SPLIT_PANE; 1490 break; 1491 case WebAccessibility::ROLE_ANNOTATION: 1492 case WebAccessibility::ROLE_STATIC_TEXT: 1493 ia_role_ = ROLE_SYSTEM_TEXT; 1494 break; 1495 case WebAccessibility::ROLE_STATUS: 1496 ia_role_ = ROLE_SYSTEM_STATUSBAR; 1497 break; 1498 case WebAccessibility::ROLE_TAB: 1499 ia_role_ = ROLE_SYSTEM_PAGETAB; 1500 break; 1501 case WebAccessibility::ROLE_TABLE: 1502 ia_role_ = ROLE_SYSTEM_TABLE; 1503 break; 1504 case WebAccessibility::ROLE_TABLE_HEADER_CONTAINER: 1505 ia_role_ = ROLE_SYSTEM_GROUPING; 1506 ia2_role_ = IA2_ROLE_SECTION; 1507 break; 1508 case WebAccessibility::ROLE_TAB_GROUP: 1509 case WebAccessibility::ROLE_TAB_LIST: 1510 case WebAccessibility::ROLE_TAB_PANEL: 1511 ia_role_ = ROLE_SYSTEM_PAGETABLIST; 1512 break; 1513 case WebAccessibility::ROLE_TEXTAREA: 1514 ia_role_ = ROLE_SYSTEM_TEXT; 1515 ia2_state_ |= IA2_STATE_MULTI_LINE; 1516 ia2_state_ |= IA2_STATE_EDITABLE; 1517 break; 1518 case WebAccessibility::ROLE_TEXT_FIELD: 1519 ia_role_ = ROLE_SYSTEM_TEXT; 1520 ia2_state_ |= IA2_STATE_SINGLE_LINE; 1521 ia2_state_ |= IA2_STATE_EDITABLE; 1522 break; 1523 case WebAccessibility::ROLE_TOOLBAR: 1524 ia_role_ = ROLE_SYSTEM_TOOLBAR; 1525 break; 1526 case WebAccessibility::ROLE_TOOLTIP: 1527 ia_role_ = ROLE_SYSTEM_TOOLTIP; 1528 break; 1529 case WebAccessibility::ROLE_TREE: 1530 ia_role_ = ROLE_SYSTEM_OUTLINE; 1531 break; 1532 case WebAccessibility::ROLE_TREE_GRID: 1533 ia_role_ = ROLE_SYSTEM_OUTLINE; 1534 break; 1535 case WebAccessibility::ROLE_TREE_ITEM: 1536 ia_role_ = ROLE_SYSTEM_OUTLINEITEM; 1537 break; 1538 case WebAccessibility::ROLE_WINDOW: 1539 ia_role_ = ROLE_SYSTEM_WINDOW; 1540 break; 1541 1542 // TODO(dmazzoni): figure out the proper MSAA role for all of these. 1543 case WebAccessibility::ROLE_BROWSER: 1544 case WebAccessibility::ROLE_BUSY_INDICATOR: 1545 case WebAccessibility::ROLE_DIRECTORY: 1546 case WebAccessibility::ROLE_DISCLOSURE_TRIANGLE: 1547 case WebAccessibility::ROLE_DRAWER: 1548 case WebAccessibility::ROLE_GROW_AREA: 1549 case WebAccessibility::ROLE_HELP_TAG: 1550 case WebAccessibility::ROLE_IGNORED: 1551 case WebAccessibility::ROLE_INCREMENTOR: 1552 case WebAccessibility::ROLE_LOG: 1553 case WebAccessibility::ROLE_MARQUEE: 1554 case WebAccessibility::ROLE_MATH: 1555 case WebAccessibility::ROLE_MATTE: 1556 case WebAccessibility::ROLE_RULER_MARKER: 1557 case WebAccessibility::ROLE_SHEET: 1558 case WebAccessibility::ROLE_SLIDER_THUMB: 1559 case WebAccessibility::ROLE_SPLITTER: 1560 case WebAccessibility::ROLE_SYSTEM_WIDE: 1561 case WebAccessibility::ROLE_TIMER: 1562 case WebAccessibility::ROLE_VALUE_INDICATOR: 1563 default: 1564 ia_role_ = ROLE_SYSTEM_CLIENT; 1565 break; 1566 } 1567 1568 // The role should always be set. 1569 DCHECK(!role_name_.empty() || ia_role_); 1570 1571 // If we didn't explicitly set the IAccessible2 role, make it the same 1572 // as the MSAA role. 1573 if (!ia2_role_) 1574 ia2_role_ = ia_role_; 1575} 1576