diff --git a/src/Avalonia.Visuals/Media/CharacterHit.cs b/src/Avalonia.Visuals/Media/CharacterHit.cs index ba691dad6e..f018b2d8a9 100644 --- a/src/Avalonia.Visuals/Media/CharacterHit.cs +++ b/src/Avalonia.Visuals/Media/CharacterHit.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; namespace Avalonia.Media { @@ -9,6 +10,7 @@ namespace Avalonia.Media /// The CharacterHit structure provides information about the index of the first /// character that got hit as well as information about leading or trailing edge. /// + [DebuggerDisplay("CharacterHit({FirstCharacterIndex}, {TrailingLength})")] public readonly struct CharacterHit : IEquatable { /// diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs index f73a7be759..435752160e 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs @@ -236,7 +236,7 @@ namespace Avalonia.Media.TextFormatting var codepointIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength; - if (codepointIndex >= TextRange.Start + TextRange.Length) + if (codepointIndex > TextRange.End) { return false; // Cannot go forward anymore } @@ -249,11 +249,14 @@ namespace Avalonia.Media.TextFormatting var foundCharacterHit = run.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex + characterHit.TrailingLength, out _); - nextCharacterHit = characterHit.TrailingLength != 0 ? + var isAtEnd = foundCharacterHit.FirstCharacterIndex + foundCharacterHit.TrailingLength == + TextRange.Length; + + nextCharacterHit = isAtEnd || characterHit.TrailingLength != 0 ? foundCharacterHit : new CharacterHit(foundCharacterHit.FirstCharacterIndex + foundCharacterHit.TrailingLength); - if (nextCharacterHit.FirstCharacterIndex > characterHit.FirstCharacterIndex) + if (isAtEnd || nextCharacterHit.FirstCharacterIndex > characterHit.FirstCharacterIndex) { return true; } @@ -272,6 +275,13 @@ namespace Avalonia.Media.TextFormatting /// private bool TryFindPreviousCharacterHit(CharacterHit characterHit, out CharacterHit previousCharacterHit) { + if (characterHit.FirstCharacterIndex == TextRange.Start) + { + previousCharacterHit = new CharacterHit(TextRange.Start); + + return true; + } + previousCharacterHit = characterHit; var codepointIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength; @@ -354,7 +364,7 @@ namespace Avalonia.Media.TextFormatting return new ShapedTextCharacters(glyphRun, textRun.Properties); } - + /// /// Gets the shaped width of specified shaped text characters. /// diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs index 09cbf3bf08..3655d78c9d 100644 --- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs +++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using Avalonia.Media; using Avalonia.Media.TextFormatting; @@ -101,7 +102,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting Assert.Equal(firstCharacterHit.FirstCharacterIndex, previousCharacterHit.FirstCharacterIndex); - Assert.Equal(firstCharacterHit.TrailingLength, previousCharacterHit.TrailingLength); + Assert.Equal(0, previousCharacterHit.TrailingLength); previousCharacterHit = new CharacterHit(clusters[^1], text.Length - clusters[^1]); @@ -119,7 +120,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting Assert.Equal(firstCharacterHit.FirstCharacterIndex, previousCharacterHit.FirstCharacterIndex); - Assert.Equal(firstCharacterHit.TrailingLength, previousCharacterHit.TrailingLength); + Assert.Equal(0, previousCharacterHit.TrailingLength); } }