Index: content/browser/accessibility/browser_accessibility_win.cc |
diff --git a/content/browser/accessibility/browser_accessibility_win.cc b/content/browser/accessibility/browser_accessibility_win.cc |
index 262d480156f03ce79a789b289ef29c00a2de3cff..9af492011e3f8d7692fc8d8a162faa7353ae9ad8 100644 |
--- a/content/browser/accessibility/browser_accessibility_win.cc |
+++ b/content/browser/accessibility/browser_accessibility_win.cc |
@@ -429,7 +429,7 @@ HRESULT BrowserAccessibilityWin::accDoDefaultAction(VARIANT var_id) { |
if (!target->HasIntAttribute(ui::AX_ATTR_ACTION)) |
return DISP_E_MEMBERNOTFOUND; |
- manager()->DoDefaultAction(*target); |
+ manager_->DoDefaultAction(*target); |
return S_OK; |
} |
@@ -450,7 +450,7 @@ STDMETHODIMP BrowserAccessibilityWin::accHitTest(LONG x_left, |
return S_FALSE; |
} |
- BrowserAccessibility* result = manager()->CachingAsyncHitTest(point); |
+ BrowserAccessibility* result = manager_->CachingAsyncHitTest(point); |
if (result == this) { |
// Point is within this object. |
child->vt = VT_I4; |
@@ -616,8 +616,8 @@ STDMETHODIMP BrowserAccessibilityWin::get_accFocus(VARIANT* focus_child) { |
if (!focus_child) |
return E_INVALIDARG; |
- BrowserAccessibilityWin* focus = static_cast<BrowserAccessibilityWin*>( |
- manager()->GetFocus()); |
+ BrowserAccessibilityWin* focus = |
+ static_cast<BrowserAccessibilityWin*>(manager_->GetFocus()); |
if (focus == this) { |
focus_child->vt = VT_I4; |
focus_child->lVal = CHILDID_SELF; |
@@ -702,7 +702,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_accParent(IDispatch** disp_parent) { |
// This happens if we're the root of the tree; |
// return the IAccessible for the window. |
parent_obj = |
- manager()->ToBrowserAccessibilityManagerWin()->GetParentIAccessible(); |
+ manager_->ToBrowserAccessibilityManagerWin()->GetParentIAccessible(); |
// |parent| can only be NULL if the manager was created before the parent |
// IAccessible was known and it wasn't subsequently set before a client |
// requested it. This has been fixed. |parent| may also be NULL during |
@@ -757,7 +757,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_accState(VARIANT var_id, |
state->vt = VT_I4; |
state->lVal = target->ia_state(); |
- if (manager()->GetFocus() == this) |
+ if (manager_->GetFocus() == this) |
state->lVal |= STATE_SYSTEM_FOCUSED; |
return S_OK; |
@@ -869,7 +869,7 @@ STDMETHODIMP BrowserAccessibilityWin::accSelect( |
return E_FAIL; |
if (flags_sel & SELFLAG_TAKEFOCUS) { |
- manager()->SetFocus(*this); |
+ manager_->SetFocus(*this); |
return S_OK; |
} |
@@ -958,7 +958,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_windowHandle(HWND* window_handle) { |
return E_INVALIDARG; |
*window_handle = |
- manager()->ToBrowserAccessibilityManagerWin()->GetParentHWND(); |
+ manager_->ToBrowserAccessibilityManagerWin()->GetParentHWND(); |
if (!*window_handle) |
return E_FAIL; |
@@ -1044,31 +1044,31 @@ STDMETHODIMP BrowserAccessibilityWin::scrollTo(IA2ScrollType scroll_type) { |
gfx::Rect r = GetFrameBoundsRect(); |
switch(scroll_type) { |
case IA2_SCROLL_TYPE_TOP_LEFT: |
- manager()->ScrollToMakeVisible(*this, gfx::Rect(r.x(), r.y(), 0, 0)); |
+ manager_->ScrollToMakeVisible(*this, gfx::Rect(r.x(), r.y(), 0, 0)); |
break; |
case IA2_SCROLL_TYPE_BOTTOM_RIGHT: |
- manager()->ScrollToMakeVisible( |
- *this, gfx::Rect(r.right(), r.bottom(), 0, 0)); |
+ manager_->ScrollToMakeVisible(*this, |
+ gfx::Rect(r.right(), r.bottom(), 0, 0)); |
break; |
case IA2_SCROLL_TYPE_TOP_EDGE: |
- manager()->ScrollToMakeVisible( |
- *this, gfx::Rect(r.x(), r.y(), r.width(), 0)); |
+ manager_->ScrollToMakeVisible(*this, |
+ gfx::Rect(r.x(), r.y(), r.width(), 0)); |
break; |
case IA2_SCROLL_TYPE_BOTTOM_EDGE: |
- manager()->ScrollToMakeVisible( |
- *this, gfx::Rect(r.x(), r.bottom(), r.width(), 0)); |
- break; |
+ manager_->ScrollToMakeVisible(*this, |
+ gfx::Rect(r.x(), r.bottom(), r.width(), 0)); |
+ break; |
case IA2_SCROLL_TYPE_LEFT_EDGE: |
- manager()->ScrollToMakeVisible( |
- *this, gfx::Rect(r.x(), r.y(), 0, r.height())); |
+ manager_->ScrollToMakeVisible(*this, |
+ gfx::Rect(r.x(), r.y(), 0, r.height())); |
break; |
case IA2_SCROLL_TYPE_RIGHT_EDGE: |
- manager()->ScrollToMakeVisible( |
- *this, gfx::Rect(r.right(), r.y(), 0, r.height())); |
+ manager_->ScrollToMakeVisible(*this, |
+ gfx::Rect(r.right(), r.y(), 0, r.height())); |
break; |
case IA2_SCROLL_TYPE_ANYWHERE: |
default: |
- manager()->ScrollToMakeVisible(*this, r); |
+ manager_->ScrollToMakeVisible(*this, r); |
break; |
} |
@@ -1086,7 +1086,7 @@ STDMETHODIMP BrowserAccessibilityWin::scrollToPoint( |
gfx::Point scroll_to(x, y); |
if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) { |
- scroll_to -= manager()->GetViewBounds().OffsetFromOrigin(); |
+ scroll_to -= manager_->GetViewBounds().OffsetFromOrigin(); |
} else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) { |
if (GetParent()) |
scroll_to += GetParent()->GetFrameBoundsRect().OffsetFromOrigin(); |
@@ -1094,7 +1094,7 @@ STDMETHODIMP BrowserAccessibilityWin::scrollToPoint( |
return E_INVALIDARG; |
} |
- manager()->ScrollToPoint(*this, scroll_to); |
+ manager_->ScrollToPoint(*this, scroll_to); |
return S_OK; |
} |
@@ -2056,7 +2056,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_columnHeaderCells( |
int index = 0; |
for (int i = 0; i < rows; ++i) { |
int cell_id = cell_ids[i * columns + column]; |
- BrowserAccessibility* cell = manager()->GetFromID(cell_id); |
+ BrowserAccessibility* cell = manager_->GetFromID(cell_id); |
if (cell && cell->GetRole() == ui::AX_ROLE_COLUMN_HEADER) { |
(*cell_accessibles)[index] = static_cast<IAccessible*>( |
ToBrowserAccessibilityWin(cell)->NewReference()); |
@@ -2149,7 +2149,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_rowHeaderCells( |
for (int i = 0; i < columns; ++i) { |
int cell_id = cell_ids[row * columns + i]; |
- BrowserAccessibility* cell = manager()->GetFromID(cell_id); |
+ BrowserAccessibility* cell = manager_->GetFromID(cell_id); |
if (cell && cell->GetRole() == ui::AX_ROLE_ROW_HEADER) |
(*n_row_header_cells)++; |
} |
@@ -2159,7 +2159,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_rowHeaderCells( |
int index = 0; |
for (int i = 0; i < columns; ++i) { |
int cell_id = cell_ids[row * columns + i]; |
- BrowserAccessibility* cell = manager()->GetFromID(cell_id); |
+ BrowserAccessibility* cell = manager_->GetFromID(cell_id); |
if (cell && cell->GetRole() == ui::AX_ROLE_ROW_HEADER) { |
(*cell_accessibles)[index] = static_cast<IAccessible*>( |
ToBrowserAccessibilityWin(cell)->NewReference()); |
@@ -2327,8 +2327,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_characterExtents( |
return E_INVALIDARG; |
const base::string16& text_str = GetText(); |
- HandleSpecialTextOffset(text_str, &offset); |
- |
+ HandleSpecialTextOffset(&offset); |
if (offset < 0 || offset > static_cast<LONG>(text_str.size())) |
return E_INVALIDARG; |
@@ -2382,15 +2381,12 @@ STDMETHODIMP BrowserAccessibilityWin::get_selection(LONG selection_index, |
if (!start_offset || !end_offset || selection_index != 0) |
return E_INVALIDARG; |
- LONG n_selections = 0; |
- if (FAILED(get_nSelections(&n_selections)) || n_selections < 1) |
- return E_INVALIDARG; |
- |
*start_offset = 0; |
*end_offset = 0; |
int selection_start, selection_end; |
GetSelectionOffsets(&selection_start, &selection_end); |
- if (selection_start >= 0 && selection_end >= 0) { |
+ if (selection_start >= 0 && selection_end >= 0 && |
+ selection_start != selection_end) { |
// We should ignore the direction of the selection when exposing start and |
// end offsets. According to the IA2 Spec the end offset is always increased |
// by one past the end of the selection. This wouldn't make sense if |
@@ -2400,9 +2396,10 @@ STDMETHODIMP BrowserAccessibilityWin::get_selection(LONG selection_index, |
*start_offset = selection_start; |
*end_offset = selection_end; |
+ return S_OK; |
} |
- return S_OK; |
+ return E_INVALIDARG; |
} |
STDMETHODIMP BrowserAccessibilityWin::get_text(LONG start_offset, |
@@ -2417,8 +2414,8 @@ STDMETHODIMP BrowserAccessibilityWin::get_text(LONG start_offset, |
return E_INVALIDARG; |
const base::string16& text_str = GetText(); |
- HandleSpecialTextOffset(text_str, &start_offset); |
- HandleSpecialTextOffset(text_str, &end_offset); |
+ HandleSpecialTextOffset(&start_offset); |
+ HandleSpecialTextOffset(&end_offset); |
// The spec allows the arguments to be reversed. |
if (start_offset > end_offset) { |
@@ -2462,7 +2459,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_textAtOffset( |
return E_INVALIDARG; |
const base::string16& text_str = GetText(); |
- HandleSpecialTextOffset(text_str, &offset); |
+ HandleSpecialTextOffset(&offset); |
if (offset < 0) |
return E_INVALIDARG; |
@@ -2673,11 +2670,8 @@ STDMETHODIMP BrowserAccessibilityWin::addSelection(LONG start_offset, |
if (!instance_active()) |
return E_FAIL; |
- const base::string16& text_str = GetText(); |
- HandleSpecialTextOffset(text_str, &start_offset); |
- HandleSpecialTextOffset(text_str, &end_offset); |
- |
- manager()->SetTextSelection(*this, start_offset, end_offset); |
+ // We only support one selection. |
+ SetIA2HypertextSelection(start_offset, end_offset); |
return S_OK; |
} |
@@ -2690,7 +2684,14 @@ STDMETHODIMP BrowserAccessibilityWin::removeSelection(LONG selection_index) { |
if (selection_index != 0) |
return E_INVALIDARG; |
- manager()->SetTextSelection(*this, 0, 0); |
+ // Simply collapse the selection to the position of the caret if a caret is |
+ // visible, otherwise set the selection to 0. |
+ LONG caret_offset = 0; |
+ int selection_start, selection_end; |
+ GetSelectionOffsets(&selection_start, &selection_end); |
+ if (HasCaret() && selection_end >= 0) |
+ caret_offset = selection_end; |
+ SetIA2HypertextSelection(caret_offset, caret_offset); |
return S_OK; |
} |
@@ -2699,10 +2700,7 @@ STDMETHODIMP BrowserAccessibilityWin::setCaretOffset(LONG offset) { |
AddAccessibilityModeFlags(ACCESSIBILITY_MODE_FLAG_SCREEN_READER); |
if (!instance_active()) |
return E_FAIL; |
- |
- const base::string16& text_str = GetText(); |
- HandleSpecialTextOffset(text_str, &offset); |
- manager()->SetTextSelection(*this, offset, offset); |
+ SetIA2HypertextSelection(offset, offset); |
return S_OK; |
} |
@@ -2713,15 +2711,9 @@ STDMETHODIMP BrowserAccessibilityWin::setSelection(LONG selection_index, |
AddAccessibilityModeFlags(ACCESSIBILITY_MODE_FLAG_SCREEN_READER); |
if (!instance_active()) |
return E_FAIL; |
- |
if (selection_index != 0) |
return E_INVALIDARG; |
- |
- const base::string16& text_str = GetText(); |
- HandleSpecialTextOffset(text_str, &start_offset); |
- HandleSpecialTextOffset(text_str, &end_offset); |
- |
- manager()->SetTextSelection(*this, start_offset, end_offset); |
+ SetIA2HypertextSelection(start_offset, end_offset); |
return S_OK; |
} |
@@ -2739,8 +2731,8 @@ STDMETHODIMP BrowserAccessibilityWin::get_attributes(LONG offset, |
if (!instance_active()) |
return E_FAIL; |
- const base::string16& text = GetText(); |
- HandleSpecialTextOffset(text, &offset); |
+ const base::string16 text = GetText(); |
+ HandleSpecialTextOffset(&offset); |
if (offset < 0 || offset > static_cast<LONG>(text.size())) |
return E_INVALIDARG; |
@@ -2958,7 +2950,7 @@ STDMETHODIMP BrowserAccessibilityWin::doAction(long action_index) { |
if (!HasIntAttribute(ui::AX_ATTR_ACTION) || action_index != 0) |
return E_INVALIDARG; |
- manager()->DoDefaultAction(*this); |
+ manager_->DoDefaultAction(*this); |
return S_OK; |
} |
@@ -3120,10 +3112,10 @@ STDMETHODIMP BrowserAccessibilityWin::get_URL(BSTR* url) { |
if (!url) |
return E_INVALIDARG; |
- if (this != manager()->GetRoot()) |
+ if (this != manager_->GetRoot()) |
return E_FAIL; |
- std::string str = manager()->GetTreeData().url; |
+ std::string str = manager_->GetTreeData().url; |
if (str.empty()) |
return S_FALSE; |
@@ -3141,7 +3133,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_title(BSTR* title) { |
if (!title) |
return E_INVALIDARG; |
- std::string str = manager()->GetTreeData().title; |
+ std::string str = manager_->GetTreeData().title; |
if (str.empty()) |
return S_FALSE; |
@@ -3159,7 +3151,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_mimeType(BSTR* mime_type) { |
if (!mime_type) |
return E_INVALIDARG; |
- std::string str = manager()->GetTreeData().mimetype; |
+ std::string str = manager_->GetTreeData().mimetype; |
if (str.empty()) |
return S_FALSE; |
@@ -3177,7 +3169,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_docType(BSTR* doc_type) { |
if (!doc_type) |
return E_INVALIDARG; |
- std::string str = manager()->GetTreeData().doctype; |
+ std::string str = manager_->GetTreeData().doctype; |
if (str.empty()) |
return S_FALSE; |
@@ -3592,8 +3584,8 @@ STDMETHODIMP BrowserAccessibilityWin::scrollToSubstring( |
return E_INVALIDARG; |
} |
- manager()->ScrollToMakeVisible(*this, GetPageBoundsForRange( |
- start_index, end_index - start_index)); |
+ manager_->ScrollToMakeVisible( |
+ *this, GetPageBoundsForRange(start_index, end_index - start_index)); |
return S_OK; |
} |
@@ -3857,6 +3849,42 @@ void BrowserAccessibilityWin::ComputeStylesIfNeeded() { |
win_attributes_->offset_to_text_attributes.swap(attributes_map); |
} |
+// |offset| could either be a text character or a child index in case of |
+// non-text objects. |
+BrowserAccessibilityWin::AXPlatformPositionInstance |
+BrowserAccessibilityWin::CreatePositionAt(int offset) const { |
+ if (!IsNativeTextControl() && !IsTextOnlyObject()) { |
+ DCHECK(manager_); |
+ const BrowserAccessibilityWin* child = this; |
+ // TODO(nektar): Make parents of text-only objects not include the text of |
+ // children in their hypertext. |
+ for (size_t i = 0; i < InternalChildCount(); ++i) { |
+ int new_offset = offset; |
+ child = ToBrowserAccessibilityWin(InternalGetChild(i)); |
+ DCHECK(child); |
+ if (child->IsTextOnlyObject()) { |
+ new_offset -= child->GetText().length(); |
+ } else { |
+ new_offset -= 1; |
+ } |
+ if (new_offset <= 0) |
+ break; |
+ offset = new_offset; |
+ } |
+ AXPlatformPositionInstance position = |
+ AXPlatformPosition::CreateTextPosition(manager_->ax_tree_id(), |
+ child->GetId(), offset, |
+ ui::AX_TEXT_AFFINITY_DOWNSTREAM) |
+ ->AsLeafTextPosition(); |
+ if (position->GetAnchor() && |
+ position->GetAnchor()->GetRole() == ui::AX_ROLE_INLINE_TEXT_BOX) { |
+ return position->CreateParentPosition(); |
+ } |
+ return position; |
+ } |
+ return BrowserAccessibility::CreatePositionAt(offset); |
+} |
+ |
base::string16 BrowserAccessibilityWin::GetText() const { |
if (PlatformIsChildOfLeaf()) |
return BrowserAccessibility::GetText(); |
@@ -4012,7 +4040,7 @@ void BrowserAccessibilityWin::UpdateStep1ComputeWinAttributes() { |
// On Windows, the value of a document should be its url. |
if (GetRole() == ui::AX_ROLE_ROOT_WEB_AREA || |
GetRole() == ui::AX_ROLE_WEB_AREA) { |
- value = base::UTF8ToUTF16(manager()->GetTreeData().url); |
+ value = base::UTF8ToUTF16(manager_->GetTreeData().url); |
} |
// 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. |
@@ -4472,6 +4500,18 @@ void BrowserAccessibilityWin::SanitizeStringAttributeForIA2( |
base::ReplaceChars(*output, L";", L"\\;", output); |
} |
+void BrowserAccessibilityWin::SetIA2HypertextSelection(LONG start_offset, |
+ LONG end_offset) { |
+ HandleSpecialTextOffset(&start_offset); |
+ HandleSpecialTextOffset(&end_offset); |
+ AXPlatformPositionInstance start_position = |
+ CreatePositionAt(static_cast<int>(start_offset)); |
+ AXPlatformPositionInstance end_position = |
+ CreatePositionAt(static_cast<int>(end_offset)); |
+ manager_->SetSelection(AXPlatformRange(start_position->AsTextPosition(), |
+ end_position->AsTextPosition())); |
+} |
+ |
void BrowserAccessibilityWin::StringAttributeToIA2( |
ui::AXStringAttribute attribute, |
const char* ia2_attr) { |
@@ -4678,22 +4718,22 @@ int BrowserAccessibilityWin::GetHypertextOffsetFromEndpoint( |
} |
int BrowserAccessibilityWin::GetSelectionAnchor() const { |
- int32_t anchor_id = manager()->GetTreeData().sel_anchor_object_id; |
+ int32_t anchor_id = manager_->GetTreeData().sel_anchor_object_id; |
const BrowserAccessibilityWin* anchor_object = GetFromID(anchor_id); |
if (!anchor_object) |
return -1; |
- int anchor_offset = manager()->GetTreeData().sel_anchor_offset; |
+ int anchor_offset = manager_->GetTreeData().sel_anchor_offset; |
return GetHypertextOffsetFromEndpoint(*anchor_object, anchor_offset); |
} |
int BrowserAccessibilityWin::GetSelectionFocus() const { |
- int32_t focus_id = manager()->GetTreeData().sel_focus_object_id; |
+ int32_t focus_id = manager_->GetTreeData().sel_focus_object_id; |
const BrowserAccessibilityWin* focus_object = GetFromID(focus_id); |
if (!focus_object) |
return -1; |
- int focus_offset = manager()->GetTreeData().sel_focus_offset; |
+ int focus_offset = manager_->GetTreeData().sel_focus_offset; |
return GetHypertextOffsetFromEndpoint(*focus_object, focus_offset); |
} |
@@ -4830,13 +4870,15 @@ void BrowserAccessibilityWin::ComputeHypertextRemovedAndInserted( |
*new_len = new_text.size() - common_prefix - common_suffix; |
} |
-void BrowserAccessibilityWin::HandleSpecialTextOffset( |
- const base::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); |
+void BrowserAccessibilityWin::HandleSpecialTextOffset(LONG* offset) { |
+ if (*offset == IA2_TEXT_OFFSET_LENGTH) { |
+ *offset = static_cast<LONG>(GetText().length()); |
+ } else if (*offset == IA2_TEXT_OFFSET_CARET) { |
+ // We shouldn't call |get_caretOffset| here as it affects UMA counts. |
+ int selection_start, selection_end; |
+ GetSelectionOffsets(&selection_start, &selection_end); |
+ *offset = selection_end; |
+ } |
} |
ui::TextBoundaryType BrowserAccessibilityWin::IA2TextBoundaryToTextBoundary( |
@@ -4866,12 +4908,11 @@ LONG BrowserAccessibilityWin::FindBoundary( |
ui::TextBoundaryDirection direction) { |
// If the boundary is relative to the caret, use the selection |
// affinity, otherwise default to downstream affinity. |
- ui::AXTextAffinity affinity = |
- start_offset == IA2_TEXT_OFFSET_CARET ? |
- manager()->GetTreeData().sel_focus_affinity : |
- ui::AX_TEXT_AFFINITY_DOWNSTREAM; |
+ ui::AXTextAffinity affinity = start_offset == IA2_TEXT_OFFSET_CARET |
+ ? manager_->GetTreeData().sel_focus_affinity |
+ : ui::AX_TEXT_AFFINITY_DOWNSTREAM; |
- HandleSpecialTextOffset(text, &start_offset); |
+ HandleSpecialTextOffset(&start_offset); |
if (ia2_boundary == IA2_TEXT_BOUNDARY_WORD) |
return GetWordStartBoundary(static_cast<int>(start_offset), direction); |
if (ia2_boundary == IA2_TEXT_BOUNDARY_LINE) { |
@@ -4916,7 +4957,7 @@ LONG BrowserAccessibilityWin::FindStartOfStyle( |
BrowserAccessibilityWin* BrowserAccessibilityWin::GetFromID(int32_t id) const { |
if (!instance_active()) |
return nullptr; |
- return ToBrowserAccessibilityWin(manager()->GetFromID(id)); |
+ return ToBrowserAccessibilityWin(manager_->GetFromID(id)); |
} |
bool BrowserAccessibilityWin::IsListBoxOptionOrMenuListOption() { |