diff options
author | nektar <nektar@chromium.org> | 2015-04-29 17:31:14 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-04-30 00:31:43 +0000 |
commit | 28f5f6444f311879cff2e7688011a54bf40a463b (patch) | |
tree | 37f8fc30bf4d3bc955f28fff42f94d76b533bf36 | |
parent | ea8c00ec4ea9fc6df348f0cb2b3a2b0f3ed2802e (diff) | |
download | chromium_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}
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); } |