Repository navigation
[Text] Snap a right-to-left buffer split to the cluster boundary - #22066
Merged
Merged
Conversation
2 of 3 tasks
Gillibald
force-pushed
the
fix/rtl-split-inside-cluster
branch
from
August 26, 2026 04:36
e04083e to
3c1f729
Compare
Gillibald
force-pushed
the
fix/rtl-split-inside-cluster
branch
from
August 26, 2026 04:51
3c1f729 to
5ff8b4c
Compare
Gillibald
force-pushed
the
fix/rtl-split-inside-cluster
branch
from
August 26, 2026 04:54
5ff8b4c to
fd4012c
Compare
Gillibald
marked this pull request as ready for review
August 26, 2026 04:55
MrJul
previously approved these changes
Aug 26, 2026
github-merge-queue
Bot
removed this pull request from the merge queue due to invalid changes in the merge commit
Aug 26, 2026
github-merge-queue
Bot
removed this pull request from the merge queue due to invalid changes in the merge commit
Aug 26, 2026
Member
|
Well, it seems like the merge queue isn't working correctly with stacked PRs, even though there's a nice UI showing that it depends on the previous one in the queue. Let's wait for #22065 to get through. |
MrJul
force-pushed
the
fix/rtl-split-inside-cluster
branch
from
August 26, 2026 09:51
fd4012c to
8880599
Compare
Member
|
Note: the force-push above happened automatically with the stacked PRs. It also automatically dismissed my review. |
MrJul
approved these changes
Aug 26, 2026
Splitting a right-to-left shaped buffer keeps a straddling cluster's glyphs together in the leading half, but cuts the text at the requested offset instead of following them. The halves then disagree about which characters their glyphs cover: the leading half claims one character while holding the glyphs for two, and the trailing half claims a character whose glyphs it doesn't have. The left-to-right path already snaps the text boundary to the cluster.
A cluster straddling the split point keeps all its glyphs in the leading half, so the text has to be cut where those glyphs end, not at the requested offset. Cutting at the offset produced two halves whose glyph and character coverage disagreed, and their shared cluster cache then described neither: measuring the trailing half returned counts that cut a cluster, and splitting it again could hand back a leading half holding every glyph and no trailing half at all - a null run that crashed the bidi reorderer. The ascending path already snapped this way; this makes the descending path match.
Gillibald
force-pushed
the
fix/rtl-split-inside-cluster
branch
from
August 26, 2026 10:36
8880599 to
8102a5e
Compare
|
You can test this PR using the following package version. |
|
You can test this PR using the following package version. |
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Aug 26, 2026
MrJul
pushed a commit
to MrJul/Avalonia
that referenced
this pull request
Sep 2, 2026
…loniaUI#22066) * Add failing test for a right-to-left split inside a cluster Splitting a right-to-left shaped buffer keeps a straddling cluster's glyphs together in the leading half, but cuts the text at the requested offset instead of following them. The halves then disagree about which characters their glyphs cover: the leading half claims one character while holding the glyphs for two, and the trailing half claims a character whose glyphs it doesn't have. The left-to-right path already snaps the text boundary to the cluster. * Snap a right-to-left split to the cluster the glyphs stay with A cluster straddling the split point keeps all its glyphs in the leading half, so the text has to be cut where those glyphs end, not at the requested offset. Cutting at the offset produced two halves whose glyph and character coverage disagreed, and their shared cluster cache then described neither: measuring the trailing half returned counts that cut a cluster, and splitting it again could hand back a leading half holding every glyph and no trailing half at all - a null run that crashed the bidi reorderer. The ascending path already snapped this way; this makes the descending path match.
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.
What does the pull request do?
Fixes
ShapedBuffer.Splitproducing two halves whose character and glyph coverage disagree when the split point falls inside a cluster of a right-to-left buffer. Downstream, this crashes the bidi reorderer with aNullReferenceException.Second layer of a stack; based on #22065.
What is the current behavior?
A cluster straddling the split point keeps all of its glyphs in the leading half. This prevents breaking a cluster, which is correct; but the text is still cut at the requested offset. The leading half then claims fewer characters than its glyphs cover, and the trailing half claims characters whose glyphs it does not have. The left-to-right path (
SplitAscending) already snaps the text boundary to the cluster; the right-to-left path did not.Both halves share the parent's cluster cache, which now describes neither of them, so everything built on it misleads in turn:
FindTrailingCharCountWithinWidthreturns a count that cuts a cluster, and splitting the half at that count returns a leading half holding every glyph and no trailing half at all. That null run reachesBidiReorderer.BidiReorderand throws.What is the updated/expected behavior with this PR?
The text boundary follows the glyphs, so the halves stay consistent: no character and no glyph is lost or duplicated, and every glyph of the trailing half belongs to a character the trailing half owns.
Should_Not_Split_RightToLeft_Clusterasserts exactly that. TheCollapsecrash disappears.As with the left-to-right path,
Split(n)may return a leading half slightly longer thannwhennlands inside a cluster - that is the only way to keep a cluster whole.How was the solution implemented (if it's not obvious)?
Checklist
SplitDescendingremarks describe the boundary and were updated in place)Breaking changes
ShapedBuffer.Split(n)on a right-to-left buffer can now return a leading half longer thannwhennfalls inside a cluster, where it previously returned exactlyncharacters with a glyph set that did not match them. This mirrors the existing left-to-right behaviour. No other public API changes.Obsoletions / Deprecations
None.
Fixed issues
No tracked issues; found while fixing #14011.