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