Skip to content

Commit

Permalink
Do not shape and render null terminator (#17119)
Browse files Browse the repository at this point in the history
* Ignore null terminator and replace them with a zero space before shaping

* Replace multiple null terminators at random positions
  • Loading branch information
Gillibald authored Sep 26, 2024
1 parent f1135d2 commit 432fbe8
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 14 deletions.
24 changes: 23 additions & 1 deletion src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ namespace Avalonia.Media.TextFormatting
/// </summary>
public class TextCharacters : TextRun
{
private static char ZeroWidthSpace = '\u200b';

/// <summary>
/// Constructs a run for text content from a string.
/// </summary>
Expand Down Expand Up @@ -82,7 +84,21 @@ private static UnshapedTextRun CreateShapeableRun(ReadOnlyMemory<char> text,
var previousGlyphTypeface = previousProperties?.CachedGlyphTypeface;
var textSpan = text.Span;

if (TryGetShapeableLength(textSpan, defaultGlyphTypeface, null, out var count))
var count = 0;
var codepoints = new CodepointEnumerator(textSpan);

while(codepoints.MoveNext(out var firstCodepoint) && firstCodepoint.Value == 0)
{
count++;
}

//Detect null terminator
if (count > 0)
{
return new UnshapedTextRun(new string(ZeroWidthSpace, count).AsMemory(), defaultProperties, biDiLevel);
}

if (TryGetShapeableLength(textSpan, defaultGlyphTypeface, null, out count))
{
return new UnshapedTextRun(text.Slice(0, count), defaultProperties.WithTypeface(defaultTypeface),
biDiLevel);
Expand Down Expand Up @@ -177,6 +193,12 @@ internal static bool TryGetShapeableLength(
var currentCodepoint = currentGrapheme.FirstCodepoint;
var currentScript = currentCodepoint.Script;

if(currentCodepoint.Value == 0)
{
//Do not include null terminators
break;
}

if (!currentCodepoint.IsWhiteSpace
&& defaultGlyphTypeface != null
&& defaultGlyphTypeface.TryGetGlyph(currentCodepoint, out _))
Expand Down
14 changes: 1 addition & 13 deletions src/Skia/Avalonia.Skia/TextShaperImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ namespace Avalonia.Skia
{
internal class TextShaperImpl : ITextShaperImpl
{
private const uint ZeroWidthSpace = '\u200b';

private static readonly ConcurrentDictionary<int, Language> s_cachedLanguage = new();

public ShapedBuffer ShapeText(ReadOnlyMemory<char> text, TextShaperOptions options)
Expand Down Expand Up @@ -69,17 +67,7 @@ public ShapedBuffer ShapeText(ReadOnlyMemory<char> text, TextShaperOptions optio

var glyphIndex = (ushort)sourceInfo.Codepoint;

var glyphCluster = (int)(sourceInfo.Cluster);

if (glyphIndex == 0)
{
var codepoint = Codepoint.ReadAt(textSpan, glyphCluster, out _);

if (codepoint.GeneralCategory == GeneralCategory.Control)
{
glyphIndex = options.Typeface.GetGlyph(ZeroWidthSpace);
}
}
var glyphCluster = (int)sourceInfo.Cluster;

var glyphAdvance = GetGlyphAdvance(glyphPositions, i, textScale) + options.LetterSpacing;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1374,6 +1374,31 @@ public void Should_GetPreviousCharacterHit_Non_Trailing()
}
}

[Theory]
[InlineData("\0", 0.0)]
[InlineData("\0\0\0", 0.0)]
[InlineData("\0A\0\0", 7.201171875)]
[InlineData("\0AA\0AA\0", 28.8046875)]
public void Should_Ignore_Null_Terminator(string text, double width)
{
using (Start())
{
var defaultProperties = new GenericTextRunProperties(Typeface.Default);
var textSource = new SingleBufferTextSource(text, defaultProperties, true);

var formatter = new TextFormatterImpl();

var textLine =
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(FlowDirection.LeftToRight, TextAlignment.Left,
true, true, defaultProperties, TextWrapping.NoWrap, 0, 0, 0));

Assert.NotNull(textLine);

Assert.Equal(width, textLine.Width);
}
}

private class FixedRunsTextSource : ITextSource
{
private readonly IReadOnlyList<TextRun> _textRuns;
Expand Down

0 comments on commit 432fbe8

Please sign in to comment.