فهرست منبع

Merge pull request #4339 from Gillibald/fixes/TextLineCaretNavigation

Make sure we always hit the outer edge at the start/end of a TextLine
danwalmsley 5 سال پیش
والد
کامیت
5184c1551e

+ 2 - 0
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.
     /// </remarks>
+    [DebuggerDisplay("CharacterHit({FirstCharacterIndex}, {TrailingLength})")]
     public readonly struct CharacterHit : IEquatable<CharacterHit>
     {
         /// <summary>

+ 14 - 4
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
         /// <returns></returns>
         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);
         }
-        
+
         /// <summary>
         /// Gets the shaped width of specified shaped text characters.
         /// </summary>

+ 3 - 2
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);
             }
         }