Browse Source

More TextAlignment fixes

pull/8347/head
Benedikt Stebner 4 years ago
parent
commit
6502fa1ef7
  1. 4
      src/Avalonia.Base/Media/TextFormatting/TextFormatterImpl.cs
  2. 2
      src/Avalonia.Base/Media/TextFormatting/TextLayout.cs
  3. 97
      tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs

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

@ -404,6 +404,10 @@ namespace Avalonia.Media.TextFormatting
{ {
endOfLine = textEndOfLine; endOfLine = textEndOfLine;
textSourceLength += textEndOfLine.TextSourceLength;
textRuns.Add(textRun);
break; break;
} }

2
src/Avalonia.Base/Media/TextFormatting/TextLayout.cs

@ -439,7 +439,7 @@ namespace Avalonia.Media.TextFormatting
var textLine = TextFormatter.Current.FormatLine(_textSource, _textSourceLength, MaxWidth, var textLine = TextFormatter.Current.FormatLine(_textSource, _textSourceLength, MaxWidth,
_paragraphProperties, previousLine?.TextLineBreak); _paragraphProperties, previousLine?.TextLineBreak);
if(textLine == null || textLine.Length == 0) if(textLine == null || textLine.Length == 0 || textLine.TextRuns.Count == 0 && textLine.TextLineBreak?.TextEndOfLine is TextEndOfParagraph)
{ {
if(previousLine != null && previousLine.NewLineLength > 0) if(previousLine != null && previousLine.NewLineLength > 0)
{ {

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

@ -134,7 +134,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var defaultProperties = new GenericTextRunProperties(Typeface.Default); var defaultProperties = new GenericTextRunProperties(Typeface.Default);
const string text = "👍 👍 👍 👍"; const string text = "👍 👍 👍 👍";
var textSource = new SingleBufferTextSource(text, defaultProperties); var textSource = new SingleBufferTextSource(text, defaultProperties);
var formatter = new TextFormatterImpl(); var formatter = new TextFormatterImpl();
@ -144,7 +144,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
new GenericTextParagraphProperties(defaultProperties)); new GenericTextParagraphProperties(defaultProperties));
Assert.Equal(1, textLine.TextRuns.Count); Assert.Equal(1, textLine.TextRuns.Count);
} }
} }
[Fact] [Fact]
@ -163,9 +163,9 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var textLine = var textLine =
formatter.FormatLine(textSource, 0, double.PositiveInfinity, formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties)); new GenericTextParagraphProperties(defaultProperties));
var firstRun = textLine.TextRuns[0]; var firstRun = textLine.TextRuns[0];
Assert.Equal(4, firstRun.Text.Length); Assert.Equal(4, firstRun.Text.Length);
} }
} }
@ -191,7 +191,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
{ {
var textLine = var textLine =
formatter.FormatLine(textSource, currentPosition, 1, formatter.FormatLine(textSource, currentPosition, 1,
new GenericTextParagraphProperties(defaultProperties, textWrap : TextWrapping.WrapWithOverflow)); new GenericTextParagraphProperties(defaultProperties, textWrap: TextWrapping.WrapWithOverflow));
if (text.Length - currentPosition > expectedCharactersPerLine) if (text.Length - currentPosition > expectedCharactersPerLine)
{ {
@ -347,8 +347,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
} }
} }
[InlineData("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor", [InlineData("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor",
new []{ "Lorem ipsum ", "dolor sit amet, ", "consectetur ", "adipisicing elit, ", "sed do eiusmod "})] new[] { "Lorem ipsum ", "dolor sit amet, ", "consectetur ", "adipisicing elit, ", "sed do eiusmod " })]
[Theory] [Theory]
public void Should_Produce_Wrapped_And_Trimmed_Lines(string text, string[] expectedLines) public void Should_Produce_Wrapped_And_Trimmed_Lines(string text, string[] expectedLines)
@ -368,7 +368,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
new ValueSpan<TextRunProperties>(28, 28, new ValueSpan<TextRunProperties>(28, 28,
new GenericTextRunProperties(new Typeface("Verdana", FontStyle.Italic),32)) new GenericTextRunProperties(new Typeface("Verdana", FontStyle.Italic),32))
}; };
var textSource = new FormattedTextSource(text.AsMemory(), defaultProperties, styleSpans); var textSource = new FormattedTextSource(text.AsMemory(), defaultProperties, styleSpans);
var formatter = new TextFormatterImpl(); var formatter = new TextFormatterImpl();
@ -389,19 +389,19 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
if (textLine.Width > 300 || currentHeight + textLine.Height > 240) if (textLine.Width > 300 || currentHeight + textLine.Height > 240)
{ {
textLine = textLine.Collapse(new TextTrailingWordEllipsis(new ReadOnlySlice<char>(new[] {TextTrimming.s_defaultEllipsisChar}), 300, defaultProperties)); textLine = textLine.Collapse(new TextTrailingWordEllipsis(new ReadOnlySlice<char>(new[] { TextTrimming.s_defaultEllipsisChar }), 300, defaultProperties));
} }
currentHeight += textLine.Height; currentHeight += textLine.Height;
var currentText = text.Substring(textLine.FirstTextSourceIndex, textLine.Length); var currentText = text.Substring(textLine.FirstTextSourceIndex, textLine.Length);
Assert.Equal(expectedLines[currentLineIndex], currentText); Assert.Equal(expectedLines[currentLineIndex], currentText);
currentLineIndex++; currentLineIndex++;
} }
Assert.Equal(expectedLines.Length,currentLineIndex); Assert.Equal(expectedLines.Length, currentLineIndex);
} }
} }
@ -412,11 +412,11 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
[InlineData("0123456789", TextAlignment.Left, FlowDirection.RightToLeft)] [InlineData("0123456789", TextAlignment.Left, FlowDirection.RightToLeft)]
[InlineData("0123456789", TextAlignment.Center, FlowDirection.RightToLeft)] [InlineData("0123456789", TextAlignment.Center, FlowDirection.RightToLeft)]
[InlineData("0123456789", TextAlignment.Right, FlowDirection.RightToLeft)] [InlineData("0123456789", TextAlignment.Right, FlowDirection.RightToLeft)]
[InlineData("שנבגק", TextAlignment.Left, FlowDirection.RightToLeft)] [InlineData("שנבגק", TextAlignment.Left, FlowDirection.RightToLeft)]
[InlineData("שנבגק", TextAlignment.Center, FlowDirection.RightToLeft)] [InlineData("שנבגק", TextAlignment.Center, FlowDirection.RightToLeft)]
[InlineData("שנבגק", TextAlignment.Right, FlowDirection.RightToLeft)] [InlineData("שנבגק", TextAlignment.Right, FlowDirection.RightToLeft)]
[Theory] [Theory]
public void Should_Align_TextLine(string text, TextAlignment textAlignment, FlowDirection flowDirection) public void Should_Align_TextLine(string text, TextAlignment textAlignment, FlowDirection flowDirection)
{ {
@ -426,44 +426,29 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var paragraphProperties = new GenericTextParagraphProperties(flowDirection, textAlignment, true, true, var paragraphProperties = new GenericTextParagraphProperties(flowDirection, textAlignment, true, true,
defaultProperties, TextWrapping.NoWrap, 0, 0); defaultProperties, TextWrapping.NoWrap, 0, 0);
var textSource = new SingleBufferTextSource(text, defaultProperties); var textSource = new SingleBufferTextSource(text, defaultProperties);
var formatter = new TextFormatterImpl(); var formatter = new TextFormatterImpl();
var textLine = var textLine =
formatter.FormatLine(textSource, 0, 100, paragraphProperties); formatter.FormatLine(textSource, 0, 100, paragraphProperties);
var expectedOffset = 0d; var expectedOffset = 0d;
if (flowDirection == FlowDirection.LeftToRight) switch (textAlignment)
{ {
switch (textAlignment) case TextAlignment.Center:
{ expectedOffset = 50 - textLine.Width / 2;
case TextAlignment.Center: break;
expectedOffset = 50 - textLine.Width / 2; case TextAlignment.Right:
break; expectedOffset = 100 - textLine.WidthIncludingTrailingWhitespace;
case TextAlignment.Right: break;
expectedOffset = 100 - textLine.WidthIncludingTrailingWhitespace;
break;
}
}
else
{
switch (textAlignment)
{
case TextAlignment.Left:
expectedOffset = 100 - textLine.WidthIncludingTrailingWhitespace;
break;
case TextAlignment.Center:
expectedOffset = 50 - textLine.Width / 2;
break;
}
} }
Assert.Equal(expectedOffset, textLine.Start); Assert.Equal(expectedOffset, textLine.Start);
} }
} }
[Fact] [Fact]
public void Should_Wrap_Syriac() public void Should_Wrap_Syriac()
{ {
@ -488,7 +473,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, textPosition, 50, paragraphProperties, lastBreak); formatter.FormatLine(textSource, textPosition, 50, paragraphProperties, lastBreak);
Assert.Equal(textLine.Length, textLine.TextRuns.Sum(x => x.TextSourceLength)); Assert.Equal(textLine.Length, textLine.TextRuns.Sum(x => x.TextSourceLength));
textPosition += textLine.Length; textPosition += textLine.Length;
lastBreak = textLine.TextLineBreak; lastBreak = textLine.TextLineBreak;
@ -503,13 +488,13 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
{ {
var defaultProperties = new GenericTextRunProperties(Typeface.Default); var defaultProperties = new GenericTextRunProperties(Typeface.Default);
var paragraphProperties = new GenericTextParagraphProperties(defaultProperties, textWrap: TextWrapping.Wrap); var paragraphProperties = new GenericTextParagraphProperties(defaultProperties, textWrap: TextWrapping.Wrap);
var textSource = new SingleBufferTextSource("0123456789_0123456789_0123456789_0123456789", defaultProperties); var textSource = new SingleBufferTextSource("0123456789_0123456789_0123456789_0123456789", defaultProperties);
var formatter = new TextFormatterImpl(); var formatter = new TextFormatterImpl();
var textLine = var textLine =
formatter.FormatLine(textSource, 0, 33, paragraphProperties); formatter.FormatLine(textSource, 0, 33, paragraphProperties);
Assert.NotNull(textLine.TextLineBreak?.RemainingRuns); Assert.NotNull(textLine.TextLineBreak?.RemainingRuns);
} }
} }
@ -524,12 +509,12 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
using (Start()) using (Start())
{ {
var formatter = new TextFormatterImpl(); var formatter = new TextFormatterImpl();
var defaultProperties = new GenericTextRunProperties(Typeface.Default); var defaultProperties = new GenericTextRunProperties(Typeface.Default);
var paragraphProperties = var paragraphProperties =
new GenericTextParagraphProperties(defaultProperties, textWrap: TextWrapping.NoWrap); new GenericTextParagraphProperties(defaultProperties, textWrap: TextWrapping.NoWrap);
var foreground = new SolidColorBrush(Colors.Red).ToImmutable(); var foreground = new SolidColorBrush(Colors.Red).ToImmutable();
var expectedTextLine = formatter.FormatLine(new SingleBufferTextSource(text, defaultProperties), var expectedTextLine = formatter.FormatLine(new SingleBufferTextSource(text, defaultProperties),
@ -548,16 +533,16 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
new ValueSpan<TextRunProperties>(i, j, new ValueSpan<TextRunProperties>(i, j,
new GenericTextRunProperties(Typeface.Default, 12, foregroundBrush: foreground)) new GenericTextRunProperties(Typeface.Default, 12, foregroundBrush: foreground))
}; };
var textSource = new FormattedTextSource(text.AsMemory(), defaultProperties, spans); var textSource = new FormattedTextSource(text.AsMemory(), defaultProperties, spans);
var textLine = var textLine =
formatter.FormatLine(textSource, 0, double.PositiveInfinity, paragraphProperties); formatter.FormatLine(textSource, 0, double.PositiveInfinity, paragraphProperties);
var shapedRuns = textLine.TextRuns.Cast<ShapedTextCharacters>().ToList(); var shapedRuns = textLine.TextRuns.Cast<ShapedTextCharacters>().ToList();
var actualGlyphs = shapedRuns.SelectMany(x => x.GlyphRun.GlyphIndices).ToList(); var actualGlyphs = shapedRuns.SelectMany(x => x.GlyphRun.GlyphIndices).ToList();
Assert.Equal(expectedGlyphs, actualGlyphs); Assert.Equal(expectedGlyphs, actualGlyphs);
} }
} }
@ -575,9 +560,9 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
{ {
var textLine = var textLine =
TextFormatter.Current.FormatLine(textSource, 0, double.PositiveInfinity, paragraphProperties); TextFormatter.Current.FormatLine(textSource, 0, double.PositiveInfinity, paragraphProperties);
Assert.Equal(3, textLine.TextRuns.Count); Assert.Equal(3, textLine.TextRuns.Count);
Assert.True(textLine.TextRuns[1] is RectangleRun); Assert.True(textLine.TextRuns[1] is RectangleRun);
} }
} }
@ -590,12 +575,12 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var defaultRunProperties = new GenericTextRunProperties(Typeface.Default); var defaultRunProperties = new GenericTextRunProperties(Typeface.Default);
var paragraphProperties = new GenericTextParagraphProperties(defaultRunProperties); var paragraphProperties = new GenericTextParagraphProperties(defaultRunProperties);
var textSource = new EndOfLineTextSource(); var textSource = new EndOfLineTextSource();
var textLine = var textLine =
TextFormatter.Current.FormatLine(textSource, 0, double.PositiveInfinity, paragraphProperties); TextFormatter.Current.FormatLine(textSource, 0, double.PositiveInfinity, paragraphProperties);
Assert.NotNull(textLine.TextLineBreak); Assert.NotNull(textLine.TextLineBreak);
Assert.Equal(TextRun.DefaultTextSourceLength, textLine.Length); Assert.Equal(TextRun.DefaultTextSourceLength, textLine.Length);
} }
} }
@ -616,7 +601,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
{ {
_text = text; _text = text;
} }
public TextRun GetTextRun(int textSourceIndex) public TextRun GetTextRun(int textSourceIndex)
{ {
if (textSourceIndex >= _text.Length + TextRun.DefaultTextSourceLength + _text.Length) if (textSourceIndex >= _text.Length + TextRun.DefaultTextSourceLength + _text.Length)

Loading…
Cancel
Save