diff --git a/third_party/txt/src/txt/paragraph.cc b/third_party/txt/src/txt/paragraph.cc index c5e10fa0776be22970b769d00c50c3785e9fb3db..65efccc8a1f1ba93f72104ef3502918611d7c697 100644 --- a/third_party/txt/src/txt/paragraph.cc +++ b/third_party/txt/src/txt/paragraph.cc @@ -534,11 +534,12 @@ void Paragraph::Layout(double width, bool force) { } } - // Exclude trailing whitespace from right and center-justified lines so the - // last visible character in the line will be flush with the right margin. + // Exclude trailing whitespace from justified lines so the last visible + // character in the line will be flush with the right margin. size_t line_end_index = (paragraph_style_.effective_align() == TextAlign::right || - paragraph_style_.effective_align() == TextAlign::center) + paragraph_style_.effective_align() == TextAlign::center || + paragraph_style_.effective_align() == TextAlign::justify) ? line_range.end_excluding_whitespace : line_range.end; @@ -552,6 +553,14 @@ void Paragraph::Layout(double width, bool force) { bidi_run.direction(), bidi_run.style()); } } + bool line_runs_all_rtl = + line_runs.size() && + std::accumulate( + line_runs.begin(), line_runs.end(), true, + [](const bool a, const BidiRun& b) { return a && b.is_rtl(); }); + if (line_runs_all_rtl) { + std::reverse(words.begin(), words.end()); + } std::vector line_glyph_positions; std::vector line_code_unit_runs; @@ -720,15 +729,26 @@ void Paragraph::Layout(double width, bool force) { grapheme_code_unit_counts[i]); } - if (word_index < words.size() && - words[word_index].start == run.start() + glyph_code_units.start) { + bool at_word_start = false; + bool at_word_end = false; + if (word_index < words.size()) { + at_word_start = + words[word_index].start == run.start() + glyph_code_units.start; + at_word_end = + words[word_index].end == run.start() + glyph_code_units.end; + if (line_runs_all_rtl) { + std::swap(at_word_start, at_word_end); + } + } + + if (at_word_start) { word_start_position = run_x_offset + glyph_x_offset; } - if (word_index < words.size() && - words[word_index].end == run.start() + glyph_code_units.end) { - if (justify_line) + if (at_word_end) { + if (justify_line) { justify_x_offset += word_gap_width; + } word_index++; if (!isnan(word_start_position)) { diff --git a/third_party/txt/src/txt/paragraph.h b/third_party/txt/src/txt/paragraph.h index 3ce1ae197973f28243a713533a0027bccfa5cb37..2866eeaf80335143df5a856012a67e0aaf3f41d4 100644 --- a/third_party/txt/src/txt/paragraph.h +++ b/third_party/txt/src/txt/paragraph.h @@ -212,6 +212,7 @@ class Paragraph { FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, RightAlignParagraph); FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, CenterAlignParagraph); FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, JustifyAlignParagraph); + FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, JustifyRTL); FRIEND_TEST(ParagraphTest, DecorationsParagraph); FRIEND_TEST(ParagraphTest, ItalicsParagraph); FRIEND_TEST(ParagraphTest, ChineseParagraph); diff --git a/third_party/txt/tests/paragraph_unittests.cc b/third_party/txt/tests/paragraph_unittests.cc index 13c41e48904017b59ab4620c339f74232d055dcf..5e37ae1d330923b11bbe87818747b5f7e03a03df 100644 --- a/third_party/txt/tests/paragraph_unittests.cc +++ b/third_party/txt/tests/paragraph_unittests.cc @@ -669,6 +669,53 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(JustifyAlignParagraph)) { ASSERT_TRUE(Snapshot()); } +TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(JustifyRTL)) { + const char* text = + "אאא בּבּבּבּ אאאא בּבּ אאא בּבּבּ אאאאא בּבּבּבּ אאאא בּבּבּבּבּ " + "אאאאא בּבּבּבּבּ אאאבּבּבּבּבּבּאאאאא בּבּבּבּבּבּאאאאאבּבּבּבּבּבּ אאאאא בּבּבּבּבּ " + "אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ"; + + 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.max_lines = 14; + paragraph_style.text_align = TextAlign::justify; + txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection()); + + txt::TextStyle text_style; + text_style.font_families = std::vector(1, "Ahem"); + text_style.font_size = 26; + text_style.color = SK_ColorBLACK; + text_style.height = 1; + builder.PushStyle(text_style); + + builder.AddText(u16_text); + + builder.Pop(); + + auto paragraph = builder.Build(); + size_t paragraph_width = GetTestCanvasWidth() - 100; + paragraph->Layout(paragraph_width); + + paragraph->Paint(GetCanvas(), 0, 0); + + ASSERT_TRUE(Snapshot()); + + auto glyph_line_width = [¶graph](int index) { + return paragraph->glyph_lines_[index].positions.back().x_pos.end; + }; + + // All lines except the last should be justified to the width of the + // paragraph. + for (size_t i = 0; i < paragraph->glyph_lines_.size() - 1; ++i) { + ASSERT_EQ(glyph_line_width(i), paragraph_width); + } + ASSERT_NE(glyph_line_width(paragraph->glyph_lines_.size() - 1), + paragraph_width); +} + TEST_F(ParagraphTest, DecorationsParagraph) { txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14;