Repository navigation
Conversation
Chrome gives some invisible characters, such as a soft hyphen (U+00AD) or a zero width space (U+200B), no text cluster. Their code units were left mapped to cluster 0, so a text range that included one could map to a cluster range that went backwards. Laying out a paragraph that ends with one of these characters failed the assertion in _TextClusterMapping.toTextRange. Map each of those code units to the cluster before it, or to the first cluster at the start of the text. A cluster range that starts at such a code unit then starts at the next cluster, so a span that starts with one covers only its own clusters. A cluster range that ends at one at the start of the text ends before the first cluster. Bidi regions and span slices that contain only these characters have no clusters, so they add no bidi run and no block to the line. A line's text range starts where the previous line ended, or at 0, so a line that starts with one of these characters still contains it. Co-authored-by: Julia Lavrova <[email protected]>
9 of 11 tasks
10 of 11 tasks
Add contract tests for paragraphs containing only clusterless characters, soft line breaks on clusterless code units before directional marks, and clusterless characters following trailing spaces. Without the fix, all 6 new tests fail (3 StateError crashes on lines.first, 2 line boundary mismatches [0, 5) vs [0, 4), and 1 AssertionError at wrapper.dart:101). Assisted-by: Gemini Pro Next
Check allClusters.length == 1 in TextLayout.wrapText and lines.isEmpty in TextLayout._calculatePaintBounds so non-empty paragraphs containing only clusterless characters (such as U+00AD, U+200B, or U+200F) get empty-text metrics and Rect.zero paintBounds instead of crashing on lines.first. Scan codeUnitFlags from the previous cluster's end to the current cluster's start in TextWrapper._isSoftLineBreak so soft line breaks that land on unmapped clusterless code units before directional marks are not missed, and use hardlineTextRange.start in TextLayout.addLine so clusterless characters after trailing spaces are included in allTextRange. Without the fix, the 6 new tests in paragraph_edge_cases_test.dart fail (3 StateError crashes on lines.first, 2 line boundary mismatches [0, 5) vs [0, 4), and 1 AssertionError at wrapper.dart:101). Assisted-by: Gemini Pro Next
Rusino
force-pushed
the
companion-pr-195384
branch
from
October 28, 2026 17:19
2393e83 to
1efa853
Compare
dbebawy
added a commit
to dbebawy/flutter
that referenced
this pull request
Nov 2, 2026
…r#195384) Chrome gives some invisible characters, such as a soft hyphen (U+00AD), a zero width space (U+200B) or a right-to-left mark (U+200F), no text cluster. WebParagraph left their code units mapped to cluster 0, so a text range that includes one can map to the wrong clusters. On master: * Laying out a paragraph that ends with a soft hyphen or zero width space fails the assertion in `_TextClusterMapping.toTextRange`. * Laying out a paragraph whose only text is one of these characters throws a `StateError`. * Wrapping text where a space is followed by one of these characters, such as `'ab \u200F\u200Fcd'`, fails an assertion in `TextWrapper.breakLines`. * `getLineNumberAt` fails an assertion for a line that starts with one of these characters. * A right-to-left mark at the start of an LTR paragraph makes the first letter count twice in the line width. * A styled span that contains only one of these characters adds an empty box to `getBoxesForRange`. This maps each of those code units to the cluster before it, or to the first cluster at the start of the text, so a range that starts or ends at one of them does not take a cluster next to it. Bidi regions and span slices with no clusters add no bidi run and no block to the line, and a line's text range starts where the previous line ended and ends where the next line starts. A paragraph with no clusters is laid out like empty text, and the line breaker also finds a soft line break that lands on one of these characters. This was the first commit of flutter#195366 (soft hyphens in WebParagraph, for flutter#193506). @Rusino found three of these cases while reviewing that PR, wrote the fixes and tests in flutter#195377, and suggested landing this part on its own first. Her two commits from flutter#195386 add the rest: paragraphs with only these characters, and line breaks next to them. ## Testing `paragraph_edge_cases_test.dart` has a new group for these characters. Eleven of its tests fail on master. The two tests for a soft line break before a direction mark after a zero width space pass on master with Chrome 145 on my machine, so they may depend on the Chrome version. I ran the `chrome-dart2js-webparagraph-ui` suite locally on macOS with `felt test --gcs-prod`. Everything passes except "Paragraph with different locales for the same language" and "paint overflows" in `paragraph_test.dart`, which fail the same way on master on my machine. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant in-code documentation (doc comments with `///`). - [x] 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). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] 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: Julia Lavrova <[email protected]>
gmackall
pushed a commit
to gmackall/flutter
that referenced
this pull request
Nov 3, 2026
…r#195384) Chrome gives some invisible characters, such as a soft hyphen (U+00AD), a zero width space (U+200B) or a right-to-left mark (U+200F), no text cluster. WebParagraph left their code units mapped to cluster 0, so a text range that includes one can map to the wrong clusters. On master: * Laying out a paragraph that ends with a soft hyphen or zero width space fails the assertion in `_TextClusterMapping.toTextRange`. * Laying out a paragraph whose only text is one of these characters throws a `StateError`. * Wrapping text where a space is followed by one of these characters, such as `'ab \u200F\u200Fcd'`, fails an assertion in `TextWrapper.breakLines`. * `getLineNumberAt` fails an assertion for a line that starts with one of these characters. * A right-to-left mark at the start of an LTR paragraph makes the first letter count twice in the line width. * A styled span that contains only one of these characters adds an empty box to `getBoxesForRange`. This maps each of those code units to the cluster before it, or to the first cluster at the start of the text, so a range that starts or ends at one of them does not take a cluster next to it. Bidi regions and span slices with no clusters add no bidi run and no block to the line, and a line's text range starts where the previous line ended and ends where the next line starts. A paragraph with no clusters is laid out like empty text, and the line breaker also finds a soft line break that lands on one of these characters. This was the first commit of flutter#195366 (soft hyphens in WebParagraph, for flutter#193506). @Rusino found three of these cases while reviewing that PR, wrote the fixes and tests in flutter#195377, and suggested landing this part on its own first. Her two commits from flutter#195386 add the rest: paragraphs with only these characters, and line breaks next to them. ## Testing `paragraph_edge_cases_test.dart` has a new group for these characters. Eleven of its tests fail on master. The two tests for a soft line break before a direction mark after a zero width space pass on master with Chrome 145 on my machine, so they may depend on the Chrome version. I ran the `chrome-dart2js-webparagraph-ui` suite locally on macOS with `felt test --gcs-prod`. Everything passes except "Paragraph with different locales for the same language" and "paint overflows" in `paragraph_test.dart`, which fail the same way on master on my machine. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant in-code documentation (doc comments with `///`). - [x] 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). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] 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: Julia Lavrova <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Companion Draft PR for #195384 (diff of just the 2 companion commits on top of
990aa341cb0):90406c4ecf7): 6 unit tests inparagraph_edge_cases_test.dart(all 6 fail on990aa341cb0on Chrome 145: 3StateErrorcrashes onlines.first, 2 line boundary mismatches[0, 5)vs[0, 4)atwidth: 35, and 1AssertionErroratwrapper.dart:101).1efa853646b): Fixes inlayout.dartandwrapper.dart(all 52 tests inparagraph_edge_cases_test.dartpass).