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 <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 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 84 } | 84 } |
| 85 // Check that cursoring is clamped at the line edge. | 85 // Check that cursoring is clamped at the line edge. |
| 86 EXPECT_EQ(expected.back(), render_text->selection_model()); | 86 EXPECT_EQ(expected.back(), render_text->selection_model()); |
| 87 // Check that it is the line edge. | 87 // Check that it is the line edge. |
| 88 render_text->MoveCursor(LINE_BREAK, direction, false); | 88 render_text->MoveCursor(LINE_BREAK, direction, false); |
| 89 EXPECT_EQ(expected.back(), render_text->selection_model()); | 89 EXPECT_EQ(expected.back(), render_text->selection_model()); |
| 90 } | 90 } |
| 91 #endif // !defined(OS_MACOSX) | 91 #endif // !defined(OS_MACOSX) |
| 92 | 92 |
| 93 // Test utility for Multiline_Newline test case. Empty |expected_range| means | 93 // Test utility for Multiline_Newline test case. Empty |expected_range| means |
| 94 // the blank line which has no segments. Otherwise |segments| should contain | 94 // the blank line which has no segments. Otherwise |segment|'s range should |
| 95 // exactly one line segment whose range equals to |expected_range|. | 95 // equal to |expected_range|. |
| 96 void VerifyLineSegments(const Range& expected_range, | 96 void VerifyLineSegments(const Range& expected_range, |
| 97 const std::vector<internal::LineSegment>& segments) { | 97 const internal::LineSegment& segment) { |
| 98 EXPECT_EQ(expected_range.is_empty() ? 0ul : 1ul, segments.size()); | |
| 99 if (!expected_range.is_empty()) | 98 if (!expected_range.is_empty()) |
| 100 EXPECT_EQ(expected_range, segments[0].char_range); | 99 EXPECT_EQ(expected_range, segment.char_range); |
| 101 } | 100 } |
| 102 | 101 |
| 103 // The class which records the drawing operations so that the test case can | 102 // The class which records the drawing operations so that the test case can |
| 104 // verify where exactly the glyphs are drawn. | 103 // verify where exactly the glyphs are drawn. |
| 105 class TestSkiaTextRenderer : public internal::SkiaTextRenderer { | 104 class TestSkiaTextRenderer : public internal::SkiaTextRenderer { |
| 106 public: | 105 public: |
| 107 struct TextLog { | 106 struct TextLog { |
| 108 TextLog() : glyph_count(0u) {} | 107 TextLog() : glyph_count(0u) {} |
| 109 PointF origin; | 108 PointF origin; |
| 110 size_t glyph_count; | 109 size_t glyph_count; |
| (...skipping 2005 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2116 } | 2115 } |
| 2117 | 2116 |
| 2118 // Ensure strings wrap onto multiple lines for a normal available width. | 2117 // Ensure strings wrap onto multiple lines for a normal available width. |
| 2119 TEST_F(RenderTextTest, Multiline_NormalWidth) { | 2118 TEST_F(RenderTextTest, Multiline_NormalWidth) { |
| 2120 const struct { | 2119 const struct { |
| 2121 const wchar_t* const text; | 2120 const wchar_t* const text; |
| 2122 const Range first_line_char_range; | 2121 const Range first_line_char_range; |
| 2123 const Range second_line_char_range; | 2122 const Range second_line_char_range; |
| 2124 bool is_ltr; | 2123 bool is_ltr; |
| 2125 } kTestStrings[] = { | 2124 } kTestStrings[] = { |
| 2126 { L"abc defg hijkl", Range(0, 9), Range(9, 14), true }, | 2125 { L"abcdefg hijkl", Range(0, 8), Range(8, 13), true }, |
|
Jun Mukai
2015/05/06 17:38:52
Why concatenating them?
What was wrong in the test
xdai1
2015/05/06 20:23:44
See line 2153: ASSERT_EQ(1U, render_text.lines_[0]
Jun Mukai
2015/05/06 20:47:55
Please do not do this. Do not update test scenario
| |
| 2127 { L"qwertyzxcvbn", Range(0, 10), Range(10, 12), true }, | 2126 { L"qwertyzxcvbn", Range(0, 10), Range(10, 12), true }, |
| 2128 { L"\x0627\x0644\x0644\x063A\x0629 " | 2127 { L"\x0627\x0644\x0644\x063A\x0629 " |
| 2129 L"\x0627\x0644\x0639\x0631\x0628\x064A\x0629", | 2128 L"\x0627\x0644\x0639\x0631\x0628\x064A\x0629", |
| 2130 Range(0, 6), Range(6, 13), false }, | 2129 Range(0, 6), Range(6, 13), false }, |
| 2131 { L"\x062A\x0641\x0627\x062D\x05EA\x05E4\x05D5\x05D6\x05D9" | 2130 { L"\x062A\x0641\x0627\x062D \x05EA\x05E4\x05D5\x05D6\x05D9" |
| 2132 L"\x05DA\x05DB\x05DD", Range(0, 4), Range(4, 12), false } | 2131 L"\x05DA\x05DB\x05DD", Range(0, 5), Range(5, 13), false } |
| 2133 }; | 2132 }; |
| 2134 | 2133 |
| 2135 RenderTextHarfBuzz render_text; | 2134 RenderTextHarfBuzz render_text; |
| 2136 // Specify the fixed width for characters to suppress the possible variations | 2135 // Specify the fixed width for characters to suppress the possible variations |
| 2137 // of linebreak results. | 2136 // of linebreak results. |
| 2138 render_text.set_glyph_width_for_test(5); | 2137 render_text.set_glyph_width_for_test(5); |
| 2139 render_text.SetDisplayRect(Rect(50, 1000)); | 2138 render_text.SetDisplayRect(Rect(50, 1000)); |
| 2140 render_text.SetMultiline(true); | 2139 render_text.SetMultiline(true); |
| 2141 render_text.SetWordWrapBehavior(WRAP_LONG_WORDS); | 2140 render_text.SetWordWrapBehavior(WRAP_LONG_WORDS); |
| 2142 render_text.SetHorizontalAlignment(ALIGN_TO_HEAD); | 2141 render_text.SetHorizontalAlignment(ALIGN_TO_HEAD); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2200 } | 2199 } |
| 2201 | 2200 |
| 2202 TEST_F(RenderTextTest, Multiline_Newline) { | 2201 TEST_F(RenderTextTest, Multiline_Newline) { |
| 2203 const struct { | 2202 const struct { |
| 2204 const wchar_t* const text; | 2203 const wchar_t* const text; |
| 2205 const size_t lines_count; | 2204 const size_t lines_count; |
| 2206 // Ranges of the characters on each line preceding the newline. | 2205 // Ranges of the characters on each line preceding the newline. |
| 2207 const Range line_char_ranges[3]; | 2206 const Range line_char_ranges[3]; |
| 2208 } kTestStrings[] = { | 2207 } kTestStrings[] = { |
| 2209 {L"abc\ndef", 2ul, { Range(0, 3), Range(4, 7), Range::InvalidRange() } }, | 2208 {L"abc\ndef", 2ul, { Range(0, 3), Range(4, 7), Range::InvalidRange() } }, |
| 2210 {L"a \n b ", 2ul, { Range(0, 2), Range(3, 6), Range::InvalidRange() } }, | 2209 {L"a \n b ", 2ul, { Range(0, 2), Range(3, 4), Range(4, 6) } }, |
|
Jun Mukai
2015/05/06 17:38:52
Consider updating the data structure a bit. The st
xdai1
2015/05/06 20:23:44
No, the run split does change to: "a ", "\n", " ",
| |
| 2211 {L"ab\n", 2ul, { Range(0, 2), Range(), Range::InvalidRange() } }, | 2210 {L"ab\n", 2ul, { Range(0, 2), Range(), Range::InvalidRange() } }, |
| 2212 {L"a\n\nb", 3ul, { Range(0, 1), Range(), Range(3, 4) } }, | 2211 {L"a\n\nb", 3ul, { Range(0, 1), Range(), Range(3, 4) } }, |
| 2213 {L"\nab", 2ul, { Range(), Range(1, 3), Range::InvalidRange() } }, | 2212 {L"\nab", 2ul, { Range(), Range(1, 3), Range::InvalidRange() } }, |
| 2214 {L"\n", 2ul, { Range(), Range(), Range::InvalidRange() } }, | 2213 {L"\n", 2ul, { Range(), Range(), Range::InvalidRange() } }, |
| 2215 }; | 2214 }; |
| 2216 | 2215 |
| 2217 RenderTextHarfBuzz render_text; | 2216 RenderTextHarfBuzz render_text; |
| 2218 render_text.SetDisplayRect(Rect(200, 1000)); | 2217 render_text.SetDisplayRect(Rect(200, 1000)); |
| 2219 render_text.SetMultiline(true); | 2218 render_text.SetMultiline(true); |
| 2220 Canvas canvas; | 2219 Canvas canvas; |
| 2221 | 2220 |
| 2222 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { | 2221 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { |
| 2223 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i)); | 2222 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i)); |
| 2224 render_text.SetText(WideToUTF16(kTestStrings[i].text)); | 2223 render_text.SetText(WideToUTF16(kTestStrings[i].text)); |
| 2225 render_text.Draw(&canvas); | 2224 render_text.Draw(&canvas); |
| 2226 EXPECT_EQ(kTestStrings[i].lines_count, render_text.lines_.size()); | 2225 EXPECT_EQ(kTestStrings[i].lines_count, render_text.lines_.size()); |
| 2227 if (kTestStrings[i].lines_count != render_text.lines_.size()) | 2226 if (kTestStrings[i].lines_count != render_text.lines_.size()) |
| 2228 continue; | 2227 continue; |
| 2229 | 2228 |
| 2230 for (size_t j = 0; j < kTestStrings[i].lines_count; ++j) { | 2229 for (size_t j = 0; j < kTestStrings[i].lines_count; ++j) { |
| 2231 SCOPED_TRACE(base::StringPrintf("Line %" PRIuS "", j)); | 2230 SCOPED_TRACE(base::StringPrintf("Line %" PRIuS "", j)); |
| 2232 VerifyLineSegments(kTestStrings[i].line_char_ranges[j], | 2231 // There might be multiple segments in one line. |
| 2233 render_text.lines_[j].segments); | 2232 for (size_t k = 0; k < render_text.lines_[j].segments.size(); ++k) { |
| 2233 VerifyLineSegments(kTestStrings[i].line_char_ranges[j + k], | |
| 2234 render_text.lines_[j].segments[k]); | |
| 2235 } | |
| 2234 } | 2236 } |
| 2235 } | 2237 } |
| 2236 } | 2238 } |
| 2237 | 2239 |
| 2238 // Make sure that multiline mode ignores elide behavior. | 2240 // Make sure that multiline mode ignores elide behavior. |
| 2239 TEST_F(RenderTextTest, Multiline_IgnoreElide) { | 2241 TEST_F(RenderTextTest, Multiline_IgnoreElide) { |
| 2240 const wchar_t kTestString[] = | 2242 const wchar_t kTestString[] = |
| 2241 L"very very very long string xxxxxxxxxxxxxxxxxxxxxxxxxx"; | 2243 L"very very very long string xxxxxxxxxxxxxxxxxxxxxxxxxx"; |
| 2242 const wchar_t kEllipsis[] = L"\x2026"; | 2244 const wchar_t kEllipsis[] = L"\x2026"; |
| 2243 | 2245 |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2358 for (size_t j = 0; j < render_text.lines().size(); ++j) { | 2360 for (size_t j = 0; j < render_text.lines().size(); ++j) { |
| 2359 SCOPED_TRACE(base::StringPrintf("%" PRIuS "-th line", j)); | 2361 SCOPED_TRACE(base::StringPrintf("%" PRIuS "-th line", j)); |
| 2360 EXPECT_EQ(kTestScenarios[i].char_ranges[j], | 2362 EXPECT_EQ(kTestScenarios[i].char_ranges[j], |
| 2361 render_text.lines()[j].segments[0].char_range); | 2363 render_text.lines()[j].segments[0].char_range); |
| 2362 EXPECT_EQ(kTestScenarios[i].char_ranges[j].length() * kGlyphSize, | 2364 EXPECT_EQ(kTestScenarios[i].char_ranges[j].length() * kGlyphSize, |
| 2363 render_text.lines()[j].size.width()); | 2365 render_text.lines()[j].size.width()); |
| 2364 } | 2366 } |
| 2365 } | 2367 } |
| 2366 } | 2368 } |
| 2367 | 2369 |
| 2370 TEST_F(RenderTextTest, Multiline_LineBreakerBehavior) { | |
| 2371 const int kGlyphSize = 5; | |
| 2372 const struct { | |
| 2373 const wchar_t* const text; | |
| 2374 const WordWrapBehavior behavior; | |
| 2375 const size_t num_lines; | |
| 2376 const Range char_ranges[3]; | |
| 2377 } kTestScenarios[] = { | |
| 2378 { L"That's good. aaa", IGNORE_LONG_WORDS, 3u, | |
| 2379 {Range(0, 7), Range(7, 13), Range(13, 16) } }, | |
| 2380 { L"That's \"good\". aaa", IGNORE_LONG_WORDS, 3u, | |
| 2381 {Range(0, 7), Range(7, 15), Range(15, 18) } }, | |
| 2382 // Test for full-width space. | |
| 2383 { L"That's\x3000good.\x3000yyy", IGNORE_LONG_WORDS, 3u, | |
| 2384 {Range(0, 7), Range(7, 13), Range(13, 16) } }, | |
| 2385 { L"abcde'f g", TRUNCATE_LONG_WORDS, 2u, | |
| 2386 {Range(0, 4), Range(8, 9), Range::InvalidRange() } } | |
| 2387 }; | |
| 2388 | |
| 2389 RenderTextHarfBuzz render_text; | |
| 2390 render_text.SetMultiline(true); | |
| 2391 render_text.set_glyph_width_for_test(kGlyphSize); | |
| 2392 render_text.SetDisplayRect(Rect(0, 0, kGlyphSize * 4, 0)); | |
| 2393 | |
| 2394 Canvas canvas; | |
| 2395 | |
| 2396 for (size_t i = 0; i < arraysize(kTestScenarios); ++i) { | |
| 2397 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i)); | |
| 2398 render_text.SetText(WideToUTF16(kTestScenarios[i].text)); | |
| 2399 render_text.SetWordWrapBehavior(kTestScenarios[i].behavior); | |
| 2400 render_text.Draw(&canvas); | |
| 2401 | |
| 2402 ASSERT_EQ(kTestScenarios[i].num_lines, render_text.lines().size()); | |
| 2403 for (size_t j = 0; j < render_text.lines().size(); ++j) { | |
| 2404 SCOPED_TRACE(base::StringPrintf("%" PRIuS "-th line", j)); | |
| 2405 // Merges all the segments ranges in the same line. | |
| 2406 size_t segment_size = render_text.lines()[j].segments.size(); | |
| 2407 Range line_range( | |
| 2408 render_text.lines()[j].segments[0].char_range.start(), | |
| 2409 render_text.lines()[j].segments[segment_size - 1].char_range.end()); | |
| 2410 EXPECT_EQ(kTestScenarios[i].char_ranges[j], line_range); | |
| 2411 EXPECT_EQ(kTestScenarios[i].char_ranges[j].length() * kGlyphSize, | |
| 2412 render_text.lines()[j].size.width()); | |
| 2413 } | |
| 2414 } | |
| 2415 } | |
| 2416 | |
| 2368 TEST_F(RenderTextTest, NewlineWithoutMultilineFlag) { | 2417 TEST_F(RenderTextTest, NewlineWithoutMultilineFlag) { |
| 2369 const wchar_t* kTestStrings[] = { | 2418 const wchar_t* kTestStrings[] = { |
| 2370 L"abc\ndef", L"a \n b ", L"ab\n", L"a\n\nb", L"\nab", L"\n", | 2419 L"abc\ndef", L"a \n b ", L"ab\n", L"a\n\nb", L"\nab", L"\n", |
| 2371 }; | 2420 }; |
| 2372 | 2421 |
| 2373 RenderTextHarfBuzz render_text; | 2422 RenderTextHarfBuzz render_text; |
| 2374 render_text.SetDisplayRect(Rect(200, 1000)); | 2423 render_text.SetDisplayRect(Rect(200, 1000)); |
| 2375 Canvas canvas; | 2424 Canvas canvas; |
| 2376 | 2425 |
| 2377 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { | 2426 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2603 render_text.EnsureLayout(); | 2652 render_text.EnsureLayout(); |
| 2604 internal::TextRunList* run_list = render_text.GetRunList(); | 2653 internal::TextRunList* run_list = render_text.GetRunList(); |
| 2605 ASSERT_EQ(3U, run_list->size()); | 2654 ASSERT_EQ(3U, run_list->size()); |
| 2606 EXPECT_EQ(Range(0, 1), run_list->runs()[0]->range); | 2655 EXPECT_EQ(Range(0, 1), run_list->runs()[0]->range); |
| 2607 EXPECT_EQ(Range(1, 2), run_list->runs()[1]->range); | 2656 EXPECT_EQ(Range(1, 2), run_list->runs()[1]->range); |
| 2608 EXPECT_EQ(Range(2, 3), run_list->runs()[2]->range); | 2657 EXPECT_EQ(Range(2, 3), run_list->runs()[2]->range); |
| 2609 | 2658 |
| 2610 render_text.SetText(WideToUTF16(L"x \x25B6 y")); | 2659 render_text.SetText(WideToUTF16(L"x \x25B6 y")); |
| 2611 render_text.EnsureLayout(); | 2660 render_text.EnsureLayout(); |
| 2612 run_list = render_text.GetRunList(); | 2661 run_list = render_text.GetRunList(); |
| 2613 ASSERT_EQ(3U, run_list->size()); | 2662 ASSERT_EQ(4U, run_list->size()); |
| 2614 EXPECT_EQ(Range(0, 2), run_list->runs()[0]->range); | 2663 EXPECT_EQ(Range(0, 2), run_list->runs()[0]->range); |
| 2615 EXPECT_EQ(Range(2, 3), run_list->runs()[1]->range); | 2664 EXPECT_EQ(Range(2, 3), run_list->runs()[1]->range); |
| 2616 EXPECT_EQ(Range(3, 5), run_list->runs()[2]->range); | 2665 EXPECT_EQ(Range(3, 4), run_list->runs()[2]->range); |
| 2666 EXPECT_EQ(Range(4, 5), run_list->runs()[3]->range); | |
| 2617 } | 2667 } |
| 2618 | 2668 |
| 2619 TEST_F(RenderTextTest, HarfBuzz_BreakRunsByEmoji) { | 2669 TEST_F(RenderTextTest, HarfBuzz_BreakRunsByEmoji) { |
| 2620 RenderTextHarfBuzz render_text; | 2670 RenderTextHarfBuzz render_text; |
| 2621 | 2671 |
| 2622 // \xF0\x9F\x98\x81 (U+1F601) is smile icon emoji. \xE2\x9C\xA8 (U+2728) is | 2672 // \xF0\x9F\x98\x81 (U+1F601) is smile icon emoji. \xE2\x9C\xA8 (U+2728) is |
| 2623 // a sparkle icon. Both can be drawn with color emoji fonts, so runs should be | 2673 // a sparkle icon. Both can be drawn with color emoji fonts, so runs should be |
| 2624 // separated. See crbug.com/448909 | 2674 // separated. See crbug.com/448909 |
| 2625 render_text.SetText(UTF8ToUTF16("x\xF0\x9F\x98\x81y\xE2\x9C\xA8")); | 2675 render_text.SetText(UTF8ToUTF16("x\xF0\x9F\x98\x81y\xE2\x9C\xA8")); |
| 2626 render_text.EnsureLayout(); | 2676 render_text.EnsureLayout(); |
| (...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2943 string_size.set_width(string_size.width() / 2); | 2993 string_size.set_width(string_size.width() / 2); |
| 2944 render_text.SetDisplayRect(gfx::Rect(string_size)); | 2994 render_text.SetDisplayRect(gfx::Rect(string_size)); |
| 2945 render_text.EnsureLayout(); | 2995 render_text.EnsureLayout(); |
| 2946 CFIndex glyph_count = CTLineGetGlyphCount(render_text.line_); | 2996 CFIndex glyph_count = CTLineGetGlyphCount(render_text.line_); |
| 2947 EXPECT_GT(text.size(), static_cast<size_t>(glyph_count)); | 2997 EXPECT_GT(text.size(), static_cast<size_t>(glyph_count)); |
| 2948 EXPECT_NE(0, glyph_count); | 2998 EXPECT_NE(0, glyph_count); |
| 2949 } | 2999 } |
| 2950 #endif | 3000 #endif |
| 2951 | 3001 |
| 2952 } // namespace gfx | 3002 } // namespace gfx |
| OLD | NEW |