diff --git a/engine/src/flutter/src/paragraph.cc b/engine/src/flutter/src/paragraph.cc index e93645935b..65d6f4060e 100644 --- a/engine/src/flutter/src/paragraph.cc +++ b/engine/src/flutter/src/paragraph.cc @@ -177,8 +177,16 @@ void Paragraph::Layout(double width, bool force) { collection_map; breaker_.setLineWidths(0.0f, 0, width_); + // TODO(garyq): Get hyphenator working. Hyphenator should be created with + // a pattern binary dataset. Should be something along these lines: + // + // minikin::Hyphenator* hyph = + // minikin::Hyphenator::loadBinary(); + // breaker_.setLocale(icu::Locale::getRoot(), &hyph); + // AddRunsToLineBreaker(collection_map); breaker_.setJustified(paragraph_style_.text_align == TextAlign::justify); + breaker_.setStrategy(paragraph_style_.break_strategy); size_t breaks_count = breaker_.computeBreaks(); const int* breaks = breaker_.getBreaks(); diff --git a/engine/src/flutter/src/paragraph.h b/engine/src/flutter/src/paragraph.h index 773cc6bb9a..b3bc991447 100644 --- a/engine/src/flutter/src/paragraph.h +++ b/engine/src/flutter/src/paragraph.h @@ -117,6 +117,7 @@ class Paragraph { FRIEND_TEST(RenderTest, ChineseParagraph); FRIEND_TEST(RenderTest, DISABLED_ArabicParagraph); FRIEND_TEST(RenderTest, SpacingParagraph); + FRIEND_TEST(RenderTest, LongWordParagraph); std::vector text_; StyledRuns runs_; diff --git a/engine/src/flutter/src/paragraph_style.h b/engine/src/flutter/src/paragraph_style.h index b6ae31e060..38f1a2278a 100644 --- a/engine/src/flutter/src/paragraph_style.h +++ b/engine/src/flutter/src/paragraph_style.h @@ -20,6 +20,7 @@ #include #include +#include "lib/txt/include/minikin/LineBreaker.h" #include "lib/txt/src/font_style.h" #include "lib/txt/src/font_weight.h" #include "lib/txt/src/text_align.h" @@ -36,6 +37,12 @@ class ParagraphStyle { size_t max_lines = UINT_MAX; double line_height = 1.0; std::string ellipsis = "..."; + // Default strategy is kBreakStrategy_Greedy. Sometimes, + // kBreakStrategy_HighQuality will produce more desireable layouts (eg, very + // long words are more likely to be reasonably placed). + // kBreakStrategy_Balanced will balance between the two. + minikin::BreakStrategy break_strategy = + minikin::BreakStrategy::kBreakStrategy_Greedy; // TODO(garyq): Implement right to left. // Right to left (Arabic, Hebrew, etc). bool rtl = false; diff --git a/engine/src/flutter/src/styled_runs.h b/engine/src/flutter/src/styled_runs.h index d88306d704..4159bc01c0 100644 --- a/engine/src/flutter/src/styled_runs.h +++ b/engine/src/flutter/src/styled_runs.h @@ -70,6 +70,7 @@ class StyledRuns { FRIEND_TEST(RenderTest, ItalicsParagraph); FRIEND_TEST(RenderTest, ChineseParagraph); FRIEND_TEST(RenderTest, DISABLED_ArabicParagraph); + FRIEND_TEST(RenderTest, LongWordParagraph); struct IndexedRun { size_t style_index = 0; diff --git a/engine/src/flutter/tests/txt/paragraph_unittests.cc b/engine/src/flutter/tests/txt/paragraph_unittests.cc index 8067118035..998843b17d 100644 --- a/engine/src/flutter/tests/txt/paragraph_unittests.cc +++ b/engine/src/flutter/tests/txt/paragraph_unittests.cc @@ -1200,7 +1200,49 @@ TEST_F(RenderTest, SpacingParagraph) { ASSERT_EQ(paragraph->records_[4].style().word_spacing, 20); ASSERT_EQ(paragraph->records_[5].style().word_spacing, 0); ASSERT_EQ(paragraph->records_[6].style().word_spacing, 20); +} +TEST_F(RenderTest, LongWordParagraph) { + const char* text = + "A " + "veryverylongwordtoseewherethiswillwraporifitwillatallandifitdoesthenthat" + "wouldbeagoodthingbecausethebreakingisworking."; + auto icu_text = icu::UnicodeString::fromUTF8(text); + std::u16string u16_text(icu_text.getBuffer(), + icu_text.getBuffer() + icu_text.length()); + + txt::ParagraphStyle paragraph_style; + paragraph_style.break_strategy = minikin::kBreakStrategy_HighQuality; + auto font_collection = FontCollection::GetFontCollection(txt::GetFontDir()); + txt::ParagraphBuilder builder(paragraph_style, &font_collection); + + txt::TextStyle text_style; + text_style.font_size = 30; + text_style.letter_spacing = 0; + text_style.word_spacing = 0; + text_style.color = SK_ColorBLACK; + text_style.height = 1; + builder.PushStyle(text_style); + builder.AddText(u16_text); + + builder.Pop(); + + auto paragraph = builder.Build(); + paragraph->Layout(GetTestCanvasWidth() / 2); + + paragraph->Paint(GetCanvas(), 0, 0); + + ASSERT_TRUE(Snapshot()); + ASSERT_EQ(paragraph->text_.size(), std::string{text}.length()); + for (size_t i = 0; i < u16_text.length(); i++) { + ASSERT_EQ(paragraph->text_[i], u16_text[i]); + } + ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull); + ASSERT_EQ(paragraph->runs_.styles_.size(), 1ull); + ASSERT_TRUE(paragraph->runs_.styles_[0].equals(text_style)); + ASSERT_EQ(paragraph->records_[0].style().color, text_style.color); + ASSERT_EQ(paragraph->GetLineCount(), 4); + ASSERT_TRUE(Snapshot()); } } // namespace txt