| 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 const base::string16 text_surrogate(kSurrogate); |
| 2442 const int kSurrogateWidth = |
| 2443 GetStringWidth(kSurrogate, render_text.font_list()); |
| 2444 |
| 2445 // Below is a Devanagari two-character combining sequence U+0921 U+093F. The |
| 2446 // sequence forms a single display character and should not be separated. |
| 2447 const base::char16 kCombiningChars[] = {0x921, 0x93F, 0}; |
| 2448 const base::string16 text_combining(kCombiningChars); |
| 2449 const int kCombiningCharsWidth = |
| 2450 GetStringWidth(kCombiningChars, render_text.font_list()); |
| 2451 |
| 2452 const struct { |
| 2453 const base::string16 text; |
| 2454 const int display_width; |
| 2455 const Range char_ranges[3]; |
| 2456 } kTestScenarios[] = { |
| 2457 { text_surrogate + text_surrogate + text_surrogate, |
| 2458 kSurrogateWidth / 2 * 3, |
| 2459 { Range(0, 2), Range(2, 4), Range(4, 6) } }, |
| 2460 { text_surrogate + UTF8ToUTF16(" ") + kCombiningChars, |
| 2461 std::min(kSurrogateWidth, kCombiningCharsWidth) / 2, |
| 2462 { Range(0, 2), Range(2, 3), Range(3, 5) } }, |
| 2463 }; |
| 2464 |
| 2465 Canvas canvas; |
| 2466 |
| 2467 for (size_t i = 0; i < arraysize(kTestScenarios); ++i) { |
| 2468 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i)); |
| 2469 render_text.SetText(kTestScenarios[i].text); |
| 2470 render_text.SetDisplayRect(Rect(0, 0, kTestScenarios[i].display_width, 0)); |
| 2471 render_text.Draw(&canvas); |
| 2472 |
| 2473 ASSERT_EQ(3u, render_text.lines().size()); |
| 2474 for (size_t j = 0; j < render_text.lines().size(); ++j) { |
| 2475 SCOPED_TRACE(base::StringPrintf("%" PRIuS "-th line", j)); |
| 2476 // There is only one segment in each line. |
| 2477 EXPECT_EQ(kTestScenarios[i].char_ranges[j], |
| 2478 render_text.lines()[j].segments[0].char_range); |
| 2479 } |
| 2480 } |
| 2481 } |
| 2482 |
| 2483 // Test that Zero width characters have the correct line breaking behavior. |
| 2484 TEST_F(RenderTextTest, Multiline_ZeroWidthChars) { |
| 2485 RenderTextHarfBuzz render_text; |
| 2486 render_text.SetMultiline(true); |
| 2487 render_text.SetWordWrapBehavior(WRAP_LONG_WORDS); |
| 2488 |
| 2489 const base::char16 kZeroWidthSpace = {0x200B}; |
| 2490 const base::string16 text(UTF8ToUTF16("test") + kZeroWidthSpace + |
| 2491 UTF8ToUTF16("\n") + kZeroWidthSpace + |
| 2492 UTF8ToUTF16("test.")); |
| 2493 const int kTestWidth = |
| 2494 GetStringWidth(UTF8ToUTF16("test"), render_text.font_list()); |
| 2495 const Range char_ranges[3] = {Range(0, 5), Range(6, 11), Range(11, 12)}; |
| 2496 |
| 2497 Canvas canvas; |
| 2498 render_text.SetText(text); |
| 2499 render_text.SetDisplayRect(Rect(0, 0, kTestWidth, 0)); |
| 2500 render_text.Draw(&canvas); |
| 2501 |
| 2502 ASSERT_EQ(3u, render_text.lines().size()); |
| 2503 for (size_t j = 0; j < render_text.lines().size(); ++j) { |
| 2504 SCOPED_TRACE(base::StringPrintf("%" PRIuS "-th line", j)); |
| 2505 int segment_size = render_text.lines()[j].segments.size(); |
| 2506 ASSERT_GT(segment_size, 0); |
| 2507 Range line_range( |
| 2508 render_text.lines()[j].segments[0].char_range.start(), |
| 2509 render_text.lines()[j].segments[segment_size - 1].char_range.end()); |
| 2510 EXPECT_EQ(char_ranges[j], line_range); |
| 2511 } |
| 2512 } |
| 2513 |
| 2368 TEST_F(RenderTextTest, NewlineWithoutMultilineFlag) { | 2514 TEST_F(RenderTextTest, NewlineWithoutMultilineFlag) { |
| 2369 const wchar_t* kTestStrings[] = { | 2515 const wchar_t* kTestStrings[] = { |
| 2370 L"abc\ndef", L"a \n b ", L"ab\n", L"a\n\nb", L"\nab", L"\n", | 2516 L"abc\ndef", L"a \n b ", L"ab\n", L"a\n\nb", L"\nab", L"\n", |
| 2371 }; | 2517 }; |
| 2372 | 2518 |
| 2373 RenderTextHarfBuzz render_text; | 2519 RenderTextHarfBuzz render_text; |
| 2374 render_text.SetDisplayRect(Rect(200, 1000)); | 2520 render_text.SetDisplayRect(Rect(200, 1000)); |
| 2375 Canvas canvas; | 2521 Canvas canvas; |
| 2376 | 2522 |
| 2377 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { | 2523 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(); | 2749 render_text.EnsureLayout(); |
| 2604 internal::TextRunList* run_list = render_text.GetRunList(); | 2750 internal::TextRunList* run_list = render_text.GetRunList(); |
| 2605 ASSERT_EQ(3U, run_list->size()); | 2751 ASSERT_EQ(3U, run_list->size()); |
| 2606 EXPECT_EQ(Range(0, 1), run_list->runs()[0]->range); | 2752 EXPECT_EQ(Range(0, 1), run_list->runs()[0]->range); |
| 2607 EXPECT_EQ(Range(1, 2), run_list->runs()[1]->range); | 2753 EXPECT_EQ(Range(1, 2), run_list->runs()[1]->range); |
| 2608 EXPECT_EQ(Range(2, 3), run_list->runs()[2]->range); | 2754 EXPECT_EQ(Range(2, 3), run_list->runs()[2]->range); |
| 2609 | 2755 |
| 2610 render_text.SetText(WideToUTF16(L"x \x25B6 y")); | 2756 render_text.SetText(WideToUTF16(L"x \x25B6 y")); |
| 2611 render_text.EnsureLayout(); | 2757 render_text.EnsureLayout(); |
| 2612 run_list = render_text.GetRunList(); | 2758 run_list = render_text.GetRunList(); |
| 2613 ASSERT_EQ(3U, run_list->size()); | 2759 ASSERT_EQ(4U, run_list->size()); |
| 2614 EXPECT_EQ(Range(0, 2), run_list->runs()[0]->range); | 2760 EXPECT_EQ(Range(0, 2), run_list->runs()[0]->range); |
| 2615 EXPECT_EQ(Range(2, 3), run_list->runs()[1]->range); | 2761 EXPECT_EQ(Range(2, 3), run_list->runs()[1]->range); |
| 2616 EXPECT_EQ(Range(3, 5), run_list->runs()[2]->range); | 2762 EXPECT_EQ(Range(3, 4), run_list->runs()[2]->range); |
| 2763 EXPECT_EQ(Range(4, 5), run_list->runs()[3]->range); |
| 2617 } | 2764 } |
| 2618 | 2765 |
| 2619 TEST_F(RenderTextTest, HarfBuzz_BreakRunsByEmoji) { | 2766 TEST_F(RenderTextTest, HarfBuzz_BreakRunsByEmoji) { |
| 2620 RenderTextHarfBuzz render_text; | 2767 RenderTextHarfBuzz render_text; |
| 2621 | 2768 |
| 2622 // \xF0\x9F\x98\x81 (U+1F601) is smile icon emoji. \xE2\x9C\xA8 (U+2728) is | 2769 // \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 | 2770 // a sparkle icon. Both can be drawn with color emoji fonts, so runs should be |
| 2624 // separated. See crbug.com/448909 | 2771 // separated. See crbug.com/448909 |
| 2625 render_text.SetText(UTF8ToUTF16("x\xF0\x9F\x98\x81y\xE2\x9C\xA8")); | 2772 render_text.SetText(UTF8ToUTF16("x\xF0\x9F\x98\x81y\xE2\x9C\xA8")); |
| 2626 render_text.EnsureLayout(); | 2773 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); | 3088 string_size.set_width(string_size.width() / 2); |
| 2942 render_text.SetDisplayRect(gfx::Rect(string_size)); | 3089 render_text.SetDisplayRect(gfx::Rect(string_size)); |
| 2943 render_text.EnsureLayout(); | 3090 render_text.EnsureLayout(); |
| 2944 CFIndex glyph_count = CTLineGetGlyphCount(render_text.line_); | 3091 CFIndex glyph_count = CTLineGetGlyphCount(render_text.line_); |
| 2945 EXPECT_GT(text.size(), static_cast<size_t>(glyph_count)); | 3092 EXPECT_GT(text.size(), static_cast<size_t>(glyph_count)); |
| 2946 EXPECT_NE(0, glyph_count); | 3093 EXPECT_NE(0, glyph_count); |
| 2947 } | 3094 } |
| 2948 #endif | 3095 #endif |
| 2949 | 3096 |
| 2950 } // namespace gfx | 3097 } // namespace gfx |
| OLD | NEW |