diff --git a/engine/src/flutter/third_party/txt/src/txt/paragraph.cc b/engine/src/flutter/third_party/txt/src/txt/paragraph.cc index 127c22061b..8147ec7dc9 100644 --- a/engine/src/flutter/third_party/txt/src/txt/paragraph.cc +++ b/engine/src/flutter/third_party/txt/src/txt/paragraph.cc @@ -362,6 +362,14 @@ void Paragraph::Layout(double width, bool force) { if (!ComputeBidiRuns(&bidi_runs)) return; + if (!grapheme_breaker_) { + UErrorCode icu_status = U_ZERO_ERROR; + grapheme_breaker_.reset( + icu::BreakIterator::createCharacterInstance(icu::Locale(), icu_status)); + if (!U_SUCCESS(icu_status)) + return; + } + SkPaint paint; paint.setAntiAlias(true); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); @@ -489,13 +497,11 @@ void Paragraph::Layout(double width, bool force) { blob_start += blob_len; } - size_t code_unit_index; - if (run.is_rtl()) { - code_unit_index = text_count; - U16_BACK_1(text_ptr + text_start, 0, code_unit_index); - } else { - code_unit_index = 0; - } + grapheme_breaker_->setText( + icu::UnicodeString(false, text_ptr + text_start, text_count)); + if (run.is_rtl()) + grapheme_breaker_->preceding(text_count); + double word_start_position = std::numeric_limits::quiet_NaN(); // Build a Skia text blob from each group of glyphs. @@ -516,34 +522,33 @@ void Paragraph::Layout(double width, bool force) { blob_buffer.pos[pos_index] = glyph_x_offset; blob_buffer.pos[pos_index + 1] = layout.getY(glyph_index); + int32_t current_grapheme = grapheme_breaker_->current(); if (word_index < words.size() && - words[word_index].start == run.start + code_unit_index) { + words[word_index].start == run.start + current_grapheme) { word_start_position = run_x_offset + glyph_x_offset; } - float glyph_advance = layout.getCharAdvance(code_unit_index); + float glyph_advance = layout.getCharAdvance(current_grapheme); // The glyph may be a ligature. Determine how many input characters // are joined into this glyph. Note that each character may be // encoded as multiple UTF-16 code units. std::vector subglyph_code_unit_counts; - size_t next_code_unit_index = code_unit_index; + int32_t next_grapheme; if (run.is_rtl()) { - U16_BACK_1(text_ptr + text_start, 0, next_code_unit_index); - subglyph_code_unit_counts.push_back(code_unit_index - - next_code_unit_index); + next_grapheme = grapheme_breaker_->previous(); + subglyph_code_unit_counts.push_back(current_grapheme - + next_grapheme); } else { - U16_FWD_1(text_ptr + text_start, next_code_unit_index, text_count); - subglyph_code_unit_counts.push_back(next_code_unit_index - - code_unit_index); - while (next_code_unit_index < text_count) { - if (layout.getCharAdvance(next_code_unit_index) != 0) + next_grapheme = grapheme_breaker_->next(); + subglyph_code_unit_counts.push_back(next_grapheme - + current_grapheme); + while (next_grapheme < static_cast(text_count)) { + if (layout.getCharAdvance(next_grapheme) != 0) break; - size_t cur_code_unit_index = next_code_unit_index; - U16_FWD_1(text_ptr + text_start, next_code_unit_index, - text_count); - subglyph_code_unit_counts.push_back(next_code_unit_index - - cur_code_unit_index); + size_t sub_grapheme = grapheme_breaker_->current(); + next_grapheme = grapheme_breaker_->next(); + subglyph_code_unit_counts.push_back(next_grapheme - sub_grapheme); } } float subglyph_advance = @@ -551,7 +556,7 @@ void Paragraph::Layout(double width, bool force) { glyph_positions.emplace_back( run_x_offset + glyph_x_offset, subglyph_advance, - run.start + code_unit_index, subglyph_code_unit_counts[0]); + run.start + current_grapheme, subglyph_code_unit_counts[0]); // Compute positions for the additional characters in the ligature. for (size_t i = 1; i < subglyph_code_unit_counts.size(); ++i) { @@ -563,7 +568,7 @@ void Paragraph::Layout(double width, bool force) { } if (word_index < words.size() && - words[word_index].end == run.start + next_code_unit_index) { + words[word_index].end == run.start + next_grapheme) { if (justify_line) justify_x_offset += word_gap_width; word_index++; @@ -575,8 +580,6 @@ void Paragraph::Layout(double width, bool force) { word_start_position = std::numeric_limits::quiet_NaN(); } } - - code_unit_index = next_code_unit_index; } SkPaint::FontMetrics metrics; diff --git a/engine/src/flutter/third_party/txt/src/txt/paragraph.h b/engine/src/flutter/third_party/txt/src/txt/paragraph.h index 438531cef7..57a95cf99e 100644 --- a/engine/src/flutter/third_party/txt/src/txt/paragraph.h +++ b/engine/src/flutter/third_party/txt/src/txt/paragraph.h @@ -182,6 +182,7 @@ class Paragraph { std::shared_ptr font_collection_; minikin::LineBreaker breaker_; + std::unique_ptr grapheme_breaker_; mutable std::unique_ptr word_breaker_; struct LineRange {