Browse Source

Add failing test

pull/10139/head
Benedikt Stebner 4 years ago
parent
commit
3f6cb82241
  1. 101
      src/Avalonia.Base/Media/TextFormatting/TextFormatterImpl.cs
  2. 14
      src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs
  3. 8
      tests/Avalonia.Skia.UnitTests/Media/TextFormatting/SingleBufferTextSource.cs
  4. 11
      tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs

101
src/Avalonia.Base/Media/TextFormatting/TextFormatterImpl.cs

@ -60,25 +60,25 @@ namespace Avalonia.Media.TextFormatting
switch (textWrapping)
{
case TextWrapping.NoWrap:
{
// perf note: if textRuns comes from remainingRuns above, it's very likely coming from this class
// which already uses an array: ToArray() won't ever be called in this case
var textRunArray = textRuns as TextRun[] ?? textRuns.ToArray();
{
// perf note: if textRuns comes from remainingRuns above, it's very likely coming from this class
// which already uses an array: ToArray() won't ever be called in this case
var textRunArray = textRuns as TextRun[] ?? textRuns.ToArray();
textLine = new TextLineImpl(textRunArray, firstTextSourceIndex, textSourceLength,
paragraphWidth, paragraphProperties, resolvedFlowDirection, nextLineBreak);
textLine = new TextLineImpl(textRunArray, firstTextSourceIndex, textSourceLength,
paragraphWidth, paragraphProperties, resolvedFlowDirection, nextLineBreak);
textLine.FinalizeLine();
textLine.FinalizeLine();
break;
}
break;
}
case TextWrapping.WrapWithOverflow:
case TextWrapping.Wrap:
{
textLine = PerformTextWrapping(textRuns, firstTextSourceIndex, paragraphWidth,
paragraphProperties, resolvedFlowDirection, nextLineBreak, objectPool, fontManager);
break;
}
{
textLine = PerformTextWrapping(textRuns, firstTextSourceIndex, paragraphWidth,
paragraphProperties, resolvedFlowDirection, nextLineBreak, objectPool, fontManager);
break;
}
default:
throw new ArgumentOutOfRangeException(nameof(textWrapping));
}
@ -249,49 +249,49 @@ namespace Avalonia.Media.TextFormatting
switch (currentRun)
{
case UnshapedTextRun shapeableRun:
{
groupedRuns.Clear();
groupedRuns.Add(shapeableRun);
{
groupedRuns.Clear();
groupedRuns.Add(shapeableRun);
var text = shapeableRun.Text;
var properties = shapeableRun.Properties;
var text = shapeableRun.Text;
var properties = shapeableRun.Properties;
while (index + 1 < processedRuns.Count)
{
if (processedRuns[index + 1] is not UnshapedTextRun nextRun)
while (index + 1 < processedRuns.Count)
{
if (processedRuns[index + 1] is not UnshapedTextRun nextRun)
{
break;
}
if (shapeableRun.BidiLevel == nextRun.BidiLevel
&& TryJoinContiguousMemories(text, nextRun.Text, out var joinedText)
&& CanShapeTogether(properties, nextRun.Properties))
{
groupedRuns.Add(nextRun);
index++;
shapeableRun = nextRun;
text = joinedText;
continue;
}
break;
}
if (shapeableRun.BidiLevel == nextRun.BidiLevel
&& TryJoinContiguousMemories(text, nextRun.Text, out var joinedText)
&& CanShapeTogether(properties, nextRun.Properties))
{
groupedRuns.Add(nextRun);
index++;
shapeableRun = nextRun;
text = joinedText;
continue;
}
var shaperOptions = new TextShaperOptions(
properties.CachedGlyphTypeface,
properties.FontRenderingEmSize, shapeableRun.BidiLevel, properties.CultureInfo,
paragraphProperties.DefaultIncrementalTab, paragraphProperties.LetterSpacing);
ShapeTogether(groupedRuns, text, shaperOptions, textShaper, shapedRuns);
break;
}
var shaperOptions = new TextShaperOptions(
properties.CachedGlyphTypeface,
properties.FontRenderingEmSize, shapeableRun.BidiLevel, properties.CultureInfo,
paragraphProperties.DefaultIncrementalTab, paragraphProperties.LetterSpacing);
ShapeTogether(groupedRuns, text, shaperOptions, textShaper, shapedRuns);
break;
}
default:
{
shapedRuns.Add(currentRun);
{
shapedRuns.Add(currentRun);
break;
}
break;
}
}
}
}
@ -712,7 +712,7 @@ namespace Avalonia.Media.TextFormatting
switch (currentRun)
{
case ShapedTextRun:
{
{
var lineBreaker = new LineBreakEnumerator(currentRun.Text.Span);
while (lineBreaker.MoveNext(out var lineBreak))
@ -754,7 +754,7 @@ namespace Avalonia.Media.TextFormatting
break;
}
while (lineBreaker.MoveNext(out lineBreak) && index < textRuns.Count)
while (lineBreaker.MoveNext(out lineBreak))
{
currentPosition += lineBreak.PositionWrap;
@ -780,6 +780,11 @@ namespace Avalonia.Media.TextFormatting
currentPosition = currentLength + lineBreak.PositionWrap;
}
//if (currentPosition == 0 && measuredLength > 0)
//{
// currentPosition = measuredLength;
//}
breakFound = true;
break;

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

@ -172,9 +172,21 @@ namespace Avalonia.Media.TextFormatting
distance -= Start;
var firstRunIndex = 0;
if (_textRuns[firstRunIndex] is TextEndOfLine)
{
firstRunIndex++;
}
if(firstRunIndex >= _textRuns.Length)
{
return new CharacterHit(FirstTextSourceIndex);
}
if (distance <= 0)
{
var firstRun = _textRuns[0];
var firstRun = _textRuns[firstRunIndex];
return GetRunCharacterHit(firstRun, FirstTextSourceIndex, 0);
}

8
tests/Avalonia.Skia.UnitTests/Media/TextFormatting/SingleBufferTextSource.cs

@ -7,25 +7,27 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
{
private readonly string _text;
private readonly GenericTextRunProperties _defaultGenericPropertiesRunProperties;
private readonly bool _addEndOfParagraph;
public SingleBufferTextSource(string text, GenericTextRunProperties defaultProperties)
public SingleBufferTextSource(string text, GenericTextRunProperties defaultProperties, bool addEndOfParagraph = false)
{
_text = text;
_defaultGenericPropertiesRunProperties = defaultProperties;
_addEndOfParagraph = addEndOfParagraph;
}
public TextRun GetTextRun(int textSourceIndex)
{
if (textSourceIndex >= _text.Length)
{
return null;
return _addEndOfParagraph ? new TextEndOfParagraph() : null;
}
var runText = _text.AsMemory(textSourceIndex);
if (runText.IsEmpty)
{
return null;
return _addEndOfParagraph ? new TextEndOfParagraph() : null;
}
return new TextCharacters(runText, _defaultGenericPropertiesRunProperties);

11
tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs

@ -242,10 +242,16 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
{
var defaultProperties = new GenericTextRunProperties(Typeface.Default);
var textSource = new SingleBufferTextSource(text, defaultProperties);
var paragraphProperties = new GenericTextParagraphProperties(defaultProperties, textWrap: TextWrapping.WrapWithOverflow);
var textSource = new SingleBufferTextSource("ABCDEFHFFHFJHKHFK", defaultProperties, true);
var formatter = new TextFormatterImpl();
var line = formatter.FormatLine(textSource, 0, 33, paragraphProperties);
textSource = new SingleBufferTextSource(text, defaultProperties);
var numberOfLines = 0;
var currentPosition = 0;
@ -253,8 +259,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
while (currentPosition < text.Length)
{
var textLine =
formatter.FormatLine(textSource, currentPosition, 1,
new GenericTextParagraphProperties(defaultProperties, textWrap: TextWrapping.WrapWithOverflow));
formatter.FormatLine(textSource, currentPosition, 1, paragraphProperties);
if (text.Length - currentPosition > expectedCharactersPerLine)
{

Loading…
Cancel
Save