summaryrefslogtreecommitdiffstats
path: root/content/browser/accessibility/browser_accessibility_win.cc
diff options
context:
space:
mode:
Diffstat (limited to 'content/browser/accessibility/browser_accessibility_win.cc')
-rw-r--r--content/browser/accessibility/browser_accessibility_win.cc1634
1 files changed, 1634 insertions, 0 deletions
diff --git a/content/browser/accessibility/browser_accessibility_win.cc b/content/browser/accessibility/browser_accessibility_win.cc
new file mode 100644
index 0000000..8cd1566
--- /dev/null
+++ b/content/browser/accessibility/browser_accessibility_win.cc
@@ -0,0 +1,1634 @@
+// Copyright (c) 2011 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 "content/browser/accessibility/browser_accessibility_win.h"
+
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "content/browser/accessibility/browser_accessibility_manager_win.h"
+#include "net/base/escape.h"
+
+using webkit_glue::WebAccessibility;
+
+// The GUID for the ISimpleDOM service is not defined in the IDL files.
+// This is taken directly from the Mozilla sources
+// (accessible/src/msaa/nsAccessNodeWrap.cpp) and it's also documented at:
+// http://developer.mozilla.org/en/Accessibility/AT-APIs/ImplementationFeatures/MSAA
+
+const GUID GUID_ISimpleDOM = {
+ 0x0c539790, 0x12e4, 0x11cf,
+ 0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8};
+
+// static
+BrowserAccessibility* BrowserAccessibility::Create() {
+ CComObject<BrowserAccessibilityWin>* instance;
+ HRESULT hr = CComObject<BrowserAccessibilityWin>::CreateInstance(&instance);
+ DCHECK(SUCCEEDED(hr));
+ return instance->NewReference();
+}
+
+BrowserAccessibilityWin* BrowserAccessibility::toBrowserAccessibilityWin() {
+ return static_cast<BrowserAccessibilityWin*>(this);
+}
+
+BrowserAccessibilityWin::BrowserAccessibilityWin()
+ : ia_role_(0),
+ ia_state_(0),
+ ia2_role_(0),
+ ia2_state_(0) {
+}
+
+BrowserAccessibilityWin::~BrowserAccessibilityWin() {
+}
+
+//
+// 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 BrowserAccessibilityWin::accDoDefaultAction(VARIANT var_id) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
+ if (!target)
+ return E_INVALIDARG;
+
+ manager_->DoDefaultAction(*target);
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::accHitTest(LONG x_left,
+ LONG y_top,
+ VARIANT* child) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!child)
+ return E_INVALIDARG;
+
+ gfx::Point point(x_left, y_top);
+ if (!GetBoundsRect().Contains(point)) {
+ // Return S_FALSE and VT_EMPTY when the outside the object's boundaries.
+ child->vt = VT_EMPTY;
+ return S_FALSE;
+ }
+
+ BrowserAccessibility* result = BrowserAccessibilityForPoint(point);
+ if (result == this) {
+ // Point is within this object.
+ child->vt = VT_I4;
+ child->lVal = CHILDID_SELF;
+ } else {
+ child->vt = VT_DISPATCH;
+ child->pdispVal = result->toBrowserAccessibilityWin()->NewReference();
+ }
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::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;
+
+ BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
+ if (!target)
+ return E_INVALIDARG;
+
+ gfx::Rect bounds = target->GetBoundsRect();
+ *x_left = bounds.x();
+ *y_top = bounds.y();
+ *width = bounds.width();
+ *height = bounds.height();
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::accNavigate(
+ LONG nav_dir, VARIANT start, VARIANT* end) {
+ BrowserAccessibilityWin* 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_.empty())
+ result = target->children_.front();
+ break;
+ case NAVDIR_LASTCHILD:
+ if (!target->children_.empty())
+ result = target->children_.back();
+ 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->toBrowserAccessibilityWin()->NewReference();
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accChild(VARIANT var_child,
+ IDispatch** disp_child) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!disp_child)
+ return E_INVALIDARG;
+
+ *disp_child = NULL;
+
+ BrowserAccessibilityWin* target = GetTargetFromChildID(var_child);
+ if (!target)
+ return E_INVALIDARG;
+
+ (*disp_child) = target->NewReference();
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::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 BrowserAccessibilityWin::get_accDefaultAction(VARIANT var_id,
+ BSTR* def_action) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!def_action)
+ return E_INVALIDARG;
+
+ BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
+ if (!target)
+ return E_INVALIDARG;
+
+ return target->GetAttributeAsBstr(
+ WebAccessibility::ATTR_SHORTCUT, def_action);
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accDescription(VARIANT var_id,
+ BSTR* desc) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!desc)
+ return E_INVALIDARG;
+
+ BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
+ if (!target)
+ return E_INVALIDARG;
+
+ return target->GetAttributeAsBstr(WebAccessibility::ATTR_DESCRIPTION, desc);
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accFocus(VARIANT* focus_child) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!focus_child)
+ return E_INVALIDARG;
+
+ BrowserAccessibilityWin* focus = static_cast<BrowserAccessibilityWin*>(
+ 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 BrowserAccessibilityWin::get_accHelp(VARIANT var_id, BSTR* help) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!help)
+ return E_INVALIDARG;
+
+ BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
+ if (!target)
+ return E_INVALIDARG;
+
+ return target->GetAttributeAsBstr(WebAccessibility::ATTR_HELP, help);
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accKeyboardShortcut(VARIANT var_id,
+ BSTR* acc_key) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!acc_key)
+ return E_INVALIDARG;
+
+ BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
+ if (!target)
+ return E_INVALIDARG;
+
+ return target->GetAttributeAsBstr(WebAccessibility::ATTR_SHORTCUT, acc_key);
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accName(VARIANT var_id, BSTR* name) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!name)
+ return E_INVALIDARG;
+
+ BrowserAccessibilityWin* 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 BrowserAccessibilityWin::get_accParent(IDispatch** disp_parent) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!disp_parent)
+ return E_INVALIDARG;
+
+ IAccessible* parent = parent_->toBrowserAccessibilityWin();
+ if (parent == NULL) {
+ // This happens if we're the root of the tree;
+ // return the IAccessible for the window.
+ parent = manager_->toBrowserAccessibilityManagerWin()->
+ GetParentWindowIAccessible();
+ }
+
+ parent->AddRef();
+ *disp_parent = parent;
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accRole(
+ VARIANT var_id, VARIANT* role) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!role)
+ return E_INVALIDARG;
+
+ BrowserAccessibilityWin* 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->ia_role_;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accState(VARIANT var_id,
+ VARIANT* state) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!state)
+ return E_INVALIDARG;
+
+ BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
+ if (!target)
+ return E_INVALIDARG;
+
+ state->vt = VT_I4;
+ state->lVal = target->ia_state_;
+ if (manager_->GetFocus(NULL) == this)
+ state->lVal |= STATE_SYSTEM_FOCUSED;
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accValue(
+ VARIANT var_id, BSTR* value) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!value)
+ return E_INVALIDARG;
+
+ BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
+ if (!target)
+ return E_INVALIDARG;
+
+ *value = SysAllocString(target->value_.c_str());
+
+ DCHECK(*value);
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accHelpTopic(
+ BSTR* help_file, VARIANT var_id, LONG* topic_id) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accSelection(VARIANT* selected) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::accSelect(
+ LONG flags_sel, VARIANT var_id) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (flags_sel & SELFLAG_TAKEFOCUS) {
+ manager_->SetFocus(this, true);
+ return S_OK;
+ }
+
+ return S_FALSE;
+}
+
+//
+// IAccessible2 methods.
+//
+
+STDMETHODIMP BrowserAccessibilityWin::role(LONG* role) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!role)
+ return E_INVALIDARG;
+
+ *role = ia2_role_;
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_attributes(BSTR* attributes) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!attributes)
+ return E_INVALIDARG;
+
+ // Follow Firefox's convention, which is to return a set of key-value pairs
+ // separated by semicolons, with a colon between the key and the value.
+ string16 str;
+ for (unsigned int i = 0; i < html_attributes_.size(); i++) {
+ if (i != 0)
+ str += L';';
+ str += Escape(html_attributes_[i].first);
+ str += L':';
+ str += Escape(html_attributes_[i].second);
+ }
+
+ if (str.empty())
+ return S_FALSE;
+
+ *attributes = SysAllocString(str.c_str());
+ DCHECK(*attributes);
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_states(AccessibleStates* states) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!states)
+ return E_INVALIDARG;
+
+ *states = ia2_state_;
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::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 BrowserAccessibilityWin::get_windowHandle(HWND* window_handle) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!window_handle)
+ return E_INVALIDARG;
+
+ *window_handle = manager_->GetParentView();
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::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 BrowserAccessibilityWin::get_description(BSTR* desc) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!desc)
+ return E_INVALIDARG;
+
+ return GetAttributeAsBstr(WebAccessibility::ATTR_DESCRIPTION, desc);
+}
+
+STDMETHODIMP BrowserAccessibilityWin::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_->GetParentView();
+ 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 BrowserAccessibilityWin::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 BrowserAccessibilityWin::get_nCharacters(LONG* n_characters) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!n_characters)
+ return E_INVALIDARG;
+
+ if (role_ == WebAccessibility::ROLE_TEXT_FIELD ||
+ role_ == WebAccessibility::ROLE_TEXTAREA) {
+ *n_characters = value_.length();
+ } else {
+ *n_characters = name_.length();
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_caretOffset(LONG* offset) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!offset)
+ return E_INVALIDARG;
+
+ if (role_ == WebAccessibility::ROLE_TEXT_FIELD ||
+ role_ == WebAccessibility::ROLE_TEXTAREA) {
+ int sel_start = 0;
+ if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start)) {
+ *offset = sel_start;
+ } else {
+ *offset = 0;
+ }
+ } else {
+ *offset = 0;
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_nSelections(LONG* n_selections) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!n_selections)
+ return E_INVALIDARG;
+
+ if (role_ == WebAccessibility::ROLE_TEXT_FIELD ||
+ role_ == WebAccessibility::ROLE_TEXTAREA) {
+ int sel_start = 0;
+ int sel_end = 0;
+ if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start) &&
+ GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_END, &sel_end) &&
+ sel_start != sel_end) {
+ *n_selections = 1;
+ } else {
+ *n_selections = 0;
+ }
+ } else {
+ *n_selections = 0;
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_selection(LONG selection_index,
+ LONG* start_offset,
+ LONG* end_offset) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!start_offset || !end_offset || selection_index != 0)
+ return E_INVALIDARG;
+
+ if (role_ == WebAccessibility::ROLE_TEXT_FIELD ||
+ role_ == WebAccessibility::ROLE_TEXTAREA) {
+ int sel_start = 0;
+ int sel_end = 0;
+ if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start) &&
+ GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_END, &sel_end)) {
+ *start_offset = sel_start;
+ *end_offset = sel_end;
+ } else {
+ *start_offset = 0;
+ *end_offset = 0;
+ }
+ } else {
+ *start_offset = 0;
+ *end_offset = 0;
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_text(
+ LONG start_offset, LONG end_offset, BSTR* text) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!text)
+ return E_INVALIDARG;
+
+ const string16& text_str = TextForIAccessibleText();
+
+ // Handle special text offsets.
+ HandleSpecialTextOffset(text_str, &start_offset);
+ HandleSpecialTextOffset(text_str, &end_offset);
+
+ // The spec allows the arguments to be reversed.
+ if (start_offset > end_offset) {
+ LONG tmp = start_offset;
+ start_offset = end_offset;
+ end_offset = tmp;
+ }
+
+ // The spec does not allow the start or end offsets to be out or range;
+ // we must return an error if so.
+ LONG len = text_str.length();
+ if (start_offset < 0)
+ return E_INVALIDARG;
+ if (end_offset > len)
+ return E_INVALIDARG;
+
+ string16 substr = text_str.substr(start_offset, end_offset - start_offset);
+ if (substr.empty())
+ return S_FALSE;
+
+ *text = SysAllocString(substr.c_str());
+ DCHECK(*text);
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_textAtOffset(
+ LONG offset,
+ enum IA2TextBoundaryType boundary_type,
+ LONG* start_offset, LONG* end_offset,
+ BSTR* text) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!start_offset || !end_offset || !text)
+ return E_INVALIDARG;
+
+ // The IAccessible2 spec says we don't have to implement the "sentence"
+ // boundary type, we can just let the screenreader handle it.
+ if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
+ *start_offset = 0;
+ *end_offset = 0;
+ *text = NULL;
+ return S_FALSE;
+ }
+
+ const string16& text_str = TextForIAccessibleText();
+
+ *start_offset = FindBoundary(text_str, boundary_type, offset, -1);
+ *end_offset = FindBoundary(text_str, boundary_type, offset, 1);
+ return get_text(*start_offset, *end_offset, text);
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_textBeforeOffset(
+ LONG offset,
+ enum IA2TextBoundaryType boundary_type,
+ LONG* start_offset, LONG* end_offset,
+ BSTR* text) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!start_offset || !end_offset || !text)
+ return E_INVALIDARG;
+
+ // The IAccessible2 spec says we don't have to implement the "sentence"
+ // boundary type, we can just let the screenreader handle it.
+ if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
+ *start_offset = 0;
+ *end_offset = 0;
+ *text = NULL;
+ return S_FALSE;
+ }
+
+ const string16& text_str = TextForIAccessibleText();
+
+ *start_offset = FindBoundary(text_str, boundary_type, offset, -1);
+ *end_offset = offset;
+ return get_text(*start_offset, *end_offset, text);
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_textAfterOffset(
+ LONG offset,
+ enum IA2TextBoundaryType boundary_type,
+ LONG* start_offset, LONG* end_offset,
+ BSTR* text) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!start_offset || !end_offset || !text)
+ return E_INVALIDARG;
+
+ // The IAccessible2 spec says we don't have to implement the "sentence"
+ // boundary type, we can just let the screenreader handle it.
+ if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
+ *start_offset = 0;
+ *end_offset = 0;
+ *text = NULL;
+ return S_FALSE;
+ }
+
+ const string16& text_str = TextForIAccessibleText();
+
+ *start_offset = offset;
+ *end_offset = FindBoundary(text_str, boundary_type, offset, 1);
+ return get_text(*start_offset, *end_offset, text);
+}
+
+//
+// ISimpleDOMDocument methods.
+//
+
+STDMETHODIMP BrowserAccessibilityWin::get_URL(BSTR* url) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!url)
+ return E_INVALIDARG;
+
+ return GetAttributeAsBstr(WebAccessibility::ATTR_DOC_URL, url);
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_title(BSTR* title) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!title)
+ return E_INVALIDARG;
+
+ return GetAttributeAsBstr(WebAccessibility::ATTR_DOC_TITLE, title);
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_mimeType(BSTR* mime_type) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!mime_type)
+ return E_INVALIDARG;
+
+ return GetAttributeAsBstr(WebAccessibility::ATTR_DOC_MIMETYPE, mime_type);
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_docType(BSTR* doc_type) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!doc_type)
+ return E_INVALIDARG;
+
+ return GetAttributeAsBstr(WebAccessibility::ATTR_DOC_DOCTYPE, doc_type);
+}
+
+//
+// ISimpleDOMNode methods.
+//
+
+STDMETHODIMP BrowserAccessibilityWin::get_nodeInfo(
+ BSTR* node_name,
+ short* name_space_id,
+ BSTR* node_value,
+ unsigned int* num_children,
+ unsigned int* unique_id,
+ unsigned short* node_type) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!node_name || !name_space_id || !node_value || !num_children ||
+ !unique_id || !node_type) {
+ return E_INVALIDARG;
+ }
+
+ string16 tag;
+ if (GetAttribute(WebAccessibility::ATTR_HTML_TAG, &tag))
+ *node_name = SysAllocString(tag.c_str());
+ else
+ *node_name = NULL;
+
+ *name_space_id = 0;
+ *node_value = SysAllocString(value_.c_str());
+ *num_children = children_.size();
+ *unique_id = child_id_;
+
+ if (ia_role_ == ROLE_SYSTEM_DOCUMENT) {
+ *node_type = NODETYPE_DOCUMENT;
+ } else if (ia_role_ == ROLE_SYSTEM_TEXT &&
+ ((ia2_state_ & IA2_STATE_EDITABLE) == 0)) {
+ *node_type = NODETYPE_TEXT;
+ } else {
+ *node_type = NODETYPE_ELEMENT;
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_attributes(
+ unsigned short max_attribs,
+ BSTR* attrib_names,
+ short* name_space_id,
+ BSTR* attrib_values,
+ unsigned short* num_attribs) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!attrib_names || !name_space_id || !attrib_values || !num_attribs)
+ return E_INVALIDARG;
+
+ *num_attribs = max_attribs;
+ if (*num_attribs > html_attributes_.size())
+ *num_attribs = html_attributes_.size();
+
+ for (unsigned short i = 0; i < *num_attribs; ++i) {
+ attrib_names[i] = SysAllocString(html_attributes_[i].first.c_str());
+ name_space_id[i] = 0;
+ attrib_values[i] = SysAllocString(html_attributes_[i].second.c_str());
+ }
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_attributesForNames(
+ unsigned short num_attribs,
+ BSTR* attrib_names,
+ short* name_space_id,
+ BSTR* attrib_values) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!attrib_names || !name_space_id || !attrib_values)
+ return E_INVALIDARG;
+
+ for (unsigned short i = 0; i < num_attribs; ++i) {
+ name_space_id[i] = 0;
+ bool found = false;
+ string16 name = (LPCWSTR)attrib_names[i];
+ for (unsigned int j = 0; j < html_attributes_.size(); ++j) {
+ if (html_attributes_[j].first == name) {
+ attrib_values[i] = SysAllocString(html_attributes_[j].second.c_str());
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ attrib_values[i] = NULL;
+ }
+ }
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_computedStyle(
+ unsigned short max_style_properties,
+ boolean use_alternate_view,
+ BSTR *style_properties,
+ BSTR *style_values,
+ unsigned short *num_style_properties) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!style_properties || !style_values)
+ return E_INVALIDARG;
+
+ // We only cache a single style property for now: DISPLAY
+
+ if (max_style_properties == 0 ||
+ !HasAttribute(WebAccessibility::ATTR_DISPLAY)) {
+ *num_style_properties = 0;
+ return S_OK;
+ }
+
+ string16 display;
+ GetAttribute(WebAccessibility::ATTR_DISPLAY, &display);
+ *num_style_properties = 1;
+ style_properties[0] = SysAllocString(L"display");
+ style_values[0] = SysAllocString(display.c_str());
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_computedStyleForProperties(
+ unsigned short num_style_properties,
+ boolean use_alternate_view,
+ BSTR* style_properties,
+ BSTR* style_values) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!style_properties || !style_values)
+ return E_INVALIDARG;
+
+ // We only cache a single style property for now: DISPLAY
+
+ for (unsigned short i = 0; i < num_style_properties; i++) {
+ string16 name = (LPCWSTR)style_properties[i];
+ StringToLowerASCII(&name);
+ if (name == L"display") {
+ string16 display;
+ GetAttribute(WebAccessibility::ATTR_DISPLAY, &display);
+ style_values[i] = SysAllocString(display.c_str());
+ } else {
+ style_values[i] = NULL;
+ }
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::scrollTo(boolean placeTopLeft) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_parentNode(ISimpleDOMNode** node) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!node)
+ return E_INVALIDARG;
+
+ *node = parent_->toBrowserAccessibilityWin()->NewReference();
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_firstChild(ISimpleDOMNode** node) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!node)
+ return E_INVALIDARG;
+
+ if (children_.size()) {
+ *node = children_[0]->toBrowserAccessibilityWin()->NewReference();
+ return S_OK;
+ } else {
+ *node = NULL;
+ return S_FALSE;
+ }
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_lastChild(ISimpleDOMNode** node) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!node)
+ return E_INVALIDARG;
+
+ if (children_.size()) {
+ *node = children_[children_.size() - 1]->toBrowserAccessibilityWin()->
+ NewReference();
+ return S_OK;
+ } else {
+ *node = NULL;
+ return S_FALSE;
+ }
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_previousSibling(
+ ISimpleDOMNode** node) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!node)
+ return E_INVALIDARG;
+
+ if (parent_ && index_in_parent_ > 0) {
+ *node = parent_->children()[index_in_parent_ - 1]->
+ toBrowserAccessibilityWin()->NewReference();
+ return S_OK;
+ } else {
+ *node = NULL;
+ return S_FALSE;
+ }
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_nextSibling(ISimpleDOMNode** node) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!node)
+ return E_INVALIDARG;
+
+ if (parent_ &&
+ index_in_parent_ >= 0 &&
+ index_in_parent_ < static_cast<int>(parent_->children().size()) - 1) {
+ *node = parent_->children()[index_in_parent_ + 1]->
+ toBrowserAccessibilityWin()->NewReference();
+ return S_OK;
+ } else {
+ *node = NULL;
+ return S_FALSE;
+ }
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_childAt(
+ unsigned int child_index,
+ ISimpleDOMNode** node) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!node)
+ return E_INVALIDARG;
+
+ if (child_index < children_.size()) {
+ *node = children_[child_index]->toBrowserAccessibilityWin()->NewReference();
+ return S_OK;
+ } else {
+ *node = NULL;
+ return S_FALSE;
+ }
+}
+
+//
+// ISimpleDOMText methods.
+//
+
+STDMETHODIMP BrowserAccessibilityWin::get_domText(BSTR* dom_text) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!dom_text)
+ return E_INVALIDARG;
+
+ if (name_.empty())
+ return S_FALSE;
+
+ *dom_text = SysAllocString(name_.c_str());
+ DCHECK(*dom_text);
+ return S_OK;
+}
+
+//
+// IServiceProvider methods.
+//
+
+STDMETHODIMP BrowserAccessibilityWin::QueryService(
+ REFGUID guidService, REFIID riid, void** object) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (guidService == IID_IAccessible ||
+ guidService == IID_IAccessible2 ||
+ guidService == IID_IAccessibleImage ||
+ guidService == IID_IAccessibleText ||
+ guidService == IID_ISimpleDOMDocument ||
+ guidService == IID_ISimpleDOMNode ||
+ guidService == IID_ISimpleDOMText ||
+ guidService == GUID_ISimpleDOM) {
+ return QueryInterface(riid, object);
+ }
+
+ *object = NULL;
+ return E_FAIL;
+}
+
+//
+// CComObjectRootEx methods.
+//
+
+HRESULT WINAPI BrowserAccessibilityWin::InternalQueryInterface(
+ void* this_ptr,
+ const _ATL_INTMAP_ENTRY* entries,
+ REFIID iid,
+ void** object) {
+ if (iid == IID_IAccessibleText) {
+ if (ia_role_ != ROLE_SYSTEM_LINK && ia_role_ != ROLE_SYSTEM_TEXT) {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+ } else if (iid == IID_IAccessibleImage) {
+ if (ia_role_ != ROLE_SYSTEM_GRAPHIC) {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+ } else if (iid == IID_ISimpleDOMDocument) {
+ if (ia_role_ != ROLE_SYSTEM_DOCUMENT) {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+ }
+
+ return CComObjectRootBase::InternalQueryInterface(
+ this_ptr, entries, iid, object);
+}
+
+//
+// Private methods.
+//
+
+// Initialize this object and mark it as active.
+void BrowserAccessibilityWin::Initialize() {
+ BrowserAccessibility::Initialize();
+
+ InitRoleAndState();
+
+ // Expose headings levels to NVDA with the "level" object attribute.
+ if (role_ == WebAccessibility::ROLE_HEADING && role_name_.size() == 2 &&
+ IsAsciiDigit(role_name_[1])) {
+ html_attributes_.push_back(std::make_pair(L"level", role_name_.substr(1)));
+ }
+
+ // Expose the "display" object attribute.
+ string16 display;
+ if (GetAttribute(WebAccessibility::ATTR_DISPLAY, &display))
+ html_attributes_.push_back(std::make_pair(L"display", display));
+
+ // If this is static text, put the text in the name rather than the value.
+ if (role_ == WebAccessibility::ROLE_STATIC_TEXT && name_.empty())
+ name_.swap(value_);
+
+ // 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_);
+
+ // If this doesn't have a value and is linked then set its value to the url
+ // attribute. This allows screen readers to read an empty link's destination.
+ if (value_.empty() && (ia_state_ & STATE_SYSTEM_LINKED) &&
+ HasAttribute(WebAccessibility::ATTR_URL)) {
+ GetAttribute(WebAccessibility::ATTR_URL, &value_);
+ }
+}
+
+void BrowserAccessibilityWin::NativeAddReference() {
+ AddRef();
+}
+
+void BrowserAccessibilityWin::NativeReleaseReference() {
+ Release();
+}
+
+BrowserAccessibilityWin* BrowserAccessibilityWin::NewReference() {
+ AddRef();
+ return this;
+}
+
+BrowserAccessibilityWin* BrowserAccessibilityWin::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<LONG>(children_.size()))
+ return children_[child_id - 1]->toBrowserAccessibilityWin();
+
+ return manager_->GetFromChildID(child_id)->toBrowserAccessibilityWin();
+}
+
+HRESULT BrowserAccessibilityWin::GetAttributeAsBstr(
+ WebAccessibility::Attribute attribute, BSTR* value_bstr) {
+ string16 str;
+
+ if (!GetAttribute(attribute, &str))
+ return S_FALSE;
+
+ if (str.empty())
+ return S_FALSE;
+
+ *value_bstr = SysAllocString(str.c_str());
+ DCHECK(*value_bstr);
+
+ return S_OK;
+}
+
+string16 BrowserAccessibilityWin::Escape(const string16& str) {
+ return EscapeQueryParamValueUTF8(str, false);
+}
+
+const string16& BrowserAccessibilityWin::TextForIAccessibleText() {
+ if (role_ == WebAccessibility::ROLE_TEXT_FIELD ||
+ role_ == WebAccessibility::ROLE_TEXTAREA) {
+ return value_;
+ } else {
+ return name_;
+ }
+}
+
+void BrowserAccessibilityWin::HandleSpecialTextOffset(
+ const string16& text, LONG* offset) {
+ if (*offset == IA2_TEXT_OFFSET_LENGTH) {
+ *offset = static_cast<LONG>(text.size());
+ } else if (*offset == IA2_TEXT_OFFSET_CARET) {
+ get_caretOffset(offset);
+ }
+}
+
+LONG BrowserAccessibilityWin::FindBoundary(
+ const string16& text,
+ IA2TextBoundaryType boundary,
+ LONG start_offset,
+ LONG direction) {
+ LONG text_size = static_cast<LONG>(text.size());
+ DCHECK((start_offset >= 0 && start_offset <= text_size) ||
+ start_offset == IA2_TEXT_OFFSET_LENGTH ||
+ start_offset == IA2_TEXT_OFFSET_CARET);
+ DCHECK(direction == 1 || direction == -1);
+
+ HandleSpecialTextOffset(text, &start_offset);
+
+ if (boundary == IA2_TEXT_BOUNDARY_CHAR) {
+ if (direction == 1 && start_offset < text_size)
+ return start_offset + 1;
+ else
+ return start_offset;
+ } else if (boundary == IA2_TEXT_BOUNDARY_LINE) {
+ if (direction == 1) {
+ for (int j = 0; j < static_cast<int>(line_breaks_.size()); j++) {
+ if (line_breaks_[j] > start_offset)
+ return line_breaks_[j];
+ }
+ return text_size;
+ } else {
+ for (int j = static_cast<int>(line_breaks_.size()) - 1; j >= 0; j--) {
+ if (line_breaks_[j] <= start_offset)
+ return line_breaks_[j];
+ }
+ return 0;
+ }
+ }
+
+ LONG result = start_offset;
+ for (;;) {
+ LONG pos;
+ if (direction == 1) {
+ if (result >= text_size)
+ return text_size;
+ pos = result;
+ } else {
+ if (result <= 0)
+ return 0;
+ pos = result - 1;
+ }
+
+ switch (boundary) {
+ case IA2_TEXT_BOUNDARY_CHAR:
+ case IA2_TEXT_BOUNDARY_LINE:
+ NOTREACHED(); // These are handled above.
+ break;
+ case IA2_TEXT_BOUNDARY_WORD:
+ if (IsWhitespace(text[pos]))
+ return result;
+ break;
+ case IA2_TEXT_BOUNDARY_PARAGRAPH:
+ if (text[pos] == '\n')
+ return result;
+ case IA2_TEXT_BOUNDARY_SENTENCE:
+ // Note that we don't actually have to implement sentence support;
+ // currently IAccessibleText functions return S_FALSE so that
+ // screenreaders will handle it on their own.
+ if ((text[pos] == '.' || text[pos] == '!' || text[pos] == '?') &&
+ (pos == text_size - 1 || IsWhitespace(text[pos + 1]))) {
+ return result;
+ }
+ case IA2_TEXT_BOUNDARY_ALL:
+ default:
+ break;
+ }
+
+ if (direction > 0) {
+ result++;
+ } else if (direction < 0) {
+ result--;
+ } else {
+ NOTREACHED();
+ return result;
+ }
+ }
+}
+
+void BrowserAccessibilityWin::InitRoleAndState() {
+ ia_state_ = 0;
+ ia2_state_ = IA2_STATE_OPAQUE;
+
+ if ((state_ >> WebAccessibility::STATE_CHECKED) & 1)
+ ia_state_ |= STATE_SYSTEM_CHECKED;
+ if ((state_ >> WebAccessibility::STATE_COLLAPSED) & 1)
+ ia_state_|= STATE_SYSTEM_COLLAPSED;
+ if ((state_ >> WebAccessibility::STATE_EXPANDED) & 1)
+ ia_state_|= STATE_SYSTEM_EXPANDED;
+ if ((state_ >> WebAccessibility::STATE_FOCUSABLE) & 1)
+ ia_state_|= STATE_SYSTEM_FOCUSABLE;
+ if ((state_ >> WebAccessibility::STATE_HASPOPUP) & 1)
+ ia_state_|= STATE_SYSTEM_HASPOPUP;
+ if ((state_ >> WebAccessibility::STATE_HOTTRACKED) & 1)
+ ia_state_|= STATE_SYSTEM_HOTTRACKED;
+ if ((state_ >> WebAccessibility::STATE_INDETERMINATE) & 1)
+ ia_state_|= STATE_SYSTEM_INDETERMINATE;
+ if ((state_ >> WebAccessibility::STATE_INVISIBLE) & 1)
+ ia_state_|= STATE_SYSTEM_INVISIBLE;
+ if ((state_ >> WebAccessibility::STATE_LINKED) & 1)
+ ia_state_|= STATE_SYSTEM_LINKED;
+ if ((state_ >> WebAccessibility::STATE_MULTISELECTABLE) & 1)
+ ia_state_|= STATE_SYSTEM_MULTISELECTABLE;
+ // TODO(ctguil): Support STATE_SYSTEM_EXTSELECTABLE/accSelect.
+ if ((state_ >> WebAccessibility::STATE_OFFSCREEN) & 1)
+ ia_state_|= STATE_SYSTEM_OFFSCREEN;
+ if ((state_ >> WebAccessibility::STATE_PRESSED) & 1)
+ ia_state_|= STATE_SYSTEM_PRESSED;
+ if ((state_ >> WebAccessibility::STATE_PROTECTED) & 1)
+ ia_state_|= STATE_SYSTEM_PROTECTED;
+ if ((state_ >> WebAccessibility::STATE_SELECTABLE) & 1)
+ ia_state_|= STATE_SYSTEM_SELECTABLE;
+ if ((state_ >> WebAccessibility::STATE_SELECTED) & 1)
+ ia_state_|= STATE_SYSTEM_SELECTED;
+ if ((state_ >> WebAccessibility::STATE_READONLY) & 1)
+ ia_state_|= STATE_SYSTEM_READONLY;
+ if ((state_ >> WebAccessibility::STATE_TRAVERSED) & 1)
+ ia_state_|= STATE_SYSTEM_TRAVERSED;
+ if ((state_ >> WebAccessibility::STATE_BUSY) & 1)
+ ia_state_|= STATE_SYSTEM_BUSY;
+ if ((state_ >> WebAccessibility::STATE_UNAVAILABLE) & 1)
+ ia_state_|= STATE_SYSTEM_UNAVAILABLE;
+
+ string16 html_tag;
+ GetAttribute(WebAccessibility::ATTR_HTML_TAG, &html_tag);
+ ia_role_ = 0;
+ ia2_role_ = 0;
+ switch (role_) {
+ case WebAccessibility::ROLE_ALERT:
+ case WebAccessibility::ROLE_ALERT_DIALOG:
+ ia_role_ = ROLE_SYSTEM_ALERT;
+ break;
+ case WebAccessibility::ROLE_APPLICATION:
+ ia_role_ = ROLE_SYSTEM_APPLICATION;
+ break;
+ case WebAccessibility::ROLE_ARTICLE:
+ ia_role_ = ROLE_SYSTEM_GROUPING;
+ ia2_role_ = IA2_ROLE_SECTION;
+ break;
+ case WebAccessibility::ROLE_BUSY_INDICATOR:
+ ia_role_ = ROLE_SYSTEM_ANIMATION;
+ break;
+ case WebAccessibility::ROLE_BUTTON:
+ ia_role_ = ROLE_SYSTEM_PUSHBUTTON;
+ break;
+ case WebAccessibility::ROLE_CELL:
+ ia_role_ = ROLE_SYSTEM_CELL;
+ break;
+ case WebAccessibility::ROLE_CHECKBOX:
+ ia_role_ = ROLE_SYSTEM_CHECKBUTTON;
+ break;
+ case WebAccessibility::ROLE_COLOR_WELL:
+ ia_role_ = ROLE_SYSTEM_CLIENT;
+ ia2_role_ = IA2_ROLE_COLOR_CHOOSER;
+ break;
+ case WebAccessibility::ROLE_COLUMN:
+ ia_role_ = ROLE_SYSTEM_COLUMN;
+ break;
+ case WebAccessibility::ROLE_COLUMN_HEADER:
+ ia_role_ = ROLE_SYSTEM_COLUMNHEADER;
+ break;
+ case WebAccessibility::ROLE_COMBO_BOX:
+ ia_role_ = ROLE_SYSTEM_COMBOBOX;
+ break;
+ case WebAccessibility::ROLE_DEFINITION_LIST_DEFINITION:
+ role_name_ = html_tag;
+ ia2_role_ = IA2_ROLE_PARAGRAPH;
+ break;
+ case WebAccessibility::ROLE_DEFINITION_LIST_TERM:
+ ia_role_ = ROLE_SYSTEM_LISTITEM;
+ break;
+ case WebAccessibility::ROLE_DIALOG:
+ ia_role_ = ROLE_SYSTEM_DIALOG;
+ break;
+ case WebAccessibility::ROLE_DISCLOSURE_TRIANGLE:
+ ia_role_ = ROLE_SYSTEM_OUTLINEBUTTON;
+ break;
+ case WebAccessibility::ROLE_DOCUMENT:
+ case WebAccessibility::ROLE_WEB_AREA:
+ ia_role_ = ROLE_SYSTEM_DOCUMENT;
+ ia_state_|= STATE_SYSTEM_READONLY;
+ ia_state_|= STATE_SYSTEM_FOCUSABLE;
+ break;
+ case WebAccessibility::ROLE_EDITABLE_TEXT:
+ ia_role_ = ROLE_SYSTEM_TEXT;
+ ia2_state_ |= IA2_STATE_SINGLE_LINE;
+ ia2_state_ |= IA2_STATE_EDITABLE;
+ break;
+ case WebAccessibility::ROLE_GRID:
+ ia_role_ = ROLE_SYSTEM_TABLE;
+ break;
+ case WebAccessibility::ROLE_GROUP:
+ if (html_tag == L"li") {
+ ia_role_ = ROLE_SYSTEM_LISTITEM;
+ } else {
+ if (html_tag.empty())
+ role_name_ = L"div";
+ else
+ role_name_ = html_tag;
+ ia2_role_ = IA2_ROLE_SECTION;
+ }
+ break;
+ case WebAccessibility::ROLE_GROW_AREA:
+ ia_role_ = ROLE_SYSTEM_GRIP;
+ break;
+ case WebAccessibility::ROLE_HEADING:
+ role_name_ = html_tag;
+ ia2_role_ = IA2_ROLE_HEADING;
+ break;
+ case WebAccessibility::ROLE_IMAGE:
+ ia_role_ = ROLE_SYSTEM_GRAPHIC;
+ break;
+ case WebAccessibility::ROLE_IMAGE_MAP:
+ role_name_ = html_tag;
+ ia2_role_ = IA2_ROLE_IMAGE_MAP;
+ break;
+ case WebAccessibility::ROLE_IMAGE_MAP_LINK:
+ ia_role_ = ROLE_SYSTEM_LINK;
+ ia_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:
+ ia_role_ = ROLE_SYSTEM_GROUPING;
+ ia2_role_ = IA2_ROLE_SECTION;
+ break;
+ case WebAccessibility::ROLE_LINK:
+ case WebAccessibility::ROLE_WEBCORE_LINK:
+ ia_role_ = ROLE_SYSTEM_LINK;
+ ia_state_|= STATE_SYSTEM_LINKED;
+ break;
+ case WebAccessibility::ROLE_LIST:
+ ia_role_ = ROLE_SYSTEM_LIST;
+ break;
+ case WebAccessibility::ROLE_LISTBOX:
+ ia_role_ = ROLE_SYSTEM_LIST;
+ break;
+ case WebAccessibility::ROLE_LISTBOX_OPTION:
+ case WebAccessibility::ROLE_LIST_ITEM:
+ case WebAccessibility::ROLE_LIST_MARKER:
+ ia_role_ = ROLE_SYSTEM_LISTITEM;
+ break;
+ case WebAccessibility::ROLE_MATH:
+ ia_role_ = ROLE_SYSTEM_EQUATION;
+ break;
+ case WebAccessibility::ROLE_MENU:
+ case WebAccessibility::ROLE_MENU_BUTTON:
+ ia_role_ = ROLE_SYSTEM_MENUPOPUP;
+ break;
+ case WebAccessibility::ROLE_MENU_BAR:
+ ia_role_ = ROLE_SYSTEM_MENUBAR;
+ break;
+ case WebAccessibility::ROLE_MENU_ITEM:
+ case WebAccessibility::ROLE_MENU_LIST_OPTION:
+ ia_role_ = ROLE_SYSTEM_MENUITEM;
+ break;
+ case WebAccessibility::ROLE_MENU_LIST_POPUP:
+ ia_role_ = ROLE_SYSTEM_MENUPOPUP;
+ break;
+ case WebAccessibility::ROLE_NOTE:
+ ia_role_ = ROLE_SYSTEM_GROUPING;
+ ia2_role_ = IA2_ROLE_NOTE;
+ break;
+ case WebAccessibility::ROLE_OUTLINE:
+ ia_role_ = ROLE_SYSTEM_OUTLINE;
+ break;
+ case WebAccessibility::ROLE_POPUP_BUTTON:
+ ia_role_ = ROLE_SYSTEM_COMBOBOX;
+ break;
+ case WebAccessibility::ROLE_PROGRESS_INDICATOR:
+ ia_role_ = ROLE_SYSTEM_PROGRESSBAR;
+ break;
+ case WebAccessibility::ROLE_RADIO_BUTTON:
+ ia_role_ = ROLE_SYSTEM_RADIOBUTTON;
+ break;
+ case WebAccessibility::ROLE_RADIO_GROUP:
+ ia_role_ = ROLE_SYSTEM_GROUPING;
+ ia2_role_ = IA2_ROLE_SECTION;
+ break;
+ case WebAccessibility::ROLE_REGION:
+ ia_role_ = ROLE_SYSTEM_GROUPING;
+ ia2_role_ = IA2_ROLE_SECTION;
+ break;
+ case WebAccessibility::ROLE_ROW:
+ ia_role_ = ROLE_SYSTEM_ROW;
+ break;
+ case WebAccessibility::ROLE_ROW_HEADER:
+ ia_role_ = ROLE_SYSTEM_ROWHEADER;
+ break;
+ case WebAccessibility::ROLE_RULER:
+ ia_role_ = ROLE_SYSTEM_CLIENT;
+ ia2_role_ = IA2_ROLE_RULER;
+ break;
+ case WebAccessibility::ROLE_SCROLLAREA:
+ ia_role_ = ROLE_SYSTEM_CLIENT;
+ ia2_role_ = IA2_ROLE_SCROLL_PANE;
+ break;
+ case WebAccessibility::ROLE_SCROLLBAR:
+ ia_role_ = ROLE_SYSTEM_SCROLLBAR;
+ break;
+ case WebAccessibility::ROLE_SLIDER:
+ ia_role_ = ROLE_SYSTEM_SLIDER;
+ break;
+ case WebAccessibility::ROLE_SPLIT_GROUP:
+ ia_role_ = ROLE_SYSTEM_CLIENT;
+ ia2_role_ = IA2_ROLE_SPLIT_PANE;
+ break;
+ case WebAccessibility::ROLE_ANNOTATION:
+ case WebAccessibility::ROLE_STATIC_TEXT:
+ ia_role_ = ROLE_SYSTEM_TEXT;
+ break;
+ case WebAccessibility::ROLE_STATUS:
+ ia_role_ = ROLE_SYSTEM_STATUSBAR;
+ break;
+ case WebAccessibility::ROLE_SPLITTER:
+ ia_role_ = ROLE_SYSTEM_SEPARATOR;
+ break;
+ case WebAccessibility::ROLE_TAB:
+ ia_role_ = ROLE_SYSTEM_PAGETAB;
+ break;
+ case WebAccessibility::ROLE_TABLE:
+ ia_role_ = ROLE_SYSTEM_TABLE;
+ break;
+ case WebAccessibility::ROLE_TABLE_HEADER_CONTAINER:
+ ia_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:
+ ia_role_ = ROLE_SYSTEM_PAGETABLIST;
+ break;
+ case WebAccessibility::ROLE_TEXTAREA:
+ ia_role_ = ROLE_SYSTEM_TEXT;
+ ia2_state_ |= IA2_STATE_MULTI_LINE;
+ ia2_state_ |= IA2_STATE_EDITABLE;
+ ia2_state_ |= IA2_STATE_SELECTABLE_TEXT;
+ break;
+ case WebAccessibility::ROLE_TEXT_FIELD:
+ ia_role_ = ROLE_SYSTEM_TEXT;
+ ia2_state_ |= IA2_STATE_SINGLE_LINE;
+ ia2_state_ |= IA2_STATE_EDITABLE;
+ ia2_state_ |= IA2_STATE_SELECTABLE_TEXT;
+ break;
+ case WebAccessibility::ROLE_TIMER:
+ ia_role_ = ROLE_SYSTEM_CLOCK;
+ break;
+ case WebAccessibility::ROLE_TOOLBAR:
+ ia_role_ = ROLE_SYSTEM_TOOLBAR;
+ break;
+ case WebAccessibility::ROLE_TOOLTIP:
+ ia_role_ = ROLE_SYSTEM_TOOLTIP;
+ break;
+ case WebAccessibility::ROLE_TREE:
+ ia_role_ = ROLE_SYSTEM_OUTLINE;
+ break;
+ case WebAccessibility::ROLE_TREE_GRID:
+ ia_role_ = ROLE_SYSTEM_OUTLINE;
+ break;
+ case WebAccessibility::ROLE_TREE_ITEM:
+ ia_role_ = ROLE_SYSTEM_OUTLINEITEM;
+ break;
+ case WebAccessibility::ROLE_WINDOW:
+ ia_role_ = ROLE_SYSTEM_WINDOW;
+ break;
+
+ // TODO(dmazzoni): figure out the proper MSAA role for all of these.
+ case WebAccessibility::ROLE_BROWSER:
+ case WebAccessibility::ROLE_DIRECTORY:
+ case WebAccessibility::ROLE_DRAWER:
+ case WebAccessibility::ROLE_HELP_TAG:
+ case WebAccessibility::ROLE_IGNORED:
+ case WebAccessibility::ROLE_INCREMENTOR:
+ case WebAccessibility::ROLE_LOG:
+ case WebAccessibility::ROLE_MARQUEE:
+ case WebAccessibility::ROLE_MATTE:
+ case WebAccessibility::ROLE_RULER_MARKER:
+ case WebAccessibility::ROLE_SHEET:
+ case WebAccessibility::ROLE_SLIDER_THUMB:
+ case WebAccessibility::ROLE_SYSTEM_WIDE:
+ case WebAccessibility::ROLE_VALUE_INDICATOR:
+ default:
+ ia_role_ = ROLE_SYSTEM_CLIENT;
+ break;
+ }
+
+ // The role should always be set.
+ DCHECK(!role_name_.empty() || ia_role_);
+
+ // If we didn't explicitly set the IAccessible2 role, make it the same
+ // as the MSAA role.
+ if (!ia2_role_)
+ ia2_role_ = ia_role_;
+}