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" |
| 11 #include "base/memory/scoped_ptr.h" | 11 #include "base/memory/scoped_ptr.h" |
| 12 #include "base/strings/string_split.h" | 12 #include "base/strings/string_split.h" |
| 13 #include "base/strings/string_util.h" | 13 #include "base/strings/string_util.h" |
| 14 #include "base/strings/stringprintf.h" | 14 #include "base/strings/stringprintf.h" |
| 15 #include "base/strings/utf_string_conversions.h" | 15 #include "base/strings/utf_string_conversions.h" |
| 16 #include "testing/gtest/include/gtest/gtest.h" | 16 #include "testing/gtest/include/gtest/gtest.h" |
| 17 #include "third_party/skia/include/core/SkSurface.h" | 17 #include "third_party/skia/include/core/SkSurface.h" |
| 18 #include "ui/gfx/break_list.h" | 18 #include "ui/gfx/break_list.h" |
| 19 #include "ui/gfx/canvas.h" | 19 #include "ui/gfx/canvas.h" |
| 20 #include "ui/gfx/color_utils.h" | 20 #include "ui/gfx/color_utils.h" |
| 21 #include "ui/gfx/font.h" | 21 #include "ui/gfx/font.h" |
| 22 #include "ui/gfx/range/range.h" | 22 #include "ui/gfx/range/range.h" |
| 23 #include "ui/gfx/range/range_f.h" | 23 #include "ui/gfx/range/range_f.h" |
| 24 #include "ui/gfx/render_text_harfbuzz.h" | 24 #include "ui/gfx/render_text_harfbuzz.h" |
| 25 #include "ui/gfx/text_utils.h" | |
| 25 | 26 |
| 26 #if defined(OS_WIN) | 27 #if defined(OS_WIN) |
| 27 #include "base/win/windows_version.h" | 28 #include "base/win/windows_version.h" |
| 28 #include "ui/gfx/platform_font_win.h" | 29 #include "ui/gfx/platform_font_win.h" |
| 29 #endif | 30 #endif |
| 30 | 31 |
| 31 #if defined(OS_MACOSX) | 32 #if defined(OS_MACOSX) |
| 32 #include <ApplicationServices/ApplicationServices.h> | 33 #include <ApplicationServices/ApplicationServices.h> |
| 33 | 34 |
| 34 #include "ui/gfx/render_text_mac.h" | 35 #include "ui/gfx/render_text_mac.h" |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 83 render_text->MoveCursor(CHARACTER_BREAK, direction, false); | 84 render_text->MoveCursor(CHARACTER_BREAK, direction, false); |
| 84 } | 85 } |
| 85 // Check that cursoring is clamped at the line edge. | 86 // Check that cursoring is clamped at the line edge. |
| 86 EXPECT_EQ(expected.back(), render_text->selection_model()); | 87 EXPECT_EQ(expected.back(), render_text->selection_model()); |
| 87 // Check that it is the line edge. | 88 // Check that it is the line edge. |
| 88 render_text->MoveCursor(LINE_BREAK, direction, false); | 89 render_text->MoveCursor(LINE_BREAK, direction, false); |
| 89 EXPECT_EQ(expected.back(), render_text->selection_model()); | 90 EXPECT_EQ(expected.back(), render_text->selection_model()); |
| 90 } | 91 } |
| 91 #endif // !defined(OS_MACOSX) | 92 #endif // !defined(OS_MACOSX) |
| 92 | 93 |
| 93 // Test utility for Multiline_Newline test case. Empty |expected_range| means | |
| 94 // the blank line which has no segments. Otherwise |segments| should contain | |
| 95 // exactly one line segment whose range equals to |expected_range|. | |
| 96 void VerifyLineSegments(const Range& expected_range, | |
| 97 const std::vector<internal::LineSegment>& segments) { | |
| 98 EXPECT_EQ(expected_range.is_empty() ? 0ul : 1ul, segments.size()); | |
| 99 if (!expected_range.is_empty()) | |
| 100 EXPECT_EQ(expected_range, segments[0].char_range); | |
| 101 } | |
| 102 | |
| 103 // The class which records the drawing operations so that the test case can | 94 // The class which records the drawing operations so that the test case can |
| 104 // verify where exactly the glyphs are drawn. | 95 // verify where exactly the glyphs are drawn. |
| 105 class TestSkiaTextRenderer : public internal::SkiaTextRenderer { | 96 class TestSkiaTextRenderer : public internal::SkiaTextRenderer { |
| 106 public: | 97 public: |
| 107 struct TextLog { | 98 struct TextLog { |
| 108 TextLog() : glyph_count(0u) {} | 99 TextLog() : glyph_count(0u) {} |
| 109 PointF origin; | 100 PointF origin; |
| 110 size_t glyph_count; | 101 size_t glyph_count; |
| 111 }; | 102 }; |
| 112 | 103 |
| (...skipping 2008 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2121 const wchar_t* const text; | 2112 const wchar_t* const text; |
| 2122 const Range first_line_char_range; | 2113 const Range first_line_char_range; |
| 2123 const Range second_line_char_range; | 2114 const Range second_line_char_range; |
| 2124 bool is_ltr; | 2115 bool is_ltr; |
| 2125 } kTestStrings[] = { | 2116 } kTestStrings[] = { |
| 2126 { L"abc defg hijkl", Range(0, 9), Range(9, 14), true }, | 2117 { L"abc defg hijkl", Range(0, 9), Range(9, 14), true }, |
| 2127 { L"qwertyzxcvbn", Range(0, 10), Range(10, 12), true }, | 2118 { L"qwertyzxcvbn", Range(0, 10), Range(10, 12), true }, |
| 2128 { L"\x0627\x0644\x0644\x063A\x0629 " | 2119 { L"\x0627\x0644\x0644\x063A\x0629 " |
| 2129 L"\x0627\x0644\x0639\x0631\x0628\x064A\x0629", | 2120 L"\x0627\x0644\x0639\x0631\x0628\x064A\x0629", |
| 2130 Range(0, 6), Range(6, 13), false }, | 2121 Range(0, 6), Range(6, 13), false }, |
| 2131 { L"\x062A\x0641\x0627\x062D\x05EA\x05E4\x05D5\x05D6\x05D9" | 2122 { L"\x062A\x0641\x0627\x062D \x05EA\x05E4\x05D5\x05D6\x05D9" |
| 2132 L"\x05DA\x05DB\x05DD", Range(0, 4), Range(4, 12), false } | 2123 L"\x05DA\x05DB\x05DD", Range(0, 5), Range(5, 13), false } |
| 2133 }; | 2124 }; |
| 2134 | 2125 |
| 2135 RenderTextHarfBuzz render_text; | 2126 RenderTextHarfBuzz render_text; |
| 2136 // Specify the fixed width for characters to suppress the possible variations | 2127 // Specify the fixed width for characters to suppress the possible variations |
| 2137 // of linebreak results. | 2128 // of linebreak results. |
| 2138 render_text.set_glyph_width_for_test(5); | 2129 render_text.set_glyph_width_for_test(5); |
| 2139 render_text.SetDisplayRect(Rect(50, 1000)); | 2130 render_text.SetDisplayRect(Rect(50, 1000)); |
| 2140 render_text.SetMultiline(true); | 2131 render_text.SetMultiline(true); |
| 2141 render_text.SetWordWrapBehavior(WRAP_LONG_WORDS); | 2132 render_text.SetWordWrapBehavior(WRAP_LONG_WORDS); |
| 2142 render_text.SetHorizontalAlignment(ALIGN_TO_HEAD); | 2133 render_text.SetHorizontalAlignment(ALIGN_TO_HEAD); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2222 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { | 2213 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { |
| 2223 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i)); | 2214 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i)); |
| 2224 render_text.SetText(WideToUTF16(kTestStrings[i].text)); | 2215 render_text.SetText(WideToUTF16(kTestStrings[i].text)); |
| 2225 render_text.Draw(&canvas); | 2216 render_text.Draw(&canvas); |
| 2226 EXPECT_EQ(kTestStrings[i].lines_count, render_text.lines_.size()); | 2217 EXPECT_EQ(kTestStrings[i].lines_count, render_text.lines_.size()); |
| 2227 if (kTestStrings[i].lines_count != render_text.lines_.size()) | 2218 if (kTestStrings[i].lines_count != render_text.lines_.size()) |
| 2228 continue; | 2219 continue; |
| 2229 | 2220 |
| 2230 for (size_t j = 0; j < kTestStrings[i].lines_count; ++j) { | 2221 for (size_t j = 0; j < kTestStrings[i].lines_count; ++j) { |
| 2231 SCOPED_TRACE(base::StringPrintf("Line %" PRIuS "", j)); | 2222 SCOPED_TRACE(base::StringPrintf("Line %" PRIuS "", j)); |
| 2232 VerifyLineSegments(kTestStrings[i].line_char_ranges[j], | 2223 // There might be multiple segments in one line. Merge all the segments |
| 2233 render_text.lines_[j].segments); | 2224 // ranges in the same line. |
| 2225 const size_t segment_size = render_text.lines()[j].segments.size(); | |
| 2226 Range line_range; | |
| 2227 if (segment_size > 0) | |
| 2228 line_range = Range( | |
| 2229 render_text.lines()[j].segments[0].char_range.start(), | |
| 2230 render_text.lines()[j].segments[segment_size - 1].char_range.end()); | |
| 2231 EXPECT_EQ(kTestStrings[i].line_char_ranges[j], line_range); | |
| 2234 } | 2232 } |
| 2235 } | 2233 } |
| 2236 } | 2234 } |
| 2237 | 2235 |
| 2238 // Make sure that multiline mode ignores elide behavior. | 2236 // Make sure that multiline mode ignores elide behavior. |
| 2239 TEST_F(RenderTextTest, Multiline_IgnoreElide) { | 2237 TEST_F(RenderTextTest, Multiline_IgnoreElide) { |
| 2240 const wchar_t kTestString[] = | 2238 const wchar_t kTestString[] = |
| 2241 L"very very very long string xxxxxxxxxxxxxxxxxxxxxxxxxx"; | 2239 L"very very very long string xxxxxxxxxxxxxxxxxxxxxxxxxx"; |
| 2242 const wchar_t kEllipsis[] = L"\x2026"; | 2240 const wchar_t kEllipsis[] = L"\x2026"; |
| 2243 | 2241 |
| (...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) { | 2356 for (size_t j = 0; j < render_text.lines().size(); ++j) { |
| 2359 SCOPED_TRACE(base::StringPrintf("%" PRIuS "-th line", j)); | 2357 SCOPED_TRACE(base::StringPrintf("%" PRIuS "-th line", j)); |
| 2360 EXPECT_EQ(kTestScenarios[i].char_ranges[j], | 2358 EXPECT_EQ(kTestScenarios[i].char_ranges[j], |
| 2361 render_text.lines()[j].segments[0].char_range); | 2359 render_text.lines()[j].segments[0].char_range); |
| 2362 EXPECT_EQ(kTestScenarios[i].char_ranges[j].length() * kGlyphSize, | 2360 EXPECT_EQ(kTestScenarios[i].char_ranges[j].length() * kGlyphSize, |
| 2363 render_text.lines()[j].size.width()); | 2361 render_text.lines()[j].size.width()); |
| 2364 } | 2362 } |
| 2365 } | 2363 } |
| 2366 } | 2364 } |
| 2367 | 2365 |
| 2366 TEST_F(RenderTextTest, Multiline_LineBreakerBehavior) { | |
| 2367 const int kGlyphSize = 5; | |
| 2368 const struct { | |
| 2369 const wchar_t* const text; | |
| 2370 const WordWrapBehavior behavior; | |
| 2371 const Range char_ranges[3]; | |
| 2372 } kTestScenarios[] = { | |
| 2373 { L"a single run", IGNORE_LONG_WORDS, | |
| 2374 {Range(0, 2), Range(2, 9), Range(9, 12) } }, | |
| 2375 // 3 words: "That's ", ""good". ", "aaa" and 7 runs: "That", "'", "s ", | |
| 2376 // """, "good", "". ", "aaa". They all mixed together. | |
| 2377 { L"That's \"good\". aaa", IGNORE_LONG_WORDS, | |
| 2378 {Range(0, 7), Range(7, 15), Range(15, 18) } }, | |
| 2379 // Test "\"" should be put into a new line correctly. | |
| 2380 { L"a \"good\" one.", IGNORE_LONG_WORDS, | |
| 2381 {Range(0, 2), Range(2, 9), Range(9, 13) } }, | |
| 2382 // Test for full-width space. | |
| 2383 { L"That's\x3000good.\x3000yyy", IGNORE_LONG_WORDS, | |
| 2384 {Range(0, 7), Range(7, 13), Range(13, 16) } }, | |
| 2385 { L"a single run", TRUNCATE_LONG_WORDS, | |
| 2386 {Range(0, 2), Range(2, 6), Range(9, 12) } }, | |
| 2387 { L"That's \"good\". aaa", TRUNCATE_LONG_WORDS, | |
| 2388 {Range(0, 4), Range(7, 11), Range(15, 18) } }, | |
| 2389 { L"That's good. aaa", TRUNCATE_LONG_WORDS, | |
| 2390 {Range(0, 4), Range(7, 11), Range(13, 16) } }, | |
| 2391 { L"a \"good\" one.", TRUNCATE_LONG_WORDS, | |
| 2392 {Range(0, 2), Range(2, 6), Range(9, 13) } }, | |
| 2393 { L"asingleword", WRAP_LONG_WORDS, | |
| 2394 {Range(0, 4), Range(4, 8), Range(8, 11) } }, | |
| 2395 { L"That's good", WRAP_LONG_WORDS, | |
| 2396 {Range(0, 4), Range(4, 7), Range(7, 11) } }, | |
| 2397 { L"That's \"g\".", WRAP_LONG_WORDS, | |
| 2398 {Range(0, 4), Range(4, 7), Range(7, 11) } }, | |
| 2399 }; | |
| 2400 | |
| 2401 RenderTextHarfBuzz render_text; | |
| 2402 render_text.SetMultiline(true); | |
| 2403 render_text.set_glyph_width_for_test(kGlyphSize); | |
| 2404 render_text.SetDisplayRect(Rect(0, 0, kGlyphSize * 4, 0)); | |
| 2405 | |
| 2406 Canvas canvas; | |
| 2407 | |
| 2408 for (size_t i = 0; i < arraysize(kTestScenarios); ++i) { | |
| 2409 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i)); | |
| 2410 render_text.SetText(WideToUTF16(kTestScenarios[i].text)); | |
| 2411 render_text.SetWordWrapBehavior(kTestScenarios[i].behavior); | |
| 2412 render_text.Draw(&canvas); | |
| 2413 | |
| 2414 ASSERT_EQ(3u, render_text.lines().size()); | |
| 2415 for (size_t j = 0; j < render_text.lines().size(); ++j) { | |
| 2416 SCOPED_TRACE(base::StringPrintf("%" PRIuS "-th line", j)); | |
| 2417 // Merge all the segments ranges in the same line. | |
| 2418 size_t segment_size = render_text.lines()[j].segments.size(); | |
| 2419 Range line_range; | |
| 2420 if (segment_size > 0) | |
| 2421 line_range = Range( | |
| 2422 render_text.lines()[j].segments[0].char_range.start(), | |
| 2423 render_text.lines()[j].segments[segment_size - 1].char_range.end()); | |
| 2424 EXPECT_EQ(kTestScenarios[i].char_ranges[j], line_range); | |
| 2425 EXPECT_EQ(kTestScenarios[i].char_ranges[j].length() * kGlyphSize, | |
| 2426 render_text.lines()[j].size.width()); | |
| 2427 } | |
| 2428 } | |
| 2429 } | |
| 2430 | |
| 2431 // Test that Surrogate pairs or combining character sequences do not get | |
| 2432 // separated by line breaking. | |
| 2433 TEST_F(RenderTextTest, Multiline_SurrogatePairsOrCombiningChars) { | |
| 2434 RenderTextHarfBuzz render_text; | |
| 2435 render_text.SetMultiline(true); | |
| 2436 render_text.SetWordWrapBehavior(WRAP_LONG_WORDS); | |
| 2437 | |
| 2438 // Below is 'MUSICAL SYMBOL G CLEF' (U+1D11E), which is represented in UTF-16 | |
| 2439 // as two code units forming a surrogate pair: 0xD834 0xDD1E. | |
| 2440 const base::char16 kSurrogate[] = {0xD834, 0xDD1E, 0}; | |
| 2441 // Below is a Devanagari two-character combining sequence U+0921 U+093F. The | |
| 2442 // sequence forms a single display character and should not be separated. | |
| 2443 const base::char16 kCombiningChars[] = {0x921, 0x93F, 0}; | |
| 2444 const float kSurrogateWidth = | |
| 2445 GetStringWidthF(kSurrogate, render_text.font_list()); | |
| 2446 const float kCombiningCharsWidth = | |
| 2447 GetStringWidthF(kCombiningChars, render_text.font_list()); | |
| 2448 | |
| 2449 // Construct two words. | |
| 2450 const base::string16 text(kSurrogate + UTF8ToUTF16(" ") + kCombiningChars); | |
| 2451 // Carefully set display rectangle width so that it will split the surrogate | |
| 2452 // pairs and combining characters. | |
| 2453 const int width = std::min(kSurrogateWidth, kCombiningCharsWidth) / 2; | |
| 2454 const Range char_ranges[3] = {Range(0, 2), Range(2, 3), Range(3, 5)}; | |
| 2455 | |
| 2456 Canvas canvas; | |
| 2457 render_text.SetText(text); | |
| 2458 render_text.SetDisplayRect(Rect(0, 0, width, 0)); | |
| 2459 render_text.Draw(&canvas); | |
| 2460 | |
| 2461 ASSERT_EQ(3u, render_text.lines().size()); | |
| 2462 for (size_t j = 0; j < render_text.lines().size(); ++j) { | |
| 2463 SCOPED_TRACE(base::StringPrintf("%" PRIuS "-th line", j)); | |
| 2464 // There is only one segment in each line. | |
| 2465 EXPECT_EQ(char_ranges[j], render_text.lines()[j].segments[0].char_range); | |
| 2466 } | |
| 2467 } | |
| 2468 | |
| 2469 // Test that Zero width characters have the correct line breaking behavior. | |
| 2470 TEST_F(RenderTextTest, Multiline_ZeroWidthChars) { | |
| 2471 RenderTextHarfBuzz render_text; | |
| 2472 render_text.SetMultiline(true); | |
| 2473 render_text.SetWordWrapBehavior(WRAP_LONG_WORDS); | |
| 2474 render_text.SetFontList(FontList("Arial, 13px")); | |
|
msw
2015/06/09 01:15:50
Avoid relying on a particular fonts, it might brea
xdai1
2015/06/09 17:59:21
Done.
| |
| 2475 | |
| 2476 const base::char16 kZeroWidthSpace = {0x200B}; | |
| 2477 const base::string16 text(UTF8ToUTF16("test") + kZeroWidthSpace + | |
| 2478 kZeroWidthSpace + UTF8ToUTF16("test.")); | |
| 2479 const int kTestWidth = | |
| 2480 GetStringWidth(UTF8ToUTF16("test"), render_text.font_list()); | |
| 2481 const Range char_ranges[3] = {Range(0, 6), Range(6, 10), Range(10, 11)}; | |
|
msw
2015/06/09 01:15:50
My concern was actually for zero width spaces at t
xdai1
2015/06/09 17:59:21
I'm not quite understand your concern... Why would
msw
2015/06/09 22:51:53
I think my concern was that the line breaker might
| |
| 2482 | |
| 2483 Canvas canvas; | |
| 2484 render_text.SetText(text); | |
| 2485 render_text.SetDisplayRect(Rect(0, 0, kTestWidth, 0)); | |
| 2486 render_text.Draw(&canvas); | |
| 2487 | |
| 2488 ASSERT_EQ(3u, render_text.lines().size()); | |
| 2489 for (size_t j = 0; j < render_text.lines().size(); ++j) { | |
| 2490 SCOPED_TRACE(base::StringPrintf("%" PRIuS "-th line", j)); | |
| 2491 // Merge all the segments ranges in the same line. | |
| 2492 size_t segment_size = render_text.lines()[j].segments.size(); | |
| 2493 Range line_range; | |
| 2494 if (segment_size > 0) | |
|
msw
2015/06/09 01:15:50
nit: instead ASSERT_GT(segment_size, 0), and "Rang
xdai1
2015/06/09 17:59:21
Done.
| |
| 2495 line_range = Range( | |
| 2496 render_text.lines()[j].segments[0].char_range.start(), | |
| 2497 render_text.lines()[j].segments[segment_size - 1].char_range.end()); | |
| 2498 // There is only one segment in each line. | |
| 2499 EXPECT_EQ(char_ranges[j], line_range); | |
| 2500 } | |
| 2501 } | |
| 2502 | |
| 2368 TEST_F(RenderTextTest, NewlineWithoutMultilineFlag) { | 2503 TEST_F(RenderTextTest, NewlineWithoutMultilineFlag) { |
| 2369 const wchar_t* kTestStrings[] = { | 2504 const wchar_t* kTestStrings[] = { |
| 2370 L"abc\ndef", L"a \n b ", L"ab\n", L"a\n\nb", L"\nab", L"\n", | 2505 L"abc\ndef", L"a \n b ", L"ab\n", L"a\n\nb", L"\nab", L"\n", |
| 2371 }; | 2506 }; |
| 2372 | 2507 |
| 2373 RenderTextHarfBuzz render_text; | 2508 RenderTextHarfBuzz render_text; |
| 2374 render_text.SetDisplayRect(Rect(200, 1000)); | 2509 render_text.SetDisplayRect(Rect(200, 1000)); |
| 2375 Canvas canvas; | 2510 Canvas canvas; |
| 2376 | 2511 |
| 2377 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { | 2512 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(); | 2738 render_text.EnsureLayout(); |
| 2604 internal::TextRunList* run_list = render_text.GetRunList(); | 2739 internal::TextRunList* run_list = render_text.GetRunList(); |
| 2605 ASSERT_EQ(3U, run_list->size()); | 2740 ASSERT_EQ(3U, run_list->size()); |
| 2606 EXPECT_EQ(Range(0, 1), run_list->runs()[0]->range); | 2741 EXPECT_EQ(Range(0, 1), run_list->runs()[0]->range); |
| 2607 EXPECT_EQ(Range(1, 2), run_list->runs()[1]->range); | 2742 EXPECT_EQ(Range(1, 2), run_list->runs()[1]->range); |
| 2608 EXPECT_EQ(Range(2, 3), run_list->runs()[2]->range); | 2743 EXPECT_EQ(Range(2, 3), run_list->runs()[2]->range); |
| 2609 | 2744 |
| 2610 render_text.SetText(WideToUTF16(L"x \x25B6 y")); | 2745 render_text.SetText(WideToUTF16(L"x \x25B6 y")); |
| 2611 render_text.EnsureLayout(); | 2746 render_text.EnsureLayout(); |
| 2612 run_list = render_text.GetRunList(); | 2747 run_list = render_text.GetRunList(); |
| 2613 ASSERT_EQ(3U, run_list->size()); | 2748 ASSERT_EQ(4U, run_list->size()); |
| 2614 EXPECT_EQ(Range(0, 2), run_list->runs()[0]->range); | 2749 EXPECT_EQ(Range(0, 2), run_list->runs()[0]->range); |
| 2615 EXPECT_EQ(Range(2, 3), run_list->runs()[1]->range); | 2750 EXPECT_EQ(Range(2, 3), run_list->runs()[1]->range); |
| 2616 EXPECT_EQ(Range(3, 5), run_list->runs()[2]->range); | 2751 EXPECT_EQ(Range(3, 4), run_list->runs()[2]->range); |
| 2752 EXPECT_EQ(Range(4, 5), run_list->runs()[3]->range); | |
| 2617 } | 2753 } |
| 2618 | 2754 |
| 2619 TEST_F(RenderTextTest, HarfBuzz_BreakRunsByEmoji) { | 2755 TEST_F(RenderTextTest, HarfBuzz_BreakRunsByEmoji) { |
| 2620 RenderTextHarfBuzz render_text; | 2756 RenderTextHarfBuzz render_text; |
| 2621 | 2757 |
| 2622 // \xF0\x9F\x98\x81 (U+1F601) is smile icon emoji. \xE2\x9C\xA8 (U+2728) is | 2758 // \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 | 2759 // a sparkle icon. Both can be drawn with color emoji fonts, so runs should be |
| 2624 // separated. See crbug.com/448909 | 2760 // separated. See crbug.com/448909 |
| 2625 render_text.SetText(UTF8ToUTF16("x\xF0\x9F\x98\x81y\xE2\x9C\xA8")); | 2761 render_text.SetText(UTF8ToUTF16("x\xF0\x9F\x98\x81y\xE2\x9C\xA8")); |
| 2626 render_text.EnsureLayout(); | 2762 render_text.EnsureLayout(); |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2941 string_size.set_width(string_size.width() / 2); | 3077 string_size.set_width(string_size.width() / 2); |
| 2942 render_text.SetDisplayRect(gfx::Rect(string_size)); | 3078 render_text.SetDisplayRect(gfx::Rect(string_size)); |
| 2943 render_text.EnsureLayout(); | 3079 render_text.EnsureLayout(); |
| 2944 CFIndex glyph_count = CTLineGetGlyphCount(render_text.line_); | 3080 CFIndex glyph_count = CTLineGetGlyphCount(render_text.line_); |
| 2945 EXPECT_GT(text.size(), static_cast<size_t>(glyph_count)); | 3081 EXPECT_GT(text.size(), static_cast<size_t>(glyph_count)); |
| 2946 EXPECT_NE(0, glyph_count); | 3082 EXPECT_NE(0, glyph_count); |
| 2947 } | 3083 } |
| 2948 #endif | 3084 #endif |
| 2949 | 3085 |
| 2950 } // namespace gfx | 3086 } // namespace gfx |
| OLD | NEW |