Skip to content

Fix TextBox caret overlapping last glyph at end of line#21059

Open
jdmichel wants to merge 1 commit intoAvaloniaUI:masterfrom
jdmichel:fix/caret-position-end-of-line
Open

Fix TextBox caret overlapping last glyph at end of line#21059
jdmichel wants to merge 1 commit intoAvaloniaUI:masterfrom
jdmichel:fix/caret-position-end-of-line

Conversation

@jdmichel
Copy link
Copy Markdown

@jdmichel jdmichel commented Apr 1, 2026

Summary

GetCaretPoints() subtracts 1px from the caret X position when the caret
is at or past the line width, to prevent clipping at the control boundary.
This causes the caret to render on top of the last character instead
of after it — visible at all font sizes and font families.

Changes

  • GetCaretPoints(): Replace x -= 1 with
    x = Math.Ceiling(X) + 0.5 so the caret snaps to the next pixel
    boundary past the glyph, guaranteeing visible separation.
  • MeasureOverride(): Reserve 2 extra pixels of width
    (textWidth + 2) so the caret is not clipped by the control boundary.

Diagnostic evidence

Minimal repro app traces _lastCharacterHit and _caretBounds via
reflection. For text "rrrrrrr" at FontSize 23:

_caretBounds.X=56.0  lineWidth=56.0

The CharacterHit logic resolves correctly. The only corruption is
x -= 1 in GetCaretPoints():

Math.Floor(56.0) + 0.5 = 56.5  →  x -= 1  →  55.5  (inside the glyph)

Repro

Any Avalonia app with a TextBox — type text and observe the caret at
the end of the string overlaps the last character. Tested on Windows
with Avalonia 11.3.12, 11.3.13, .NET 9, .NET 10, multiple fonts and
font sizes.

Fixes #12809

GetCaretPoints() subtracted 1px from the caret X position when the caret
was at or past the line width, to prevent clipping at the control boundary.
This caused the caret to render on top of the last character instead of
after it — visible at all font sizes and font families.

Fix: replace "x -= 1" with "x = Math.Ceiling(X) + 0.5" so the caret
snaps to the next pixel boundary past the glyph.  Reserve 2px of extra
width in MeasureOverride so the caret is not clipped.

Fixes AvaloniaUI#12809
@MrJul MrJul added bug backport-candidate-11.3.x Consider this PR for backporting to 11.3 branch labels Apr 1, 2026
@Gillibald
Copy link
Copy Markdown
Contributor

A real fix to this issue is drawing the caret via an adorner layer

@cla-avalonia
Copy link
Copy Markdown
Collaborator

cla-avalonia commented Apr 1, 2026

  • All contributors have signed the CLA.

@avaloniaui-bot
Copy link
Copy Markdown

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

@jdmichel
Copy link
Copy Markdown
Author

jdmichel commented Apr 2, 2026

@cla-avalonia agree

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

Labels

backport-candidate-11.3.x Consider this PR for backporting to 11.3 branch bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TextBox caret has incorrect position at the end of the string

5 participants