summaryrefslogtreecommitdiffstats
path: root/chrome/browser/accessibility
diff options
context:
space:
mode:
authordmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-08 18:01:38 +0000
committerdmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-08 18:01:38 +0000
commitd1fdc6f83a75e316aafef3ff0f84f30a132f08c3 (patch)
tree0bb8fa503fcdc9ff4e73cdcef887e1f3054edd6d /chrome/browser/accessibility
parente6025de05d4f747edb3f638ed99b95b1b08360b2 (diff)
downloadchromium_src-d1fdc6f83a75e316aafef3ff0f84f30a132f08c3.zip
chromium_src-d1fdc6f83a75e316aafef3ff0f84f30a132f08c3.tar.gz
chromium_src-d1fdc6f83a75e316aafef3ff0f84f30a132f08c3.tar.bz2
Implement additional IAccessibleText methods to return the nearest
character, word, line, sentence, or paragraph within a text field. These methods are needed by SAToGo. BUG=36217 TEST=Added new unit test. Review URL: http://codereview.chromium.org/3550017 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@61979 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/accessibility')
-rw-r--r--chrome/browser/accessibility/browser_accessibility_win.cc232
-rw-r--r--chrome/browser/accessibility/browser_accessibility_win.h52
-rw-r--r--chrome/browser/accessibility/browser_accessibility_win_unittest.cc85
3 files changed, 304 insertions, 65 deletions
diff --git a/chrome/browser/accessibility/browser_accessibility_win.cc b/chrome/browser/accessibility/browser_accessibility_win.cc
index 432eb1a..8817dfa 100644
--- a/chrome/browser/accessibility/browser_accessibility_win.cc
+++ b/chrome/browser/accessibility/browser_accessibility_win.cc
@@ -54,7 +54,7 @@ HRESULT BrowserAccessibilityWin::accDoDefaultAction(VARIANT var_id) {
}
STDMETHODIMP BrowserAccessibilityWin::accHitTest(LONG x_left, LONG y_top,
- VARIANT* child) {
+ VARIANT* child) {
if (!instance_active_)
return E_FAIL;
@@ -65,8 +65,8 @@ STDMETHODIMP BrowserAccessibilityWin::accHitTest(LONG x_left, LONG y_top,
}
STDMETHODIMP BrowserAccessibilityWin::accLocation(LONG* x_left, LONG* y_top,
- LONG* width, LONG* height,
- VARIANT var_id) {
+ LONG* width, LONG* height,
+ VARIANT var_id) {
if (!instance_active_)
return E_FAIL;
@@ -534,45 +534,6 @@ STDMETHODIMP BrowserAccessibilityWin::get_nCharacters(LONG* n_characters) {
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;
-
- string16 text_str;
- if (role_ == WebAccessibility::ROLE_TEXT_FIELD) {
- text_str = value_;
- } else {
- text_str = name_;
- }
-
- // 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_caretOffset(LONG* offset) {
if (!instance_active_)
return E_FAIL;
@@ -585,7 +546,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_caretOffset(LONG* offset) {
if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start)) {
*offset = sel_start;
} else {
- *offset = 0;
+ *offset = 0;
}
} else {
*offset = 0;
@@ -646,6 +607,121 @@ STDMETHODIMP BrowserAccessibilityWin::get_selection(LONG selection_index,
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();
+
+ // 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.
//
@@ -1129,6 +1205,76 @@ string16 BrowserAccessibilityWin::Escape(string16 str) {
return EscapeQueryParamValueUTF8(str, false);
}
+const string16& BrowserAccessibilityWin::TextForIAccessibleText() {
+ if (role_ == WebAccessibility::ROLE_TEXT_FIELD) {
+ return value_;
+ } else {
+ return name_;
+ }
+}
+
+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);
+ DCHECK(direction == 1 || direction == -1);
+
+ if (boundary == IA2_TEXT_BOUNDARY_CHAR) {
+ if (direction == 1 && start_offset < text_size)
+ return start_offset + 1;
+ else
+ return start_offset;
+ }
+
+ 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_WORD:
+ if (IsWhitespace(text[pos]))
+ return result;
+ break;
+ case IA2_TEXT_BOUNDARY_LINE:
+ 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;
diff --git a/chrome/browser/accessibility/browser_accessibility_win.h b/chrome/browser/accessibility/browser_accessibility_win.h
index dbd014f..16ea136 100644
--- a/chrome/browser/accessibility/browser_accessibility_win.h
+++ b/chrome/browser/accessibility/browser_accessibility_win.h
@@ -230,8 +230,6 @@ class BrowserAccessibilityWin
STDMETHODIMP get_nCharacters(LONG* n_characters);
- STDMETHODIMP get_text(LONG start_offset, LONG end_offset, BSTR* text);
-
STDMETHODIMP get_caretOffset(LONG* offset);
STDMETHODIMP get_nSelections(LONG* n_selections);
@@ -240,6 +238,22 @@ class BrowserAccessibilityWin
LONG* start_offset,
LONG* end_offset);
+ 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);
// IAccessibleText methods not implemented.
STDMETHODIMP addSelection(LONG start_offset, LONG end_offset) {
@@ -256,26 +270,8 @@ class BrowserAccessibilityWin
return E_NOTIMPL;
}
STDMETHODIMP get_offsetAtPoint(LONG x, LONG y,
- enum IA2CoordinateType coord_type,
- LONG* offset) {
- 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_textAtOffset(LONG offset,
- enum IA2TextBoundaryType boundary_type,
- LONG* start_offset, LONG* end_offset,
- BSTR* text) {
+ enum IA2CoordinateType coord_type,
+ LONG* offset) {
return E_NOTIMPL;
}
STDMETHODIMP removeSelection(LONG selection_index) {
@@ -484,6 +480,18 @@ class BrowserAccessibilityWin
// Escape a string like it would be escaped for a URL or HTML form.
string16 Escape(string16 str);
+ // Get the text of this node for the purposes of IAccessibleText - it may
+ // be the name, it may be the value, etc. depending on the role.
+ const string16& TextForIAccessibleText();
+
+ // 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.
+ LONG FindBoundary(const string16& text,
+ IA2TextBoundaryType boundary,
+ LONG start_offset,
+ LONG direction);
+
// COM objects are reference-counted. When we're done with this object
// and it's removed from our accessibility tree, a client may still be
// holding onto a pointer to this object, so we mark it as inactive
diff --git a/chrome/browser/accessibility/browser_accessibility_win_unittest.cc b/chrome/browser/accessibility/browser_accessibility_win_unittest.cc
index 549700a..dd264a1 100644
--- a/chrome/browser/accessibility/browser_accessibility_win_unittest.cc
+++ b/chrome/browser/accessibility/browser_accessibility_win_unittest.cc
@@ -274,3 +274,88 @@ TEST_F(BrowserAccessibilityTest, TestChildrenChangeNoLeaks) {
delete manager;
ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_);
}
+
+TEST_F(BrowserAccessibilityTest, TestTextBoundaries) {
+ WebAccessibility text1;
+ text1.id = 11;
+ text1.role = WebAccessibility::ROLE_TEXT_FIELD;
+ text1.state = 0;
+ text1.value = L"One two three.\nFour five six.";
+
+ WebAccessibility root;
+ root.id = 1;
+ root.role = WebAccessibility::ROLE_DOCUMENT;
+ root.state = 0;
+ root.children.push_back(text1);
+
+ CountedBrowserAccessibility::global_obj_count_ = 0;
+ BrowserAccessibilityManager* manager = BrowserAccessibilityManager::Create(
+ GetDesktopWindow(), root, NULL,
+ new CountedBrowserAccessibilityFactory());
+ ASSERT_EQ(2, CountedBrowserAccessibility::global_obj_count_);
+
+ BrowserAccessibilityWin* root_obj =
+ manager->GetRoot()->toBrowserAccessibilityWin();
+ BrowserAccessibilityWin* text1_obj =
+ root_obj->GetChild(0)->toBrowserAccessibilityWin();
+
+ BSTR text;
+ long start;
+ long end;
+
+ long text1_len;
+ ASSERT_EQ(S_OK, text1_obj->get_nCharacters(&text1_len));
+
+ ASSERT_EQ(S_OK, text1_obj->get_text(0, text1_len, &text));
+ ASSERT_EQ(text, text1.value);
+ SysFreeString(text);
+
+ ASSERT_EQ(S_OK, text1_obj->get_text(0, 4, &text));
+ ASSERT_EQ(text, std::wstring(L"One "));
+ SysFreeString(text);
+
+ ASSERT_EQ(S_OK, text1_obj->get_textAtOffset(
+ 1, IA2_TEXT_BOUNDARY_CHAR, &start, &end, &text));
+ ASSERT_EQ(start, 1);
+ ASSERT_EQ(end, 2);
+ ASSERT_EQ(text, std::wstring(L"n"));
+ SysFreeString(text);
+
+ ASSERT_EQ(S_FALSE, text1_obj->get_textAtOffset(
+ text1_len, IA2_TEXT_BOUNDARY_CHAR, &start, &end, &text));
+ ASSERT_EQ(start, text1_len);
+ ASSERT_EQ(end, text1_len);
+
+ ASSERT_EQ(S_OK, text1_obj->get_textAtOffset(
+ 1, IA2_TEXT_BOUNDARY_WORD, &start, &end, &text));
+ ASSERT_EQ(start, 0);
+ ASSERT_EQ(end, 3);
+ ASSERT_EQ(text, std::wstring(L"One"));
+ SysFreeString(text);
+
+ ASSERT_EQ(S_OK, text1_obj->get_textAtOffset(
+ 6, IA2_TEXT_BOUNDARY_WORD, &start, &end, &text));
+ ASSERT_EQ(start, 4);
+ ASSERT_EQ(end, 7);
+ ASSERT_EQ(text, std::wstring(L"two"));
+ SysFreeString(text);
+
+ ASSERT_EQ(S_OK, text1_obj->get_textAtOffset(
+ text1_len, IA2_TEXT_BOUNDARY_WORD, &start, &end, &text));
+ ASSERT_EQ(start, 25);
+ ASSERT_EQ(end, 29);
+ ASSERT_EQ(text, std::wstring(L"six."));
+ SysFreeString(text);
+
+ ASSERT_EQ(S_OK, text1_obj->get_textAtOffset(
+ 1, IA2_TEXT_BOUNDARY_LINE, &start, &end, &text));
+ ASSERT_EQ(start, 0);
+ ASSERT_EQ(end, 13);
+ ASSERT_EQ(text, std::wstring(L"One two three"));
+ SysFreeString(text);
+
+ // Delete the manager and test that all BrowserAccessibility instances are
+ // deleted.
+ delete manager;
+ ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_);
+}