diff options
author | dmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-04 21:38:31 +0000 |
---|---|---|
committer | dmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-04 21:38:31 +0000 |
commit | bde0a751f7ad87186a0340bfe45ce304fefc1932 (patch) | |
tree | 445874f9ff127480a5ca5d2830961742c9216bfe | |
parent | d7ea8374f21ca55608eb5541712379aef11c79dc (diff) | |
download | chromium_src-bde0a751f7ad87186a0340bfe45ce304fefc1932.zip chromium_src-bde0a751f7ad87186a0340bfe45ce304fefc1932.tar.gz chromium_src-bde0a751f7ad87186a0340bfe45ce304fefc1932.tar.bz2 |
Implement more IAccessibleText in NativeViewAccessibilityWin.
This enables NVDA to provide more accessibility for the omnibox.
This code was previously implemented in BrowserAccessibilityWin,
so as much of the logic as possible is abstracted into
a new utility function in ui/base/accessibility.
BUG=102485
TEST=Explore omnibox with NVDA
Review URL: http://codereview.chromium.org/8437063
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@108718 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | content/browser/accessibility/browser_accessibility_win.cc | 110 | ||||
-rw-r--r-- | content/browser/accessibility/browser_accessibility_win.h | 27 | ||||
-rw-r--r-- | ui/base/accessibility/accessible_text_utils.cc | 90 | ||||
-rw-r--r-- | ui/base/accessibility/accessible_text_utils.h | 55 | ||||
-rw-r--r-- | ui/ui.gyp | 2 | ||||
-rw-r--r-- | views/accessibility/native_view_accessibility_win.cc | 119 | ||||
-rw-r--r-- | views/accessibility/native_view_accessibility_win.h | 53 |
7 files changed, 347 insertions, 109 deletions
diff --git a/content/browser/accessibility/browser_accessibility_win.cc b/content/browser/accessibility/browser_accessibility_win.cc index 7be2664..5d23cdc 100644 --- a/content/browser/accessibility/browser_accessibility_win.cc +++ b/content/browser/accessibility/browser_accessibility_win.cc @@ -11,6 +11,7 @@ #include "content/browser/accessibility/browser_accessibility_manager_win.h" #include "content/common/view_messages.h" #include "net/base/escape.h" +#include "ui/base/accessibility/accessible_text_utils.h" using webkit_glue::WebAccessibility; @@ -1746,8 +1747,10 @@ STDMETHODIMP BrowserAccessibilityWin::get_textAtOffset( const string16& text_str = TextForIAccessibleText(); - *start_offset = FindBoundary(text_str, boundary_type, offset, -1); - *end_offset = FindBoundary(text_str, boundary_type, offset, 1); + *start_offset = FindBoundary( + text_str, boundary_type, offset, ui::BACKWARDS_DIRECTION); + *end_offset = FindBoundary( + text_str, boundary_type, offset, ui::FORWARDS_DIRECTION); return get_text(*start_offset, *end_offset, text); } @@ -1773,7 +1776,8 @@ STDMETHODIMP BrowserAccessibilityWin::get_textBeforeOffset( const string16& text_str = TextForIAccessibleText(); - *start_offset = FindBoundary(text_str, boundary_type, offset, -1); + *start_offset = FindBoundary( + text_str, boundary_type, offset, ui::BACKWARDS_DIRECTION); *end_offset = offset; return get_text(*start_offset, *end_offset, text); } @@ -1801,7 +1805,8 @@ STDMETHODIMP BrowserAccessibilityWin::get_textAfterOffset( const string16& text_str = TextForIAccessibleText(); *start_offset = offset; - *end_offset = FindBoundary(text_str, boundary_type, offset, 1); + *end_offset = FindBoundary( + text_str, boundary_type, offset, ui::FORWARDS_DIRECTION); return get_text(*start_offset, *end_offset, text); } @@ -2530,87 +2535,30 @@ void BrowserAccessibilityWin::HandleSpecialTextOffset( } } +ui::TextBoundaryType BrowserAccessibilityWin::IA2TextBoundaryToTextBoundary( + IA2TextBoundaryType ia2_boundary) { + switch(ia2_boundary) { + case IA2_TEXT_BOUNDARY_CHAR: return ui::CHAR_BOUNDARY; + case IA2_TEXT_BOUNDARY_WORD: return ui::WORD_BOUNDARY; + case IA2_TEXT_BOUNDARY_LINE: return ui::LINE_BOUNDARY; + case IA2_TEXT_BOUNDARY_SENTENCE: return ui::SENTENCE_BOUNDARY; + case IA2_TEXT_BOUNDARY_PARAGRAPH: return ui::PARAGRAPH_BOUNDARY; + case IA2_TEXT_BOUNDARY_ALL: return ui::ALL_BOUNDARY; + default: + NOTREACHED(); + return ui::CHAR_BOUNDARY; + } +} + LONG BrowserAccessibilityWin::FindBoundary( const string16& text, - IA2TextBoundaryType boundary, + IA2TextBoundaryType ia2_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); - + ui::TextBoundaryDirection direction) { 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; - } - } + ui::TextBoundaryType boundary = IA2TextBoundaryToTextBoundary(ia2_boundary); + return ui::FindAccessibleTextBoundary( + text, line_breaks_, boundary, start_offset, direction); } BrowserAccessibilityWin* BrowserAccessibilityWin::GetFromRendererID( diff --git a/content/browser/accessibility/browser_accessibility_win.h b/content/browser/accessibility/browser_accessibility_win.h index d20b650..0af601d 100644 --- a/content/browser/accessibility/browser_accessibility_win.h +++ b/content/browser/accessibility/browser_accessibility_win.h @@ -23,6 +23,11 @@ class BrowserAccessibilityManagerWin; class BrowserAccessibilityRelation; +namespace ui { +enum TextBoundaryDirection; +enum TextBoundaryType; +} + using webkit_glue::WebAccessibility; //////////////////////////////////////////////////////////////////////////////// @@ -416,17 +421,20 @@ BrowserAccessibilityWin CONTENT_EXPORT STDMETHODIMP get_text(LONG start_offset, LONG end_offset, BSTR* text); - CONTENT_EXPORT STDMETHODIMP get_textAtOffset(LONG offset, + CONTENT_EXPORT STDMETHODIMP get_textAtOffset( + LONG offset, enum IA2TextBoundaryType boundary_type, LONG* start_offset, LONG* end_offset, BSTR* text); - CONTENT_EXPORT STDMETHODIMP get_textBeforeOffset(LONG offset, + CONTENT_EXPORT STDMETHODIMP get_textBeforeOffset( + LONG offset, enum IA2TextBoundaryType boundary_type, LONG* start_offset, LONG* end_offset, BSTR* text); - CONTENT_EXPORT STDMETHODIMP get_textAfterOffset(LONG offset, + CONTENT_EXPORT STDMETHODIMP get_textAfterOffset( + LONG offset, enum IA2TextBoundaryType boundary_type, LONG* start_offset, LONG* end_offset, BSTR* text); @@ -677,13 +685,16 @@ BrowserAccessibilityWin // value of offset and returns, otherwise offset remains unchanged. void HandleSpecialTextOffset(const string16& text, LONG* offset); - // Search forwards (direction == 1) or backwards (direction == -1) from - // the given offset until the given IAccessible2 boundary (like word, - // sentence) is found, and return its offset. + // Convert from a IA2TextBoundaryType to a ui::TextBoundaryType. + ui::TextBoundaryType IA2TextBoundaryToTextBoundary(IA2TextBoundaryType type); + + // Search forwards (direction == 1) or backwards (direction == -1) + // from the given offset until the given boundary is found, and + // return the offset of that boundary. LONG FindBoundary(const string16& text, - IA2TextBoundaryType boundary, + IA2TextBoundaryType ia2_boundary, LONG start_offset, - LONG direction); + ui::TextBoundaryDirection direction); // Return a pointer to the object corresponding to the given renderer_id, // does not make a new reference. diff --git a/ui/base/accessibility/accessible_text_utils.cc b/ui/base/accessibility/accessible_text_utils.cc new file mode 100644 index 0000000..2d8754d --- /dev/null +++ b/ui/base/accessibility/accessible_text_utils.cc @@ -0,0 +1,90 @@ +// 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 "ui/base/accessibility/accessible_text_utils.h" + +#include "base/logging.h" +#include "base/string_util.h" + +namespace ui { + +size_t FindAccessibleTextBoundary(const string16& text, + const std::vector<int>& line_breaks, + TextBoundaryType boundary, + size_t start_offset, + TextBoundaryDirection direction) { + size_t text_size = text.size(); + DCHECK(start_offset <= text_size); + + if (boundary == CHAR_BOUNDARY) { + if (direction == FORWARDS_DIRECTION && start_offset < text_size) + return start_offset + 1; + else + return start_offset; + } else if (boundary == LINE_BOUNDARY) { + if (direction == FORWARDS_DIRECTION) { + for (size_t j = 0; j < line_breaks.size(); ++j) { + size_t line_break = line_breaks[j] >= 0 ? line_breaks[j] : 0; + if (line_break > start_offset) + return line_break; + } + return text_size; + } else { + // Note: j is unsigned, so for loop continues until j wraps around + // and becomes greater than the starting value. + for (size_t j = line_breaks.size() - 1; + j < line_breaks.size(); + --j) { + size_t line_break = line_breaks[j] >= 0 ? line_breaks[j] : 0; + if (line_break <= start_offset) + return line_break; + } + return 0; + } + } + + size_t result = start_offset; + for (;;) { + size_t pos; + if (direction == FORWARDS_DIRECTION) { + if (result >= text_size) + return text_size; + pos = result; + } else { + if (result == 0) + return 0; + pos = result - 1; + } + + switch (boundary) { + case CHAR_BOUNDARY: + case LINE_BOUNDARY: + NOTREACHED(); // These are handled above. + break; + case WORD_BOUNDARY: + if (IsWhitespace(text[pos])) + return result; + break; + case PARAGRAPH_BOUNDARY: + if (text[pos] == '\n') + return result; + case SENTENCE_BOUNDARY: + if ((text[pos] == '.' || text[pos] == '!' || text[pos] == '?') && + (pos == text_size - 1 || IsWhitespace(text[pos + 1]))) { + return result; + } + case ALL_BOUNDARY: + default: + break; + } + + if (direction == FORWARDS_DIRECTION) { + result++; + } else { + result--; + } + } +} + +} // Namespace ui diff --git a/ui/base/accessibility/accessible_text_utils.h b/ui/base/accessibility/accessible_text_utils.h new file mode 100644 index 0000000..40253f6 --- /dev/null +++ b/ui/base/accessibility/accessible_text_utils.h @@ -0,0 +1,55 @@ +// 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. + +#ifndef UI_BASE_ACCESSIBILITY_ACCESSIBLE_TEXT_UTILS_H_ +#define UI_BASE_ACCESSIBILITY_ACCESSIBLE_TEXT_UTILS_H_ +#pragma once + +#include <vector> + +#include "base/basictypes.h" +#include "base/string16.h" +#include "ui/base/ui_export.h" + +namespace ui { + +// Boundaries that can be passed to FindAccessibleTextBoundary, +// representing various visual boundaries in (potentially multi-line) +// text. This is used by assistive technology in order to, for example, +// retrieve the nearest word to the cursor, or retrieve all of the +// text from the current cursor position to the end of the line. +// These should be self-explanatory; "line" here refers to the visual +// line as currently displayed (possibly affected by wrapping). +enum UI_EXPORT TextBoundaryType { + CHAR_BOUNDARY, + WORD_BOUNDARY, + LINE_BOUNDARY, + SENTENCE_BOUNDARY, + PARAGRAPH_BOUNDARY, + ALL_BOUNDARY +}; + +// A direction when searching for the next boundary. +enum UI_EXPORT TextBoundaryDirection { + // Search forwards for the next boundary past the starting position. + FORWARDS_DIRECTION, + // Search backwards for the previous boundary before the starting position. + BACKWARDS_DIRECTION +}; + +// Convenience method needed to implement platform-specific text +// accessibility APIs like IAccessible2. Search forwards or backwards +// (depending on |direction|) from the given |start_offset| until the +// given boundary is found, and return the offset of that boundary, +// using the vector of line break character offsets in |line_breaks|. +size_t UI_EXPORT FindAccessibleTextBoundary( + const string16& text, + const std::vector<int>& line_breaks, + TextBoundaryType boundary, + size_t start_offset, + TextBoundaryDirection direction); + +} // namespace ui + +#endif // UI_BASE_ACCESSIBILITY_ACCESSIBLE_TEXT_UTILS_H_ @@ -47,6 +47,8 @@ ], 'sources': [ 'base/accessibility/accessibility_types.h', + 'base/accessibility/accessible_text_utils.cc', + 'base/accessibility/accessible_text_utils.h', 'base/accessibility/accessible_view_state.cc', 'base/accessibility/accessible_view_state.h', 'base/animation/animation.cc', diff --git a/views/accessibility/native_view_accessibility_win.cc b/views/accessibility/native_view_accessibility_win.cc index 064f181..1c7bddd 100644 --- a/views/accessibility/native_view_accessibility_win.cc +++ b/views/accessibility/native_view_accessibility_win.cc @@ -5,9 +5,12 @@ #include <atlbase.h> #include <atlcom.h> +#include <vector> + #include "views/accessibility/native_view_accessibility_win.h" #include "third_party/iaccessible2/ia2_api_all.h" +#include "ui/base/accessibility/accessible_text_utils.h" #include "ui/base/accessibility/accessible_view_state.h" #include "ui/base/view_prop.h" #include "views/widget/native_widget_win.h" @@ -634,8 +637,8 @@ STDMETHODIMP NativeViewAccessibilityWin::get_selection(LONG selection_index, } STDMETHODIMP NativeViewAccessibilityWin::get_text(LONG start_offset, - LONG end_offset, - BSTR* text) { + LONG end_offset, + BSTR* text) { if (!view_) return E_FAIL; @@ -678,6 +681,82 @@ STDMETHODIMP NativeViewAccessibilityWin::get_text(LONG start_offset, return S_OK; } +STDMETHODIMP NativeViewAccessibilityWin::get_textAtOffset( + LONG offset, + enum IA2TextBoundaryType boundary_type, + LONG* start_offset, LONG* end_offset, + BSTR* text) { + 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, ui::BACKWARDS_DIRECTION); + *end_offset = FindBoundary( + text_str, boundary_type, offset, ui::FORWARDS_DIRECTION); + return get_text(*start_offset, *end_offset, text); +} + +STDMETHODIMP NativeViewAccessibilityWin::get_textBeforeOffset( + LONG offset, + enum IA2TextBoundaryType boundary_type, + LONG* start_offset, LONG* end_offset, + BSTR* text) { + 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, ui::BACKWARDS_DIRECTION); + *end_offset = offset; + return get_text(*start_offset, *end_offset, text); +} + +STDMETHODIMP NativeViewAccessibilityWin::get_textAfterOffset( + LONG offset, + enum IA2TextBoundaryType boundary_type, + LONG* start_offset, LONG* end_offset, + BSTR* text) { + 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, ui::FORWARDS_DIRECTION); + return get_text(*start_offset, *end_offset, text); +} + STDMETHODIMP NativeViewAccessibilityWin::get_offsetAtPoint( LONG x, LONG y, enum IA2CoordinateType coord_type, LONG* offset) { if (!view_) @@ -913,3 +992,39 @@ string16 NativeViewAccessibilityWin::TextForIAccessibleText() { else return state.name; } + +void NativeViewAccessibilityWin::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); + } +} + +ui::TextBoundaryType NativeViewAccessibilityWin::IA2TextBoundaryToTextBoundary( + IA2TextBoundaryType ia2_boundary) { + switch(ia2_boundary) { + case IA2_TEXT_BOUNDARY_CHAR: return ui::CHAR_BOUNDARY; + case IA2_TEXT_BOUNDARY_WORD: return ui::WORD_BOUNDARY; + case IA2_TEXT_BOUNDARY_LINE: return ui::LINE_BOUNDARY; + case IA2_TEXT_BOUNDARY_SENTENCE: return ui::SENTENCE_BOUNDARY; + case IA2_TEXT_BOUNDARY_PARAGRAPH: return ui::PARAGRAPH_BOUNDARY; + case IA2_TEXT_BOUNDARY_ALL: return ui::ALL_BOUNDARY; + default: + NOTREACHED(); + return ui::CHAR_BOUNDARY; + } +} + +LONG NativeViewAccessibilityWin::FindBoundary( + const string16& text, + IA2TextBoundaryType ia2_boundary, + LONG start_offset, + ui::TextBoundaryDirection direction) { + HandleSpecialTextOffset(text, &start_offset); + ui::TextBoundaryType boundary = IA2TextBoundaryToTextBoundary(ia2_boundary); + std::vector<int32> line_breaks; + return ui::FindAccessibleTextBoundary( + text, line_breaks, boundary, start_offset, direction); +} diff --git a/views/accessibility/native_view_accessibility_win.h b/views/accessibility/native_view_accessibility_win.h index 395ae5b..854f023 100644 --- a/views/accessibility/native_view_accessibility_win.h +++ b/views/accessibility/native_view_accessibility_win.h @@ -17,6 +17,11 @@ #include "views/controls/native/native_view_host.h" #include "views/view.h" +namespace ui { +enum TextBoundaryDirection; +enum TextBoundaryType; +} + // Note: do not put NativeViewAccessibilityWin in the namespace "views"; // Visual Studio 2005 does not allow an ATL::CComObject symbol in a namespace. @@ -208,6 +213,21 @@ NativeViewAccessibilityWin STDMETHODIMP get_text(LONG start_offset, LONG end_offset, BSTR* text); + STDMETHODIMP get_textAtOffset(LONG offset, + enum IA2TextBoundaryType boundary_type, + LONG* start_offset, LONG* end_offset, + BSTR* text); + + STDMETHODIMP get_textBeforeOffset(LONG offset, + enum IA2TextBoundaryType boundary_type, + LONG* start_offset, LONG* end_offset, + BSTR* text); + + STDMETHODIMP get_textAfterOffset(LONG offset, + enum IA2TextBoundaryType boundary_type, + LONG* start_offset, LONG* end_offset, + BSTR* text); + STDMETHODIMP get_offsetAtPoint(LONG x, LONG y, enum IA2CoordinateType coord_type, LONG* offset); @@ -216,24 +236,6 @@ NativeViewAccessibilityWin // IAccessibleText methods not implemented. // - STDMETHODIMP get_textAtOffset(LONG offset, - enum IA2TextBoundaryType boundary_type, - LONG* start_offset, LONG* end_offset, - BSTR* text) { - return E_NOTIMPL; - } - STDMETHODIMP get_textBeforeOffset(LONG offset, - enum IA2TextBoundaryType boundary_type, - LONG* start_offset, LONG* end_offset, - BSTR* text) { - return E_NOTIMPL; - } - STDMETHODIMP get_textAfterOffset(LONG offset, - enum IA2TextBoundaryType boundary_type, - LONG* start_offset, LONG* end_offset, - BSTR* text) { - return E_NOTIMPL; - } STDMETHODIMP get_newText(IA2TextSegment* new_text) { return E_NOTIMPL; } @@ -320,6 +322,21 @@ NativeViewAccessibilityWin // Return the text to use for IAccessibleText. string16 TextForIAccessibleText(); + // If offset is a member of IA2TextSpecialOffsets this function updates the + // value of offset and returns, otherwise offset remains unchanged. + void HandleSpecialTextOffset(const string16& text, LONG* offset); + + // Convert from a IA2TextBoundaryType to a ui::TextBoundaryType. + ui::TextBoundaryType IA2TextBoundaryToTextBoundary(IA2TextBoundaryType type); + + // Search forwards (direction == 1) or backwards (direction == -1) + // from the given offset until the given boundary is found, and + // return the offset of that boundary. + LONG FindBoundary(const string16& text, + IA2TextBoundaryType ia2_boundary, + LONG start_offset, + ui::TextBoundaryDirection direction); + // Give CComObject access to the class constructor. template <class Base> friend class CComObject; |