Repository navigation
[web] Render soft hyphens on Skwasm - #193850
Conversation
Adds a paragraphStyle_setRenderSoftHyphens binding to Skwasm and sets it from SkwasmParagraphStyle, so Hyphens behaves the same as on native: soft hyphens render at a line break unless Hyphens.hidden is set. CanvasKit still ignores hyphens until its ParagraphStyle binding in Skia exposes renderSoftHyphens. Part of flutter#193506
Skwasm now renders soft hyphens, so the TextPainter tests only skip on CanvasKit, and the TextPainter.hyphens docs say that only Skwasm supports this on the web so far.
There was a problem hiding this comment.
Code Review
This pull request implements support for rendering soft hyphens in the Skwasm web renderer by exposing and wiring the setRenderSoftHyphens property to the underlying Skia paragraph style. It also updates documentation and enables relevant tests for Web WASM while skipping them for CanvasKit. The review feedback suggests skipping the new hyphen tests on any renderer other than Skwasm (such as the HTML renderer) to prevent potential test failures.
With the FlutterTest font the widths are exact, so check them like the TextPainter test does.
The default test environment does not load FlutterTest, so the font fell back to Roboto and the pinned hyphen widths did not match. Force the test fonts, as line_metrics_test does.
|
@mdebbar Pinning the widths showed that this test file never loaded the FlutterTest font. Without |
|
@mdebbar The FlutterTest fix worked: the Skwasm suites that failed before, firefox-dart2wasm-skwasm-ui and chrome-dart2wasm-wimp-ui, now pass. Could you take another look? The only failure is Windows framework_tests_libraries, where the popup_menu_test.dart process stopped partway through with no error, so it looks like a flake. Could someone rerun it? |
mdebbar
left a comment
There was a problem hiding this comment.
Thank you for pushing this through!
|
@mdebbar Thank you. Google testing failed again with "Smoke tests failed", and I cannot see the internal results. #194321 and #194055 hit the same failure in the last day, so it may be unrelated, but could you check go/frob_pr/193850 or re-run it? If it passes, could you also add the autosubmit label? If the failure is related to this change, I am happy to fix it. |
|
Don't think the g3 failure is related (the build is broken by semantics changes in a different PR). |
|
Thank you, @LongCatIsLooong. Google testing passed after the merge. The only remaining failure is Linux mac_clang_tidy, which timed out waiting for Mac machines and was cancelled. Could someone rerun it and add the autosubmit label? |
|
@LongCatIsLooong could you approve so we can merge the PR? |
flutter/flutter@5c7e45a...a3d71d8 2026-10-16 [email protected] 0 Initialize variables in the DlComplexityPathReceiver helper (flutter/flutter#194540) 2026-10-16 [email protected] Roll Fuchsia Test Scripts from V-qQL4158Nw6L-QLi... to 2T18KC7-LDQtmQiLP... (flutter/flutter#194527) 2026-10-16 [email protected] Remove BorderMaskBlur (flutter/flutter#194508) 2026-10-16 [email protected] Roll Skia from a577264dc087 to 470b8816a261 (1 revision) (flutter/flutter#194526) 2026-10-16 [email protected] [ios] Use DFS traversal to find engines of a scene automatically (rather than manually manage the engines list) (flutter/flutter#192457) 2026-10-16 [email protected] [Skia][DisplayList] Map local bounds through the local matrix in DlLocalMatrixImageFilter (flutter/flutter#193963) 2026-10-16 [email protected] [framework] Fix avoid_setters_without_getters warnings on mixin declarations (flutter/flutter#193856) 2026-10-16 [email protected] Roll Dart SDK from 84686ea04815 to 55a734a01fb1 (3 revisions) (flutter/flutter#194522) 2026-10-16 [email protected] Roll Skia from d131b7789482 to a577264dc087 (7 revisions) (flutter/flutter#194514) 2026-10-16 [email protected] Roll Fuchsia GN SDK from PDJz3b3CL31uoLOkD... to kFdyRnojbVy0cxvRZ... (flutter/flutter#194510) 2026-10-16 [email protected] Roll GN to f9eca75ae554 (flutter/flutter#194471) 2026-10-16 [email protected] refactor(flutter_tools): migrate RunCommand and RunCommandBase to OptionDescriptor and OptionBundle (flutter/flutter#194362) 2026-10-15 [email protected] refactor(flutter_tools): finish TestCommand OptionDescriptor and OptionBundle migration (flutter/flutter#194361) 2026-10-15 [email protected] [iOS][a11y] Fix VoiceOver announcement for unfocused password fields (flutter/flutter#192851) 2026-10-15 [email protected] Roll pub packages (flutter/flutter#194477) 2026-10-15 [email protected] refactor(flutter_tools): finish DriveCommand OptionDescriptor migration (flutter/flutter#194360) 2026-10-15 [email protected] [flutter_tools] Roll package:vm_service to 15.4.0 (flutter/flutter#194467) 2026-10-15 [email protected] refactor(flutter_tools): migrate AttachCommand to OptionDescriptor and OptionBundle (flutter/flutter#194359) 2026-10-15 [email protected] [flutter_tools] Inject dependencies into update-packages and package_map (flutter/flutter#194046) 2026-10-15 [email protected] [impeller] parallelize opengles shader compiles (flutter/flutter#194022) 2026-10-15 [email protected] Roll pub packages (flutter/flutter#194469) 2026-10-15 [email protected] Restrict web dev server to loopback by default (flutter/flutter#187595) 2026-10-15 [email protected] Roll Packages from a1ed23c to da40eaf (33 revisions) (flutter/flutter#194459) 2026-10-15 [email protected] [web] Render soft hyphens on Skwasm (flutter/flutter#193850) 2026-10-15 [email protected] refactor(flutter_tools): migrate AssembleCommand to OptionDescriptor (flutter/flutter#194358) 2026-10-15 [email protected] [windows] Add OpenGL golden test against ANGLE at D3D11 feature level 10_0 (flutter/flutter#194321) If this roll has caused a breakage, revert this CL and set the roller to dry run mode using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC [email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Makes `Hyphens` work on the CanvasKit renderer, following flutter#193850 for Skwasm. CanvasKit's `ParagraphStyle` gained `renderSoftHyphens` in Skia (https://skia-review.googlesource.com/c/skia/+/1378836), which rolled into Flutter with flutter#193884. `CkParagraphStyle` now sets it the same way the native engine and Skwasm do: soft hyphens render at a line break unless `Hyphens.hidden` is set. Because CanvasKit is the default renderer for `flutter build web`, text containing U+00AD in most web apps now shows a hyphen at soft-hyphen line breaks, matching native and Skwasm. This also covers a `--wasm` app that falls back to CanvasKit. With both web renderers supported, the hyphen tests in `paragraph_builder_test.dart` and the `TextPainter` hyphen tests no longer skip on the web, and the `TextPainter.hyphens` docs drop the web caveat. WebParagraph, which is experimental and off by default, still ignores `hyphens`; its TODO stays on flutter#193506. Part of flutter#193506. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant in-code documentation (doc comments with `///`). - [ ] If this PR introduces a new feature or capability, I created and linked a website documentation issue or PR in [flutter/website] (or verified none is needed). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [AI contribution guidelines]: https://github.com/flutter/flutter/blob/main/CONTRIBUTING.ai.md [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [flutter/website]: https://github.com/flutter/website [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
Makes `Hyphens` work on the Skwasm renderer. flutter#185152 added the `Hyphens` API, but the web renderers only store the value. Skwasm gets a `paragraphStyle_setRenderSoftHyphens` binding, and `SkwasmParagraphStyle` sets it the same way the native engine does: soft hyphens render at a line break unless `Hyphens.hidden` is set. So text containing U+00AD now shows a hyphen at soft-hyphen line breaks on Skwasm, matching native since flutter#185152. It also updates the `TextPainter.hyphens` docs, which said the web doesn't support this yet, and runs the `TextPainter` hyphen tests on Skwasm. They still skip on CanvasKit. CanvasKit isn't covered here. Its `ParagraphStyle` binding lives in Skia (`modules/canvaskit/paragraph_bindings.cpp`) and doesn't expose `renderSoftHyphens` yet, so that needs a Skia change first: https://skia-review.googlesource.com/c/skia/+/1378836. Once that rolls, the Flutter side is a few lines in `CkParagraphStyle`. Until then, a `--wasm` app that falls back to CanvasKit won't show the hyphen. WebParagraph also still ignores `hyphens`. Part of flutter#193506. ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant in-code documentation (doc comments with `///`). - [ ] If this PR introduces a new feature or capability, I created and linked a website documentation issue or PR in [flutter/website] (or verified none is needed). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [AI contribution guidelines]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/website]: https://github.com/flutter/website [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --------- Co-authored-by: LongCatIsLooong <[email protected]>
Makes `Hyphens` work on the CanvasKit renderer, following flutter#193850 for Skwasm. CanvasKit's `ParagraphStyle` gained `renderSoftHyphens` in Skia (https://skia-review.googlesource.com/c/skia/+/1378836), which rolled into Flutter with flutter#193884. `CkParagraphStyle` now sets it the same way the native engine and Skwasm do: soft hyphens render at a line break unless `Hyphens.hidden` is set. Because CanvasKit is the default renderer for `flutter build web`, text containing U+00AD in most web apps now shows a hyphen at soft-hyphen line breaks, matching native and Skwasm. This also covers a `--wasm` app that falls back to CanvasKit. With both web renderers supported, the hyphen tests in `paragraph_builder_test.dart` and the `TextPainter` hyphen tests no longer skip on the web, and the `TextPainter.hyphens` docs drop the web caveat. WebParagraph, which is experimental and off by default, still ignores `hyphens`; its TODO stays on flutter#193506. Part of flutter#193506. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant in-code documentation (doc comments with `///`). - [ ] If this PR introduces a new feature or capability, I created and linked a website documentation issue or PR in [flutter/website] (or verified none is needed). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [AI contribution guidelines]: https://github.com/flutter/flutter/blob/main/CONTRIBUTING.ai.md [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [flutter/website]: https://github.com/flutter/website [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
Makes
Hyphenswork on the Skwasm renderer. #185152 added theHyphensAPI, but the web renderers only store the value.Skwasm gets a
paragraphStyle_setRenderSoftHyphensbinding, andSkwasmParagraphStylesets it the same way the native engine does: soft hyphens render at a line break unlessHyphens.hiddenis set. So text containing U+00AD now shows a hyphen at soft-hyphen line breaks on Skwasm, matching native since #185152.It also updates the
TextPainter.hyphensdocs, which said the web doesn't support this yet, and runs theTextPainterhyphen tests on Skwasm. They still skip on CanvasKit.CanvasKit isn't covered here. Its
ParagraphStylebinding lives in Skia (modules/canvaskit/paragraph_bindings.cpp) and doesn't exposerenderSoftHyphensyet, so that needs a Skia change first: https://skia-review.googlesource.com/c/skia/+/1378836. Once that rolls, the Flutter side is a few lines inCkParagraphStyle. Until then, a--wasmapp that falls back to CanvasKit won't show the hyphen. WebParagraph also still ignoreshyphens.Part of #193506.
Pre-launch Checklist
///).