未验证 提交 b6ba69ba 编写于 作者: J Jason Simmons 提交者: GitHub

libtxt: add boxes representing empty lines in GetRectsForRange (#5043)

If the start/end range passed to GetRectsForRange includes lines of text
that did not render any glyphs, then GetRectsForRange should add a placeholder
for that line.  In particular, the framework expects this so that it can
position the cursor on an empty line when editing text.

Fixes https://github.com/flutter/flutter/issues/16418
上级 388f0199
......@@ -249,7 +249,7 @@ bool Paragraph::ComputeLineBreaks() {
size_t block_size = block_end - block_start;
if (block_size == 0) {
line_ranges_.emplace_back(block_start, block_start, true);
line_ranges_.emplace_back(block_start, block_end, block_end + 1, true);
line_widths_.push_back(0);
continue;
}
......@@ -297,8 +297,13 @@ bool Paragraph::ComputeLineBreaks() {
const int* breaks = breaker_.getBreaks();
for (size_t i = 0; i < breaks_count; ++i) {
size_t break_start = (i > 0) ? breaks[i - 1] : 0;
line_ranges_.emplace_back(break_start + block_start,
breaks[i] + block_start, i == breaks_count - 1);
size_t line_start = break_start + block_start;
size_t line_end = breaks[i] + block_start;
bool hard_break = i == breaks_count - 1;
size_t line_end_including_newline =
(hard_break && line_end < text_.size()) ? line_end + 1 : line_end;
line_ranges_.emplace_back(line_start, line_end,
line_end_including_newline, hard_break);
line_widths_.push_back(breaker_.getWidths()[i]);
}
......@@ -437,9 +442,9 @@ void Paragraph::Layout(double width, bool force) {
std::vector<Range<size_t>> words;
double word_gap_width = 0;
size_t word_index = 0;
bool justify_line = (paragraph_style_.text_align == TextAlign::justify &&
line_number != line_limit - 1 &&
!line_ranges_[line_number].hard_break);
bool justify_line =
(paragraph_style_.text_align == TextAlign::justify &&
line_number != line_limit - 1 && !line_range.hard_break);
FindWords(text_, line_range.start, line_range.end, &words);
if (justify_line) {
if (words.size() > 1) {
......@@ -986,7 +991,7 @@ void Paragraph::PaintDecorations(SkCanvas* canvas, const PaintRecord& record) {
std::vector<Paragraph::TextBox> Paragraph::GetRectsForRange(size_t start,
size_t end) const {
std::vector<TextBox> boxes;
std::map<size_t, std::vector<Paragraph::TextBox>> line_boxes;
for (const CodeUnitRun& run : code_unit_runs_) {
if (run.code_units.start >= end)
......@@ -1014,10 +1019,34 @@ std::vector<Paragraph::TextBox> Paragraph::GetRectsForRange(size_t start,
if (left == SK_ScalarMax || right == SK_ScalarMin)
continue;
}
boxes.emplace_back(SkRect::MakeLTRB(left, top, right, bottom),
run.direction);
line_boxes[run.line_number].emplace_back(
SkRect::MakeLTRB(left, top, right, bottom), run.direction);
}
// Add empty rectangles representing any line within the range that did not
// render any glyphs.
for (size_t line_number = 0; line_number < line_ranges_.size(); ++line_number) {
const LineRange& line = line_ranges_[line_number];
if (line.start >= end)
break;
if (line.end_including_newline <= start)
continue;
if (line_boxes.find(line_number) == line_boxes.end()) {
// If the range starts after the beginning of this line, then place the
// rectangle at the end of the line's width. This is intended to
// handle ranges encompassing the newline character at the end of a line.
SkScalar x = (start > line.start) ? line_widths_[line_number] : 0;
SkScalar top = (line_number > 0) ? line_heights_[line_number - 1] : 0;
SkScalar bottom = line_heights_[line_number];
line_boxes[line_number].emplace_back(
SkRect::MakeLTRB(x, top, x, bottom), TextDirection::ltr);
}
}
std::vector<Paragraph::TextBox> boxes;
for (const auto& kv : line_boxes) {
boxes.insert(boxes.end(), kv.second.begin(), kv.second.end());
}
return boxes;
}
......
......@@ -63,8 +63,8 @@ class Paragraph {
};
struct TextBox {
const SkRect rect;
const TextDirection direction;
SkRect rect;
TextDirection direction;
TextBox(SkRect r, TextDirection d) : rect(r), direction(d) {}
};
......@@ -187,8 +187,10 @@ class Paragraph {
mutable std::unique_ptr<icu::BreakIterator> word_breaker_;
struct LineRange {
LineRange(size_t s, size_t e, bool h) : start(s), end(e), hard_break(h) {}
LineRange(size_t s, size_t e, size_t ewn, bool h)
: start(s), end(e), end_including_newline(ewn), hard_break(h) {}
size_t start, end;
size_t end_including_newline;
bool hard_break;
};
std::vector<LineRange> line_ranges_;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册