Repository navigation
Description
Steps to reproduce
With Hyphens.manual (the default since #185152), lay out text whose line breaks at a soft hyphen (U+00AD) when the line would not fit with the hyphen added, but an earlier break opportunity exists on the same line.
Expected results
The hyphen fits within the paragraph width. Browsers count the hyphen when choosing a soft-hyphen break: if the break does not fit with its hyphen, they break at the previous opportunity on the line instead, such as a space or an earlier soft hyphen. In Chrome (hyphens: manual), the example below gives the lines "ab" and "cdef". Browsers let the hyphen overflow only when the soft hyphen is the first break opportunity on the line, so splitting the word is the only option.
Actual results
The lines are "ab cd-" and "ef", and longestLine is 60, wider than the 55 constraint. The hyphen is drawn past the paragraph width and paints outside the Text widget's bounds, unclipped. TextPainter.width and the RenderParagraph size stay at 55, so Flutter's overflow handling does not see it. With real fonts this is a few pixels:
The same text in Georgia at 22px in a 226px box; the red line is the box edge. Flutter draws "incompre-" past the edge. Chrome breaks at the earlier soft hyphen instead ("incom-").
Code sample
import 'dart:ui' as ui;
import 'package:flutter_test/flutter_test.dart';
void main() {
test('the rendered soft hyphen fits within the paragraph width', () {
// With the FlutterTest font at 10px, every glyph, including the space, is 10 wide.
final ui.ParagraphBuilder builder = ui.ParagraphBuilder(
ui.ParagraphStyle(fontFamily: 'FlutterTest', fontSize: 10, hyphens: ui.Hyphens.manual),
)..addText('ab cd\u00ADef');
final ui.Paragraph paragraph = builder.build()
..layout(const ui.ParagraphConstraints(width: 55));
expect(paragraph.longestLine, lessThanOrEqualTo(55)); // Fails: 60.0
});
}Cause
The layout comes from Skia's skparagraph. TextWrapper::lookAhead chooses the break without counting the hyphen, and TextLine::createSoftHyphen adds the hyphen after the line is built, so the framework cannot correct it after layout. A fix in the skparagraph line breaker is in review: https://skia-review.googlesource.com/c/skia/+/1397276.
Flutter version
master at a3d71d8 (2026-10-16).
Activity
saurabh-mirajkar commentedon Oct 19, 2026
@dbebawy Thanks for the detailed report. I reproduced this on master. I'll label this and route it to the engine team for further investigation.
Related: #185154
Test Result
master
gaaclarke commentedon Oct 19, 2026
fyi @Rusino, I know there is a CL in progress for this.
[skparagraph] Reserve room for the hyphen at soft hyphen line breaks
[skparagraph] Count the hyphen in min intrinsic width at soft hyphens
[skparagraph] Count only soft hyphens when measuring too-long words
dbebawy commentedon Oct 23, 2026
Fixed in Skia, and now in Flutter master:
The code sample in the issue now passes on master: the lines are "ab" and "cdef", and
longestLineis 40.The same text as the image in the issue description, as the box narrows from 300px to 171px and back. Before the fix, the hyphen crosses the box edge at 18 of the 44 widths. On master it never does, and the line breaks match Chrome.
As in browsers, the hyphen can still extend past the edge when the soft hyphen is the first break opportunity on a line, since the only alternative would be splitting the word.
The Skia changes include their own tests. Thanks @Rusino for the reviews and the edge-case fixes.
[skparagraph] Leave room for the soft hyphen when justifying
github-actions commentedon Nov 7, 2026
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of
flutter doctor -vand a minimal reproduction of the issue.