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