diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs
index 980b1a2d40..f73a7be759 100644
--- a/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs
+++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs
@@ -181,7 +181,7 @@ namespace Avalonia.Media.TextFormatting
return nextCharacterHit;
}
- return new CharacterHit(TextRange.End); // Can't move, we're after the last character
+ return characterHit; // Can't move, we're after the last character
}
///
@@ -192,7 +192,7 @@ namespace Avalonia.Media.TextFormatting
return previousCharacterHit;
}
- return new CharacterHit(TextRange.Start); // Can't move, we're before the first character
+ return characterHit; // Can't move, we're before the first character
}
///
@@ -247,9 +247,13 @@ namespace Avalonia.Media.TextFormatting
{
var run = _textRuns[runIndex];
- nextCharacterHit = run.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex + characterHit.TrailingLength, out _);
+ var foundCharacterHit = run.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex + characterHit.TrailingLength, out _);
- if (codepointIndex <= nextCharacterHit.FirstCharacterIndex + nextCharacterHit.TrailingLength)
+ nextCharacterHit = characterHit.TrailingLength != 0 ?
+ foundCharacterHit :
+ new CharacterHit(foundCharacterHit.FirstCharacterIndex + foundCharacterHit.TrailingLength);
+
+ if (nextCharacterHit.FirstCharacterIndex > characterHit.FirstCharacterIndex)
{
return true;
}
@@ -283,9 +287,13 @@ namespace Avalonia.Media.TextFormatting
{
var run = _textRuns[runIndex];
- previousCharacterHit = run.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex - 1, out _);
+ var foundCharacterHit = run.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex - 1, out _);
+
+ previousCharacterHit = characterHit.TrailingLength != 0 ?
+ foundCharacterHit :
+ new CharacterHit(foundCharacterHit.FirstCharacterIndex);
- if (previousCharacterHit.FirstCharacterIndex < codepointIndex)
+ if (previousCharacterHit.FirstCharacterIndex < characterHit.FirstCharacterIndex)
{
return true;
}
diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs
index f0951c61d3..09cbf3bf08 100644
--- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs
+++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs
@@ -31,12 +31,37 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var nextCharacterHit = new CharacterHit(0);
- for (var i = 1; i < clusters.Length; i++)
+ for (var i = 0; i < clusters.Length; i++)
{
+ Assert.Equal(clusters[i], nextCharacterHit.FirstCharacterIndex);
+
nextCharacterHit = textLine.GetNextCaretCharacterHit(nextCharacterHit);
+ }
+
+ var lastCharacterHit = nextCharacterHit;
+
+ nextCharacterHit = textLine.GetNextCaretCharacterHit(lastCharacterHit);
+
+ Assert.Equal(lastCharacterHit.FirstCharacterIndex, nextCharacterHit.FirstCharacterIndex);
+
+ Assert.Equal(lastCharacterHit.TrailingLength, nextCharacterHit.TrailingLength);
+
+ nextCharacterHit = new CharacterHit(0, clusters[1] - clusters[0]);
- Assert.Equal(clusters[i], nextCharacterHit.FirstCharacterIndex + nextCharacterHit.TrailingLength);
+ for (var i = 0; i < clusters.Length; i++)
+ {
+ Assert.Equal(clusters[i], nextCharacterHit.FirstCharacterIndex);
+
+ nextCharacterHit = textLine.GetNextCaretCharacterHit(nextCharacterHit);
}
+
+ lastCharacterHit = nextCharacterHit;
+
+ nextCharacterHit = textLine.GetNextCaretCharacterHit(lastCharacterHit);
+
+ Assert.Equal(lastCharacterHit.FirstCharacterIndex, nextCharacterHit.FirstCharacterIndex);
+
+ Assert.Equal(lastCharacterHit.TrailingLength, nextCharacterHit.TrailingLength);
}
}
@@ -60,14 +85,41 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var clusters = textLine.TextRuns.Cast().SelectMany(x => x.GlyphRun.GlyphClusters)
.ToArray();
- var previousCharacterHit = new CharacterHit(clusters[^1]);
+ var previousCharacterHit = new CharacterHit(text.Length);
- for (var i = clusters.Length - 2; i > 0; i--)
+ for (var i = clusters.Length - 1; i >= 0; i--)
{
previousCharacterHit = textLine.GetPreviousCaretCharacterHit(previousCharacterHit);
- Assert.Equal(clusters[i], previousCharacterHit.FirstCharacterIndex);
+ Assert.Equal(clusters[i],
+ previousCharacterHit.FirstCharacterIndex + previousCharacterHit.TrailingLength);
}
+
+ var firstCharacterHit = previousCharacterHit;
+
+ previousCharacterHit = textLine.GetPreviousCaretCharacterHit(firstCharacterHit);
+
+ Assert.Equal(firstCharacterHit.FirstCharacterIndex, previousCharacterHit.FirstCharacterIndex);
+
+ Assert.Equal(firstCharacterHit.TrailingLength, previousCharacterHit.TrailingLength);
+
+ previousCharacterHit = new CharacterHit(clusters[^1], text.Length - clusters[^1]);
+
+ for (var i = clusters.Length - 1; i > 0; i--)
+ {
+ previousCharacterHit = textLine.GetPreviousCaretCharacterHit(previousCharacterHit);
+
+ Assert.Equal(clusters[i],
+ previousCharacterHit.FirstCharacterIndex + previousCharacterHit.TrailingLength);
+ }
+
+ firstCharacterHit = previousCharacterHit;
+
+ previousCharacterHit = textLine.GetPreviousCaretCharacterHit(firstCharacterHit);
+
+ Assert.Equal(firstCharacterHit.FirstCharacterIndex, previousCharacterHit.FirstCharacterIndex);
+
+ Assert.Equal(firstCharacterHit.TrailingLength, previousCharacterHit.TrailingLength);
}
}