diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs index a0aae76fad..94095cf82b 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs @@ -176,7 +176,7 @@ namespace Avalonia.Media.TextFormatting return GetRunCharacterHit(firstRun, FirstTextSourceIndex, 0); } - if (distance > WidthIncludingTrailingWhitespace) + if (distance >= WidthIncludingTrailingWhitespace) { var lastRun = _textRuns[_textRuns.Count - 1]; @@ -195,7 +195,7 @@ namespace Avalonia.Media.TextFormatting if(currentRun is ShapedTextCharacters shapedRun && !shapedRun.ShapedBuffer.IsLeftToRight) { var rightToLeftIndex = i; - var rightToLeftDistance = shapedRun.Size.Width; + currentPosition += currentRun.TextSourceLength; while (rightToLeftIndex + 1 <= _textRuns.Count - 1) { @@ -206,19 +206,24 @@ namespace Avalonia.Media.TextFormatting break; } - rightToLeftIndex++; + currentPosition += nextShaped.TextSourceLength; - rightToLeftDistance += nextShaped.Size.Width; + rightToLeftIndex++; } - for (var j = rightToLeftIndex; rightToLeftIndex >= 0; j--) + for (var j = i; i <= rightToLeftIndex; j++) { + if(j > _textRuns.Count - 1) + { + break; + } + currentRun = _textRuns[j]; - if(distance <= currentDistance + rightToLeftDistance - currentRun.Size.Width) + if(currentDistance + currentRun.Size.Width <= distance) { - currentPosition += currentRun.TextSourceLength; - rightToLeftDistance -= currentRun.Size.Width; + currentDistance += currentRun.Size.Width; + currentPosition -= currentRun.TextSourceLength; continue; } @@ -255,14 +260,18 @@ namespace Avalonia.Media.TextFormatting { characterHit = shapedRun.GlyphRun.GetCharacterHitFromDistance(distance, out _); - var offset = Math.Max(0, currentPosition - shapedRun.Text.Start); + //var offset = 0; - if (!shapedRun.GlyphRun.IsLeftToRight) - { - offset = Math.Max(0, offset - shapedRun.Text.End); - } + //if (shapedRun.GlyphRun.IsLeftToRight) + //{ + // offset = Math.Max(0, currentPosition - shapedRun.Text.Start); + //} + //else + //{ + // offset = Math.Max(0, currentPosition - shapedRun.Text.Start + shapedRun.Text.Length); + //} - characterHit = new CharacterHit(characterHit.FirstCharacterIndex + offset, characterHit.TrailingLength); + //characterHit = new CharacterHit(characterHit.FirstCharacterIndex + offset, characterHit.TrailingLength); break; } @@ -303,35 +312,50 @@ namespace Avalonia.Media.TextFormatting { var i = index; + var rightToLeftWidth = currentRun.Size.Width; + while (i + 1 <= _textRuns.Count - 1) { var nextRun = _textRuns[i + 1]; - if (nextRun is ShapedTextCharacters nextShapedRun) + if (nextRun is ShapedTextCharacters nextShapedRun && !nextShapedRun.ShapedBuffer.IsLeftToRight) { - if (nextShapedRun.ShapedBuffer.IsLeftToRight) - { - break; - } - } + i++; + + rightToLeftWidth += nextRun.Size.Width; - i++; + continue; + } + + break; } - while (i > index) + if(i > index) { - var rightToLeftRun = _textRuns[i]; + while (i >= index) + { + currentRun = _textRuns[i]; + + rightToLeftWidth -= currentRun.Size.Width; - currentPosition += rightToLeftRun.TextSourceLength; + if (currentPosition + currentRun.TextSourceLength >= characterIndex) + { + break; + } - remainingLength -= rightToLeftRun.TextSourceLength; + currentPosition += currentRun.TextSourceLength; - i--; + remainingLength -= currentRun.TextSourceLength; + + i--; + } + + currentDistance += rightToLeftWidth; } } - if (TryGetDistanceFromCharacterHit(currentRun, characterHit, currentPosition, remainingLength, - flowDirection, out var distance, out _)) + if (currentPosition + currentRun.TextSourceLength >= characterIndex && + TryGetDistanceFromCharacterHit(currentRun, characterHit, currentPosition, remainingLength, flowDirection, out var distance, out _)) { return currentDistance + distance; } @@ -608,6 +632,15 @@ namespace Avalonia.Media.TextFormatting } else { + if (currentPosition + currentRun.TextSourceLength <= firstTextSourceIndex) + { + startX += currentRun.Size.Width; + + currentPosition += currentRun.TextSourceLength; + + continue; + } + if (currentPosition < firstTextSourceIndex) { startX += currentRun.Size.Width;