From 14ea7b44ed6c90ffbe3f5d58741e7aa545042e3c Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 11 Jun 2021 18:46:13 +0200 Subject: [PATCH] Fix caret positioning with empty newlines. `FormattedTextImpl` on Skia adds a special empty line when there is a trailing newline in the string. However this line is reported as having a width due to `SKPaint.MeasureText` returning a non-zero value for `\r` and `\n`. We can't simply always use 0 width when we encounter a control char when building the rects as that breaks hit testing. Instead, mark the empty trailing line with a flag and and treat it differently when building the rects and hit-testing a range. Yes, this is a big hack but as far as I understand the whole of `FormattedTextImpl` on Skia is a bit of a hack, but until @Gillibald's new `TextPresenter` is ready, this _might_ be a good enough fix? --- src/Skia/Avalonia.Skia/FormattedTextImpl.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs index 5e630e54a6..5f4980e461 100644 --- a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs +++ b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Avalonia.Media; using Avalonia.Platform; @@ -175,7 +176,8 @@ namespace Avalonia.Skia foreach (var line in _skiaLines.Where(l => (l.Start + l.Length) > index && - lastIndex >= l.Start)) + lastIndex >= l.Start && + !l.IsEmptyTrailingLine)) { int lineEndIndex = line.Start + (line.Length > 0 ? line.Length - 1 : 0); @@ -466,7 +468,8 @@ namespace Avalonia.Skia for (int i = line.Start; i < line.Start + line.TextLength; i++) { - float w = _paint.MeasureText(Text[i].ToString()); + var c = Text[i]; + var w = line.IsEmptyTrailingLine ? 0 :_paint.MeasureText(Text[i].ToString()); _rects.Add(new Rect( prevRight, @@ -611,6 +614,7 @@ namespace Avalonia.Skia lastLine.Width = lastLineWidth; lastLine.Height = _lineHeight; lastLine.Top = curY; + lastLine.IsEmptyTrailingLine = true; _skiaLines.Add(lastLine); @@ -713,6 +717,7 @@ namespace Avalonia.Skia public int TextLength; public float Top; public float Width; + public bool IsEmptyTrailingLine; }; private struct FBrushRange