Skip to content

Soft hyphen is not counted when choosing a line break, so it can overflow #194582

Closed

Description

@dbebawy

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:

Image

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

  1. saurabh-mirajkar commented on Oct 19, 2026

    @saurabh-mirajkar
    Contributor

    @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
    00:04 +0 -1: the rendered soft hyphen fits within the paragraph width [E]                                             
      Expected: a value less than or equal to <55>
        Actual: <60.0>
         Which: is not a value less than or equal to <55>
      
      package:matcher                                     expect
      package:flutter_test/src/widget_tester.dart 476:18  expect
      test/soft_hyphen_test.dart 19:5                     main.<fn>
      
    
    To run this test again: /Users/admin/develop/flutter_dev/bin/cache/dart-sdk/bin/dart test /Users/admin/develop/projects/issue_194582_repro/test/soft_hyphen_test.dart -p vm --plain-name 'the rendered soft hyphen fits within the paragraph width'
    00:04 +0 -1: Some tests failed.              
    master
    Flutter 3.50.0-1.0.pre-122 • channel master • https://github.com/saurabh-mirajkar/flutter.git
    Framework • revision f2cf71a790 (69 minutes ago) • 2026-10-19 09:54:37 +0000
    Engine • hash e0462bb4b7f33fb7bf4c59ba2a73cfa1d0385ce1 (revision 2f3aa2ced6) (12 hours ago) • 2026-10-18 21:57:22.000Z
    Tools • Dart 3.15.0 (build 3.15.0-47.0.dev) • DevTools 2.61.0
  2. added
    engineflutter/engine related. See also e: labels.
    a: typographyText rendering, possibly libtxt
    c: renderingUI glitches reported at the engine/skia or impeller rendering level
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    and removed
    in triagePresently being triaged by the triage team
    on Oct 19, 2026
  3. gaaclarke commented on Oct 19, 2026

    @gaaclarke
    Member

    fyi @Rusino, I know there is a CL in progress for this.

  4. added
    P2Important issues not at the top of the work list
    on Oct 19, 2026
  5. assigned and unassigned on Oct 23, 2026
  6. dbebawy commented on Oct 23, 2026

    @dbebawy
    ContributorAuthor

    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 longestLine is 40.

    Image Image

    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.

  7. github-actions commented on Nov 7, 2026

    @github-actions

    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 -v and a minimal reproduction of the issue.

  8. locked as resolved and limited conversation to collaborators on Nov 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P2Important issues not at the top of the work lista: typographyText rendering, possibly libtxtc: renderingUI glitches reported at the engine/skia or impeller rendering leveldependency: skiaSkia team may need to help usengineflutter/engine related. See also e: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onteam-engineOwned by Engine teamtriaged-engineTriaged by Engine team

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions