Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions lib/web_ui/lib/src/engine/text/layout_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ class TextLayoutService {
// *** THE MAIN MEASUREMENT PART *** //
// ********************************* //

final isLastSpan = spanIndex == spanCount - 1;

if (span is PlaceholderSpan) {
if (currentLine.widthIncludingSpace + span.width <= constraints.width) {
// The placeholder fits on the current line.
Expand All @@ -119,6 +121,11 @@ class TextLayoutService {
}
currentLine.addPlaceholder(span);
}

if (isLastSpan) {
lines.add(currentLine.build());
break;
}
} else if (span is FlatTextSpan) {
spanometer.currentSpan = span;
final LineBreakResult nextBreak = currentLine.findNextBreak(span.end);
Expand Down Expand Up @@ -219,17 +226,23 @@ class TextLayoutService {
minIntrinsicWidth = widthOfLastSegment;
}

// Max intrinsic width includes the width of trailing spaces.
if (maxIntrinsicWidth < currentLine.widthIncludingSpace) {
maxIntrinsicWidth = currentLine.widthIncludingSpace;
}

if (currentLine.end.isHard) {
// Max intrinsic width includes the width of trailing spaces.
if (maxIntrinsicWidth < currentLine.widthIncludingSpace) {
maxIntrinsicWidth = currentLine.widthIncludingSpace;
}
currentLine = currentLine.nextLine();
}

// Only go to the next span if we've reached the end of this span.
if (currentLine.end.index >= span.end && spanIndex < spanCount - 1) {
span = paragraph.spans[++spanIndex];
if (currentLine.end.index >= span.end) {
if (spanIndex < spanCount - 1) {
span = paragraph.spans[++spanIndex];
} else {
// We reached the end of the last span in the paragraph.
break;
}
}
}
}
Expand Down Expand Up @@ -632,7 +645,10 @@ class LineSegment {
double get widthOfTrailingSpace => widthIncludingSpace - width;

/// Whether this segment is made of only white space.
bool get isSpaceOnly => start.index == end.indexWithoutTrailingSpaces;
///
/// We rely on the [width] to determine this because relying on incides
/// doesn't work well for placeholders (they are zero-length strings).
bool get isSpaceOnly => width == 0;
}

/// Builds instances of [EngineLineMetrics] for the given [paragraph].
Expand Down
18 changes: 18 additions & 0 deletions lib/web_ui/test/text/layout_service_rich_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,22 @@ void testMain() async {
l('ipsum', 6, 11, hardBreak: true, width: 50.0, left: 0.0),
]);
});

test('should handle placeholder-only paragraphs', () {
final EngineParagraphStyle paragraphStyle = EngineParagraphStyle(
fontFamily: 'ahem',
fontSize: 10,
textAlign: ui.TextAlign.center,
);
final CanvasParagraph paragraph = rich(paragraphStyle, (builder) {
builder.addPlaceholder(300.0, 50.0, ui.PlaceholderAlignment.baseline, baseline: ui.TextBaseline.alphabetic);
})..layout(constrain(500.0));

expect(paragraph.maxIntrinsicWidth, 300.0);
expect(paragraph.minIntrinsicWidth, 300.0);
expect(paragraph.height, 50.0);
expectLines(paragraph, [
l('', 0, 0, hardBreak: false, width: 300.0, left: 100.0),
]);
});
}