diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs b/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs index 590d2f2133..34dc8e8420 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs @@ -273,11 +273,6 @@ namespace Avalonia.Media.TextFormatting } } - /// - /// Get minimum width of all text lines that can be layouted horizontally without trimming or wrapping. - /// - internal double MinTextWidth => _metrics.MinTextWidth; - /// /// Draws the text layout. /// @@ -679,45 +674,30 @@ namespace Avalonia.Media.TextFormatting private void UpdateMetrics(TextLineImpl currentLine, ref bool first) { - // 1) Offset each line’s bounding rectangles by the total height so far, - // so we keep an overall bounding box for the entire text block. - var lineTop = _metrics.Height; - - // Offset the line's Bounds - var lineBoundsRect = new Rect( - currentLine.Bounds.X, - lineTop + currentLine.Bounds.Y, - currentLine.Bounds.Width, - currentLine.Bounds.Height); - - _metrics.Bounds = _metrics.Bounds.Union(lineBoundsRect); - - // Offset the line's InkBounds - var lineInkRect = new Rect( - currentLine.InkBounds.X, - lineTop + currentLine.InkBounds.Y, - currentLine.InkBounds.Width, - currentLine.InkBounds.Height); - - _metrics.InkBounds = _metrics.InkBounds.Union(lineInkRect); - - // 2) Accumulate total layout height by adding the line’s Height. + // 1) Accumulate total layout height by adding the line’s Height. _metrics.Height += currentLine.Height; - // 3) For the layout’s Width and WidthIncludingTrailingWhitespace, + // 2) For the layout’s Width and WidthIncludingTrailingWhitespace, // use the maximum of the line widths rather than the bounding box. _metrics.Width = Math.Max(_metrics.Width, currentLine.Width); - _metrics.WidthIncludingTrailingWhitespace = Math.Max(_metrics.WidthIncludingTrailingWhitespace, currentLine.WidthIncludingTrailingWhitespace); - // 4) Extent is the max black-pixel extent among lines. + // 3) Extent is the max black-pixel extent among lines. _metrics.Extent = Math.Max(_metrics.Extent, currentLine.Extent); - // 5) We can track min-text-width or overhangs similarly if needed. - _metrics.MinTextWidth = Math.Max(_metrics.MinTextWidth, currentLine.Width); + // 4) TextWidth is the max of the text width among lines. + // We choose to update all related metrics at once (OverhangLeading, WidthIncludingTrailingWhitespace, OverhangTrailing) + // if the current line has a larger text width. + var previousTextWidth = _metrics.OverhangLeading + _metrics.WidthIncludingTrailingWhitespace + _metrics.OverhangTrailing; + var textWidth = currentLine.OverhangLeading + currentLine.WidthIncludingTrailingWhitespace + currentLine.OverhangTrailing; + if (previousTextWidth < textWidth) + { + _metrics.WidthIncludingTrailingWhitespace = currentLine.WidthIncludingTrailingWhitespace; + _metrics.OverhangLeading = currentLine.OverhangLeading; + _metrics.OverhangTrailing = currentLine.OverhangTrailing; + } - _metrics.OverhangLeading = Math.Max(_metrics.OverhangLeading, currentLine.OverhangLeading); - _metrics.OverhangTrailing = Math.Max(_metrics.OverhangTrailing, currentLine.OverhangTrailing); - _metrics.OverhangAfter = Math.Max(_metrics.OverhangAfter, currentLine.OverhangAfter); + // 5) OverhangAfter is the last line’s OverhangAfter. + _metrics.OverhangAfter = currentLine.OverhangAfter; // 6) Capture the baseline from the first line. if (first) @@ -768,11 +748,6 @@ namespace Avalonia.Media.TextFormatting // horizontal bounding box metrics public double OverhangLeading; public double OverhangTrailing; - - public Rect Bounds; - public Rect InkBounds; - - public double MinTextWidth; } } } diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs index e0cb22607d..67aa4de569 100644 --- a/src/Avalonia.Controls/Presenters/TextPresenter.cs +++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs @@ -627,8 +627,8 @@ namespace Avalonia.Controls.Presenters InvalidateArrange(); + // The textWidth used here is matching that TextBlock uses to measure the text. var textWidth = TextLayout.OverhangLeading + TextLayout.WidthIncludingTrailingWhitespace + TextLayout.OverhangTrailing; - return new Size(textWidth, TextLayout.Height); } @@ -636,7 +636,8 @@ namespace Avalonia.Controls.Presenters { var finalWidth = finalSize.Width; - var textWidth = Math.Ceiling(TextLayout.OverhangLeading + TextLayout.WidthIncludingTrailingWhitespace + TextLayout.OverhangTrailing); + var textWidth = TextLayout.OverhangLeading + TextLayout.WidthIncludingTrailingWhitespace + TextLayout.OverhangTrailing; + textWidth = Math.Ceiling(textWidth); if (finalSize.Width < textWidth) { diff --git a/src/Avalonia.Controls/TextBlock.cs b/src/Avalonia.Controls/TextBlock.cs index a8324b2a5a..40d7aa907f 100644 --- a/src/Avalonia.Controls/TextBlock.cs +++ b/src/Avalonia.Controls/TextBlock.cs @@ -628,7 +628,7 @@ namespace Avalonia.Controls protected virtual void RenderTextLayout(DrawingContext context, Point origin) { - TextLayout.Draw(context, origin + new Point(TextLayout.OverhangLeading, 0)); + TextLayout.Draw(context, origin); } private bool _clearTextInternal; @@ -740,7 +740,8 @@ namespace Avalonia.Controls //This implicitly recreated the TextLayout with a new constraint if we previously reset it. var textLayout = TextLayout; - var size = LayoutHelper.RoundLayoutSizeUp(new Size(textLayout.MinTextWidth, textLayout.Height).Inflate(padding), 1, 1); + // The textWidth used here is matching that TextPresenter uses to measure the text. + var size = LayoutHelper.RoundLayoutSizeUp(new Size(textLayout.WidthIncludingTrailingWhitespace, textLayout.Height).Inflate(padding), 1, 1); return size; } diff --git a/src/Skia/Avalonia.Skia/GlyphRunImpl.cs b/src/Skia/Avalonia.Skia/GlyphRunImpl.cs index 205daf4c7b..001dced0d4 100644 --- a/src/Skia/Avalonia.Skia/GlyphRunImpl.cs +++ b/src/Skia/Avalonia.Skia/GlyphRunImpl.cs @@ -74,12 +74,6 @@ namespace Avalonia.Skia currentX += advance; } - - if (runBounds.Left < 0) - { - runBounds = runBounds.Translate(new Vector(-runBounds.Left, 0)); - } - ArrayPool.Shared.Return(glyphBounds); BaselineOrigin = baselineOrigin; diff --git a/src/Windows/Avalonia.Direct2D1/Media/GlyphRunImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/GlyphRunImpl.cs index 875164df96..7f8282e4ed 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/GlyphRunImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/GlyphRunImpl.cs @@ -50,7 +50,10 @@ namespace Avalonia.Direct2D1.Media } _glyphOffsets = new GlyphOffset[glyphCount]; - + + var runBounds = new Rect(); + var currentX = 0.0; + var scale = fontRenderingEmSize / glyphTypeface.Metrics.DesignEmHeight; for (var i = 0; i < glyphCount; i++) { var (x, y) = glyphInfos[i].GlyphOffset; @@ -60,13 +63,29 @@ namespace Avalonia.Direct2D1.Media AdvanceOffset = (float)x, AscenderOffset = (float)y }; - } - var scale = fontRenderingEmSize / glyphTypeface.Metrics.DesignEmHeight; + if (_glyphTypefaceImpl.TryGetGlyphMetrics(glyphInfos[i].GlyphIndex, out var metrics)) + { + // Found metrics with negative height, prefer to adjust it to positive. + var ybearing = metrics.YBearing; + var height = metrics.Height; + if (height < 0) + { + ybearing += height; + height = -height; + } + + // Not entirely sure about why we need to do this, but it seems to work + var xOffset = metrics.XBearing * scale; + var xWidth = xOffset > 0 ? xOffset : 0; + var xBearing = xOffset < 0 ? xOffset : 0; + runBounds = runBounds.Union(new Rect(currentX + xBearing, baselineOrigin.Y + ybearing, xWidth + metrics.Width * scale, height * scale)); + } - var height = glyphTypeface.Metrics.LineSpacing * scale; + currentX += glyphInfos[i].GlyphAdvance; + } - Bounds = new Rect(baselineOrigin.X, 0, width, height); + Bounds = runBounds.Translate(new Vector(baselineOrigin.X, 0)); } public SharpDX.DirectWrite.GlyphRun GlyphRun diff --git a/tests/Avalonia.Controls.UnitTests/TextBlockTests.cs b/tests/Avalonia.Controls.UnitTests/TextBlockTests.cs index f1399d83bc..8ed2e5199c 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBlockTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBlockTests.cs @@ -66,7 +66,7 @@ namespace Avalonia.Controls.UnitTests var textLayout = textBlock.TextLayout; - var constraint = LayoutHelper.RoundLayoutSizeUp(new Size(textLayout.MinTextWidth, textLayout.Height), 1, 1); + var constraint = LayoutHelper.RoundLayoutSizeUp(new Size(textLayout.Width, textLayout.Height), 1, 1); Assert.Equal(textBlock.DesiredSize, constraint); } diff --git a/tests/Avalonia.RenderTests/Assets/SourceSerif4_36pt-Italic.ttf b/tests/Avalonia.RenderTests/Assets/SourceSerif4_36pt-Italic.ttf new file mode 100644 index 0000000000..901eb7e6b1 Binary files /dev/null and b/tests/Avalonia.RenderTests/Assets/SourceSerif4_36pt-Italic.ttf differ diff --git a/tests/Avalonia.RenderTests/Controls/TextBlockTests.cs b/tests/Avalonia.RenderTests/Controls/TextBlockTests.cs index 473461dcb4..ad543ae4e7 100644 --- a/tests/Avalonia.RenderTests/Controls/TextBlockTests.cs +++ b/tests/Avalonia.RenderTests/Controls/TextBlockTests.cs @@ -1,3 +1,5 @@ +using System; +using System.IO; using System.Net; using System.Threading.Tasks; using Avalonia.Controls; @@ -5,7 +7,6 @@ using Avalonia.Controls.Documents; using Avalonia.Layout; using Avalonia.Media; using Xunit; -using static System.Net.Mime.MediaTypeNames; #if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests @@ -217,60 +218,60 @@ namespace Avalonia.Direct2D1.RenderTests.Controls TextWrapping = textWrapping }); - target.Children.Add(new TextBlock + target.Children.Add(new TextBlock { Text = text, Background = Brushes.Red, HorizontalAlignment = HorizontalAlignment.Center, - TextAlignment = TextAlignment.Left, - Width = width, + TextAlignment = TextAlignment.Left, + Width = width, TextWrapping = textWrapping }); - target.Children.Add(new TextBlock - { - Text = text, - Background = Brushes.Red, - HorizontalAlignment = HorizontalAlignment.Center, - TextAlignment = TextAlignment.Center, + target.Children.Add(new TextBlock + { + Text = text, + Background = Brushes.Red, + HorizontalAlignment = HorizontalAlignment.Center, + TextAlignment = TextAlignment.Center, Width = width, TextWrapping = textWrapping }); - target.Children.Add(new TextBlock - { + target.Children.Add(new TextBlock + { Text = text, Background = Brushes.Red, HorizontalAlignment = HorizontalAlignment.Center, - TextAlignment = TextAlignment.Right, + TextAlignment = TextAlignment.Right, Width = width, - TextWrapping = textWrapping + TextWrapping = textWrapping }); - target.Children.Add(new TextBlock - { + target.Children.Add(new TextBlock + { Text = text, - Background = Brushes.Red, + Background = Brushes.Red, HorizontalAlignment = HorizontalAlignment.Right, - TextAlignment = TextAlignment.Left, - Width = width, + TextAlignment = TextAlignment.Left, + Width = width, TextWrapping = textWrapping }); - target.Children.Add(new TextBlock - { - Text = text, - Background = Brushes.Red, - HorizontalAlignment = HorizontalAlignment.Right, - TextAlignment = TextAlignment.Center, - Width = width, - TextWrapping = textWrapping + target.Children.Add(new TextBlock + { + Text = text, + Background = Brushes.Red, + HorizontalAlignment = HorizontalAlignment.Right, + TextAlignment = TextAlignment.Center, + Width = width, + TextWrapping = textWrapping }); - target.Children.Add(new TextBlock - { - Text = text, - Background = Brushes.Red, - HorizontalAlignment = HorizontalAlignment.Right, - TextAlignment = TextAlignment.Right, - Width = width, - TextWrapping = textWrapping + target.Children.Add(new TextBlock + { + Text = text, + Background = Brushes.Red, + HorizontalAlignment = HorizontalAlignment.Right, + TextAlignment = TextAlignment.Right, + Width = width, + TextWrapping = textWrapping }); var testName = $"Should_Measure_Arrange_TextBlock_{width}_{textWrapping}"; @@ -278,5 +279,124 @@ namespace Avalonia.Direct2D1.RenderTests.Controls await RenderToFile(target, testName); CompareImages(testName); } + + [Win32Fact("Has text")] + public async Task Should_Keep_TrailingWhiteSpace() + { + // + // + // + // + // + // + + var target = new StackPanel + { + VerticalAlignment = VerticalAlignment.Center, + HorizontalAlignment = HorizontalAlignment.Center, + Width = 300, + Height = 300, + }; + target.Children.Add(CreateText("aaaa")); + target.Children.Add(CreateText("a a ")); + target.Children.Add(CreateText(" ")); // This one does not render correctly on Direct2D1 + target.Children.Add(CreateText("LLLL")); + + var testName = $"Should_Keep_TrailingWhiteSpace"; + await RenderToFile(target, testName); + CompareImages(testName); + + static TextBlock CreateText(string text) => new TextBlock + { + Margin = new Thickness(0, 10, 0, 0), + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + Background = Brushes.Magenta, + FontSize = 44, + Text = text, + FontFamily = new FontFamily("Courier New") + }; + } + + [Win32Fact("Has text")] + public async Task Should_Account_For_Overhang_Leading_And_Trailing() + { + var target = new StackPanel + { + VerticalAlignment = VerticalAlignment.Center, + HorizontalAlignment = HorizontalAlignment.Center, + Width = 300, + Height = 600, + Background = new SolidColorBrush(Colors.White), // Required antialiasing to work for Overhang + }; + + target.Children.Add(CreateText("f")); + target.Children.Add(CreateText("y")); + target.Children.Add(CreateText("ff")); + target.Children.Add(CreateText("yy")); + target.Children.Add(CreateText("faaf")); + target.Children.Add(CreateText("yaay")); + target.Children.Add(CreateText("y y ")); + target.Children.Add(CreateText("f f ")); + + var testName = $"Should_Account_For_Overhang_Leading_And_Trailing"; + await RenderToFile(target, testName); + CompareImages(testName); + +#if AVALONIA_SKIA + const string symbolsFont = "resm:Avalonia.Skia.RenderTests.Assets?assembly=Avalonia.Skia.RenderTests#Source Serif 4 36pt"; +#else + const string symbolsFont = "resm:Avalonia.Direct2D1.RenderTests.Assets?assembly=Avalonia.Direct2D1.RenderTests#Source Serif 4 36pt"; +#endif + static TextBlock CreateText(string text) => new TextBlock + { + ClipToBounds = false, + Margin = new Thickness(4), + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + Background = Brushes.Magenta, + FontStyle = FontStyle.Italic, + FontSize = 44, + Text = text, + FontFamily = new FontFamily(symbolsFont) + }; + } + + [Win32Fact("Has text")] + public async Task Should_Draw_MultiLineText_WithOverHandLeadingTrailing() + { + var target = new StackPanel + { + VerticalAlignment = VerticalAlignment.Center, + HorizontalAlignment = HorizontalAlignment.Center, + Width = 600, + Height = 200, + Background = new SolidColorBrush(Colors.White), // Required antialiasing to work for Overhang + }; + + target.Children.Add(CreateText("fff Why this is a\nbig text yyy\nyyy with multiple lines fff")); + + var testName = $"Should_Draw_MultiLineText_WithOverHandLeadingTrailing"; + await RenderToFile(target, testName); + CompareImages(testName); + +#if AVALONIA_SKIA + const string symbolsFont = "resm:Avalonia.Skia.RenderTests.Assets?assembly=Avalonia.Skia.RenderTests#Source Serif 4 36pt"; +#else + const string symbolsFont = "resm:Avalonia.Direct2D1.RenderTests.Assets?assembly=Avalonia.Direct2D1.RenderTests#Source Serif 4 36pt"; +#endif + static TextBlock CreateText(string text) => new TextBlock + { + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + TextAlignment = TextAlignment.Center, + Background = Brushes.Magenta, + FontStyle = FontStyle.Italic, + FontSize = 44, + Text = text, + FontFamily = new FontFamily(symbolsFont) + }; + } + } } diff --git a/tests/Avalonia.Skia.UnitTests/Avalonia.Skia.UnitTests.csproj b/tests/Avalonia.Skia.UnitTests/Avalonia.Skia.UnitTests.csproj index d092e3b0b9..98a93596fa 100644 --- a/tests/Avalonia.Skia.UnitTests/Avalonia.Skia.UnitTests.csproj +++ b/tests/Avalonia.Skia.UnitTests/Avalonia.Skia.UnitTests.csproj @@ -10,12 +10,8 @@ - - - - - - + + diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs index 5440d980ab..e78f7ba1b9 100644 --- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs +++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs @@ -1184,6 +1184,35 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting } } + [Fact] + public void Should_Measure_TextLayoutSymbolWithAndWidthIncludingTrailingWhitespaceAndMinTextWidth() + { + using (Start()) + { + var typeFace = new Typeface("Courier New"); + var textLayout0 = new TextLayout("aaaa", typeFace, 12.0, Brushes.White); + Assert.Equal(textLayout0.WidthIncludingTrailingWhitespace, textLayout0.Width); + + var textLayout01 = new TextLayout("a a", typeFace, 12.0, Brushes.White); + var textLayout1 = new TextLayout("a a ", typeFace, 12.0, Brushes.White); + Assert.Equal(new Size(textLayout0.Width, textLayout0.Height), new Size(textLayout1.WidthIncludingTrailingWhitespace, textLayout1.Height)); + Assert.Equal(textLayout0.WidthIncludingTrailingWhitespace, textLayout1.WidthIncludingTrailingWhitespace); + + + var textLayout2 = new TextLayout(" aa ", typeFace, 12.0, Brushes.White); + Assert.Equal(new Size(textLayout1.Width, textLayout1.Height), new Size(textLayout2.Width, textLayout2.Height)); + Assert.Equal(textLayout0.WidthIncludingTrailingWhitespace, textLayout2.WidthIncludingTrailingWhitespace); + Assert.Equal(textLayout01.Width, textLayout2.Width); + + var textLayout3 = new TextLayout(" ", typeFace, 12.0, Brushes.White); + Assert.Equal(new Size(0, textLayout0.Height), new Size(textLayout3.Width, textLayout3.Height)); + Assert.Equal(textLayout0.WidthIncludingTrailingWhitespace, textLayout3.WidthIncludingTrailingWhitespace); + Assert.Equal(0, textLayout3.Width); + } + } + + private static void AssertGreaterThan(double x, double y, string message) => Assert.True(x > y, $"{message}. {x} is not > {y}"); + private static IDisposable Start() { var disposable = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface diff --git a/tests/TestFiles/Direct2D1/Controls/TextBlock/RestrictedHeight_VerticalAlign.expected.png b/tests/TestFiles/Direct2D1/Controls/TextBlock/RestrictedHeight_VerticalAlign.expected.png index c2466dcd8e..b65d33de37 100644 Binary files a/tests/TestFiles/Direct2D1/Controls/TextBlock/RestrictedHeight_VerticalAlign.expected.png and b/tests/TestFiles/Direct2D1/Controls/TextBlock/RestrictedHeight_VerticalAlign.expected.png differ diff --git a/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Account_For_Overhang_Leading_And_Trailing.expected.png b/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Account_For_Overhang_Leading_And_Trailing.expected.png new file mode 100644 index 0000000000..0a6667d134 Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Account_For_Overhang_Leading_And_Trailing.expected.png differ diff --git a/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Draw_MultiLineText_WithOverHandLeadingTrailing.expected.png b/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Draw_MultiLineText_WithOverHandLeadingTrailing.expected.png new file mode 100644 index 0000000000..2e02aea30c Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Draw_MultiLineText_WithOverHandLeadingTrailing.expected.png differ diff --git a/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Draw_Run_With_Background.expected.png b/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Draw_Run_With_Background.expected.png index bc6ba9f4d3..a382da4478 100644 Binary files a/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Draw_Run_With_Background.expected.png and b/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Draw_Run_With_Background.expected.png differ diff --git a/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Draw_TextDecorations.expected.png b/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Draw_TextDecorations.expected.png index 494c8a9002..5c62bfd179 100644 Binary files a/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Draw_TextDecorations.expected.png and b/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Draw_TextDecorations.expected.png differ diff --git a/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Keep_TrailingWhiteSpace.expected.png b/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Keep_TrailingWhiteSpace.expected.png new file mode 100644 index 0000000000..d0922b25ab Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Keep_TrailingWhiteSpace.expected.png differ diff --git a/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_150_NoWrap.expected.png b/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_150_NoWrap.expected.png index 5b83d6404d..7546a2d532 100644 Binary files a/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_150_NoWrap.expected.png and b/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_150_NoWrap.expected.png differ diff --git a/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_NoWrap.expected.png b/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_NoWrap.expected.png index 1f5f1e5bc5..bd94817c75 100644 Binary files a/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_NoWrap.expected.png and b/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_NoWrap.expected.png differ diff --git a/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_Wrap.expected.png b/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_Wrap.expected.png index db493fa9e7..9b0a492027 100644 Binary files a/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_Wrap.expected.png and b/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_Wrap.expected.png differ diff --git a/tests/TestFiles/Direct2D1/Controls/TextBlock/Wrapping_NoWrap.expected.png b/tests/TestFiles/Direct2D1/Controls/TextBlock/Wrapping_NoWrap.expected.png index 2296e02d68..f91d165886 100644 Binary files a/tests/TestFiles/Direct2D1/Controls/TextBlock/Wrapping_NoWrap.expected.png and b/tests/TestFiles/Direct2D1/Controls/TextBlock/Wrapping_NoWrap.expected.png differ diff --git a/tests/TestFiles/Skia/Controls/TextBlock/Should_Account_For_Overhang_Leading_And_Trailing.expected.png b/tests/TestFiles/Skia/Controls/TextBlock/Should_Account_For_Overhang_Leading_And_Trailing.expected.png new file mode 100644 index 0000000000..23267da7df Binary files /dev/null and b/tests/TestFiles/Skia/Controls/TextBlock/Should_Account_For_Overhang_Leading_And_Trailing.expected.png differ diff --git a/tests/TestFiles/Skia/Controls/TextBlock/Should_Draw_MultiLineText_WithOverHandLeadingTrailing.expected.png b/tests/TestFiles/Skia/Controls/TextBlock/Should_Draw_MultiLineText_WithOverHandLeadingTrailing.expected.png new file mode 100644 index 0000000000..7b4541d3f8 Binary files /dev/null and b/tests/TestFiles/Skia/Controls/TextBlock/Should_Draw_MultiLineText_WithOverHandLeadingTrailing.expected.png differ diff --git a/tests/TestFiles/Skia/Controls/TextBlock/Should_Keep_TrailingWhiteSpace.expected.png b/tests/TestFiles/Skia/Controls/TextBlock/Should_Keep_TrailingWhiteSpace.expected.png new file mode 100644 index 0000000000..ff8f49b60b Binary files /dev/null and b/tests/TestFiles/Skia/Controls/TextBlock/Should_Keep_TrailingWhiteSpace.expected.png differ