Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit c8c353d

Browse files
committed
[web] Refactor line breaker to resemble how v8BreakIterator works
1 parent 7f2af2c commit c8c353d

File tree

3 files changed

+342
-245
lines changed

3 files changed

+342
-245
lines changed

lib/web_ui/lib/src/engine/text/layout_service.dart

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ class TextLayoutService {
5959
String? get ellipsis => paragraph.paragraphStyle.ellipsis;
6060
bool get hasEllipsis => ellipsis != null;
6161

62+
late final List<LineBreakResult> breaks = computeLineBreaks(paragraph.toPlainText());
63+
6264
/// Performs the layout on a paragraph given the [constraints].
6365
///
6466
/// The function starts by resetting all layout-related properties. Then it
@@ -142,7 +144,7 @@ class TextLayoutService {
142144
spanIndex++;
143145
} else if (span is FlatTextSpan) {
144146
spanometer.currentSpan = span;
145-
final DirectionalPosition nextBreak = currentLine.findNextBreak();
147+
final DirectionalPosition nextBreak = findNextBreak(currentLine);
146148
final double additionalWidth =
147149
currentLine.getAdditionalWidthTo(nextBreak.lineBreak);
148150

@@ -275,7 +277,7 @@ class TextLayoutService {
275277
spanIndex++;
276278
} else if (span is FlatTextSpan) {
277279
spanometer.currentSpan = span;
278-
final DirectionalPosition nextBreak = currentLine.findNextBreak();
280+
final DirectionalPosition nextBreak = findNextBreak(currentLine);
279281

280282
// For the purpose of max intrinsic width, we don't care if the line
281283
// fits within the constraints or not. So we always extend it.
@@ -395,6 +397,24 @@ class TextLayoutService {
395397
}
396398
}
397399

400+
/// Finds the next line break after the end of the line being built.
401+
DirectionalPosition findNextBreak(LineBuilder lineBuilder) {
402+
final String text = paragraph.toPlainText();
403+
final int maxEnd = lineBuilder.spanometer.currentSpan.end;
404+
405+
int i = lineBuilder.end.index;
406+
LineBreakResult nextBreak = breaks[i];
407+
while (++i <= maxEnd) {
408+
nextBreak = breaks[i];
409+
if (nextBreak.type != LineBreakType.prohibited) {
410+
break;
411+
}
412+
}
413+
414+
// The current end of the line is the beginning of the next block.
415+
return getDirectionalBlockEnd(text, lineBuilder.end, nextBreak);
416+
}
417+
398418
/// Positions a sequence of boxes in the direction opposite to the paragraph
399419
/// text direction.
400420
///
@@ -1540,23 +1560,6 @@ class LineBuilder {
15401560
}
15411561
}
15421562

1543-
LineBreakResult? _cachedNextBreak;
1544-
1545-
/// Finds the next line break after the end of this line.
1546-
DirectionalPosition findNextBreak() {
1547-
LineBreakResult? nextBreak = _cachedNextBreak;
1548-
final String text = paragraph.toPlainText();
1549-
// Don't recompute the `nextBreak` until the line has reached the previously
1550-
// computed `nextBreak`.
1551-
if (nextBreak == null || end.index >= nextBreak.index) {
1552-
final int maxEnd = spanometer.currentSpan.end;
1553-
nextBreak = nextLineBreak(text, end.index, maxEnd: maxEnd);
1554-
_cachedNextBreak = nextBreak;
1555-
}
1556-
// The current end of the line is the beginning of the next block.
1557-
return getDirectionalBlockEnd(text, end, nextBreak);
1558-
}
1559-
15601563
/// Creates a new [LineBuilder] to build the next line in the paragraph.
15611564
LineBuilder nextLine() {
15621565
return LineBuilder._(

0 commit comments

Comments
 (0)