libtxt: use an ICU character iterator that can handle complex grapheme clusters (flutter/engine#4548)
This commit is contained in:
@@ -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<double>::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<size_t> 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<int32_t>(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<double>::quiet_NaN();
|
||||
}
|
||||
}
|
||||
|
||||
code_unit_index = next_code_unit_index;
|
||||
}
|
||||
|
||||
SkPaint::FontMetrics metrics;
|
||||
|
||||
@@ -182,6 +182,7 @@ class Paragraph {
|
||||
std::shared_ptr<FontCollection> font_collection_;
|
||||
|
||||
minikin::LineBreaker breaker_;
|
||||
std::unique_ptr<icu::BreakIterator> grapheme_breaker_;
|
||||
mutable std::unique_ptr<icu::BreakIterator> word_breaker_;
|
||||
|
||||
struct LineRange {
|
||||
|
||||
Reference in New Issue
Block a user