// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/browser_accessibility_win.h" #include "base/logging.h" #include "chrome/browser/browser_accessibility_manager_win.h" using webkit_glue::WebAccessibility; BrowserAccessibility::BrowserAccessibility() : manager_(NULL), parent_(NULL), child_id_(-1), index_in_parent_(-1), renderer_id_(-1), instance_active_(false) { } BrowserAccessibility::~BrowserAccessibility() { InactivateTree(); } void BrowserAccessibility::Initialize( BrowserAccessibilityManager* manager, BrowserAccessibility* parent, LONG child_id, LONG index_in_parent, const webkit_glue::WebAccessibility& src) { manager_ = manager; parent_ = parent; child_id_ = child_id; index_in_parent_ = index_in_parent; renderer_id_ = src.id; name_ = src.name; value_ = src.value; attributes_ = src.attributes; location_ = src.location; InitRoleAndState(src.role, src.state); // If this object doesn't have a name but it does have a description, // use the description as its name - because some screen readers only // announce the name. if (name_.empty() && HasAttribute(WebAccessibility::ATTR_DESCRIPTION)) { GetAttribute(WebAccessibility::ATTR_DESCRIPTION, &name_); } instance_active_ = true; } void BrowserAccessibility::AddChild(BrowserAccessibility* child) { children_.push_back(child); } void BrowserAccessibility::InactivateTree() { // Mark this object as inactive, so calls to all COM methods will return // failure. instance_active_ = false; // Now we can safely call InactivateTree on our children and remove // references to them, so that as much of the tree as possible will be // destroyed now - however, nodes that still have references to them // might stick around a while until all clients have released them. for (std::vector::iterator iter = children_.begin(); iter != children_.end(); ++iter) { (*iter)->InactivateTree(); (*iter)->Release(); } children_.clear(); } bool BrowserAccessibility::IsDescendantOf(BrowserAccessibility* ancestor) { if (this == ancestor) { return true; } else if (parent_) { return parent_->IsDescendantOf(ancestor); } return false; } BrowserAccessibility* BrowserAccessibility::GetPreviousSibling() { if (parent_ && index_in_parent_ > 0) return parent_->children_[index_in_parent_ - 1]; return NULL; } BrowserAccessibility* BrowserAccessibility::GetNextSibling() { if (parent_ && index_in_parent_ < static_cast(parent_->children_.size() - 1)) { return parent_->children_[index_in_parent_ + 1]; } return NULL; } BrowserAccessibility* BrowserAccessibility::NewReference() { AddRef(); return this; } // // IAccessible methods. // // Conventions: // * Always test for instance_active_ first and return E_FAIL if it's false. // * Always check for invalid arguments first, even if they're unused. // * Return S_FALSE if the only output is a string argument and it's empty. // HRESULT BrowserAccessibility::accDoDefaultAction(VARIANT var_id) { if (!instance_active_) return E_FAIL; BrowserAccessibility* target = GetTargetFromChildID(var_id); if (!target) return E_INVALIDARG; manager_->DoDefaultAction(*target); return S_OK; } STDMETHODIMP BrowserAccessibility::accHitTest(LONG x_left, LONG y_top, VARIANT* child) { if (!instance_active_) return E_FAIL; if (!child) return E_INVALIDARG; return E_NOTIMPL; } STDMETHODIMP BrowserAccessibility::accLocation(LONG* x_left, LONG* y_top, LONG* width, LONG* height, VARIANT var_id) { if (!instance_active_) return E_FAIL; if (!x_left || !y_top || !width || !height) return E_INVALIDARG; BrowserAccessibility* target = GetTargetFromChildID(var_id); if (!target) return E_INVALIDARG; // Find the top left corner of the containing window in screen coords, and // adjust the output position by this amount. HWND parent_hwnd = manager_->GetParentHWND(); POINT top_left = {0, 0}; ::ClientToScreen(parent_hwnd, &top_left); *x_left = target->location_.x + top_left.x; *y_top = target->location_.y + top_left.y; *width = target->location_.width; *height = target->location_.height; return S_OK; } STDMETHODIMP BrowserAccessibility::accNavigate( LONG nav_dir, VARIANT start, VARIANT* end) { BrowserAccessibility* target = GetTargetFromChildID(start); if (!target) return E_INVALIDARG; if ((nav_dir == NAVDIR_LASTCHILD || nav_dir == NAVDIR_FIRSTCHILD) && start.lVal != CHILDID_SELF) { // MSAA states that navigating to first/last child can only be from self. return E_INVALIDARG; } BrowserAccessibility* result = NULL; switch (nav_dir) { case NAVDIR_DOWN: case NAVDIR_UP: case NAVDIR_LEFT: case NAVDIR_RIGHT: // These directions are not implemented, matching Mozilla and IE. return E_NOTIMPL; case NAVDIR_FIRSTCHILD: if (target->children_.size() > 0) result = target->children_[0]; break; case NAVDIR_LASTCHILD: if (target->children_.size() > 0) result = target->children_[target->children_.size() - 1]; break; case NAVDIR_NEXT: result = target->GetNextSibling(); break; case NAVDIR_PREVIOUS: result = target->GetPreviousSibling(); break; } if (!result) { end->vt = VT_EMPTY; return S_FALSE; } end->vt = VT_DISPATCH; end->pdispVal = result->NewReference(); return S_OK; } STDMETHODIMP BrowserAccessibility::get_accChild(VARIANT var_child, IDispatch** disp_child) { if (!instance_active_) return E_FAIL; if (!disp_child) return E_INVALIDARG; *disp_child = NULL; BrowserAccessibility* target = GetTargetFromChildID(var_child); if (!target) return E_INVALIDARG; (*disp_child) = target->NewReference(); return S_OK; } STDMETHODIMP BrowserAccessibility::get_accChildCount(LONG* child_count) { if (!instance_active_) return E_FAIL; if (!child_count) return E_INVALIDARG; *child_count = children_.size(); return S_OK; } STDMETHODIMP BrowserAccessibility::get_accDefaultAction(VARIANT var_id, BSTR* def_action) { if (!instance_active_) return E_FAIL; if (!def_action) return E_INVALIDARG; BrowserAccessibility* target = GetTargetFromChildID(var_id); if (!target) return E_INVALIDARG; string16 action; if (!target->GetAttribute(WebAccessibility::ATTR_SHORTCUT, &action)) return S_FALSE; if (action.empty()) return S_FALSE; *def_action = SysAllocString(action.c_str()); DCHECK(*def_action); return S_OK; } STDMETHODIMP BrowserAccessibility::get_accDescription(VARIANT var_id, BSTR* desc) { if (!instance_active_) return E_FAIL; if (!desc) return E_INVALIDARG; BrowserAccessibility* target = GetTargetFromChildID(var_id); if (!target) return E_INVALIDARG; string16 description; if (!target->GetAttribute(WebAccessibility::ATTR_DESCRIPTION, &description)) return S_FALSE; if (description.empty()) return S_FALSE; *desc = SysAllocString(description.c_str()); DCHECK(*desc); return S_OK; } STDMETHODIMP BrowserAccessibility::get_accFocus(VARIANT* focus_child) { if (!instance_active_) return E_FAIL; if (!focus_child) return E_INVALIDARG; BrowserAccessibility* focus = manager_->GetFocus(this); if (focus == this) { focus_child->vt = VT_I4; focus_child->lVal = CHILDID_SELF; } else if (focus == NULL) { focus_child->vt = VT_EMPTY; } else { focus_child->vt = VT_DISPATCH; focus_child->pdispVal = focus->NewReference(); } return S_OK; } STDMETHODIMP BrowserAccessibility::get_accHelp(VARIANT var_id, BSTR* help) { if (!instance_active_) return E_FAIL; if (!help) return E_INVALIDARG; BrowserAccessibility* target = GetTargetFromChildID(var_id); if (!target) return E_INVALIDARG; string16 help_str; if (!target->GetAttribute(WebAccessibility::ATTR_HELP, &help_str)) return S_FALSE; if (help_str.empty()) return S_FALSE; *help = SysAllocString(help_str.c_str()); DCHECK(*help); return S_OK; } STDMETHODIMP BrowserAccessibility::get_accKeyboardShortcut(VARIANT var_id, BSTR* acc_key) { if (!instance_active_) return E_FAIL; if (!acc_key) return E_INVALIDARG; BrowserAccessibility* target = GetTargetFromChildID(var_id); if (!target) return E_INVALIDARG; string16 shortcut; if (!target->GetAttribute(WebAccessibility::ATTR_SHORTCUT, &shortcut)) return S_FALSE; if (shortcut.empty()) return S_FALSE; *acc_key = SysAllocString(shortcut.c_str()); DCHECK(*acc_key); return S_OK; } STDMETHODIMP BrowserAccessibility::get_accName(VARIANT var_id, BSTR* name) { if (!instance_active_) return E_FAIL; if (!name) return E_INVALIDARG; BrowserAccessibility* target = GetTargetFromChildID(var_id); if (!target) return E_INVALIDARG; if (target->name_.empty()) return S_FALSE; *name = SysAllocString(target->name_.c_str()); DCHECK(*name); return S_OK; } STDMETHODIMP BrowserAccessibility::get_accParent(IDispatch** disp_parent) { if (!instance_active_) return E_FAIL; if (!disp_parent) return E_INVALIDARG; IAccessible* parent = parent_; if (parent == NULL) { // This happens if we're the root of the tree; // return the IAccessible for the window. parent = manager_->GetParentWindowIAccessible(); } parent->AddRef(); *disp_parent = parent; return S_OK; } STDMETHODIMP BrowserAccessibility::get_accRole(VARIANT var_id, VARIANT* role) { if (!instance_active_) return E_FAIL; if (!role) return E_INVALIDARG; BrowserAccessibility* target = GetTargetFromChildID(var_id); if (!target) return E_INVALIDARG; if (!target->role_name_.empty()) { role->vt = VT_BSTR; role->bstrVal = SysAllocString(target->role_name_.c_str()); } else { role->vt = VT_I4; role->lVal = target->role_; } return S_OK; } STDMETHODIMP BrowserAccessibility::get_accState(VARIANT var_id, VARIANT* state) { if (!instance_active_) return E_FAIL; if (!state) return E_INVALIDARG; BrowserAccessibility* target = GetTargetFromChildID(var_id); if (!target) return E_INVALIDARG; state->vt = VT_I4; state->lVal = target->state_; if (manager_->GetFocus(NULL) == this) state->lVal |= STATE_SYSTEM_FOCUSED; return S_OK; } STDMETHODIMP BrowserAccessibility::get_accValue(VARIANT var_id, BSTR* value) { if (!instance_active_) return E_FAIL; if (!value) return E_INVALIDARG; BrowserAccessibility* target = GetTargetFromChildID(var_id); if (!target) return E_INVALIDARG; *value = SysAllocString(target->value_.c_str()); DCHECK(*value); return S_OK; } STDMETHODIMP BrowserAccessibility::get_accHelpTopic(BSTR* help_file, VARIANT var_id, LONG* topic_id) { return E_NOTIMPL; } STDMETHODIMP BrowserAccessibility::get_accSelection(VARIANT* selected) { if (!instance_active_) return E_FAIL; return E_NOTIMPL; } STDMETHODIMP BrowserAccessibility::accSelect(LONG flags_sel, VARIANT var_id) { if (!instance_active_) return E_FAIL; if (flags_sel & SELFLAG_TAKEFOCUS) { manager_->SetFocus(*this); return S_OK; } return S_FALSE; } // // IAccessible2 methods. // STDMETHODIMP BrowserAccessibility::role(LONG* role) { if (!instance_active_) return E_FAIL; if (!role) return E_INVALIDARG; *role = ia2_role_; return S_OK; } STDMETHODIMP BrowserAccessibility::get_attributes(BSTR* attributes) { if (!instance_active_) return E_FAIL; if (!attributes) return E_INVALIDARG; return S_FALSE; } STDMETHODIMP BrowserAccessibility::get_states(AccessibleStates* states) { if (!instance_active_) return E_FAIL; if (!states) return E_INVALIDARG; *states = ia2_state_; return S_OK; } STDMETHODIMP BrowserAccessibility::get_uniqueID(LONG* unique_id) { if (!instance_active_) return E_FAIL; if (!unique_id) return E_INVALIDARG; *unique_id = child_id_; return S_OK; } STDMETHODIMP BrowserAccessibility::get_windowHandle(HWND* window_handle) { if (!instance_active_) return E_FAIL; if (!window_handle) return E_INVALIDARG; *window_handle = manager_->GetParentHWND(); return S_OK; } STDMETHODIMP BrowserAccessibility::get_indexInParent(LONG* index_in_parent) { if (!instance_active_) return E_FAIL; if (!index_in_parent) return E_INVALIDARG; *index_in_parent = index_in_parent_; return S_OK; } // // IAccessibleImage methods. // STDMETHODIMP BrowserAccessibility::get_description(BSTR* desc) { if (!instance_active_) return E_FAIL; if (!desc) return E_INVALIDARG; string16 description; if (!GetAttribute(WebAccessibility::ATTR_DESCRIPTION, &description)) return S_FALSE; if (description.empty()) return S_FALSE; *desc = SysAllocString(description.c_str()); DCHECK(*desc); return S_OK; } STDMETHODIMP BrowserAccessibility::get_imagePosition( enum IA2CoordinateType coordinate_type, long* x, long* y) { if (!instance_active_) return E_FAIL; if (!x || !y) return E_INVALIDARG; if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) { HWND parent_hwnd = manager_->GetParentHWND(); POINT top_left = {0, 0}; ::ClientToScreen(parent_hwnd, &top_left); *x = location_.x + top_left.x; *y = location_.y + top_left.y; } else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) { *x = location_.x; *y = location_.y; if (parent_) { *x -= parent_->location_.x; *y -= parent_->location_.y; } } else { return E_INVALIDARG; } return S_OK; } STDMETHODIMP BrowserAccessibility::get_imageSize(long* height, long* width) { if (!instance_active_) return E_FAIL; if (!height || !width) return E_INVALIDARG; *height = location_.height; *width = location_.width; return S_OK; } // // IAccessibleText methods. // STDMETHODIMP BrowserAccessibility::get_nCharacters(long* n_characters) { if (!instance_active_) return E_FAIL; if (!n_characters) return E_INVALIDARG; *n_characters = name_.length(); return S_OK; } STDMETHODIMP BrowserAccessibility::get_text( long start_offset, long end_offset, BSTR* text) { if (!instance_active_) return E_FAIL; if (!text) return E_INVALIDARG; long len = name_.length(); if (start_offset < 0) start_offset = 0; if (end_offset > len) end_offset = len; *text = SysAllocString( name_.substr(start_offset, end_offset - start_offset).c_str()); return S_OK; } STDMETHODIMP BrowserAccessibility::get_caretOffset(long* offset) { *offset = 0; return S_OK; } // // IServiceProvider methods. // STDMETHODIMP BrowserAccessibility::QueryService( REFGUID guidService, REFIID riid, void** object) { if (!instance_active_) return E_FAIL; if (guidService == IID_IAccessible || guidService == IID_IAccessible2) return QueryInterface(riid, object); *object = NULL; return E_FAIL; } // // CComObjectRootEx methods. // HRESULT WINAPI BrowserAccessibility::InternalQueryInterface( void* this_ptr, const _ATL_INTMAP_ENTRY* entries, REFIID iid, void** object) { if (iid == IID_IAccessibleText) { if (role_ != ROLE_SYSTEM_LINK) { *object = NULL; return E_NOINTERFACE; } } else if (iid == IID_IAccessibleImage) { if (role_ != ROLE_SYSTEM_GRAPHIC) { *object = NULL; return E_NOINTERFACE; } } return CComObjectRootBase::InternalQueryInterface( this_ptr, entries, iid, object); } // // Private methods. // BrowserAccessibility* BrowserAccessibility::GetTargetFromChildID( const VARIANT& var_id) { if (var_id.vt != VT_I4) return NULL; LONG child_id = var_id.lVal; if (child_id == CHILDID_SELF) return this; if (child_id >= 1 && child_id <= static_cast(children_.size())) return children_[child_id - 1]; return manager_->GetFromChildID(child_id); } bool BrowserAccessibility::HasAttribute(WebAccessibility::Attribute attribute) { return (attributes_.find(attribute) != attributes_.end()); } bool BrowserAccessibility::GetAttribute( WebAccessibility::Attribute attribute, string16* value) { std::map::iterator iter = attributes_.find(attribute); if (iter != attributes_.end()) { *value = iter->second; return true; } return false; } void BrowserAccessibility::InitRoleAndState(LONG web_role, LONG web_state) { state_ = 0; ia2_state_ = IA2_STATE_OPAQUE; if ((web_state >> WebAccessibility::STATE_CHECKED) & 1) state_ |= STATE_SYSTEM_CHECKED; if ((web_state >> WebAccessibility::STATE_FOCUSABLE) & 1) state_ |= STATE_SYSTEM_FOCUSABLE; if ((web_state >> WebAccessibility::STATE_HOTTRACKED) & 1) state_ |= STATE_SYSTEM_HOTTRACKED; if ((web_state >> WebAccessibility::STATE_INDETERMINATE) & 1) state_ |= STATE_SYSTEM_INDETERMINATE; if ((web_state >> WebAccessibility::STATE_LINKED) & 1) state_ |= STATE_SYSTEM_LINKED; if ((web_state >> WebAccessibility::STATE_MULTISELECTABLE) & 1) state_ |= STATE_SYSTEM_MULTISELECTABLE; if ((web_state >> WebAccessibility::STATE_OFFSCREEN) & 1) state_ |= STATE_SYSTEM_OFFSCREEN; if ((web_state >> WebAccessibility::STATE_PRESSED) & 1) state_ |= STATE_SYSTEM_PRESSED; if ((web_state >> WebAccessibility::STATE_PROTECTED) & 1) state_ |= STATE_SYSTEM_PROTECTED; if ((web_state >> WebAccessibility::STATE_READONLY) & 1) state_ |= STATE_SYSTEM_READONLY; if ((web_state >> WebAccessibility::STATE_TRAVERSED) & 1) state_ |= STATE_SYSTEM_TRAVERSED; if ((web_state >> WebAccessibility::STATE_UNAVAILABLE) & 1) state_ |= STATE_SYSTEM_UNAVAILABLE; role_ = 0; ia2_role_ = 0; switch (web_role) { case WebAccessibility::ROLE_ALERT: case WebAccessibility::ROLE_ALERT_DIALOG: role_ = ROLE_SYSTEM_ALERT; break; case WebAccessibility::ROLE_APPLICATION: role_ = ROLE_SYSTEM_APPLICATION; break; case WebAccessibility::ROLE_ARTICLE: role_ = ROLE_SYSTEM_GROUPING; ia2_role_ = IA2_ROLE_SECTION; break; case WebAccessibility::ROLE_BUTTON: role_ = ROLE_SYSTEM_PUSHBUTTON; break; case WebAccessibility::ROLE_CELL: role_ = ROLE_SYSTEM_CELL; break; case WebAccessibility::ROLE_CHECKBOX: role_ = ROLE_SYSTEM_CHECKBUTTON; break; case WebAccessibility::ROLE_COLOR_WELL: role_ = ROLE_SYSTEM_CLIENT; ia2_role_ = IA2_ROLE_COLOR_CHOOSER; break; case WebAccessibility::ROLE_COLUMN: role_ = ROLE_SYSTEM_COLUMN; break; case WebAccessibility::ROLE_COLUMN_HEADER: role_ = ROLE_SYSTEM_COLUMNHEADER; break; case WebAccessibility::ROLE_COMBO_BOX: role_ = ROLE_SYSTEM_COMBOBOX; break; case WebAccessibility::ROLE_DEFINITION_LIST_DEFINITION: role_name_ = L"dd"; ia2_role_ = IA2_ROLE_PARAGRAPH; break; case WebAccessibility::ROLE_DEFINITION_LIST_TERM: role_ = ROLE_SYSTEM_LISTITEM; break; case WebAccessibility::ROLE_DIALOG: role_ = ROLE_SYSTEM_DIALOG; break; case WebAccessibility::ROLE_DOCUMENT: case WebAccessibility::ROLE_WEB_AREA: role_ = ROLE_SYSTEM_DOCUMENT; state_ |= STATE_SYSTEM_READONLY; state_ |= STATE_SYSTEM_FOCUSABLE; break; case WebAccessibility::ROLE_EDITABLE_TEXT: role_ = ROLE_SYSTEM_TEXT; ia2_state_ |= IA2_STATE_SINGLE_LINE; ia2_state_ |= IA2_STATE_EDITABLE; break; case WebAccessibility::ROLE_GRID: role_ = ROLE_SYSTEM_TABLE; break; case WebAccessibility::ROLE_GROUP: role_name_ = L"div"; ia2_role_ = IA2_ROLE_SECTION; break; case WebAccessibility::ROLE_HEADING: // TODO(dmazzoni): support all heading levels role_name_ = L"h1"; ia2_role_ = IA2_ROLE_HEADING; break; case WebAccessibility::ROLE_IMAGE: role_ = ROLE_SYSTEM_GRAPHIC; break; case WebAccessibility::ROLE_IMAGE_MAP: role_name_ = L"map"; ia2_role_ = IA2_ROLE_IMAGE_MAP; break; case WebAccessibility::ROLE_IMAGE_MAP_LINK: role_ = ROLE_SYSTEM_LINK; state_ |= STATE_SYSTEM_LINKED; break; case WebAccessibility::ROLE_LANDMARK_APPLICATION: case WebAccessibility::ROLE_LANDMARK_BANNER: case WebAccessibility::ROLE_LANDMARK_COMPLEMENTARY: case WebAccessibility::ROLE_LANDMARK_CONTENTINFO: case WebAccessibility::ROLE_LANDMARK_MAIN: case WebAccessibility::ROLE_LANDMARK_NAVIGATION: case WebAccessibility::ROLE_LANDMARK_SEARCH: role_ = ROLE_SYSTEM_GROUPING; ia2_role_ = IA2_ROLE_SECTION; break; case WebAccessibility::ROLE_LINK: case WebAccessibility::ROLE_WEBCORE_LINK: role_ = ROLE_SYSTEM_LINK; state_ |= STATE_SYSTEM_LINKED; break; case WebAccessibility::ROLE_LIST: role_ = ROLE_SYSTEM_LIST; break; case WebAccessibility::ROLE_LISTBOX: role_ = ROLE_SYSTEM_LIST; break; case WebAccessibility::ROLE_LISTBOX_OPTION: case WebAccessibility::ROLE_LIST_ITEM: case WebAccessibility::ROLE_LIST_MARKER: role_ = ROLE_SYSTEM_LISTITEM; break; case WebAccessibility::ROLE_MENU: case WebAccessibility::ROLE_MENU_BUTTON: role_ = ROLE_SYSTEM_MENUPOPUP; break; case WebAccessibility::ROLE_MENU_BAR: role_ = ROLE_SYSTEM_MENUBAR; break; case WebAccessibility::ROLE_MENU_ITEM: case WebAccessibility::ROLE_MENU_LIST_OPTION: role_ = ROLE_SYSTEM_MENUITEM; break; case WebAccessibility::ROLE_MENU_LIST_POPUP: role_ = ROLE_SYSTEM_MENUPOPUP; break; case WebAccessibility::ROLE_NOTE: role_ = ROLE_SYSTEM_GROUPING; ia2_role_ = IA2_ROLE_NOTE; break; case WebAccessibility::ROLE_OUTLINE: role_ = ROLE_SYSTEM_OUTLINE; break; case WebAccessibility::ROLE_POPUP_BUTTON: role_ = ROLE_SYSTEM_COMBOBOX; break; case WebAccessibility::ROLE_PROGRESS_INDICATOR: role_ = ROLE_SYSTEM_PROGRESSBAR; break; case WebAccessibility::ROLE_RADIO_BUTTON: role_ = ROLE_SYSTEM_RADIOBUTTON; break; case WebAccessibility::ROLE_RADIO_GROUP: role_ = ROLE_SYSTEM_GROUPING; ia2_role_ = IA2_ROLE_SECTION; break; case WebAccessibility::ROLE_REGION: role_ = ROLE_SYSTEM_GROUPING; ia2_role_ = IA2_ROLE_SECTION; break; case WebAccessibility::ROLE_ROW: role_ = ROLE_SYSTEM_ROW; break; case WebAccessibility::ROLE_ROW_HEADER: role_ = ROLE_SYSTEM_ROWHEADER; break; case WebAccessibility::ROLE_RULER: role_ = ROLE_SYSTEM_CLIENT; ia2_role_ = IA2_ROLE_RULER; break; case WebAccessibility::ROLE_SCROLLAREA: role_ = ROLE_SYSTEM_CLIENT; ia2_role_ = IA2_ROLE_SCROLL_PANE; break; case WebAccessibility::ROLE_SCROLLBAR: role_ = ROLE_SYSTEM_SCROLLBAR; break; case WebAccessibility::ROLE_SLIDER: role_ = ROLE_SYSTEM_SLIDER; break; case WebAccessibility::ROLE_SPLIT_GROUP: role_ = ROLE_SYSTEM_CLIENT; ia2_role_ = IA2_ROLE_SPLIT_PANE; break; case WebAccessibility::ROLE_ANNOTATION: case WebAccessibility::ROLE_STATIC_TEXT: role_ = ROLE_SYSTEM_TEXT; break; case WebAccessibility::ROLE_STATUS: role_ = ROLE_SYSTEM_STATUSBAR; break; case WebAccessibility::ROLE_TAB: role_ = ROLE_SYSTEM_PAGETAB; break; case WebAccessibility::ROLE_TABLE: role_ = ROLE_SYSTEM_TABLE; break; case WebAccessibility::ROLE_TABLE_HEADER_CONTAINER: role_ = ROLE_SYSTEM_GROUPING; ia2_role_ = IA2_ROLE_SECTION; break; case WebAccessibility::ROLE_TAB_GROUP: case WebAccessibility::ROLE_TAB_LIST: case WebAccessibility::ROLE_TAB_PANEL: role_ = ROLE_SYSTEM_PAGETABLIST; break; case WebAccessibility::ROLE_TEXTAREA: role_ = ROLE_SYSTEM_TEXT; ia2_state_ |= IA2_STATE_MULTI_LINE; ia2_state_ |= IA2_STATE_EDITABLE; break; case WebAccessibility::ROLE_TEXT_FIELD: role_ = ROLE_SYSTEM_TEXT; ia2_state_ |= IA2_STATE_SINGLE_LINE; ia2_state_ |= IA2_STATE_EDITABLE; break; case WebAccessibility::ROLE_TOOLBAR: role_ = ROLE_SYSTEM_TOOLBAR; break; case WebAccessibility::ROLE_TOOLTIP: role_ = ROLE_SYSTEM_TOOLTIP; break; case WebAccessibility::ROLE_TREE: role_ = ROLE_SYSTEM_OUTLINE; break; case WebAccessibility::ROLE_TREE_GRID: role_ = ROLE_SYSTEM_OUTLINE; break; case WebAccessibility::ROLE_TREE_ITEM: role_ = ROLE_SYSTEM_OUTLINEITEM; break; case WebAccessibility::ROLE_WINDOW: role_ = ROLE_SYSTEM_WINDOW; break; // TODO(dmazzoni): figure out the proper MSAA role for all of these. case WebAccessibility::ROLE_BROWSER: case WebAccessibility::ROLE_BUSY_INDICATOR: case WebAccessibility::ROLE_DIRECTORY: case WebAccessibility::ROLE_DISCLOSURE_TRIANGLE: case WebAccessibility::ROLE_DRAWER: case WebAccessibility::ROLE_GROW_AREA: case WebAccessibility::ROLE_HELP_TAG: case WebAccessibility::ROLE_IGNORED: case WebAccessibility::ROLE_INCREMENTOR: case WebAccessibility::ROLE_LOG: case WebAccessibility::ROLE_MARQUEE: case WebAccessibility::ROLE_MATH: case WebAccessibility::ROLE_MATTE: case WebAccessibility::ROLE_RULER_MARKER: case WebAccessibility::ROLE_SHEET: case WebAccessibility::ROLE_SLIDER_THUMB: case WebAccessibility::ROLE_SPLITTER: case WebAccessibility::ROLE_SYSTEM_WIDE: case WebAccessibility::ROLE_TIMER: case WebAccessibility::ROLE_VALUE_INDICATOR: default: role_ = ROLE_SYSTEM_CLIENT; break; } // The role should always be set. DCHECK(!role_name_.empty() || role_); // If we didn't explicitly set the IAccessible2 role, make it the same // as the MSAA role. if (!ia2_role_) ia2_role_ = role_; }