| 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 <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/format_macros.h" | 9 #include "base/format_macros.h" |
| 10 #include "base/i18n/break_iterator.h" | 10 #include "base/i18n/break_iterator.h" |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 83 } | 83 } |
| 84 // Check that cursoring is clamped at the line edge. | 84 // Check that cursoring is clamped at the line edge. |
| 85 EXPECT_EQ(expected.back(), render_text->selection_model()); | 85 EXPECT_EQ(expected.back(), render_text->selection_model()); |
| 86 // Check that it is the line edge. | 86 // Check that it is the line edge. |
| 87 render_text->MoveCursor(LINE_BREAK, direction, false); | 87 render_text->MoveCursor(LINE_BREAK, direction, false); |
| 88 EXPECT_EQ(expected.back(), render_text->selection_model()); | 88 EXPECT_EQ(expected.back(), render_text->selection_model()); |
| 89 } | 89 } |
| 90 #endif // !defined(OS_MACOSX) | 90 #endif // !defined(OS_MACOSX) |
| 91 | 91 |
| 92 // Test utility for Multiline_Newline test case. Empty |expected_range| means | 92 // Test utility for Multiline_Newline test case. Empty |expected_range| means |
| 93 // the blank line which has no segments. Otherwise |segments| should contain | 93 // the blank line which has no segments. Otherwise |segment|'s range should |
| 94 // exactly one line segment whose range equals to |expected_range|. | 94 // equal to |expected_range|. |
| 95 void VerifyLineSegments(const Range& expected_range, | 95 void VerifyLineSegments(const Range& expected_range, |
| 96 const std::vector<internal::LineSegment>& segments) { | 96 const internal::LineSegment& segment) { |
| 97 EXPECT_EQ(expected_range.is_empty() ? 0ul : 1ul, segments.size()); | |
| 98 if (!expected_range.is_empty()) | 97 if (!expected_range.is_empty()) |
| 99 EXPECT_EQ(expected_range, segments[0].char_range); | 98 EXPECT_EQ(expected_range, segment.char_range); |
| 100 } | 99 } |
| 101 | 100 |
| 102 // The class which records the drawing operations so that the test case can | 101 // The class which records the drawing operations so that the test case can |
| 103 // verify where exactly the glyphs are drawn. | 102 // verify where exactly the glyphs are drawn. |
| 104 class TestSkiaTextRenderer : public internal::SkiaTextRenderer { | 103 class TestSkiaTextRenderer : public internal::SkiaTextRenderer { |
| 105 public: | 104 public: |
| 106 struct TextLog { | 105 struct TextLog { |
| 107 TextLog() : glyph_count(0u) {} | 106 TextLog() : glyph_count(0u) {} |
| 108 PointF origin; | 107 PointF origin; |
| 109 size_t glyph_count; | 108 size_t glyph_count; |
| (...skipping 1997 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2107 const wchar_t* const text; | 2106 const wchar_t* const text; |
| 2108 const Range first_line_char_range; | 2107 const Range first_line_char_range; |
| 2109 const Range second_line_char_range; | 2108 const Range second_line_char_range; |
| 2110 bool is_ltr; | 2109 bool is_ltr; |
| 2111 } kTestStrings[] = { | 2110 } kTestStrings[] = { |
| 2112 { L"abc defg hijkl", Range(0, 9), Range(9, 14), true }, | 2111 { L"abc defg hijkl", Range(0, 9), Range(9, 14), true }, |
| 2113 { L"qwertyzxcvbn", Range(0, 10), Range(10, 12), true }, | 2112 { L"qwertyzxcvbn", Range(0, 10), Range(10, 12), true }, |
| 2114 { L"\x0627\x0644\x0644\x063A\x0629 " | 2113 { L"\x0627\x0644\x0644\x063A\x0629 " |
| 2115 L"\x0627\x0644\x0639\x0631\x0628\x064A\x0629", | 2114 L"\x0627\x0644\x0639\x0631\x0628\x064A\x0629", |
| 2116 Range(0, 6), Range(6, 13), false }, | 2115 Range(0, 6), Range(6, 13), false }, |
| 2117 { L"\x062A\x0641\x0627\x062D\x05EA\x05E4\x05D5\x05D6\x05D9" | 2116 { L"\x062A\x0641\x0627\x062D \x05EA\x05E4\x05D5\x05D6\x05D9" |
| 2118 L"\x05DA\x05DB\x05DD", Range(0, 4), Range(4, 12), false } | 2117 L"\x05DA\x05DB\x05DD", Range(0, 5), Range(5, 13), false } |
| 2119 }; | 2118 }; |
| 2120 | 2119 |
| 2121 RenderTextHarfBuzz render_text; | 2120 RenderTextHarfBuzz render_text; |
| 2122 // Specify the fixed width for characters to suppress the possible variations | 2121 // Specify the fixed width for characters to suppress the possible variations |
| 2123 // of linebreak results. | 2122 // of linebreak results. |
| 2124 render_text.set_glyph_width_for_test(5); | 2123 render_text.set_glyph_width_for_test(5); |
| 2125 render_text.SetDisplayRect(Rect(50, 1000)); | 2124 render_text.SetDisplayRect(Rect(50, 1000)); |
| 2126 render_text.SetMultiline(true); | 2125 render_text.SetMultiline(true); |
| 2127 render_text.SetWordWrapBehavior(WRAP_LONG_WORDS); | 2126 render_text.SetWordWrapBehavior(WRAP_LONG_WORDS); |
| 2128 render_text.SetHorizontalAlignment(ALIGN_TO_HEAD); | 2127 render_text.SetHorizontalAlignment(ALIGN_TO_HEAD); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2186 } | 2185 } |
| 2187 | 2186 |
| 2188 TEST_F(RenderTextTest, Multiline_Newline) { | 2187 TEST_F(RenderTextTest, Multiline_Newline) { |
| 2189 const struct { | 2188 const struct { |
| 2190 const wchar_t* const text; | 2189 const wchar_t* const text; |
| 2191 const size_t lines_count; | 2190 const size_t lines_count; |
| 2192 // Ranges of the characters on each line preceding the newline. | 2191 // Ranges of the characters on each line preceding the newline. |
| 2193 const Range line_char_ranges[3]; | 2192 const Range line_char_ranges[3]; |
| 2194 } kTestStrings[] = { | 2193 } kTestStrings[] = { |
| 2195 {L"abc\ndef", 2ul, { Range(0, 3), Range(4, 7), Range::InvalidRange() } }, | 2194 {L"abc\ndef", 2ul, { Range(0, 3), Range(4, 7), Range::InvalidRange() } }, |
| 2196 {L"a \n b ", 2ul, { Range(0, 2), Range(3, 6), Range::InvalidRange() } }, | 2195 {L"a \n b ", 2ul, { Range(0, 2), Range(3, 4), Range(4, 6) } }, |
| 2197 {L"ab\n", 2ul, { Range(0, 2), Range(), Range::InvalidRange() } }, | 2196 {L"ab\n", 2ul, { Range(0, 2), Range(), Range::InvalidRange() } }, |
| 2198 {L"a\n\nb", 3ul, { Range(0, 1), Range(), Range(3, 4) } }, | 2197 {L"a\n\nb", 3ul, { Range(0, 1), Range(), Range(3, 4) } }, |
| 2199 {L"\nab", 2ul, { Range(), Range(1, 3), Range::InvalidRange() } }, | 2198 {L"\nab", 2ul, { Range(), Range(1, 3), Range::InvalidRange() } }, |
| 2200 {L"\n", 2ul, { Range(), Range(), Range::InvalidRange() } }, | 2199 {L"\n", 2ul, { Range(), Range(), Range::InvalidRange() } }, |
| 2201 }; | 2200 }; |
| 2202 | 2201 |
| 2203 RenderTextHarfBuzz render_text; | 2202 RenderTextHarfBuzz render_text; |
| 2204 render_text.SetDisplayRect(Rect(200, 1000)); | 2203 render_text.SetDisplayRect(Rect(200, 1000)); |
| 2205 render_text.SetMultiline(true); | 2204 render_text.SetMultiline(true); |
| 2206 Canvas canvas; | 2205 Canvas canvas; |
| 2207 | 2206 |
| 2208 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { | 2207 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { |
| 2209 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i)); | 2208 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i)); |
| 2210 render_text.SetText(WideToUTF16(kTestStrings[i].text)); | 2209 render_text.SetText(WideToUTF16(kTestStrings[i].text)); |
| 2211 render_text.Draw(&canvas); | 2210 render_text.Draw(&canvas); |
| 2212 EXPECT_EQ(kTestStrings[i].lines_count, render_text.lines_.size()); | 2211 EXPECT_EQ(kTestStrings[i].lines_count, render_text.lines_.size()); |
| 2213 if (kTestStrings[i].lines_count != render_text.lines_.size()) | 2212 if (kTestStrings[i].lines_count != render_text.lines_.size()) |
| 2214 continue; | 2213 continue; |
| 2215 | 2214 |
| 2216 for (size_t j = 0; j < kTestStrings[i].lines_count; ++j) { | 2215 for (size_t j = 0; j < kTestStrings[i].lines_count; ++j) { |
| 2217 SCOPED_TRACE(base::StringPrintf("Line %" PRIuS "", j)); | 2216 SCOPED_TRACE(base::StringPrintf("Line %" PRIuS "", j)); |
| 2218 VerifyLineSegments(kTestStrings[i].line_char_ranges[j], | 2217 // There might be multiple segments in one line. |
| 2219 render_text.lines_[j].segments); | 2218 for (size_t k = 0; k < render_text.lines_[j].segments.size(); ++k) { |
| 2219 VerifyLineSegments(kTestStrings[i].line_char_ranges[j + k], |
| 2220 render_text.lines_[j].segments[k]); |
| 2221 } |
| 2220 } | 2222 } |
| 2221 } | 2223 } |
| 2222 } | 2224 } |
| 2223 | 2225 |
| 2224 // Make sure that multiline mode ignores elide behavior. | 2226 // Make sure that multiline mode ignores elide behavior. |
| 2225 TEST_F(RenderTextTest, Multiline_IgnoreElide) { | 2227 TEST_F(RenderTextTest, Multiline_IgnoreElide) { |
| 2226 const wchar_t kTestString[] = | 2228 const wchar_t kTestString[] = |
| 2227 L"very very very long string xxxxxxxxxxxxxxxxxxxxxxxxxx"; | 2229 L"very very very long string xxxxxxxxxxxxxxxxxxxxxxxxxx"; |
| 2228 const wchar_t kEllipsis[] = L"\x2026"; | 2230 const wchar_t kEllipsis[] = L"\x2026"; |
| 2229 | 2231 |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2344 for (size_t j = 0; j < render_text.lines().size(); ++j) { | 2346 for (size_t j = 0; j < render_text.lines().size(); ++j) { |
| 2345 SCOPED_TRACE(base::StringPrintf("%" PRIuS "-th line", j)); | 2347 SCOPED_TRACE(base::StringPrintf("%" PRIuS "-th line", j)); |
| 2346 EXPECT_EQ(kTestScenarios[i].char_ranges[j], | 2348 EXPECT_EQ(kTestScenarios[i].char_ranges[j], |
| 2347 render_text.lines()[j].segments[0].char_range); | 2349 render_text.lines()[j].segments[0].char_range); |
| 2348 EXPECT_EQ(kTestScenarios[i].char_ranges[j].length() * kGlyphSize, | 2350 EXPECT_EQ(kTestScenarios[i].char_ranges[j].length() * kGlyphSize, |
| 2349 render_text.lines()[j].size.width()); | 2351 render_text.lines()[j].size.width()); |
| 2350 } | 2352 } |
| 2351 } | 2353 } |
| 2352 } | 2354 } |
| 2353 | 2355 |
| 2356 TEST_F(RenderTextTest, Multiline_LineBreakerBehavior) { |
| 2357 const int kGlyphSize = 5; |
| 2358 const struct { |
| 2359 const wchar_t* const text; |
| 2360 const size_t num_lines; |
| 2361 const Range char_ranges[3]; |
| 2362 } kTestScenarios[] = { |
| 2363 { L"That's good. aaa", 3u, |
| 2364 {Range(0, 7), Range(7, 13), Range(13, 16) } }, |
| 2365 { |
| 2366 L"That's \"good\". aaa", 3u, |
| 2367 {Range(0, 7), Range(7, 15), Range(15, 18) } } |
| 2368 }; |
| 2369 |
| 2370 RenderTextHarfBuzz render_text; |
| 2371 render_text.SetMultiline(true); |
| 2372 render_text.set_glyph_width_for_test(kGlyphSize); |
| 2373 render_text.SetDisplayRect(Rect(0, 0, kGlyphSize * 4, 0)); |
| 2374 render_text.SetWordWrapBehavior(IGNORE_LONG_WORDS); |
| 2375 |
| 2376 Canvas canvas; |
| 2377 |
| 2378 for (size_t i = 0; i < arraysize(kTestScenarios); ++i) { |
| 2379 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i)); |
| 2380 render_text.SetText(WideToUTF16(kTestScenarios[i].text)); |
| 2381 render_text.Draw(&canvas); |
| 2382 |
| 2383 ASSERT_EQ(kTestScenarios[i].num_lines, render_text.lines().size()); |
| 2384 for (size_t j = 0; j < render_text.lines().size(); ++j) { |
| 2385 SCOPED_TRACE(base::StringPrintf("%" PRIuS "-th line", j)); |
| 2386 // Merges all the segments ranges in the same line. |
| 2387 size_t segment_size = render_text.lines()[j].segments.size(); |
| 2388 Range line_range( |
| 2389 render_text.lines()[j].segments[0].char_range.start(), |
| 2390 render_text.lines()[j].segments[segment_size - 1].char_range.end()); |
| 2391 EXPECT_EQ(kTestScenarios[i].char_ranges[j], line_range); |
| 2392 EXPECT_EQ(kTestScenarios[i].char_ranges[j].length() * kGlyphSize, |
| 2393 render_text.lines()[j].size.width()); |
| 2394 } |
| 2395 } |
| 2396 } |
| 2397 |
| 2354 TEST_F(RenderTextTest, NewlineWithoutMultilineFlag) { | 2398 TEST_F(RenderTextTest, NewlineWithoutMultilineFlag) { |
| 2355 const wchar_t* kTestStrings[] = { | 2399 const wchar_t* kTestStrings[] = { |
| 2356 L"abc\ndef", L"a \n b ", L"ab\n", L"a\n\nb", L"\nab", L"\n", | 2400 L"abc\ndef", L"a \n b ", L"ab\n", L"a\n\nb", L"\nab", L"\n", |
| 2357 }; | 2401 }; |
| 2358 | 2402 |
| 2359 RenderTextHarfBuzz render_text; | 2403 RenderTextHarfBuzz render_text; |
| 2360 render_text.SetDisplayRect(Rect(200, 1000)); | 2404 render_text.SetDisplayRect(Rect(200, 1000)); |
| 2361 Canvas canvas; | 2405 Canvas canvas; |
| 2362 | 2406 |
| 2363 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { | 2407 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2589 render_text.EnsureLayout(); | 2633 render_text.EnsureLayout(); |
| 2590 internal::TextRunList* run_list = render_text.GetRunList(); | 2634 internal::TextRunList* run_list = render_text.GetRunList(); |
| 2591 ASSERT_EQ(3U, run_list->size()); | 2635 ASSERT_EQ(3U, run_list->size()); |
| 2592 EXPECT_EQ(Range(0, 1), run_list->runs()[0]->range); | 2636 EXPECT_EQ(Range(0, 1), run_list->runs()[0]->range); |
| 2593 EXPECT_EQ(Range(1, 2), run_list->runs()[1]->range); | 2637 EXPECT_EQ(Range(1, 2), run_list->runs()[1]->range); |
| 2594 EXPECT_EQ(Range(2, 3), run_list->runs()[2]->range); | 2638 EXPECT_EQ(Range(2, 3), run_list->runs()[2]->range); |
| 2595 | 2639 |
| 2596 render_text.SetText(WideToUTF16(L"x \x25B6 y")); | 2640 render_text.SetText(WideToUTF16(L"x \x25B6 y")); |
| 2597 render_text.EnsureLayout(); | 2641 render_text.EnsureLayout(); |
| 2598 run_list = render_text.GetRunList(); | 2642 run_list = render_text.GetRunList(); |
| 2599 ASSERT_EQ(3U, run_list->size()); | 2643 ASSERT_EQ(4U, run_list->size()); |
| 2600 EXPECT_EQ(Range(0, 2), run_list->runs()[0]->range); | 2644 EXPECT_EQ(Range(0, 2), run_list->runs()[0]->range); |
| 2601 EXPECT_EQ(Range(2, 3), run_list->runs()[1]->range); | 2645 EXPECT_EQ(Range(2, 3), run_list->runs()[1]->range); |
| 2602 EXPECT_EQ(Range(3, 5), run_list->runs()[2]->range); | 2646 EXPECT_EQ(Range(3, 4), run_list->runs()[2]->range); |
| 2647 EXPECT_EQ(Range(4, 5), run_list->runs()[3]->range); |
| 2603 } | 2648 } |
| 2604 | 2649 |
| 2605 TEST_F(RenderTextTest, HarfBuzz_BreakRunsByEmoji) { | 2650 TEST_F(RenderTextTest, HarfBuzz_BreakRunsByEmoji) { |
| 2606 RenderTextHarfBuzz render_text; | 2651 RenderTextHarfBuzz render_text; |
| 2607 | 2652 |
| 2608 // \xF0\x9F\x98\x81 (U+1F601) is smile icon emoji. \xE2\x9C\xA8 (U+2728) is | 2653 // \xF0\x9F\x98\x81 (U+1F601) is smile icon emoji. \xE2\x9C\xA8 (U+2728) is |
| 2609 // a sparkle icon. Both can be drawn with color emoji fonts, so runs should be | 2654 // a sparkle icon. Both can be drawn with color emoji fonts, so runs should be |
| 2610 // separated. See crbug.com/448909 | 2655 // separated. See crbug.com/448909 |
| 2611 render_text.SetText(UTF8ToUTF16("x\xF0\x9F\x98\x81y\xE2\x9C\xA8")); | 2656 render_text.SetText(UTF8ToUTF16("x\xF0\x9F\x98\x81y\xE2\x9C\xA8")); |
| 2612 render_text.EnsureLayout(); | 2657 render_text.EnsureLayout(); |
| (...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2928 string_size.set_width(string_size.width() / 2); | 2973 string_size.set_width(string_size.width() / 2); |
| 2929 render_text.SetDisplayRect(gfx::Rect(string_size)); | 2974 render_text.SetDisplayRect(gfx::Rect(string_size)); |
| 2930 render_text.EnsureLayout(); | 2975 render_text.EnsureLayout(); |
| 2931 CFIndex glyph_count = CTLineGetGlyphCount(render_text.line_); | 2976 CFIndex glyph_count = CTLineGetGlyphCount(render_text.line_); |
| 2932 EXPECT_GT(text.size(), static_cast<size_t>(glyph_count)); | 2977 EXPECT_GT(text.size(), static_cast<size_t>(glyph_count)); |
| 2933 EXPECT_NE(0, glyph_count); | 2978 EXPECT_NE(0, glyph_count); |
| 2934 } | 2979 } |
| 2935 #endif | 2980 #endif |
| 2936 | 2981 |
| 2937 } // namespace gfx | 2982 } // namespace gfx |
| OLD | NEW |