libtxt: use an ICU character iterator that can handle complex grapheme clusters (flutter/engine#4548)

This commit is contained in:
Jason Simmons
2018-01-16 10:43:00 -08:00
committed by GitHub
parent e7c2f2dfb6
commit 6590ae48d6
2 changed files with 31 additions and 27 deletions

View File

@@ -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;

View File

@@ -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 {