Skip to content

Commit d10ad46

Browse files
authored
[web] Fix placeholder-only paragraphs (flutter#24572)
1 parent f7cafe1 commit d10ad46

File tree

2 files changed

+41
-7
lines changed

2 files changed

+41
-7
lines changed

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

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ class TextLayoutService {
107107
// *** THE MAIN MEASUREMENT PART *** //
108108
// ********************************* //
109109

110+
final isLastSpan = spanIndex == spanCount - 1;
111+
110112
if (span is PlaceholderSpan) {
111113
if (currentLine.widthIncludingSpace + span.width <= constraints.width) {
112114
// The placeholder fits on the current line.
@@ -119,6 +121,11 @@ class TextLayoutService {
119121
}
120122
currentLine.addPlaceholder(span);
121123
}
124+
125+
if (isLastSpan) {
126+
lines.add(currentLine.build());
127+
break;
128+
}
122129
} else if (span is FlatTextSpan) {
123130
spanometer.currentSpan = span;
124131
final LineBreakResult nextBreak = currentLine.findNextBreak(span.end);
@@ -219,17 +226,23 @@ class TextLayoutService {
219226
minIntrinsicWidth = widthOfLastSegment;
220227
}
221228

229+
// Max intrinsic width includes the width of trailing spaces.
230+
if (maxIntrinsicWidth < currentLine.widthIncludingSpace) {
231+
maxIntrinsicWidth = currentLine.widthIncludingSpace;
232+
}
233+
222234
if (currentLine.end.isHard) {
223-
// Max intrinsic width includes the width of trailing spaces.
224-
if (maxIntrinsicWidth < currentLine.widthIncludingSpace) {
225-
maxIntrinsicWidth = currentLine.widthIncludingSpace;
226-
}
227235
currentLine = currentLine.nextLine();
228236
}
229237

230238
// Only go to the next span if we've reached the end of this span.
231-
if (currentLine.end.index >= span.end && spanIndex < spanCount - 1) {
232-
span = paragraph.spans[++spanIndex];
239+
if (currentLine.end.index >= span.end) {
240+
if (spanIndex < spanCount - 1) {
241+
span = paragraph.spans[++spanIndex];
242+
} else {
243+
// We reached the end of the last span in the paragraph.
244+
break;
245+
}
233246
}
234247
}
235248
}
@@ -632,7 +645,10 @@ class LineSegment {
632645
double get widthOfTrailingSpace => widthIncludingSpace - width;
633646

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

638654
/// Builds instances of [EngineLineMetrics] for the given [paragraph].

lib/web_ui/test/text/layout_service_rich_test.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,22 @@ void testMain() async {
149149
l('ipsum', 6, 11, hardBreak: true, width: 50.0, left: 0.0),
150150
]);
151151
});
152+
153+
test('should handle placeholder-only paragraphs', () {
154+
final EngineParagraphStyle paragraphStyle = EngineParagraphStyle(
155+
fontFamily: 'ahem',
156+
fontSize: 10,
157+
textAlign: ui.TextAlign.center,
158+
);
159+
final CanvasParagraph paragraph = rich(paragraphStyle, (builder) {
160+
builder.addPlaceholder(300.0, 50.0, ui.PlaceholderAlignment.baseline, baseline: ui.TextBaseline.alphabetic);
161+
})..layout(constrain(500.0));
162+
163+
expect(paragraph.maxIntrinsicWidth, 300.0);
164+
expect(paragraph.minIntrinsicWidth, 300.0);
165+
expect(paragraph.height, 50.0);
166+
expectLines(paragraph, [
167+
l('', 0, 0, hardBreak: false, width: 300.0, left: 100.0),
168+
]);
169+
});
152170
}

0 commit comments

Comments
 (0)