libtxt: support justification of RTL text (flutter/engine#7719)
Fixes https://github.com/flutter/flutter/issues/25567
This commit is contained in:
@@ -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<GlyphPosition> line_glyph_positions;
|
||||
std::vector<CodeUnitRun> 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)) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<std::string>(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;
|
||||
|
||||
Reference in New Issue
Block a user