Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(510)

Side by Side Diff: ui/gfx/render_text_unittest.cc

Issue 2639493002: MacViews: Enable word lookup for selectable views::Labels and multi-line text. (Closed)
Patch Set: Nit. Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/gfx/render_text_harfbuzz.cc ('k') | ui/views/controls/label.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/gfx/render_text.h" 5 #include "ui/gfx/render_text.h"
6 6
7 #include <limits.h> 7 #include <limits.h>
8 #include <stddef.h> 8 #include <stddef.h>
9 #include <stdint.h> 9 #include <stdint.h>
10 10
(...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after
466 return static_cast<RenderTextHarfBuzz*>(GetRenderText()); 466 return static_cast<RenderTextHarfBuzz*>(GetRenderText());
467 } 467 }
468 468
469 #if defined(OS_MACOSX) 469 #if defined(OS_MACOSX)
470 RenderTextMac* GetRenderTextMac() { 470 RenderTextMac* GetRenderTextMac() {
471 DCHECK_EQ(RENDER_TEXT_MAC, GetParam()); 471 DCHECK_EQ(RENDER_TEXT_MAC, GetParam());
472 return static_cast<RenderTextMac*>(GetRenderText()); 472 return static_cast<RenderTextMac*>(GetRenderText());
473 } 473 }
474 #endif 474 #endif
475 475
476 Rect GetSelectionBoundsUnion() { 476 Rect GetSubstringBoundsUnionForRange(const Range& range) {
477 const std::vector<Rect> bounds = 477 const std::vector<Rect> bounds =
478 render_text_->GetSubstringBoundsForTesting(render_text_->selection()); 478 render_text_->GetSubstringBoundsForTesting(range);
479 return std::accumulate(bounds.begin(), bounds.end(), Rect(), UnionRects); 479 return std::accumulate(bounds.begin(), bounds.end(), Rect(), UnionRects);
480 } 480 }
tapted 2017/01/20 06:24:50 Can we keep an overload? i.e. Rect GetSelectionBo
karandeepb 2017/01/20 07:29:10 Done.
481 481
482 Canvas* canvas() { return &canvas_; } 482 Canvas* canvas() { return &canvas_; }
483 TestSkiaTextRenderer* renderer() { return &renderer_; } 483 TestSkiaTextRenderer* renderer() { return &renderer_; }
484 test::RenderTextTestApi* test_api() { return test_api_.get(); }; 484 test::RenderTextTestApi* test_api() { return test_api_.get(); };
485 485
486 private: 486 private:
487 std::unique_ptr<RenderText> render_text_; 487 std::unique_ptr<RenderText> render_text_;
488 std::unique_ptr<test::RenderTextTestApi> test_api_; 488 std::unique_ptr<test::RenderTextTestApi> test_api_;
489 Canvas canvas_; 489 Canvas canvas_;
490 TestSkiaTextRenderer renderer_; 490 TestSkiaTextRenderer renderer_;
(...skipping 1174 matching lines...) Expand 10 before | Expand all | Expand 10 after
1665 TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRight_MeiryoUILigatures) { 1665 TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRight_MeiryoUILigatures) {
1666 RenderText* render_text = GetRenderText(); 1666 RenderText* render_text = GetRenderText();
1667 // Meiryo UI uses single-glyph ligatures for 'ff' and 'ffi', but each letter 1667 // Meiryo UI uses single-glyph ligatures for 'ff' and 'ffi', but each letter
1668 // (code point) has unique bounds, so mid-glyph cursoring should be possible. 1668 // (code point) has unique bounds, so mid-glyph cursoring should be possible.
1669 render_text->SetFontList(FontList("Meiryo UI, 12px")); 1669 render_text->SetFontList(FontList("Meiryo UI, 12px"));
1670 render_text->SetText(WideToUTF16(L"ff ffi")); 1670 render_text->SetText(WideToUTF16(L"ff ffi"));
1671 render_text->SetDisplayRect(gfx::Rect(100, 100)); 1671 render_text->SetDisplayRect(gfx::Rect(100, 100));
1672 test_api()->EnsureLayout(); 1672 test_api()->EnsureLayout();
1673 EXPECT_EQ(0U, render_text->cursor_position()); 1673 EXPECT_EQ(0U, render_text->cursor_position());
1674 1674
1675 gfx::Rect last_selection_bounds = GetSelectionBoundsUnion(); 1675 gfx::Rect last_selection_bounds =
1676 GetSubstringBoundsUnionForRange(render_text->selection());
1676 for (size_t i = 0; i < render_text->text().length(); ++i) { 1677 for (size_t i = 0; i < render_text->text().length(); ++i) {
1677 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, SELECTION_RETAIN); 1678 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, SELECTION_RETAIN);
1678 EXPECT_EQ(i + 1, render_text->cursor_position()); 1679 EXPECT_EQ(i + 1, render_text->cursor_position());
1679 1680
1680 // Verify the selection bounds also increase and that the correct bounds are 1681 // Verify the selection bounds also increase and that the correct bounds are
1681 // returned even when the grapheme boundary lies within a glyph. 1682 // returned even when the grapheme boundary lies within a glyph.
1682 const gfx::Rect selection_bounds = GetSelectionBoundsUnion(); 1683 const gfx::Rect selection_bounds =
1684 GetSubstringBoundsUnionForRange(render_text->selection());
1683 EXPECT_GT(selection_bounds.right(), last_selection_bounds.right()); 1685 EXPECT_GT(selection_bounds.right(), last_selection_bounds.right());
1684 EXPECT_EQ(selection_bounds.x(), last_selection_bounds.x()); 1686 EXPECT_EQ(selection_bounds.x(), last_selection_bounds.x());
1685 last_selection_bounds = selection_bounds; 1687 last_selection_bounds = selection_bounds;
1686 } 1688 }
1687 EXPECT_EQ(6U, render_text->cursor_position()); 1689 EXPECT_EQ(6U, render_text->cursor_position());
1688 } 1690 }
1689 #endif // !defined(OS_MACOSX) 1691 #endif // !defined(OS_MACOSX)
1690 1692
1691 // TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618 1693 // TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
1692 TEST_P(RenderTextHarfBuzzTest, GraphemePositions) { 1694 TEST_P(RenderTextHarfBuzzTest, GraphemePositions) {
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
1786 render_text->SetText(cases[i]); 1788 render_text->SetText(cases[i]);
1787 EXPECT_TRUE(render_text->IsValidLogicalIndex(1)); 1789 EXPECT_TRUE(render_text->IsValidLogicalIndex(1));
1788 EXPECT_FALSE(render_text->IsValidCursorIndex(1)); 1790 EXPECT_FALSE(render_text->IsValidCursorIndex(1));
1789 EXPECT_TRUE(render_text->SelectRange(Range(2, 1))); 1791 EXPECT_TRUE(render_text->SelectRange(Range(2, 1)));
1790 EXPECT_EQ(Range(2, 1), render_text->selection()); 1792 EXPECT_EQ(Range(2, 1), render_text->selection());
1791 EXPECT_EQ(1U, render_text->cursor_position()); 1793 EXPECT_EQ(1U, render_text->cursor_position());
1792 1794
1793 // Verify that the selection bounds extend over the entire grapheme, even if 1795 // Verify that the selection bounds extend over the entire grapheme, even if
1794 // the selection is set amid the grapheme. 1796 // the selection is set amid the grapheme.
1795 test_api()->EnsureLayout(); 1797 test_api()->EnsureLayout();
1796 const gfx::Rect mid_grapheme_bounds = GetSelectionBoundsUnion(); 1798 const gfx::Rect mid_grapheme_bounds =
1799 GetSubstringBoundsUnionForRange(render_text->selection());
1797 render_text->SelectAll(false); 1800 render_text->SelectAll(false);
1798 EXPECT_EQ(GetSelectionBoundsUnion(), mid_grapheme_bounds); 1801 EXPECT_EQ(GetSubstringBoundsUnionForRange(render_text->selection()),
1802 mid_grapheme_bounds);
1799 1803
1800 // Although selection bounds may be set within a multi-character grapheme, 1804 // Although selection bounds may be set within a multi-character grapheme,
1801 // cursor movement (e.g. via arrow key) should avoid those indices. 1805 // cursor movement (e.g. via arrow key) should avoid those indices.
1802 EXPECT_TRUE(render_text->SelectRange(Range(2, 1))); 1806 EXPECT_TRUE(render_text->SelectRange(Range(2, 1)));
1803 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, SELECTION_NONE); 1807 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, SELECTION_NONE);
1804 EXPECT_EQ(0U, render_text->cursor_position()); 1808 EXPECT_EQ(0U, render_text->cursor_position());
1805 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, SELECTION_NONE); 1809 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, SELECTION_NONE);
1806 EXPECT_EQ(2U, render_text->cursor_position()); 1810 EXPECT_EQ(2U, render_text->cursor_position());
1807 } 1811 }
1808 } 1812 }
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
1842 EXPECT_EQ(2u, test_api()->lines().size()); 1846 EXPECT_EQ(2u, test_api()->lines().size());
1843 1847
1844 const bool is_ltr = 1848 const bool is_ltr =
1845 render_text->GetDisplayTextDirection() == base::i18n::LEFT_TO_RIGHT; 1849 render_text->GetDisplayTextDirection() == base::i18n::LEFT_TO_RIGHT;
1846 for (size_t j = 0; j < render_text->text().length(); ++j) { 1850 for (size_t j = 0; j < render_text->text().length(); ++j) {
1847 SCOPED_TRACE(base::StringPrintf( 1851 SCOPED_TRACE(base::StringPrintf(
1848 "Testing index %" PRIuS " for case %" PRIuS "", j, i)); 1852 "Testing index %" PRIuS " for case %" PRIuS "", j, i));
1849 render_text->SelectRange(Range(j, j + 1)); 1853 render_text->SelectRange(Range(j, j + 1));
1850 1854
1851 // Test a point inside the leading edge of the glyph bounds. 1855 // Test a point inside the leading edge of the glyph bounds.
1852 const Rect bounds = GetSelectionBoundsUnion(); 1856 const Rect bounds =
1857 GetSubstringBoundsUnionForRange(render_text->selection());
1853 const Point cursor_position(is_ltr ? bounds.x() + 1 : bounds.right() - 1, 1858 const Point cursor_position(is_ltr ? bounds.x() + 1 : bounds.right() - 1,
1854 bounds.y() + 1); 1859 bounds.y() + 1);
1855 1860
1856 const SelectionModel model = 1861 const SelectionModel model =
1857 render_text->FindCursorPosition(cursor_position); 1862 render_text->FindCursorPosition(cursor_position);
1858 EXPECT_EQ(j, model.caret_pos()); 1863 EXPECT_EQ(j, model.caret_pos());
1859 EXPECT_EQ(CURSOR_FORWARD, model.caret_affinity()); 1864 EXPECT_EQ(CURSOR_FORWARD, model.caret_affinity());
1860 } 1865 }
1861 } 1866 }
1862 } 1867 }
(...skipping 2290 matching lines...) Expand 10 before | Expand all | Expand 10 after
4153 if (i < kWordTwoStartIndex) { 4158 if (i < kWordTwoStartIndex) {
4154 VerifyDecoratedWordsAreEqual(expected_word_1, decorated_word); 4159 VerifyDecoratedWordsAreEqual(expected_word_1, decorated_word);
4155 EXPECT_TRUE(left_glyph_word_1.Contains(baseline_point)); 4160 EXPECT_TRUE(left_glyph_word_1.Contains(baseline_point));
4156 } else { 4161 } else {
4157 VerifyDecoratedWordsAreEqual(expected_word_2, decorated_word); 4162 VerifyDecoratedWordsAreEqual(expected_word_2, decorated_word);
4158 EXPECT_TRUE(left_glyph_word_2.Contains(baseline_point)); 4163 EXPECT_TRUE(left_glyph_word_2.Contains(baseline_point));
4159 } 4164 }
4160 } 4165 }
4161 } 4166 }
4162 4167
4168 // Test that GetDecoratedWordAtPoint behaves correctly for multiline text.
4169 TEST_P(RenderTextHarfBuzzTest, GetDecoratedWordAtPoint_Multiline) {
4170 const base::string16 text = ASCIIToUTF16("a b\n..\nc.");
4171 const size_t kWordOneIndex = 0; // Index of character 'a'.
4172 const size_t kWordTwoIndex = 2; // Index of character 'b'.
4173 const size_t kWordThreeIndex = 7; // Index of character 'c'.
4174
4175 // Set up render text.
4176 RenderText* render_text = GetRenderText();
4177 render_text->SetMultiline(true);
4178 render_text->SetDisplayRect(Rect(500, 500));
4179 render_text->SetText(text);
4180 render_text->ApplyWeight(Font::Weight::SEMIBOLD, Range(0, 3));
4181 render_text->ApplyStyle(UNDERLINE, true, Range(1, 7));
4182 render_text->ApplyStyle(STRIKE, true, Range(1, 8));
4183 render_text->ApplyStyle(ITALIC, true, Range(5, 8));
4184
4185 // Set up test expectations.
4186 const std::vector<RenderText::FontSpan> font_spans =
4187 render_text->GetFontSpansForTesting();
4188
4189 DecoratedText expected_word_1;
4190 expected_word_1.text = ASCIIToUTF16("a");
4191 expected_word_1.attributes.push_back(CreateRangedAttribute(
4192 font_spans, 0, kWordOneIndex, Font::Weight::SEMIBOLD, 0));
4193 const Rect left_glyph_word_1 =
4194 GetSubstringBoundsUnionForRange(Range(kWordOneIndex, kWordOneIndex + 1));
4195
4196 DecoratedText expected_word_2;
4197 expected_word_2.text = ASCIIToUTF16("b");
4198 expected_word_2.attributes.push_back(CreateRangedAttribute(
4199 font_spans, 0, kWordTwoIndex, Font::Weight::SEMIBOLD,
4200 UNDERLINE_MASK | STRIKE_MASK));
4201 const Rect left_glyph_word_2 =
4202 GetSubstringBoundsUnionForRange(Range(kWordTwoIndex, kWordTwoIndex + 1));
4203
4204 DecoratedText expected_word_3;
4205 expected_word_3.text = ASCIIToUTF16("c");
4206 expected_word_3.attributes.push_back(
4207 CreateRangedAttribute(font_spans, 0, kWordThreeIndex,
4208 Font::Weight::NORMAL, STRIKE_MASK | ITALIC_MASK));
4209 const Rect left_glyph_word_3 = GetSubstringBoundsUnionForRange(
4210 Range(kWordThreeIndex, kWordThreeIndex + 1));
4211
4212 DecoratedText decorated_word;
4213 Point baseline_point;
4214 {
4215 SCOPED_TRACE(base::StringPrintf("Query to the left of first line."));
tapted 2017/01/20 06:24:50 This can just be a comment I think -- SCOPED_TRACE
karandeepb 2017/01/20 07:29:10 Done.
4216 EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(
4217 Point(-5, GetCursorYForTesting(0)), &decorated_word, &baseline_point));
4218 VerifyDecoratedWordsAreEqual(expected_word_1, decorated_word);
4219 EXPECT_TRUE(left_glyph_word_1.Contains(baseline_point));
4220 }
4221 {
4222 SCOPED_TRACE(base::StringPrintf("Query on the second line"));
4223 EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(
4224 Point(5, GetCursorYForTesting(1)), &decorated_word, &baseline_point));
4225 VerifyDecoratedWordsAreEqual(expected_word_2, decorated_word);
4226 EXPECT_TRUE(left_glyph_word_2.Contains(baseline_point));
4227 }
4228 {
4229 SCOPED_TRACE(base::StringPrintf("Query on the third line"));
4230
4231 // Query at the center point of the character 'c'.
4232 EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(
4233 left_glyph_word_3.CenterPoint(), &decorated_word, &baseline_point));
4234 VerifyDecoratedWordsAreEqual(expected_word_3, decorated_word);
4235 EXPECT_TRUE(left_glyph_word_3.Contains(baseline_point));
4236 }
4237 {
4238 SCOPED_TRACE(base::StringPrintf("Query to the right of the third line"));
4239 EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(
4240 Point(505, GetCursorYForTesting(2)), &decorated_word, &baseline_point));
4241 VerifyDecoratedWordsAreEqual(expected_word_3, decorated_word);
4242 EXPECT_TRUE(left_glyph_word_3.Contains(baseline_point));
4243 }
4244 }
4245
4163 // Verify the boolean return value of GetDecoratedWordAtPoint. 4246 // Verify the boolean return value of GetDecoratedWordAtPoint.
4164 TEST_P(RenderTextHarfBuzzTest, GetDecoratedWordAtPoint_Return) { 4247 TEST_P(RenderTextHarfBuzzTest, GetDecoratedWordAtPoint_Return) {
4165 RenderText* render_text = GetRenderText(); 4248 RenderText* render_text = GetRenderText();
4166 render_text->SetText(ASCIIToUTF16("...")); 4249 render_text->SetText(ASCIIToUTF16("..."));
4167 4250
4168 DecoratedText decorated_word; 4251 DecoratedText decorated_word;
4169 Point baseline_point; 4252 Point baseline_point;
4170 4253
4171 // False should be returned, when the text does not contain any word. 4254 // False should be returned, when the text does not contain any word.
4172 Point query = 4255 Point query =
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
4250 for (size_t i = 0; i < test_api()->lines().size(); i++) { 4333 for (size_t i = 0; i < test_api()->lines().size(); i++) {
4251 SCOPED_TRACE(base::StringPrintf("Testing bounds for line %" PRIuS "", i)); 4334 SCOPED_TRACE(base::StringPrintf("Testing bounds for line %" PRIuS "", i));
4252 const internal::Line& line = test_api()->lines()[i]; 4335 const internal::Line& line = test_api()->lines()[i];
4253 const Size line_size(std::ceil(line.size.width()), 4336 const Size line_size(std::ceil(line.size.width()),
4254 std::ceil(line.size.height())); 4337 std::ceil(line.size.height()));
4255 const Rect expected_line_bounds = 4338 const Rect expected_line_bounds =
4256 render_text->GetLineOffset(i) + Rect(line_size); 4339 render_text->GetLineOffset(i) + Rect(line_size);
4257 expected_total_bounds.Union(expected_line_bounds); 4340 expected_total_bounds.Union(expected_line_bounds);
4258 4341
4259 render_text->SelectRange(line_char_range[i]); 4342 render_text->SelectRange(line_char_range[i]);
4260 EXPECT_EQ(expected_line_bounds, GetSelectionBoundsUnion()); 4343 EXPECT_EQ(expected_line_bounds,
4344 GetSubstringBoundsUnionForRange(render_text->selection()));
4261 } 4345 }
4262 4346
4263 // Test complete bounds. 4347 // Test complete bounds.
4264 render_text->SelectAll(false); 4348 render_text->SelectAll(false);
4265 EXPECT_EQ(expected_total_bounds, GetSelectionBoundsUnion()); 4349 EXPECT_EQ(expected_total_bounds,
4350 GetSubstringBoundsUnionForRange(render_text->selection()));
4266 } 4351 }
4267 4352
4268 // Prefix for test instantiations intentionally left blank since each test 4353 // Prefix for test instantiations intentionally left blank since each test
4269 // fixture class has a single parameterization. 4354 // fixture class has a single parameterization.
4270 #if defined(OS_MACOSX) 4355 #if defined(OS_MACOSX)
4271 INSTANTIATE_TEST_CASE_P(, 4356 INSTANTIATE_TEST_CASE_P(,
4272 RenderTextTest, 4357 RenderTextTest,
4273 ::testing::Values(RENDER_TEXT_HARFBUZZ, 4358 ::testing::Values(RENDER_TEXT_HARFBUZZ,
4274 RENDER_TEXT_MAC), 4359 RENDER_TEXT_MAC),
4275 PrintRenderTextBackend()); 4360 PrintRenderTextBackend());
4276 INSTANTIATE_TEST_CASE_P(, 4361 INSTANTIATE_TEST_CASE_P(,
4277 RenderTextMacTest, 4362 RenderTextMacTest,
4278 ::testing::Values(RENDER_TEXT_MAC), 4363 ::testing::Values(RENDER_TEXT_MAC),
4279 PrintRenderTextBackend()); 4364 PrintRenderTextBackend());
4280 #else 4365 #else
4281 INSTANTIATE_TEST_CASE_P(, 4366 INSTANTIATE_TEST_CASE_P(,
4282 RenderTextTest, 4367 RenderTextTest,
4283 ::testing::Values(RENDER_TEXT_HARFBUZZ), 4368 ::testing::Values(RENDER_TEXT_HARFBUZZ),
4284 PrintRenderTextBackend()); 4369 PrintRenderTextBackend());
4285 #endif 4370 #endif
4286 4371
4287 INSTANTIATE_TEST_CASE_P(, 4372 INSTANTIATE_TEST_CASE_P(,
4288 RenderTextHarfBuzzTest, 4373 RenderTextHarfBuzzTest,
4289 ::testing::Values(RENDER_TEXT_HARFBUZZ), 4374 ::testing::Values(RENDER_TEXT_HARFBUZZ),
4290 PrintRenderTextBackend()); 4375 PrintRenderTextBackend());
4291 4376
4292 } // namespace gfx 4377 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/render_text_harfbuzz.cc ('k') | ui/views/controls/label.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698