diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs index 3f0cf7c680..4b5568e71a 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs @@ -233,16 +233,16 @@ namespace Avalonia.Media.TextFormatting var textLine = TextFormatter.Current.FormatLine(textSource, 0, MaxWidth, _paragraphProperties); + UpdateBounds(textLine, ref left, ref right, ref bottom); + + textLines.Add(textLine); + if (!double.IsPositiveInfinity(MaxHeight) && bottom + textLine.LineMetrics.Size.Height > MaxHeight) { currentPosition = _text.Length; break; } - UpdateBounds(textLine, ref left, ref right, ref bottom); - - textLines.Add(textLine); - if (_paragraphProperties.TextTrimming != TextTrimming.None) { currentPosition += remainingLength; @@ -254,22 +254,15 @@ namespace Avalonia.Media.TextFormatting currentPosition += textLine.Text.Length; } + } - if (lineBreaker.Current.Required && currentPosition == _text.Length) - { - var emptyTextLine = CreateEmptyTextLine(currentPosition); - - if (!double.IsPositiveInfinity(MaxHeight) && bottom + emptyTextLine.LineMetrics.Size.Height > MaxHeight) - { - break; - } - - UpdateBounds(emptyTextLine, ref left, ref right, ref bottom); + if (lineBreaker.Current.Required && currentPosition == _text.Length) + { + var emptyTextLine = CreateEmptyTextLine(currentPosition); - textLines.Add(emptyTextLine); + UpdateBounds(emptyTextLine, ref left, ref right, ref bottom); - break; - } + textLines.Add(emptyTextLine); } Bounds = new Rect(left, 0, right, bottom); diff --git a/tests/Avalonia.Skia.UnitTests/TextLayoutTests.cs b/tests/Avalonia.Skia.UnitTests/TextLayoutTests.cs index 702e2118f5..15ad51ec47 100644 --- a/tests/Avalonia.Skia.UnitTests/TextLayoutTests.cs +++ b/tests/Avalonia.Skia.UnitTests/TextLayoutTests.cs @@ -29,10 +29,10 @@ namespace Avalonia.Skia.UnitTests var layout = new TextLayout( s_multiLineText, - Typeface.Default, + Typeface.Default, 12.0f, Brushes.Black.ToImmutable(), - textStyleOverrides : spans); + textStyleOverrides: spans); var textLine = layout.TextLines[0]; @@ -72,16 +72,16 @@ namespace Avalonia.Skia.UnitTests 12.0f, Brushes.Black.ToImmutable(), textWrapping: TextWrapping.Wrap, - maxWidth : 25); + maxWidth: 25); var actual = new TextLayout( s_multiLineText, Typeface.Default, 12.0f, Brushes.Black.ToImmutable(), - textWrapping : TextWrapping.Wrap, - maxWidth : 25, - textStyleOverrides : spans); + textWrapping: TextWrapping.Wrap, + maxWidth: 25, + textStyleOverrides: spans); Assert.Equal(expected.TextLines.Count, actual.TextLines.Count); @@ -115,7 +115,7 @@ namespace Avalonia.Skia.UnitTests Typeface.Default, 12.0f, Brushes.Black.ToImmutable(), - textStyleOverrides : spans); + textStyleOverrides: spans); var textLine = layout.TextLines[0]; @@ -153,7 +153,7 @@ namespace Avalonia.Skia.UnitTests Typeface.Default, 12.0f, Brushes.Black.ToImmutable(), - textStyleOverrides : spans); + textStyleOverrides: spans); var textLine = layout.TextLines[0]; @@ -190,7 +190,7 @@ namespace Avalonia.Skia.UnitTests Typeface.Default, 12.0f, Brushes.Black.ToImmutable(), - textStyleOverrides : spans); + textStyleOverrides: spans); var textLine = layout.TextLines[0]; @@ -301,8 +301,8 @@ namespace Avalonia.Skia.UnitTests Typeface.Default, 12.0f, Brushes.Black.ToImmutable(), - textWrapping : TextWrapping.Wrap, - maxWidth : 180, + textWrapping: TextWrapping.Wrap, + maxWidth: 180, textStyleOverrides: spans); Assert.Equal( @@ -332,8 +332,8 @@ namespace Avalonia.Skia.UnitTests Typeface.Default, 12.0f, Brushes.Black.ToImmutable(), - maxWidth : 200, - maxHeight : 125, + maxWidth: 200, + maxHeight: 125, textStyleOverrides: spans); Assert.Equal(foreground, layout.TextLines[0].TextRuns[1].Style.Foreground); @@ -430,7 +430,7 @@ namespace Avalonia.Skia.UnitTests Assert.Equal(5, ((ShapedTextRun)layout.TextLines[0].TextRuns[0]).GlyphRun.GlyphClusters[5]); - if(expectedLength == 7) + if (expectedLength == 7) { Assert.Equal(5, ((ShapedTextRun)layout.TextLines[0].TextRuns[0]).GlyphRun.GlyphClusters[6]); } @@ -480,12 +480,38 @@ namespace Avalonia.Skia.UnitTests } } + [InlineData("0123456789\r0123456789", 2)] + [InlineData("0123456789", 1)] + [Theory] + public void Should_Include_Last_Line_When_Constraint_Is_Surpassed(string text, int numberOfLines) + { + using (Start()) + { + var glyphTypeface = Typeface.Default.GlyphTypeface; + + var emHeight = glyphTypeface.DesignEmHeight; + + var lineHeight = (glyphTypeface.Descent - glyphTypeface.Ascent) * (12.0 / emHeight); + + var layout = new TextLayout( + text, + Typeface.Default, + 12, + Brushes.Black.ToImmutable(), + maxHeight: lineHeight * numberOfLines - lineHeight * 0.5); + + Assert.Equal(numberOfLines, layout.TextLines.Count); + + Assert.Equal(numberOfLines * lineHeight, layout.Bounds.Height); + } + } + public static IDisposable Start() { var disposable = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface - .With(renderInterface: new PlatformRenderInterface(null), + .With(renderInterface: new PlatformRenderInterface(null), textShaperImpl: new TextShaperImpl(), - fontManagerImpl : new CustomFontManagerImpl())); + fontManagerImpl: new CustomFontManagerImpl())); return disposable; }