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 93eb1b2d86..7e11a42a27 100644 --- a/engine/src/flutter/third_party/txt/src/txt/paragraph.cc +++ b/engine/src/flutter/third_party/txt/src/txt/paragraph.cc @@ -201,7 +201,7 @@ void Paragraph::Layout(double width, bool force) { breaker_.setJustified(paragraph_style_.text_align == TextAlign::justify); breaker_.setStrategy(paragraph_style_.break_strategy); - size_t breaks_count = breaker_.computeBreaks(); + breaks_count_ = breaker_.computeBreaks(); const int* breaks = breaker_.getBreaks(); // Create a copy of text_ to use locally so that any changes made to the @@ -226,12 +226,9 @@ void Paragraph::Layout(double width, bool force) { glyph_position_x_ = std::vector>(); std::vector glyph_single_line_position_x; - // Track the x of the previous run to maintain accurate xposition when - // multiple SkTextBlobs make up a single line. - double previous_run_x_position = 0.0f; - SkScalar x = 0.0f; - SkScalar y = 0.0f; + SkScalar x_offset = GetLineXOffset(0); + SkScalar y_offset = 0.0f; size_t break_index = 0; double max_line_spacing = 0.0f; double max_descent = 0.0f; @@ -240,71 +237,13 @@ void Paragraph::Layout(double width, bool force) { double justify_spacing = 0.0f; double prev_word_pos = 0.0f; double prev_char_advance = 0.0f; - double current_x_position = previous_run_x_position; + double current_x_position = 0.0f; std::vector buffers; std::vector buffer_sizes; int word_count = 0; size_t max_lines = paragraph_style_.max_lines; - auto postprocess_line = [this, &x_queue, &y]() -> void { - size_t record_index = 0; - for (size_t i = 0; i < x_queue.size(); ++i) { - record_index = records_.size() - (x_queue.size() - i); - records_[record_index].SetOffset(SkPoint::Make(x_queue[i], y)); - // Adjust the offsets for each of the different alignments. - switch (paragraph_style_.text_align) { - case TextAlign::left: - break; - case TextAlign::right: { - records_[record_index].SetOffset(SkPoint::Make( - records_[record_index].offset().x() + width_ - - breaker_.getWidths()[records_[record_index].line()], - records_[record_index].offset().y())); - break; - } - case TextAlign::center: { - records_[record_index].SetOffset(SkPoint::Make( - records_[record_index].offset().x() + - (width_ - - breaker_.getWidths()[records_[record_index].line()]) / - 2, - records_[record_index].offset().y())); - break; - } - case TextAlign::justify: { - break; - } - } - } - // Correct positions stored in the member vars. - for (size_t y_index = 0; y_index < lines_; ++y_index) { - switch (paragraph_style_.text_align) { - case TextAlign::left: - break; - case TextAlign::right: { - for (size_t i = 0; i < glyph_position_x_[y_index].size(); ++i) { - glyph_position_x_[y_index][i].start += - width_ - breaker_.getWidths()[y_index]; - } - break; - } - case TextAlign::center: { - for (size_t i = 0; i < glyph_position_x_[y_index].size(); ++i) { - glyph_position_x_[y_index][i].start += - (width_ - breaker_.getWidths()[y_index]) / 2; - } - break; - } - case TextAlign::justify: { - // TODO(garyq): Track position changes due to justify in justify - // method. - break; - } - } - } - x_queue.clear(); - }; for (size_t run_index = 0; run_index < runs_.size(); ++run_index) { auto run = runs_.GetRun(run_index); bool is_newline = text_[run.start] == '\n' && run.end - run.start == 1; @@ -319,7 +258,7 @@ void Paragraph::Layout(double width, bool force) { size_t layout_start = run.start; // Layout until the end of the run or too many lines. while (layout_start < run.end && lines_ < max_lines) { - const size_t next_break = (break_index > breaks_count - 1) + const size_t next_break = (break_index > breaks_count_ - 1) ? std::numeric_limits::max() : breaks[break_index]; const size_t layout_end = std::min(run.end, next_break); @@ -441,8 +380,7 @@ void Paragraph::Layout(double width, bool force) { size_t ligature_width = ligature_end - character_index; float subglyph_advance = glyph_advance / ligature_width; glyph_single_line_position_x.emplace_back( - current_x_position + previous_run_x_position + letter_spacing, - subglyph_advance); + x_offset + current_x_position + letter_spacing, subglyph_advance); // Compute positions for the additional characters in the ligature. for (size_t i = 1; i < ligature_width; ++i) { @@ -469,7 +407,6 @@ void Paragraph::Layout(double width, bool force) { } } blob_start += blob_length; - previous_run_x_position += current_x_position + letter_spacing; } // TODO(abarth): We could keep the same SkTextBlobBuilder as long as the @@ -486,7 +423,7 @@ void Paragraph::Layout(double width, bool force) { // Must adjust each line to the largest text in the line, so cannot // directly push the offset property of PaintRecord until line is // finished. - x_queue.push_back(x); + x_queue.push_back(x_offset); temp_line_spacing = lines_ == 0 ? -metrics.fAscent * run.style.height : (-metrics.fAscent + metrics.fLeading) * @@ -506,27 +443,31 @@ void Paragraph::Layout(double width, bool force) { max_descent = temp_line_spacing; if (layout_end == next_break || is_newline) { - y += roundf(max_line_spacing + prev_max_descent); + y_offset += roundf(max_line_spacing + prev_max_descent); + for (size_t i = 0; i < x_queue.size(); ++i) { + PaintRecord& record = records_[records_.size() - x_queue.size() + i]; + record.SetOffset(SkPoint::Make(x_queue[i], y_offset)); + } + x_queue.clear(); + line_heights_.push_back( (line_heights_.empty() ? 0 : line_heights_.back()) + roundf(max_line_spacing + max_descent)); glyph_position_x_.push_back(glyph_single_line_position_x); prev_max_descent = max_descent; - postprocess_line(); // Reset Variables for next line. max_line_spacing = 0.0f; max_descent = 0.0f; - x = 0.0f; prev_word_pos = 0; prev_char_advance = 0.0f; - previous_run_x_position = 0.0f; current_x_position = 0.0f; break_index += 1; lines_++; + x_offset = GetLineXOffset(lines_); glyph_single_line_position_x.clear(); } else { - x += layout.getAdvance(); + x_offset += layout.getAdvance(); } layout_start = layout_end; @@ -542,6 +483,19 @@ void Paragraph::Layout(double width, bool force) { breaker_.finish(); } +double Paragraph::GetLineXOffset(size_t line) { + if (line >= breaks_count_) + return 0; + + if (paragraph_style_.text_align == TextAlign::right) { + return width_ - breaker_.getWidths()[line]; + } else if (paragraph_style_.text_align == TextAlign::center) { + return (width_ - breaker_.getWidths()[line]) / 2; + } else { + return 0; + } +} + // Amends the buffers to incorporate justification. void Paragraph::JustifyLine( std::vector& buffers, 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 0bdaa5d6b8..0deaede94b 100644 --- a/engine/src/flutter/third_party/txt/src/txt/paragraph.h +++ b/engine/src/flutter/third_party/txt/src/txt/paragraph.h @@ -179,6 +179,7 @@ class Paragraph { std::shared_ptr font_collection_; minikin::LineBreaker breaker_; + size_t breaks_count_ = 0; // Stores the result of Layout(). std::vector records_; @@ -243,6 +244,10 @@ class Paragraph { // justifying. void FillWhitespaceSet(size_t start, size_t end, hb_font_t* hb_font); + // Calculate the starting X offset of a line based on the line's width and + // alignment. + double GetLineXOffset(size_t line); + // Calculates and amends the layout for one line to be justified. void JustifyLine(std::vector& buffers, std::vector& buffer_sizes,