Skip to content

Fix NullReferenceException in TextLeadingPrefixCharacterEllipsis when collapsing an unbreakable cluster#21371

Open
Symbai wants to merge 1 commit into
AvaloniaUI:masterfrom
Symbai:master
Open

Fix NullReferenceException in TextLeadingPrefixCharacterEllipsis when collapsing an unbreakable cluster#21371
Symbai wants to merge 1 commit into
AvaloniaUI:masterfrom
Symbai:master

Conversation

@Symbai
Copy link
Copy Markdown
Contributor

@Symbai Symbai commented May 16, 2026

What does the pull request do?

Fixes a latent NullReferenceException in TextLeadingPrefixCharacterEllipsis.Collapse (the PrefixCharacterEllipsis text-trimming mode). When the suffix portion of a collapsed line ends in an unbreakable cluster, a ligature, or a base character with combining marks, shaped as a single glyph cluster, the code dereferences a null split result and crashes.

What is the current behavior?

While building the trailing suffix of an ellipsized line, Collapse calls endShapedRun.Split(run.Length - suffixCount) and unconditionally uses splitSuffix.Second!:

var splitSuffix = endShapedRun.Split(run.Length - suffixCount);
collapsedRuns.Add(splitSuffix.Second!);

Since #21351, ShapedTextRun.Split returns (first, null) - rather than throwing - when the requested split position falls inside an unbreakable cluster that reaches the end of the run. In that case splitSuffix.Second is null, and splitSuffix.Second! throws a NullReferenceException, crashing layout/rendering.

What is the updated/expected behavior with this PR?

When the suffix run cannot be split because it is a single unbreakable cluster, the whole run is kept as the suffix instead of crashing, which is the correct outcome, since an indivisible cluster is an all-or-nothing unit:

var splitSuffix = endShapedRun.Split(run.Length - suffixCount);
collapsedRuns.Add(splitSuffix.Second ?? splitSuffix.First!);

To test: apply TextTrimming.PrefixCharacterEllipsis to text whose trailing portion is a single unbreakable cluster, in a width that forces collapsing. Before this PR it crashes; after it, the line collapses normally with the cluster preserved as the suffix.

How was the solution implemented (if it's not obvious)?

The fix is a single defensive null-coalesce. ShapedTextRun.Split always returns a non-null First (the whole run when no further split is possible), so falling back to splitSuffix.First is safe and complete. This mirrors the pattern already used by TextFormatterImpl.SplitTextRuns, which null-checks split.Second before consuming it.

No unit test is included: reproducing this branch end-to-end requires a font that produces multi-character clusters (e.g. Thai combining marks). The only such font in the test assets is the monospace Cascadia Code, and with a monospace font the widths required to reach this branch are mutually exclusive, it would need a proportional cluster-capable font, which the test project does not ship.

Checklist

Breaking changes

None.

Obsoletions / Deprecations

None.

@avaloniaui-bot
Copy link
Copy Markdown

You can test this PR using the following package version. 12.1.999-cibuild0065447-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@MrJul MrJul added bug area-textprocessing backport-candidate-12.0.x Consider this PR for backporting to 12.0 branch labels May 18, 2026
Copy link
Copy Markdown
Contributor

@Gillibald Gillibald left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no matching unit test that covers the failing scenario. Please add a unit test.

@Symbai
Copy link
Copy Markdown
Contributor Author

Symbai commented May 18, 2026

@Gillibald reproducing this branch end-to-end requires a font that produces multi-character clusters (e.g. Thai combining marks). The only such font in the test assets is the monospace Cascadia Code, and with a monospace font the widths required to reach this branch are mutually exclusive, it would need a proportional cluster-capable font, which the test project does not ship.

@MrJul
Copy link
Copy Markdown
Member

MrJul commented May 19, 2026

it would need a proportional cluster-capable font, which the test project does not ship.

Feel free to add any font needed to the test project (as long as the license allows it).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-textprocessing backport-candidate-12.0.x Consider this PR for backporting to 12.0 branch bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants