summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornektar <nektar@chromium.org>2015-04-29 17:31:14 -0700
committerCommit bot <commit-bot@chromium.org>2015-04-30 00:31:43 +0000
commit28f5f6444f311879cff2e7688011a54bf40a463b (patch)
tree37f8fc30bf4d3bc955f28fff42f94d76b533bf36
parentea8c00ec4ea9fc6df348f0cb2b3a2b0f3ed2802e (diff)
downloadchromium_src-28f5f6444f311879cff2e7688011a54bf40a463b.zip
chromium_src-28f5f6444f311879cff2e7688011a54bf40a463b.tar.gz
chromium_src-28f5f6444f311879cff2e7688011a54bf40a463b.tar.bz2
Fixed word and line navigation in multi-line text fields.
This might also fix the line break issue where lines appear joined together. This CL should be submitted only after the Blink change removing a spurious line break at the end of all text fields is rolled into Chromium. BUG=102231 R=dmazzoni Review URL: https://codereview.chromium.org/1111163002 Cr-Commit-Position: refs/heads/master@{#327629}
-rw-r--r--content/browser/accessibility/accessibility_win_browsertest.cc6
-rw-r--r--content/browser/accessibility/browser_accessibility.cc154
-rw-r--r--content/browser/accessibility/browser_accessibility.h8
-rw-r--r--content/browser/accessibility/browser_accessibility_win_unittest.cc171
-rw-r--r--ui/accessibility/ax_text_utils.cc7
-rw-r--r--ui/accessibility/ax_text_utils_unittest.cc66
6 files changed, 261 insertions, 151 deletions
diff --git a/content/browser/accessibility/accessibility_win_browsertest.cc b/content/browser/accessibility/accessibility_win_browsertest.cc
index 0618374..7c3480d 100644
--- a/content/browser/accessibility/accessibility_win_browsertest.cc
+++ b/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -1209,7 +1209,7 @@ IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
}
IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
- DISABLED_TestMultiLineTextAtOffsetWithBoundaryCharacter) {
+ TestMultiLineTextAtOffsetWithBoundaryCharacter) {
base::win::ScopedComPtr<IAccessibleText> textarea_text;
SetUpTextareaField(&textarea_text);
for (LONG offset = 0; offset < CONTENTS_LENGTH; ++offset) {
@@ -1305,7 +1305,7 @@ IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
}
IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
- DISABLED_TestMultiLineTextAtOffsetWithBoundaryWord) {
+ TestMultiLineTextAtOffsetWithBoundaryWord) {
base::win::ScopedComPtr<IAccessibleText> textarea_text;
SetUpTextareaField(&textarea_text);
@@ -1423,7 +1423,7 @@ IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
}
IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
- DISABLED_TestMultiLineTextAtOffsetWithBoundaryLine) {
+ TestMultiLineTextAtOffsetWithBoundaryLine) {
base::win::ScopedComPtr<IAccessibleText> textarea_text;
SetUpTextareaField(&textarea_text);
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index 16a8ed2..0fdad54 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -228,7 +228,12 @@ gfx::Rect BrowserAccessibility::GetLocalBoundsForRange(int start, int len)
gfx::Rect bounds;
for (size_t i = 0; i < InternalChildCount() && child_end < start + len; ++i) {
BrowserAccessibility* child = InternalGetChild(i);
- DCHECK_EQ(child->GetRole(), ui::AX_ROLE_INLINE_TEXT_BOX);
+ if (child->GetRole() != ui::AX_ROLE_INLINE_TEXT_BOX) {
+ DLOG(WARNING) << "BrowserAccessibility objects with role STATIC_TEXT " <<
+ "should have children of role INLINE_TEXT_BOX.";
+ continue;
+ }
+
std::string child_text;
child->GetStringAttribute(ui::AX_ATTR_VALUE, &child_text);
int child_len = static_cast<int>(child_text.size());
@@ -311,71 +316,104 @@ gfx::Rect BrowserAccessibility::GetGlobalBoundsForRange(int start, int len)
int BrowserAccessibility::GetWordStartBoundary(
int start, ui::TextBoundaryDirection direction) const {
- int word_start = 0;
- int prev_word_start = 0;
- if (GetRole() != ui::AX_ROLE_STATIC_TEXT) {
- for (size_t i = 0; i < InternalChildCount(); ++i) {
- BrowserAccessibility* child = InternalGetChild(i);
- int child_len = child->GetStaticTextLenRecursive();
- int child_word_start = child->GetWordStartBoundary(start, direction);
- word_start += child_word_start;
- if (child_word_start != child_len)
- break;
- start -= child_len;
- }
- return word_start;
- }
+ DCHECK_GE(start, -1);
+ // Special offset that indicates that a word boundary has not been found.
+ int word_start_not_found = GetStaticTextLenRecursive();
+ int word_start = word_start_not_found;
- int child_start = 0;
- int child_end = 0;
- for (size_t i = 0; i < InternalChildCount(); ++i) {
- // The next child starts where the previous one ended.
- child_start = child_end;
- BrowserAccessibility* child = InternalGetChild(i);
- DCHECK_EQ(child->GetRole(), ui::AX_ROLE_INLINE_TEXT_BOX);
- const std::string& child_text = child->GetStringAttribute(
- ui::AX_ATTR_VALUE);
- int child_len = static_cast<int>(child_text.size());
- child_end += child_len; // End is one past the last character.
+ switch (GetRole()) {
+ case ui::AX_ROLE_STATIC_TEXT: {
+ int prev_word_start = word_start_not_found;
+ int child_start = 0;
+ int child_end = 0;
+
+ // Go through the inline text boxes.
+ for (size_t i = 0; i < InternalChildCount(); ++i) {
+ // The next child starts where the previous one ended.
+ child_start = child_end;
+ BrowserAccessibility* child = InternalGetChild(i);
+ DCHECK_EQ(child->GetRole(), ui::AX_ROLE_INLINE_TEXT_BOX);
+ const std::string& child_text = child->GetStringAttribute(
+ ui::AX_ATTR_VALUE);
+ int child_len = static_cast<int>(child_text.size());
+ child_end += child_len; // End is one past the last character.
+
+ const std::vector<int32>& word_starts = child->GetIntListAttribute(
+ ui::AX_ATTR_WORD_STARTS);
+ if (word_starts.empty()) {
+ word_start = child_end;
+ continue;
+ }
- const std::vector<int32>& word_starts = child->GetIntListAttribute(
- ui::AX_ATTR_WORD_STARTS);
- if (word_starts.empty()) {
- word_start = child_end;
- continue;
- }
+ int local_start = start - child_start;
+ std::vector<int32>::const_iterator iter = std::upper_bound(
+ word_starts.begin(), word_starts.end(), local_start);
+ if (iter != word_starts.end()) {
+ if (direction == ui::FORWARDS_DIRECTION) {
+ word_start = child_start + *iter;
+ } else if (direction == ui::BACKWARDS_DIRECTION) {
+ if (iter == word_starts.begin()) {
+ // Return the position of the last word in the previous child.
+ word_start = prev_word_start;
+ } else {
+ word_start = child_start + *(iter - 1);
+ }
+ } else {
+ NOTREACHED();
+ }
+ break;
+ }
- int local_start = start - child_start;
- std::vector<int32>::const_iterator iter = std::upper_bound(
- word_starts.begin(), word_starts.end(), local_start);
- if (iter != word_starts.end()) {
- if (direction == ui::FORWARDS_DIRECTION) {
- word_start = child_start + *iter;
- } else if (direction == ui::BACKWARDS_DIRECTION) {
- if (iter == word_starts.begin()) {
- // Return the position of the last word in the previous child.
+ // No word start that is greater than the requested offset has been
+ // found.
+ prev_word_start = child_start + *(iter - 1);
+ if (direction == ui::FORWARDS_DIRECTION) {
+ word_start = child_end;
+ } else if (direction == ui::BACKWARDS_DIRECTION) {
word_start = prev_word_start;
} else {
- word_start = child_start + *(iter - 1);
+ NOTREACHED();
}
- } else {
- NOTREACHED();
}
- break;
+ return word_start;
}
- // No word start that is >= to the requested offset has been found.
- prev_word_start = child_start + *(iter - 1);
- if (direction == ui::FORWARDS_DIRECTION) {
- word_start = child_end;
- } else if (direction == ui::BACKWARDS_DIRECTION) {
- word_start = prev_word_start;
- } else {
- NOTREACHED();
- }
- }
+ case ui::AX_ROLE_LINE_BREAK:
+ // Words never start at a line break.
+ return word_start_not_found;
- return word_start;
+ default:
+ // If there are no children, the word start boundary is still unknown or
+ // found previously depending on the direction.
+ if (!InternalChildCount())
+ return word_start_not_found;
+
+ int child_start = 0;
+ for (size_t i = 0; i < InternalChildCount(); ++i) {
+ BrowserAccessibility* child = InternalGetChild(i);
+ int child_len = child->GetStaticTextLenRecursive();
+ int child_word_start = child->GetWordStartBoundary(start, direction);
+ if (child_word_start < child_len) {
+ // We have found a possible word boundary.
+ word_start = child_start + child_word_start;
+ }
+
+ // Decide when to stop searching.
+ if ((word_start != word_start_not_found &&
+ direction == ui::FORWARDS_DIRECTION) ||
+ (start < child_len &&
+ direction == ui::BACKWARDS_DIRECTION)) {
+ break;
+ }
+
+ child_start += child_len;
+ if (start >= child_len)
+ start -= child_len;
+ else
+ start = -1;
+ }
+ return word_start;
+ }
}
BrowserAccessibility* BrowserAccessibility::BrowserAccessibilityForPoint(
@@ -722,8 +760,10 @@ bool BrowserAccessibility::IsWebAreaForPresentationalIframe() const {
}
int BrowserAccessibility::GetStaticTextLenRecursive() const {
- if (GetRole() == ui::AX_ROLE_STATIC_TEXT)
+ if (GetRole() == ui::AX_ROLE_STATIC_TEXT ||
+ GetRole() == ui::AX_ROLE_LINE_BREAK) {
return static_cast<int>(GetStringAttribute(ui::AX_ATTR_VALUE).size());
+ }
int len = 0;
for (size_t i = 0; i < InternalChildCount(); ++i)
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index e0b18bd..4f6b3086 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -114,6 +114,14 @@ class CONTENT_EXPORT BrowserAccessibility {
// Searches in the given text and from the given offset until the start of
// the next or previous word is found and returns its position.
+ // In case there is no word boundary before or after the given offset, it
+ // returns one past the last character, i.e. the text's length.
+ // If the given offset is already at the start of a word, returns the start
+ // of the next word if the search is forwards and the given offset if it is
+ // backwards.
+ // If the start offset is equal to -1 and the search is in the forwards
+ // direction, returns the start boundary of the first word.
+ // Start offsets that are not in the range -1 to text length are invalid.
int GetWordStartBoundary(
int start, ui::TextBoundaryDirection direction) const;
diff --git a/content/browser/accessibility/browser_accessibility_win_unittest.cc b/content/browser/accessibility/browser_accessibility_win_unittest.cc
index 7983953..501490e 100644
--- a/content/browser/accessibility/browser_accessibility_win_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_win_unittest.cc
@@ -323,104 +323,157 @@ TEST_F(BrowserAccessibilityTest, TestChildrenChangeNoLeaks) {
ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
}
-TEST_F(BrowserAccessibilityTest, DISABLED_TestTextBoundaries) {
- std::string text1_value = "One two three.\nFour five six.";
-
- ui::AXNodeData text1;
- text1.id = 11;
- text1.role = ui::AX_ROLE_TEXT_FIELD;
- text1.state = 0;
- text1.AddStringAttribute(ui::AX_ATTR_VALUE, text1_value);
- std::vector<int32> line_breaks;
- line_breaks.push_back(15);
- text1.AddIntListAttribute(
- ui::AX_ATTR_LINE_BREAKS, line_breaks);
+TEST_F(BrowserAccessibilityTest, TestTextBoundaries) {
+ std::string line1 = "One two three.";
+ std::string line2 = "Four five six.";
+ std::string text_value = line1 + '\n' + line2;
ui::AXNodeData root;
root.id = 1;
root.role = ui::AX_ROLE_ROOT_WEB_AREA;
- root.state = 0;
- root.child_ids.push_back(11);
+ root.child_ids.push_back(2);
+
+ ui::AXNodeData text_field;
+ text_field.id = 2;
+ text_field.role = ui::AX_ROLE_TEXT_FIELD;
+ text_field.AddStringAttribute(ui::AX_ATTR_VALUE, text_value);
+ std::vector<int32> line_start_offsets;
+ line_start_offsets.push_back(15);
+ text_field.AddIntListAttribute(
+ ui::AX_ATTR_LINE_BREAKS, line_start_offsets);
+ text_field.child_ids.push_back(3);
+ text_field.child_ids.push_back(5);
+ text_field.child_ids.push_back(6);
+
+ ui::AXNodeData static_text1;
+ static_text1.id = 3;
+ static_text1.role = ui::AX_ROLE_STATIC_TEXT;
+ static_text1.AddStringAttribute(ui::AX_ATTR_VALUE, line1);
+ static_text1.child_ids.push_back(4);
+
+ ui::AXNodeData inline_box1;
+ inline_box1.id = 4;
+ inline_box1.role = ui::AX_ROLE_INLINE_TEXT_BOX;
+ inline_box1.AddStringAttribute(ui::AX_ATTR_VALUE, line1);
+ std::vector<int32> word_start_offsets1;
+ word_start_offsets1.push_back(0);
+ word_start_offsets1.push_back(4);
+ word_start_offsets1.push_back(8);
+ inline_box1.AddIntListAttribute(
+ ui::AX_ATTR_WORD_STARTS, word_start_offsets1);
+
+ ui::AXNodeData line_break;
+ line_break.id = 5;
+ line_break.role = ui::AX_ROLE_LINE_BREAK;
+ line_break.AddStringAttribute(ui::AX_ATTR_VALUE, "\n");
+
+ ui::AXNodeData static_text2;
+ static_text2.id = 6;
+ static_text2.role = ui::AX_ROLE_STATIC_TEXT;
+ static_text2.AddStringAttribute(ui::AX_ATTR_VALUE, line2);
+ static_text2.child_ids.push_back(7);
+
+ ui::AXNodeData inline_box2;
+ inline_box2.id = 7;
+ inline_box2.role = ui::AX_ROLE_INLINE_TEXT_BOX;
+ inline_box2.AddStringAttribute(ui::AX_ATTR_VALUE, line2);
+ std::vector<int32> word_start_offsets2;
+ word_start_offsets2.push_back(0);
+ word_start_offsets2.push_back(5);
+ word_start_offsets2.push_back(10);
+ inline_box2.AddIntListAttribute(
+ ui::AX_ATTR_WORD_STARTS, word_start_offsets2);
CountedBrowserAccessibility::reset();
scoped_ptr<BrowserAccessibilityManager> manager(
BrowserAccessibilityManager::Create(
- MakeAXTreeUpdate(root, text1),
- NULL, new CountedBrowserAccessibilityFactory()));
- ASSERT_EQ(2, CountedBrowserAccessibility::num_instances());
+ MakeAXTreeUpdate(root, text_field, static_text1, inline_box1,
+ line_break, static_text2, inline_box2),
+ nullptr, new CountedBrowserAccessibilityFactory()));
+ ASSERT_EQ(7, CountedBrowserAccessibility::num_instances());
BrowserAccessibilityWin* root_obj =
manager->GetRoot()->ToBrowserAccessibilityWin();
- BrowserAccessibilityWin* text1_obj =
+ ASSERT_NE(nullptr, root_obj);
+ ASSERT_EQ(1, root_obj->PlatformChildCount());
+
+ BrowserAccessibilityWin* text_field_obj =
root_obj->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+ ASSERT_NE(nullptr, text_field_obj);
- long text1_len;
- ASSERT_EQ(S_OK, text1_obj->get_nCharacters(&text1_len));
+ long text_len;
+ EXPECT_EQ(S_OK, text_field_obj->get_nCharacters(&text_len));
base::win::ScopedBstr text;
- ASSERT_EQ(S_OK, text1_obj->get_text(0, text1_len, text.Receive()));
- ASSERT_EQ(text1_value, base::UTF16ToUTF8(base::string16(text)));
+ EXPECT_EQ(S_OK, text_field_obj->get_text(0, text_len, text.Receive()));
+ EXPECT_EQ(text_value, base::UTF16ToUTF8(base::string16(text)));
text.Reset();
- ASSERT_EQ(S_OK, text1_obj->get_text(0, 4, text.Receive()));
- ASSERT_STREQ(L"One ", text);
+ EXPECT_EQ(S_OK, text_field_obj->get_text(0, 4, text.Receive()));
+ EXPECT_STREQ(L"One ", text);
text.Reset();
long start;
long end;
- ASSERT_EQ(S_OK, text1_obj->get_textAtOffset(
+ EXPECT_EQ(S_OK, text_field_obj->get_textAtOffset(
1, IA2_TEXT_BOUNDARY_CHAR, &start, &end, text.Receive()));
- ASSERT_EQ(1, start);
- ASSERT_EQ(2, end);
- ASSERT_STREQ(L"n", text);
+ EXPECT_EQ(1, start);
+ EXPECT_EQ(2, end);
+ EXPECT_STREQ(L"n", text);
+ text.Reset();
+
+ EXPECT_EQ(S_FALSE, text_field_obj->get_textAtOffset(
+ text_len, IA2_TEXT_BOUNDARY_CHAR, &start, &end, text.Receive()));
+ EXPECT_EQ(0, start);
+ EXPECT_EQ(0, end);
+ EXPECT_EQ(nullptr, text);
text.Reset();
- ASSERT_EQ(S_FALSE, text1_obj->get_textAtOffset(
- text1_len, IA2_TEXT_BOUNDARY_CHAR, &start, &end, text.Receive()));
- ASSERT_EQ(0, start);
- ASSERT_EQ(0, end);
+ EXPECT_EQ(S_FALSE, text_field_obj->get_textAtOffset(
+ text_len, IA2_TEXT_BOUNDARY_WORD, &start, &end, text.Receive()));
+ EXPECT_EQ(0, start);
+ EXPECT_EQ(0, end);
+ EXPECT_EQ(nullptr, text);
text.Reset();
- ASSERT_EQ(S_OK, text1_obj->get_textAtOffset(
+ EXPECT_EQ(S_OK, text_field_obj->get_textAtOffset(
1, IA2_TEXT_BOUNDARY_WORD, &start, &end, text.Receive()));
- ASSERT_EQ(0, start);
- ASSERT_EQ(4, end);
- ASSERT_STREQ(L"One ", text);
+ EXPECT_EQ(0, start);
+ EXPECT_EQ(4, end);
+ EXPECT_STREQ(L"One ", text);
text.Reset();
- ASSERT_EQ(S_OK, text1_obj->get_textAtOffset(
+ EXPECT_EQ(S_OK, text_field_obj->get_textAtOffset(
6, IA2_TEXT_BOUNDARY_WORD, &start, &end, text.Receive()));
- ASSERT_EQ(4, start);
- ASSERT_EQ(8, end);
- ASSERT_STREQ(L"two\n", text);
+ EXPECT_EQ(4, start);
+ EXPECT_EQ(8, end);
+ EXPECT_STREQ(L"two ", text);
text.Reset();
- ASSERT_EQ(S_OK, text1_obj->get_textAtOffset(
- text1_len, IA2_TEXT_BOUNDARY_WORD, &start, &end, text.Receive()));
- ASSERT_EQ(25, start);
- ASSERT_EQ(29, end);
- ASSERT_STREQ(L"six.", text);
+ EXPECT_EQ(S_OK, text_field_obj->get_textAtOffset(
+ text_len - 1, IA2_TEXT_BOUNDARY_WORD, &start, &end, text.Receive()));
+ EXPECT_EQ(25, start);
+ EXPECT_EQ(29, end);
+ EXPECT_STREQ(L"six.", text);
text.Reset();
- ASSERT_EQ(S_OK, text1_obj->get_textAtOffset(
+ EXPECT_EQ(S_OK, text_field_obj->get_textAtOffset(
1, IA2_TEXT_BOUNDARY_LINE, &start, &end, text.Receive()));
- ASSERT_EQ(0, start);
- ASSERT_EQ(15, end);
- ASSERT_STREQ(L"One two three.\n", text);
+ EXPECT_EQ(0, start);
+ EXPECT_EQ(15, end);
+ EXPECT_STREQ(L"One two three.\n", text);
text.Reset();
- ASSERT_EQ(S_OK, text1_obj->get_textAtOffset(
- text1_len, IA2_TEXT_BOUNDARY_LINE, &start, &end, text.Receive()));
- ASSERT_EQ(15, start);
- ASSERT_EQ(text1_len, end);
- ASSERT_STREQ(L"Four five six.", text);
+ EXPECT_EQ(S_OK, text_field_obj->get_textAtOffset(
+ text_len, IA2_TEXT_BOUNDARY_LINE, &start, &end, text.Receive()));
+ EXPECT_EQ(15, start);
+ EXPECT_EQ(text_len, end);
+ EXPECT_STREQ(L"Four five six.", text);
text.Reset();
- ASSERT_EQ(S_OK,
- text1_obj->get_text(0, IA2_TEXT_OFFSET_LENGTH, text.Receive()));
- ASSERT_EQ(0, start);
- ASSERT_EQ(text1_len, end);
- ASSERT_STREQ(L"One two three.\nFour five six.", text);
+ EXPECT_EQ(S_OK, text_field_obj->get_text(
+ 0, IA2_TEXT_OFFSET_LENGTH, text.Receive()));
+ EXPECT_EQ(text_value, base::UTF16ToUTF8(base::string16(text)));
// Delete the manager and test that all BrowserAccessibility instances are
// deleted.
diff --git a/ui/accessibility/ax_text_utils.cc b/ui/accessibility/ax_text_utils.cc
index cac5aee..da336b6 100644
--- a/ui/accessibility/ax_text_utils.cc
+++ b/ui/accessibility/ax_text_utils.cc
@@ -9,13 +9,16 @@
namespace ui {
+// line_breaks is a Misnomer. Blink provides the start offsets of each line
+// not the line breaks.
+// TODO(nektar): Rename line_breaks a11y attribute and variable references.
size_t FindAccessibleTextBoundary(const base::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);
+ DCHECK_LE(start_offset, text_size);
if (boundary == CHAR_BOUNDARY) {
if (direction == FORWARDS_DIRECTION && start_offset < text_size)
@@ -33,7 +36,7 @@ size_t FindAccessibleTextBoundary(const base::string16& text,
} else {
for (size_t j = line_breaks.size(); j != 0; --j) {
size_t line_break = line_breaks[j - 1] >= 0 ? line_breaks[j - 1] : 0;
- if (line_break < start_offset)
+ if (line_break <= start_offset)
return line_break;
}
return 0;
diff --git a/ui/accessibility/ax_text_utils_unittest.cc b/ui/accessibility/ax_text_utils_unittest.cc
index 7163ef84..806401b 100644
--- a/ui/accessibility/ax_text_utils_unittest.cc
+++ b/ui/accessibility/ax_text_utils_unittest.cc
@@ -9,54 +9,60 @@
namespace ui {
TEST(AXTextUtils, FindAccessibleTextBoundaryLine) {
- const base::string16 text = base::UTF8ToUTF16("Line 1.\nLine 2\n");
+ const base::string16 text = base::UTF8ToUTF16("Line 1.\nLine 2\n\t");
const size_t text_length = text.length();
- std::vector<int> line_breaks;
- line_breaks.push_back(7);
- line_breaks.push_back(14);
+ std::vector<int> line_start_offsets;
+ line_start_offsets.push_back(8);
+ line_start_offsets.push_back(15);
size_t result;
// Basic cases.
- result = FindAccessibleTextBoundary(text, line_breaks, LINE_BOUNDARY, 5,
- FORWARDS_DIRECTION);
- EXPECT_EQ(7UL, result);
- result = FindAccessibleTextBoundary(text, line_breaks, LINE_BOUNDARY, 9,
- BACKWARDS_DIRECTION);
- EXPECT_EQ(7UL, result);
- result = FindAccessibleTextBoundary(text, line_breaks, LINE_BOUNDARY, 10,
- FORWARDS_DIRECTION);
- EXPECT_EQ(14UL, result);
+ result = FindAccessibleTextBoundary(text, line_start_offsets, LINE_BOUNDARY,
+ 5, FORWARDS_DIRECTION);
+ EXPECT_EQ(8UL, result);
+ result = FindAccessibleTextBoundary(text, line_start_offsets, LINE_BOUNDARY,
+ 9, BACKWARDS_DIRECTION);
+ EXPECT_EQ(8UL, result);
+ result = FindAccessibleTextBoundary(text, line_start_offsets, LINE_BOUNDARY,
+ 10, FORWARDS_DIRECTION);
+ EXPECT_EQ(15UL, result);
// Edge cases.
- result = FindAccessibleTextBoundary(text, line_breaks, LINE_BOUNDARY,
+ result = FindAccessibleTextBoundary(text, line_start_offsets, LINE_BOUNDARY,
text_length, BACKWARDS_DIRECTION);
- EXPECT_EQ(14UL, result);
+ EXPECT_EQ(15UL, result);
- // When the start_offset is on a line break and we are searching backwards,
- // it should return the previous line break.
- result = FindAccessibleTextBoundary(text, line_breaks, LINE_BOUNDARY, 14,
- BACKWARDS_DIRECTION);
- EXPECT_EQ(7UL, result);
+ // When the start_offset is at the start of the next line and we are searching
+ // backwards, it should not move.
+ result = FindAccessibleTextBoundary(text, line_start_offsets, LINE_BOUNDARY,
+ 15, BACKWARDS_DIRECTION);
+ EXPECT_EQ(15UL, result);
- // When the start_offset is on a line break and we are searching forwards,
- // it should return the next line break.
- result = FindAccessibleTextBoundary(text, line_breaks, LINE_BOUNDARY, 7,
- FORWARDS_DIRECTION);
- EXPECT_EQ(14UL, result);
+ // When the start_offset is at a hard line break and we are searching
+ // backwards, it should return the start of the previous line.
+ result = FindAccessibleTextBoundary(text, line_start_offsets, LINE_BOUNDARY,
+ 14, BACKWARDS_DIRECTION);
+ EXPECT_EQ(8UL, result);
+
+ // When the start_offset is at the start of a line and we are searching
+ // forwards, it should return the start of the next line.
+ result = FindAccessibleTextBoundary(text, line_start_offsets, LINE_BOUNDARY,
+ 8, FORWARDS_DIRECTION);
+ EXPECT_EQ(15UL, result);
// When there is no previous line break and we are searching backwards,
// it should return 0.
- result = FindAccessibleTextBoundary(text, line_breaks, LINE_BOUNDARY, 4,
- BACKWARDS_DIRECTION);
+ result = FindAccessibleTextBoundary(text, line_start_offsets, LINE_BOUNDARY,
+ 4, BACKWARDS_DIRECTION);
EXPECT_EQ(0UL, result);
- // When we are on the last line break and we are searching forwards.
+ // When we are at the start of the last line and we are searching forwards.
// it should return the text length.
- result = FindAccessibleTextBoundary(text, line_breaks, LINE_BOUNDARY, 14,
- FORWARDS_DIRECTION);
+ result = FindAccessibleTextBoundary(text, line_start_offsets, LINE_BOUNDARY,
+ 15, FORWARDS_DIRECTION);
EXPECT_EQ(text_length, result);
}