Repository navigation
Add breaking change page for soft hyphen rendering - #13945
Conversation
Covers flutter/flutter#185152: soft hyphens (U+00AD) now render at line breaks, and TextStyle.getParagraphStyle gained a hyphens parameter.
Lines still break in the same places, and hit testing isn't affected. Note that the web doesn't render soft hyphens yet, and that editable text and SelectableText can't opt out yet. Use \u00AD escapes in the code samples so the soft hyphen is visible.
…5152) ## Summary Adds visible soft hyphen (U+00AD) rendering at line breaks, with a new `Hyphens` API to opt out. Fixes flutter#18443 on native platforms; web rendering is tracked in flutter#193506. A line break that falls on a soft hyphen now renders a visible `-` by default. A new `Hyphens { manual, hidden }` enum controls this: - `Hyphens.manual` (default): render a hyphen at the break. - `Hyphens.hidden`: don't render the hyphen. The soft hyphen is still a break opportunity. `hyphens` is a parameter on `Text` / `RichText`, `TextPainter`, `RenderParagraph`, `TextStyle.getParagraphStyle` and `dart:ui`'s `ParagraphStyle`, following `textAlign` / `maxLines`. It is not a `TextStyle` field. Customizing the hyphen string is deferred to flutter#189617. Design doc: [flutter.dev/go/soft-hyphens](https://flutter.dev/go/soft-hyphens) (tracking issue flutter#185154). ## Background Flutter already breaks lines at U+00AD but never draws the hyphen, so it behaves like a zero-width space. This change doesn't add any new break opportunities or change where lines break, but the rendered hyphen makes its line wider, so it can change `Paragraph.longestLine` and the size of text laid out with `TextWidthBasis.longestLine`. The Skia side landed in [`98daf58d`](google/skia@98daf58d4c) (Skia CL [1208837](https://skia-review.googlesource.com/c/skia/+/1208837)), behind `ParagraphStyle::setRenderSoftHyphens(bool)`, which defaults to `false` for other Skia clients. ## Changes **Engine** - `txt::ParagraphStyle` gains a `render_soft_hyphens` flag (default `true`), which `ParagraphBuilderSkia::TxtToSkia` forwards to `setRenderSoftHyphens`. The Impeller interop toolkit builds `txt::ParagraphStyle` too, so it also gets the new default. - `paragraph_builder.cc` decodes `ParagraphStyle.hyphens` from the FFI buffer (mask bit 13, slot 7). - `dart:ui` adds the public `Hyphens` enum and `ParagraphStyle.hyphens`. The web `dart:ui` accepts and stores the value; web rendering is flutter#193506. **Framework** - `Hyphens` is re-exported from `dart:ui` via `painting/basic_types.dart`. - `hyphens` is threaded through `TextStyle.getParagraphStyle` → `TextPainter` → `RenderParagraph` → `RichText` → `Text` / `Text.rich`, including the selectable-text path. ## Breaking change - **API:** adding `hyphens` to `TextStyle.getParagraphStyle` breaks classes that override it. In practice that's test doubles like the `_TextStyleProxy` in `test/material/theme_test.dart`, updated here; material_ui's copy was removed in flutter/packages#12728. The fix is to add `Hyphens? hyphens` to the override. Migration guide: flutter/website#13945. - **Rendering:** text containing U+00AD now shows a hyphen at soft-hyphen line breaks by default. `Hyphens.hidden` restores the old look. ## Known limitations - The hyphen is appended after line breaking, so a line can exceed `maxWidth` by the hyphen's advance. - The rendered hyphen isn't included in selection highlight rects (flutter#189234). - `EditableText` (and so `TextField`) and `SelectableText` don't take a `hyphens` parameter yet, so they always render the hyphen. - Skia also draws the hyphen when a line ends in U+00AD without breaking there (text ending in U+00AD, or U+00AD right before a space or newline). The Skia fix is in review ([CL 1378356](https://skia-review.googlesource.com/c/skia/+/1378356)) and will come in with a Skia roll once it lands. ## Test plan - [ ] `paragraph_builder_skia_tests.cc::RenderSoftHyphensEnabled`: `render_soft_hyphens` maps onto Skia in both states - [ ] `testing/dart/text_test.dart`: `ParagraphStyle.hyphens` encodes and round-trips in `toString` - [ ] `testing/dart/paragraph_test.dart`: `ParagraphStyle.hyphens` reaches the text layout (a line that breaks at a soft hyphen is wider with `manual` than with `hidden`, and unset matches `manual`), which covers decoding the setting in the engine - [ ] `test/widgets/rich_text_test.dart`: `RichText` exposes `hyphens` via `debugFillProperties` - [ ] `test/widgets/text_test.dart`: `Text` forwards `hyphens` to `RenderParagraph` (incl. selectable path); default resolves to `Hyphens.manual` - [ ] `test/rendering/paragraph_test.dart`: `RenderParagraph.hyphens` setter triggers relayout - [ ] `test/painting/text_painter_test.dart`: `TextPainter.hyphens` setter; the same width check through `TextPainter`, and changing `hyphens` after layout changes the width - [ ] Google internal testing - [ ] Manual smoke: `Text('inter\u00ADnational')` in a narrow container shows `inter-` / `national`
Say the hyphen shows wherever a line breaks at a soft hyphen, and fill in the version where the change landed on master.
There was a problem hiding this comment.
Code Review
This pull request adds a new breaking change document explaining that soft hyphens (U+00AD) now render at line breaks in Flutter, introducing the Hyphens enum and a new hyphens parameter in TextStyle.getParagraphStyle. The review feedback suggests improving the grammar and style guide compliance of a sentence regarding editable text widgets, and updating the migration code example to use the ui. prefix for the Hyphens type to ensure correct compilation.
SelectableText isn't editable, but it's built on EditableText, as TextField is.
|
@sfshaza2 updated per your comments; the one open thread is a small tweak to your wording suggestion. PTAL when you get a chance. |
|
Thanks @dbebawy! The updates addressing the earlier review comments look great (keeping "at a soft hyphen" on line 34 makes sense). It looks like |
…s-breaking-change # Conflicts: # sites/docs/src/content/release/breaking-changes/index.md
|
Thank you, @conooi. I merged |
|
I resolved the conflicts. Landing once the build is happy. |
|
/gcbrun |
|
Staged preview of the updated docs.flutter.dev site (updated for commit f00d81a): |
…5152) ## Summary Adds visible soft hyphen (U+00AD) rendering at line breaks, with a new `Hyphens` API to opt out. Fixes flutter#18443 on native platforms; web rendering is tracked in flutter#193506. A line break that falls on a soft hyphen now renders a visible `-` by default. A new `Hyphens { manual, hidden }` enum controls this: - `Hyphens.manual` (default): render a hyphen at the break. - `Hyphens.hidden`: don't render the hyphen. The soft hyphen is still a break opportunity. `hyphens` is a parameter on `Text` / `RichText`, `TextPainter`, `RenderParagraph`, `TextStyle.getParagraphStyle` and `dart:ui`'s `ParagraphStyle`, following `textAlign` / `maxLines`. It is not a `TextStyle` field. Customizing the hyphen string is deferred to flutter#189617. Design doc: [flutter.dev/go/soft-hyphens](https://flutter.dev/go/soft-hyphens) (tracking issue flutter#185154). ## Background Flutter already breaks lines at U+00AD but never draws the hyphen, so it behaves like a zero-width space. This change doesn't add any new break opportunities or change where lines break, but the rendered hyphen makes its line wider, so it can change `Paragraph.longestLine` and the size of text laid out with `TextWidthBasis.longestLine`. The Skia side landed in [`98daf58d`](google/skia@98daf58d4c) (Skia CL [1208837](https://skia-review.googlesource.com/c/skia/+/1208837)), behind `ParagraphStyle::setRenderSoftHyphens(bool)`, which defaults to `false` for other Skia clients. ## Changes **Engine** - `txt::ParagraphStyle` gains a `render_soft_hyphens` flag (default `true`), which `ParagraphBuilderSkia::TxtToSkia` forwards to `setRenderSoftHyphens`. The Impeller interop toolkit builds `txt::ParagraphStyle` too, so it also gets the new default. - `paragraph_builder.cc` decodes `ParagraphStyle.hyphens` from the FFI buffer (mask bit 13, slot 7). - `dart:ui` adds the public `Hyphens` enum and `ParagraphStyle.hyphens`. The web `dart:ui` accepts and stores the value; web rendering is flutter#193506. **Framework** - `Hyphens` is re-exported from `dart:ui` via `painting/basic_types.dart`. - `hyphens` is threaded through `TextStyle.getParagraphStyle` → `TextPainter` → `RenderParagraph` → `RichText` → `Text` / `Text.rich`, including the selectable-text path. ## Breaking change - **API:** adding `hyphens` to `TextStyle.getParagraphStyle` breaks classes that override it. In practice that's test doubles like the `_TextStyleProxy` in `test/material/theme_test.dart`, updated here; material_ui's copy was removed in flutter/packages#12728. The fix is to add `Hyphens? hyphens` to the override. Migration guide: flutter/website#13945. - **Rendering:** text containing U+00AD now shows a hyphen at soft-hyphen line breaks by default. `Hyphens.hidden` restores the old look. ## Known limitations - The hyphen is appended after line breaking, so a line can exceed `maxWidth` by the hyphen's advance. - The rendered hyphen isn't included in selection highlight rects (flutter#189234). - `EditableText` (and so `TextField`) and `SelectableText` don't take a `hyphens` parameter yet, so they always render the hyphen. - Skia also draws the hyphen when a line ends in U+00AD without breaking there (text ending in U+00AD, or U+00AD right before a space or newline). The Skia fix is in review ([CL 1378356](https://skia-review.googlesource.com/c/skia/+/1378356)) and will come in with a Skia roll once it lands. ## Test plan - [ ] `paragraph_builder_skia_tests.cc::RenderSoftHyphensEnabled`: `render_soft_hyphens` maps onto Skia in both states - [ ] `testing/dart/text_test.dart`: `ParagraphStyle.hyphens` encodes and round-trips in `toString` - [ ] `testing/dart/paragraph_test.dart`: `ParagraphStyle.hyphens` reaches the text layout (a line that breaks at a soft hyphen is wider with `manual` than with `hidden`, and unset matches `manual`), which covers decoding the setting in the engine - [ ] `test/widgets/rich_text_test.dart`: `RichText` exposes `hyphens` via `debugFillProperties` - [ ] `test/widgets/text_test.dart`: `Text` forwards `hyphens` to `RenderParagraph` (incl. selectable path); default resolves to `Hyphens.manual` - [ ] `test/rendering/paragraph_test.dart`: `RenderParagraph.hyphens` setter triggers relayout - [ ] `test/painting/text_painter_test.dart`: `TextPainter.hyphens` setter; the same width check through `TextPainter`, and changing `hyphens` after layout changes the width - [ ] Google internal testing - [ ] Manual smoke: `Text('inter\u00ADnational')` in a narrow container shows `inter-` / `national`
Description of what this PR is changing or adding, and why:
Adds a breaking change page for flutter/flutter#185152. Soft hyphens (U+00AD) now render as a visible hyphen at line breaks, controlled by a new
Hyphensenum, andTextStyle.getParagraphStylegained ahyphensparameter, which breaks classes that override it. The page covers both, with a migration for each.Issues fixed by this PR (if any):
None.
PRs or commits this PR depends on (if any):
flutter/flutter#185152, which landed on master on October 3.
Presubmit checklist
of 80 characters or fewer.