Browse Source

Fixes TextLineImpl.GetTextBounds with trailing zero width (#19616)

* Fixes TextLineImpl.GetTextBounds with trailing zero width

* Add assert
pull/19618/head
Benedikt Stebner 5 months ago
committed by GitHub
parent
commit
ec9f50db3d
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 18
      src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs
  2. 38
      tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs

18
src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs

@ -1118,23 +1118,29 @@ namespace Avalonia.Media.TextFormatting
} }
// Find the start of the hit // Find the start of the hit
var startHit = currentRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _); var startHit = currentRun.GlyphRun.FindNearestCharacterHit(startIndex, out _);
var startHitIndex = startHit.FirstCharacterIndex + startHit.TrailingLength; var startHitIndex = startHit.FirstCharacterIndex;
//If the requested text range starts at the trailing edge we need to move at the end of the hit
if(startHitIndex < startIndex)
{
startHitIndex += startHit.TrailingLength;
}
//Find the next possible position that contains the endIndex //Find the next possible position that contains the endIndex
var nearestCharacterHit = currentRun.GlyphRun.FindNearestCharacterHit(endIndex, out _); var nearestEndHit = currentRun.GlyphRun.FindNearestCharacterHit(endIndex, out _);
int endHitIndex; int endHitIndex;
if (nearestCharacterHit.FirstCharacterIndex < endIndex) if (nearestEndHit.FirstCharacterIndex < endIndex)
{ {
//The hit is inside or at the trailing edge //The hit is inside or at the trailing edge
endHitIndex = nearestCharacterHit.FirstCharacterIndex + nearestCharacterHit.TrailingLength; endHitIndex = nearestEndHit.FirstCharacterIndex + nearestEndHit.TrailingLength;
} }
else else
{ {
//The hit is at the leading edge //The hit is at the leading edge
endHitIndex = nearestCharacterHit.FirstCharacterIndex; endHitIndex = nearestEndHit.FirstCharacterIndex;
} }
var coveredLength = Math.Max(0, Math.Abs(startHitIndex - endHitIndex) - clusterOffset); var coveredLength = Math.Max(0, Math.Abs(startHitIndex - endHitIndex) - clusterOffset);

38
tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs

@ -2135,6 +2135,44 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
} }
} }
[Fact]
public void Should_GetTextBounds_Trailing_ZeroWidth()
{
var text = "dasdsad\r\n";
using (Start())
{
var typeface = Typeface.Default;
var defaultProperties = new GenericTextRunProperties(typeface);
var shaperOption = new TextShaperOptions(typeface.GlyphTypeface);
var textSource = new SingleBufferTextSource(text, defaultProperties);
var formatter = new TextFormatterImpl();
var textLine =
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
var textBounds = textLine.GetTextBounds(7, 3);
Assert.NotEmpty(textBounds);
var firstBounds = textBounds[0];
Assert.NotEmpty(firstBounds.TextRunBounds);
var firstRunBounds = firstBounds.TextRunBounds[0];
Assert.Equal(7, firstRunBounds.TextSourceCharacterIndex);
Assert.Equal(2, firstRunBounds.Length);
}
}
private class FixedRunsTextSource : ITextSource private class FixedRunsTextSource : ITextSource
{ {
private readonly IReadOnlyList<TextRun> _textRuns; private readonly IReadOnlyList<TextRun> _textRuns;

Loading…
Cancel
Save