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