From c5edf9bc5da4e1dabad5d5a9f3cd8b078bd254d2 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Mon, 20 Jul 2020 18:37:11 +0200 Subject: [PATCH] Initial --- .../Media/TextFormatting/TextLineImpl.cs | 20 ++++-- .../Media/TextFormatting/TextLineTests.cs | 62 +++++++++++++++++-- 2 files changed, 71 insertions(+), 11 deletions(-) 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); } }