Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 |
| 11 #include <algorithm> | 11 #include <algorithm> |
| 12 #include <memory> | 12 #include <memory> |
| 13 #include <numeric> | |
| 13 | 14 |
| 14 #include "base/format_macros.h" | 15 #include "base/format_macros.h" |
| 15 #include "base/i18n/break_iterator.h" | 16 #include "base/i18n/break_iterator.h" |
| 16 #include "base/macros.h" | 17 #include "base/macros.h" |
| 17 #include "base/memory/ptr_util.h" | 18 #include "base/memory/ptr_util.h" |
| 18 #include "base/run_loop.h" | 19 #include "base/run_loop.h" |
| 19 #include "base/strings/string_split.h" | 20 #include "base/strings/string_split.h" |
| 20 #include "base/strings/string_util.h" | 21 #include "base/strings/string_util.h" |
| 21 #include "base/strings/stringprintf.h" | 22 #include "base/strings/stringprintf.h" |
| 22 #include "base/strings/utf_string_conversions.h" | 23 #include "base/strings/utf_string_conversions.h" |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 107 size_t DisplayIndexToTextIndex(size_t index) { | 108 size_t DisplayIndexToTextIndex(size_t index) { |
| 108 return render_text_->DisplayIndexToTextIndex(index); | 109 return render_text_->DisplayIndexToTextIndex(index); |
| 109 } | 110 } |
| 110 | 111 |
| 111 void EnsureLayout() { render_text_->EnsureLayout(); } | 112 void EnsureLayout() { render_text_->EnsureLayout(); } |
| 112 | 113 |
| 113 Vector2d GetAlignmentOffset(size_t line_number) { | 114 Vector2d GetAlignmentOffset(size_t line_number) { |
| 114 return render_text_->GetAlignmentOffset(line_number); | 115 return render_text_->GetAlignmentOffset(line_number); |
| 115 } | 116 } |
| 116 | 117 |
| 118 std::vector<Rect> GetSubstringBounds(const Range& range) { | |
| 119 return render_text_->GetSubstringBounds(range); | |
| 120 } | |
| 121 | |
| 117 private: | 122 private: |
| 118 RenderText* render_text_; | 123 RenderText* render_text_; |
| 119 | 124 |
| 120 DISALLOW_COPY_AND_ASSIGN(RenderTextTestApi); | 125 DISALLOW_COPY_AND_ASSIGN(RenderTextTestApi); |
| 121 }; | 126 }; |
| 122 | 127 |
| 123 } // namespace test | 128 } // namespace test |
| 124 | 129 |
| 125 namespace { | 130 namespace { |
| 126 | 131 |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 465 return static_cast<RenderTextHarfBuzz*>(GetRenderText()); | 470 return static_cast<RenderTextHarfBuzz*>(GetRenderText()); |
| 466 } | 471 } |
| 467 | 472 |
| 468 #if defined(OS_MACOSX) | 473 #if defined(OS_MACOSX) |
| 469 RenderTextMac* GetRenderTextMac() { | 474 RenderTextMac* GetRenderTextMac() { |
| 470 DCHECK_EQ(RENDER_TEXT_MAC, GetParam()); | 475 DCHECK_EQ(RENDER_TEXT_MAC, GetParam()); |
| 471 return static_cast<RenderTextMac*>(GetRenderText()); | 476 return static_cast<RenderTextMac*>(GetRenderText()); |
| 472 } | 477 } |
| 473 #endif | 478 #endif |
| 474 | 479 |
| 480 Rect GetSelectionBoundsUnion() { | |
| 481 const std::vector<Rect> bounds = | |
| 482 test_api_->GetSubstringBounds(render_text_->selection()); | |
| 483 return std::accumulate(bounds.begin(), bounds.end(), Rect(), UnionRects); | |
| 484 } | |
| 485 | |
| 475 Canvas* canvas() { return &canvas_; } | 486 Canvas* canvas() { return &canvas_; } |
| 476 TestSkiaTextRenderer* renderer() { return &renderer_; } | 487 TestSkiaTextRenderer* renderer() { return &renderer_; } |
| 477 test::RenderTextTestApi* test_api() { return test_api_.get(); }; | 488 test::RenderTextTestApi* test_api() { return test_api_.get(); }; |
| 478 | 489 |
| 479 private: | 490 private: |
| 480 std::unique_ptr<RenderText> render_text_; | 491 std::unique_ptr<RenderText> render_text_; |
| 481 std::unique_ptr<test::RenderTextTestApi> test_api_; | 492 std::unique_ptr<test::RenderTextTestApi> test_api_; |
| 482 Canvas canvas_; | 493 Canvas canvas_; |
| 483 TestSkiaTextRenderer renderer_; | 494 TestSkiaTextRenderer renderer_; |
| 484 | 495 |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 507 GetRenderTextHarfBuzz()->set_glyph_width_for_test(test_width); | 518 GetRenderTextHarfBuzz()->set_glyph_width_for_test(test_width); |
| 508 } | 519 } |
| 509 | 520 |
| 510 bool ShapeRunWithFont(const base::string16& text, | 521 bool ShapeRunWithFont(const base::string16& text, |
| 511 const Font& font, | 522 const Font& font, |
| 512 const FontRenderParams& params, | 523 const FontRenderParams& params, |
| 513 internal::TextRunHarfBuzz* run) { | 524 internal::TextRunHarfBuzz* run) { |
| 514 return GetRenderTextHarfBuzz()->ShapeRunWithFont(text, font, params, run); | 525 return GetRenderTextHarfBuzz()->ShapeRunWithFont(text, font, params, run); |
| 515 } | 526 } |
| 516 | 527 |
| 528 int GetCursorYForTesting(int line_num = 0) { | |
| 529 return GetRenderText()->GetLineOffset(line_num).y() + 1; | |
| 530 } | |
| 531 | |
| 517 private: | 532 private: |
| 518 DISALLOW_COPY_AND_ASSIGN(RenderTextHarfBuzzTest); | 533 DISALLOW_COPY_AND_ASSIGN(RenderTextHarfBuzzTest); |
| 519 }; | 534 }; |
| 520 | 535 |
| 521 #if defined(OS_MACOSX) | 536 #if defined(OS_MACOSX) |
| 522 // Test fixture class. Use for tests which are only to be run for RenderTextMac. | 537 // Test fixture class. Use for tests which are only to be run for RenderTextMac. |
| 523 class RenderTextMacTest : public RenderTextTest { | 538 class RenderTextMacTest : public RenderTextTest { |
| 524 public: | 539 public: |
| 525 RenderTextMacTest() {} | 540 RenderTextMacTest() {} |
| 526 | 541 |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 781 EXPECT_EQ(1U, test_api()->TextIndexToDisplayIndex(1U)); | 796 EXPECT_EQ(1U, test_api()->TextIndexToDisplayIndex(1U)); |
| 782 EXPECT_EQ(1U, test_api()->TextIndexToDisplayIndex(2U)); | 797 EXPECT_EQ(1U, test_api()->TextIndexToDisplayIndex(2U)); |
| 783 EXPECT_EQ(0U, test_api()->DisplayIndexToTextIndex(0U)); | 798 EXPECT_EQ(0U, test_api()->DisplayIndexToTextIndex(0U)); |
| 784 EXPECT_EQ(2U, test_api()->DisplayIndexToTextIndex(1U)); | 799 EXPECT_EQ(2U, test_api()->DisplayIndexToTextIndex(1U)); |
| 785 EXPECT_TRUE(render_text->IsValidCursorIndex(0U)); | 800 EXPECT_TRUE(render_text->IsValidCursorIndex(0U)); |
| 786 EXPECT_FALSE(render_text->IsValidCursorIndex(1U)); | 801 EXPECT_FALSE(render_text->IsValidCursorIndex(1U)); |
| 787 EXPECT_TRUE(render_text->IsValidCursorIndex(2U)); | 802 EXPECT_TRUE(render_text->IsValidCursorIndex(2U)); |
| 788 | 803 |
| 789 // FindCursorPosition() should not return positions between a surrogate pair. | 804 // FindCursorPosition() should not return positions between a surrogate pair. |
| 790 render_text->SetDisplayRect(Rect(0, 0, 20, 20)); | 805 render_text->SetDisplayRect(Rect(0, 0, 20, 20)); |
| 791 EXPECT_EQ(render_text->FindCursorPosition(Point(0, 0)).caret_pos(), 0U); | 806 const int cursor_y = GetCursorYForTesting(); |
| 792 EXPECT_EQ(render_text->FindCursorPosition(Point(20, 0)).caret_pos(), 2U); | 807 EXPECT_EQ(render_text->FindCursorPosition(Point(0, cursor_y)).caret_pos(), |
| 808 0U); | |
| 809 EXPECT_EQ(render_text->FindCursorPosition(Point(20, cursor_y)).caret_pos(), | |
| 810 2U); | |
| 793 for (int x = -1; x <= 20; ++x) { | 811 for (int x = -1; x <= 20; ++x) { |
| 794 SelectionModel selection = render_text->FindCursorPosition(Point(x, 0)); | 812 SelectionModel selection = |
| 813 render_text->FindCursorPosition(Point(x, cursor_y)); | |
| 795 EXPECT_TRUE(selection.caret_pos() == 0U || selection.caret_pos() == 2U); | 814 EXPECT_TRUE(selection.caret_pos() == 0U || selection.caret_pos() == 2U); |
| 796 } | 815 } |
| 797 | 816 |
| 798 // GetGlyphBounds() should yield the entire string bounds for text index 0. | 817 // GetGlyphBounds() should yield the entire string bounds for text index 0. |
| 799 EXPECT_EQ(render_text->GetStringSize().width(), | 818 EXPECT_EQ(render_text->GetStringSize().width(), |
| 800 static_cast<int>(render_text->GetGlyphBounds(0U).length())); | 819 static_cast<int>(render_text->GetGlyphBounds(0U).length())); |
| 801 | 820 |
| 802 // Cursoring is independent of underlying characters when text is obscured. | 821 // Cursoring is independent of underlying characters when text is obscured. |
| 803 const wchar_t* const texts[] = { | 822 const wchar_t* const texts[] = { |
| 804 kWeak, kLtr, kLtrRtl, kLtrRtlLtr, kRtl, kRtlLtr, kRtlLtrRtl, | 823 kWeak, kLtr, kLtrRtl, kLtrRtlLtr, kRtl, kRtlLtr, kRtlLtrRtl, |
| (...skipping 971 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1776 const wchar_t* kTestStrings[] = { kLtrRtl, kLtrRtlLtr, kRtlLtr, kRtlLtrRtl }; | 1795 const wchar_t* kTestStrings[] = { kLtrRtl, kLtrRtlLtr, kRtlLtr, kRtlLtrRtl }; |
| 1777 RenderText* render_text = GetRenderText(); | 1796 RenderText* render_text = GetRenderText(); |
| 1778 render_text->SetDisplayRect(Rect(0, 0, 100, 20)); | 1797 render_text->SetDisplayRect(Rect(0, 0, 100, 20)); |
| 1779 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { | 1798 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { |
| 1780 SCOPED_TRACE(base::StringPrintf("Testing case[%" PRIuS "]", i)); | 1799 SCOPED_TRACE(base::StringPrintf("Testing case[%" PRIuS "]", i)); |
| 1781 render_text->SetText(WideToUTF16(kTestStrings[i])); | 1800 render_text->SetText(WideToUTF16(kTestStrings[i])); |
| 1782 for (size_t j = 0; j < render_text->text().length(); ++j) { | 1801 for (size_t j = 0; j < render_text->text().length(); ++j) { |
| 1783 const Range range(render_text->GetGlyphBounds(j)); | 1802 const Range range(render_text->GetGlyphBounds(j)); |
| 1784 // Test a point just inside the leading edge of the glyph bounds. | 1803 // Test a point just inside the leading edge of the glyph bounds. |
| 1785 int x = range.is_reversed() ? range.GetMax() - 1 : range.GetMin() + 1; | 1804 int x = range.is_reversed() ? range.GetMax() - 1 : range.GetMin() + 1; |
| 1786 EXPECT_EQ(j, render_text->FindCursorPosition(Point(x, 0)).caret_pos()); | 1805 EXPECT_EQ( |
| 1806 j, render_text->FindCursorPosition(Point(x, GetCursorYForTesting())) | |
| 1807 .caret_pos()); | |
| 1787 } | 1808 } |
| 1788 } | 1809 } |
| 1789 } | 1810 } |
| 1811 | |
| 1812 // Tests that FindCursorPosition behaves correctly for multi-line text. | |
| 1813 TEST_P(RenderTextHarfBuzzTest, FindCursorPositionMultiline) { | |
|
msw
2016/12/13 03:04:56
q: should we have any multi-char grapheme test cas
karandeepb
2016/12/16 02:58:38
Thanks for pointing this out. The existing impleme
| |
| 1814 struct { | |
| 1815 const wchar_t* const text; | |
| 1816 bool is_ltr; | |
|
msw
2016/12/13 03:04:56
optional nit: check RenderText::GetDisplayTextDire
karandeepb
2016/12/16 02:58:38
Done.
| |
| 1817 } cases[] = {{L"abc def", true}, {L"\x5d0\x5d1\x5d2 \x5d3\x5d4\x5d5", false}}; | |
| 1818 | |
| 1819 SetGlyphWidth(5); | |
| 1820 RenderText* render_text = GetRenderText(); | |
| 1821 render_text->SetDisplayRect(Rect(25, 1000)); | |
| 1822 render_text->SetMultiline(true); | |
| 1823 | |
| 1824 for (size_t i = 0; i < arraysize(cases); i++) { | |
| 1825 render_text->SetText(WideToUTF16(cases[i].text)); | |
| 1826 test_api()->EnsureLayout(); | |
| 1827 EXPECT_EQ(2u, test_api()->lines().size()); | |
| 1828 | |
| 1829 for (size_t j = 0; j < render_text->text().length(); ++j) { | |
| 1830 SCOPED_TRACE(base::StringPrintf( | |
| 1831 "Testing index %" PRIuS " for case %" PRIuS "", j, i)); | |
| 1832 render_text->SelectRange(Range(j, j + 1)); | |
| 1833 | |
| 1834 // Test a point inside the leading edge of the glyph bounds. | |
| 1835 const Rect bounds = GetSelectionBoundsUnion(); | |
| 1836 const Point query(cases[i].is_ltr ? bounds.x() + 1 : bounds.right() - 1, | |
|
msw
2016/12/13 03:04:56
nit: name this cursor_position?
karandeepb
2016/12/16 02:58:38
Done.
| |
| 1837 bounds.y() + 1); | |
| 1838 | |
| 1839 const SelectionModel model_for_query = | |
|
msw
2016/12/13 03:04:56
nit: name this model?
karandeepb
2016/12/16 02:58:38
Done.
| |
| 1840 render_text->FindCursorPosition(query); | |
| 1841 EXPECT_EQ(j, model_for_query.caret_pos()); | |
| 1842 EXPECT_EQ(CURSOR_FORWARD, model_for_query.caret_affinity()); | |
| 1843 } | |
| 1844 } | |
| 1845 } | |
| 1790 | 1846 |
| 1791 TEST_P(RenderTextTest, EdgeSelectionModels) { | 1847 TEST_P(RenderTextTest, EdgeSelectionModels) { |
| 1792 // Simple Latin text. | 1848 // Simple Latin text. |
| 1793 const base::string16 kLatin = WideToUTF16(L"abc"); | 1849 const base::string16 kLatin = WideToUTF16(L"abc"); |
| 1794 // LTR 2-character grapheme. | 1850 // LTR 2-character grapheme. |
| 1795 const base::string16 kLTRGrapheme = WideToUTF16(L"\x0915\x093f"); | 1851 const base::string16 kLTRGrapheme = WideToUTF16(L"\x0915\x093f"); |
| 1796 // LTR 2-character grapheme, LTR a, LTR 2-character grapheme. | 1852 // LTR 2-character grapheme, LTR a, LTR 2-character grapheme. |
| 1797 const base::string16 kHindiLatin = | 1853 const base::string16 kHindiLatin = |
| 1798 WideToUTF16(L"\x0915\x093f" L"a" L"\x0915\x093f"); | 1854 WideToUTF16(L"\x0915\x093f" L"a" L"\x0915\x093f"); |
| 1799 // RTL 2-character grapheme. | 1855 // RTL 2-character grapheme. |
| (...skipping 1056 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2856 } | 2912 } |
| 2857 } | 2913 } |
| 2858 | 2914 |
| 2859 TEST_P(RenderTextHarfBuzzTest, Multiline_Newline) { | 2915 TEST_P(RenderTextHarfBuzzTest, Multiline_Newline) { |
| 2860 const struct { | 2916 const struct { |
| 2861 const wchar_t* const text; | 2917 const wchar_t* const text; |
| 2862 const size_t lines_count; | 2918 const size_t lines_count; |
| 2863 // Ranges of the characters on each line preceding the newline. | 2919 // Ranges of the characters on each line preceding the newline. |
| 2864 const Range line_char_ranges[3]; | 2920 const Range line_char_ranges[3]; |
| 2865 } kTestStrings[] = { | 2921 } kTestStrings[] = { |
| 2866 {L"abc\ndef", 2ul, { Range(0, 3), Range(4, 7), Range::InvalidRange() } }, | 2922 {L"abc\ndef", 2ul, {Range(0, 3), Range(4, 7), Range::InvalidRange()}}, |
| 2867 {L"a \n b ", 2ul, { Range(0, 2), Range(3, 6), Range::InvalidRange() } }, | 2923 {L"a \n b ", 2ul, {Range(0, 2), Range(3, 6), Range::InvalidRange()}}, |
| 2868 {L"ab\n", 2ul, { Range(0, 2), Range(), Range::InvalidRange() } }, | 2924 {L"ab\n", 2ul, {Range(0, 2), Range(), Range::InvalidRange()}}, |
| 2869 {L"a\n\nb", 3ul, { Range(0, 1), Range(), Range(3, 4) } }, | 2925 {L"a\n\nb", 3ul, {Range(0, 1), Range(2, 3), Range(3, 4)}}, |
| 2870 {L"\nab", 2ul, { Range(), Range(1, 3), Range::InvalidRange() } }, | 2926 {L"\nab", 2ul, {Range(0, 1), Range(1, 3), Range::InvalidRange()}}, |
| 2871 {L"\n", 2ul, { Range(), Range(), Range::InvalidRange() } }, | 2927 {L"\n", 2ul, {Range(0, 1), Range(), Range::InvalidRange()}}, |
| 2872 }; | 2928 }; |
| 2873 | 2929 |
| 2874 RenderText* render_text = GetRenderText(); | 2930 RenderText* render_text = GetRenderText(); |
| 2875 render_text->SetDisplayRect(Rect(200, 1000)); | 2931 render_text->SetDisplayRect(Rect(200, 1000)); |
| 2876 render_text->SetMultiline(true); | 2932 render_text->SetMultiline(true); |
| 2877 | 2933 |
| 2878 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { | 2934 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { |
| 2879 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i)); | 2935 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i)); |
| 2880 render_text->SetText(WideToUTF16(kTestStrings[i].text)); | 2936 render_text->SetText(WideToUTF16(kTestStrings[i].text)); |
| 2881 render_text->Draw(canvas()); | 2937 render_text->Draw(canvas()); |
| (...skipping 1009 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3891 const int kWordTwoStartIndex = 6; | 3947 const int kWordTwoStartIndex = 6; |
| 3892 | 3948 |
| 3893 RenderText* render_text = GetRenderText(); | 3949 RenderText* render_text = GetRenderText(); |
| 3894 render_text->SetDisplayRect(Rect(100, 30)); | 3950 render_text->SetDisplayRect(Rect(100, 30)); |
| 3895 render_text->SetText(ltr); | 3951 render_text->SetText(ltr); |
| 3896 render_text->ApplyWeight(Font::Weight::SEMIBOLD, Range(0, 3)); | 3952 render_text->ApplyWeight(Font::Weight::SEMIBOLD, Range(0, 3)); |
| 3897 render_text->ApplyStyle(UNDERLINE, true, Range(1, 5)); | 3953 render_text->ApplyStyle(UNDERLINE, true, Range(1, 5)); |
| 3898 render_text->ApplyStyle(ITALIC, true, Range(3, 8)); | 3954 render_text->ApplyStyle(ITALIC, true, Range(3, 8)); |
| 3899 render_text->ApplyStyle(DIAGONAL_STRIKE, true, Range(5, 7)); | 3955 render_text->ApplyStyle(DIAGONAL_STRIKE, true, Range(5, 7)); |
| 3900 render_text->ApplyStyle(STRIKE, true, Range(1, 7)); | 3956 render_text->ApplyStyle(STRIKE, true, Range(1, 7)); |
| 3957 const int cursor_y = GetCursorYForTesting(); | |
| 3901 | 3958 |
| 3902 const std::vector<RenderText::FontSpan> font_spans = | 3959 const std::vector<RenderText::FontSpan> font_spans = |
| 3903 render_text->GetFontSpansForTesting(); | 3960 render_text->GetFontSpansForTesting(); |
| 3904 | 3961 |
| 3905 // Create expected decorated text instances. | 3962 // Create expected decorated text instances. |
| 3906 DecoratedText expected_word_1; | 3963 DecoratedText expected_word_1; |
| 3907 expected_word_1.text = ASCIIToUTF16("ab"); | 3964 expected_word_1.text = ASCIIToUTF16("ab"); |
| 3908 // Attributes for the characters 'a' and 'b' at logical indices 2 and 3 | 3965 // Attributes for the characters 'a' and 'b' at logical indices 2 and 3 |
| 3909 // respectively. | 3966 // respectively. |
| 3910 expected_word_1.attributes.push_back(CreateRangedAttribute( | 3967 expected_word_1.attributes.push_back(CreateRangedAttribute( |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 3924 ITALIC_MASK | DIAGONAL_STRIKE_MASK | STRIKE_MASK)); | 3981 ITALIC_MASK | DIAGONAL_STRIKE_MASK | STRIKE_MASK)); |
| 3925 const Rect left_glyph_word_2 = render_text->GetCursorBounds( | 3982 const Rect left_glyph_word_2 = render_text->GetCursorBounds( |
| 3926 SelectionModel(kWordTwoStartIndex, CURSOR_FORWARD), false); | 3983 SelectionModel(kWordTwoStartIndex, CURSOR_FORWARD), false); |
| 3927 | 3984 |
| 3928 DecoratedText decorated_word; | 3985 DecoratedText decorated_word; |
| 3929 Point baseline_point; | 3986 Point baseline_point; |
| 3930 | 3987 |
| 3931 { | 3988 { |
| 3932 SCOPED_TRACE(base::StringPrintf("Query to the left of text bounds")); | 3989 SCOPED_TRACE(base::StringPrintf("Query to the left of text bounds")); |
| 3933 EXPECT_TRUE(render_text->GetDecoratedWordAtPoint( | 3990 EXPECT_TRUE(render_text->GetDecoratedWordAtPoint( |
| 3934 Point(-5, 5), &decorated_word, &baseline_point)); | 3991 Point(-5, cursor_y), &decorated_word, &baseline_point)); |
| 3935 VerifyDecoratedWordsAreEqual(expected_word_1, decorated_word); | 3992 VerifyDecoratedWordsAreEqual(expected_word_1, decorated_word); |
| 3936 EXPECT_TRUE(left_glyph_word_1.Contains(baseline_point)); | 3993 EXPECT_TRUE(left_glyph_word_1.Contains(baseline_point)); |
| 3937 } | 3994 } |
| 3938 { | 3995 { |
| 3939 SCOPED_TRACE(base::StringPrintf("Query to the right of text bounds")); | 3996 SCOPED_TRACE(base::StringPrintf("Query to the right of text bounds")); |
| 3940 EXPECT_TRUE(render_text->GetDecoratedWordAtPoint( | 3997 EXPECT_TRUE(render_text->GetDecoratedWordAtPoint( |
| 3941 Point(105, 5), &decorated_word, &baseline_point)); | 3998 Point(105, cursor_y), &decorated_word, &baseline_point)); |
| 3942 VerifyDecoratedWordsAreEqual(expected_word_2, decorated_word); | 3999 VerifyDecoratedWordsAreEqual(expected_word_2, decorated_word); |
| 3943 EXPECT_TRUE(left_glyph_word_2.Contains(baseline_point)); | 4000 EXPECT_TRUE(left_glyph_word_2.Contains(baseline_point)); |
| 3944 } | 4001 } |
| 3945 | 4002 |
| 3946 for (size_t i = 0; i < render_text->text().length(); i++) { | 4003 for (size_t i = 0; i < render_text->text().length(); i++) { |
| 3947 SCOPED_TRACE(base::StringPrintf("Case[%" PRIuS "]", i)); | 4004 SCOPED_TRACE(base::StringPrintf("Case[%" PRIuS "]", i)); |
| 3948 // Query the decorated word using the origin of the i'th glyph's bounds. | 4005 // Query the decorated word using the origin of the i'th glyph's bounds. |
| 3949 const Point query = | 4006 const Point query = |
| 3950 render_text->GetCursorBounds(SelectionModel(i, CURSOR_FORWARD), false) | 4007 render_text->GetCursorBounds(SelectionModel(i, CURSOR_FORWARD), false) |
| 3951 .origin(); | 4008 .origin(); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 3975 const int kWordTwoStartIndex = 5; | 4032 const int kWordTwoStartIndex = 5; |
| 3976 | 4033 |
| 3977 RenderText* render_text = GetRenderText(); | 4034 RenderText* render_text = GetRenderText(); |
| 3978 render_text->SetDisplayRect(Rect(100, 30)); | 4035 render_text->SetDisplayRect(Rect(100, 30)); |
| 3979 render_text->SetText(rtl); | 4036 render_text->SetText(rtl); |
| 3980 render_text->ApplyWeight(Font::Weight::SEMIBOLD, Range(2, 3)); | 4037 render_text->ApplyWeight(Font::Weight::SEMIBOLD, Range(2, 3)); |
| 3981 render_text->ApplyStyle(UNDERLINE, true, Range(3, 6)); | 4038 render_text->ApplyStyle(UNDERLINE, true, Range(3, 6)); |
| 3982 render_text->ApplyStyle(ITALIC, true, Range(0, 3)); | 4039 render_text->ApplyStyle(ITALIC, true, Range(0, 3)); |
| 3983 render_text->ApplyStyle(DIAGONAL_STRIKE, true, Range(0, 2)); | 4040 render_text->ApplyStyle(DIAGONAL_STRIKE, true, Range(0, 2)); |
| 3984 render_text->ApplyStyle(STRIKE, true, Range(2, 5)); | 4041 render_text->ApplyStyle(STRIKE, true, Range(2, 5)); |
| 4042 const int cursor_y = GetCursorYForTesting(); | |
| 3985 | 4043 |
| 3986 const std::vector<RenderText::FontSpan> font_spans = | 4044 const std::vector<RenderText::FontSpan> font_spans = |
| 3987 render_text->GetFontSpansForTesting(); | 4045 render_text->GetFontSpansForTesting(); |
| 3988 | 4046 |
| 3989 // Create expected decorated text instance. | 4047 // Create expected decorated text instance. |
| 3990 DecoratedText expected_word_1; | 4048 DecoratedText expected_word_1; |
| 3991 expected_word_1.text = WideToUTF16(L"\x0634\x0632"); | 4049 expected_word_1.text = WideToUTF16(L"\x0634\x0632"); |
| 3992 // Attributes for characters at logical indices 1 and 2. | 4050 // Attributes for characters at logical indices 1 and 2. |
| 3993 expected_word_1.attributes.push_back(CreateRangedAttribute( | 4051 expected_word_1.attributes.push_back(CreateRangedAttribute( |
| 3994 font_spans, 0, kWordOneStartIndex, Font::Weight::NORMAL, | 4052 font_spans, 0, kWordOneStartIndex, Font::Weight::NORMAL, |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 4007 font_spans, 0, kWordTwoStartIndex, Font::Weight::NORMAL, UNDERLINE_MASK)); | 4065 font_spans, 0, kWordTwoStartIndex, Font::Weight::NORMAL, UNDERLINE_MASK)); |
| 4008 const Rect left_glyph_word_2 = render_text->GetCursorBounds( | 4066 const Rect left_glyph_word_2 = render_text->GetCursorBounds( |
| 4009 SelectionModel(kWordTwoStartIndex, CURSOR_FORWARD), false); | 4067 SelectionModel(kWordTwoStartIndex, CURSOR_FORWARD), false); |
| 4010 | 4068 |
| 4011 DecoratedText decorated_word; | 4069 DecoratedText decorated_word; |
| 4012 Point baseline_point; | 4070 Point baseline_point; |
| 4013 | 4071 |
| 4014 { | 4072 { |
| 4015 SCOPED_TRACE(base::StringPrintf("Query to the left of text bounds")); | 4073 SCOPED_TRACE(base::StringPrintf("Query to the left of text bounds")); |
| 4016 EXPECT_TRUE(render_text->GetDecoratedWordAtPoint( | 4074 EXPECT_TRUE(render_text->GetDecoratedWordAtPoint( |
| 4017 Point(-5, 5), &decorated_word, &baseline_point)); | 4075 Point(-5, cursor_y), &decorated_word, &baseline_point)); |
| 4018 VerifyDecoratedWordsAreEqual(expected_word_2, decorated_word); | 4076 VerifyDecoratedWordsAreEqual(expected_word_2, decorated_word); |
| 4019 EXPECT_TRUE(left_glyph_word_2.Contains(baseline_point)); | 4077 EXPECT_TRUE(left_glyph_word_2.Contains(baseline_point)); |
| 4020 } | 4078 } |
| 4021 { | 4079 { |
| 4022 SCOPED_TRACE(base::StringPrintf("Query to the right of text bounds")); | 4080 SCOPED_TRACE(base::StringPrintf("Query to the right of text bounds")); |
| 4023 EXPECT_TRUE(render_text->GetDecoratedWordAtPoint( | 4081 EXPECT_TRUE(render_text->GetDecoratedWordAtPoint( |
| 4024 Point(105, 5), &decorated_word, &baseline_point)); | 4082 Point(105, cursor_y), &decorated_word, &baseline_point)); |
| 4025 VerifyDecoratedWordsAreEqual(expected_word_1, decorated_word); | 4083 VerifyDecoratedWordsAreEqual(expected_word_1, decorated_word); |
| 4026 EXPECT_TRUE(left_glyph_word_1.Contains(baseline_point)); | 4084 EXPECT_TRUE(left_glyph_word_1.Contains(baseline_point)); |
| 4027 } | 4085 } |
| 4028 | 4086 |
| 4029 for (size_t i = 0; i < render_text->text().length(); i++) { | 4087 for (size_t i = 0; i < render_text->text().length(); i++) { |
| 4030 SCOPED_TRACE(base::StringPrintf("Case[%" PRIuS "]", i)); | 4088 SCOPED_TRACE(base::StringPrintf("Case[%" PRIuS "]", i)); |
| 4031 | 4089 |
| 4032 // Query the decorated word using the top right point of the i'th glyph's | 4090 // Query the decorated word using the top right point of the i'th glyph's |
| 4033 // bounds. | 4091 // bounds. |
| 4034 const Point query = | 4092 const Point query = |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4069 &baseline_point)); | 4127 &baseline_point)); |
| 4070 | 4128 |
| 4071 // False should be returned for obscured text. | 4129 // False should be returned for obscured text. |
| 4072 render_text->SetObscured(true); | 4130 render_text->SetObscured(true); |
| 4073 query = render_text->GetCursorBounds(SelectionModel(0, CURSOR_FORWARD), false) | 4131 query = render_text->GetCursorBounds(SelectionModel(0, CURSOR_FORWARD), false) |
| 4074 .origin(); | 4132 .origin(); |
| 4075 EXPECT_FALSE(render_text->GetDecoratedWordAtPoint(query, &decorated_word, | 4133 EXPECT_FALSE(render_text->GetDecoratedWordAtPoint(query, &decorated_word, |
| 4076 &baseline_point)); | 4134 &baseline_point)); |
| 4077 } | 4135 } |
| 4078 | 4136 |
| 4137 // Tests text selection made at end points of individual lines of multiline | |
| 4138 // text. | |
| 4139 TEST_P(RenderTextHarfBuzzTest, LineEndSelections) { | |
| 4140 const wchar_t* const ltr = L"abc\n\ndef"; | |
| 4141 const wchar_t* const rtl = L"\x5d0\x5d1\x5d2\n\n\x5d3\x5d4\x5d5"; | |
| 4142 const int left_x = -100; | |
| 4143 const int right_x = 100; | |
| 4144 struct { | |
| 4145 const wchar_t* const text; | |
| 4146 const int line_num; | |
| 4147 const int x; | |
| 4148 const wchar_t* const selected_text; | |
| 4149 } cases[] = { | |
| 4150 {ltr, 1, left_x, L"abc\n"}, | |
| 4151 {ltr, 1, right_x, L"abc\n\n"}, | |
| 4152 {ltr, 2, left_x, L"abc\n\n"}, | |
| 4153 {ltr, 2, right_x, ltr}, | |
| 4154 | |
| 4155 {rtl, 1, left_x, L"\x5d0\x5d1\x5d2\n\n"}, | |
| 4156 {rtl, 1, right_x, L"\x5d0\x5d1\x5d2\n"}, | |
| 4157 {rtl, 2, left_x, rtl}, | |
| 4158 {rtl, 2, right_x, L"\x5d0\x5d1\x5d2\n\n"}, | |
| 4159 }; | |
| 4160 | |
| 4161 RenderText* render_text = GetRenderText(); | |
| 4162 render_text->SetMultiline(true); | |
| 4163 render_text->SetDisplayRect(Rect(200, 1000)); | |
| 4164 | |
| 4165 for (size_t i = 0; i < arraysize(cases); i++) { | |
| 4166 SCOPED_TRACE(base::StringPrintf("Testing case %" PRIuS "", i)); | |
| 4167 render_text->SetText(WideToUTF16(cases[i].text)); | |
| 4168 test_api()->EnsureLayout(); | |
| 4169 | |
| 4170 EXPECT_EQ(3u, test_api()->lines().size()); | |
| 4171 // Position the cursor at the logical beginning of text. | |
| 4172 render_text->SelectRange(Range(0)); | |
| 4173 | |
| 4174 render_text->MoveCursorTo( | |
| 4175 Point(cases[i].x, GetCursorYForTesting(cases[i].line_num)), true); | |
| 4176 EXPECT_EQ(WideToUTF16(cases[i].selected_text), | |
| 4177 GetSelectedText(render_text)); | |
| 4178 } | |
| 4179 } | |
| 4180 | |
| 4181 // Tests that GetSubstringBounds returns the correct bounds for multiline text. | |
| 4182 TEST_P(RenderTextHarfBuzzTest, GetSubstringBoundsMultiline) { | |
| 4183 RenderText* render_text = GetRenderText(); | |
| 4184 render_text->SetMultiline(true); | |
| 4185 render_text->SetDisplayRect(Rect(200, 1000)); | |
| 4186 render_text->SetText(WideToUTF16(L"abc\n\ndef")); | |
| 4187 test_api()->EnsureLayout(); | |
| 4188 | |
| 4189 const std::vector<Range> line_char_range = {Range(0, 3), Range(4, 5), | |
| 4190 Range(5, 8)}; | |
| 4191 | |
| 4192 // Test bounds for individual lines. | |
| 4193 EXPECT_EQ(3u, test_api()->lines().size()); | |
| 4194 Rect expected_total_bounds; | |
| 4195 for (size_t i = 0; i < test_api()->lines().size(); i++) { | |
| 4196 SCOPED_TRACE(base::StringPrintf("Testing bounds for line %" PRIuS "", i)); | |
| 4197 const internal::Line& line = test_api()->lines()[i]; | |
| 4198 const Size line_size(std::ceil(line.size.width()), | |
| 4199 std::ceil(line.size.height())); | |
| 4200 const Rect expected_line_bounds = | |
| 4201 render_text->GetLineOffset(i) + Rect(line_size); | |
| 4202 expected_total_bounds.Union(expected_line_bounds); | |
| 4203 | |
| 4204 render_text->SelectRange(line_char_range[i]); | |
| 4205 EXPECT_EQ(expected_line_bounds, GetSelectionBoundsUnion()); | |
| 4206 } | |
| 4207 | |
| 4208 // Test complete bounds. | |
| 4209 render_text->SelectAll(false); | |
| 4210 EXPECT_EQ(expected_total_bounds, GetSelectionBoundsUnion()); | |
| 4211 } | |
| 4212 | |
| 4079 // Prefix for test instantiations intentionally left blank since each test | 4213 // Prefix for test instantiations intentionally left blank since each test |
| 4080 // fixture class has a single parameterization. | 4214 // fixture class has a single parameterization. |
| 4081 #if defined(OS_MACOSX) | 4215 #if defined(OS_MACOSX) |
| 4082 INSTANTIATE_TEST_CASE_P(, | 4216 INSTANTIATE_TEST_CASE_P(, |
| 4083 RenderTextTest, | 4217 RenderTextTest, |
| 4084 ::testing::Values(RENDER_TEXT_HARFBUZZ, | 4218 ::testing::Values(RENDER_TEXT_HARFBUZZ, |
| 4085 RENDER_TEXT_MAC), | 4219 RENDER_TEXT_MAC), |
| 4086 PrintRenderTextBackend()); | 4220 PrintRenderTextBackend()); |
| 4087 INSTANTIATE_TEST_CASE_P(, | 4221 INSTANTIATE_TEST_CASE_P(, |
| 4088 RenderTextMacTest, | 4222 RenderTextMacTest, |
| 4089 ::testing::Values(RENDER_TEXT_MAC), | 4223 ::testing::Values(RENDER_TEXT_MAC), |
| 4090 PrintRenderTextBackend()); | 4224 PrintRenderTextBackend()); |
| 4091 #else | 4225 #else |
| 4092 INSTANTIATE_TEST_CASE_P(, | 4226 INSTANTIATE_TEST_CASE_P(, |
| 4093 RenderTextTest, | 4227 RenderTextTest, |
| 4094 ::testing::Values(RENDER_TEXT_HARFBUZZ), | 4228 ::testing::Values(RENDER_TEXT_HARFBUZZ), |
| 4095 PrintRenderTextBackend()); | 4229 PrintRenderTextBackend()); |
| 4096 #endif | 4230 #endif |
| 4097 | 4231 |
| 4098 INSTANTIATE_TEST_CASE_P(, | 4232 INSTANTIATE_TEST_CASE_P(, |
| 4099 RenderTextHarfBuzzTest, | 4233 RenderTextHarfBuzzTest, |
| 4100 ::testing::Values(RENDER_TEXT_HARFBUZZ), | 4234 ::testing::Values(RENDER_TEXT_HARFBUZZ), |
| 4101 PrintRenderTextBackend()); | 4235 PrintRenderTextBackend()); |
| 4102 | 4236 |
| 4103 } // namespace gfx | 4237 } // namespace gfx |
| OLD | NEW |