diff --git a/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs b/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs
index 64befe2e5c..33d1b30e3c 100644
--- a/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs
+++ b/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs
@@ -47,7 +47,7 @@ namespace Avalonia.Media.TextFormatting
///
public override void Draw(DrawingContext drawingContext, Point origin)
{
- using (drawingContext.PushPostTransform(Matrix.CreateTranslation(origin)))
+ using (drawingContext.PushPreTransform(Matrix.CreateTranslation(origin)))
{
if (GlyphRun.GlyphIndices.Length == 0)
{
diff --git a/tests/Avalonia.RenderTests/Media/TextFormatting/TextLayoutTests.cs b/tests/Avalonia.RenderTests/Media/TextFormatting/TextLayoutTests.cs
new file mode 100644
index 0000000000..b1a2d00b00
--- /dev/null
+++ b/tests/Avalonia.RenderTests/Media/TextFormatting/TextLayoutTests.cs
@@ -0,0 +1,106 @@
+using Avalonia.Controls;
+using Avalonia.Media;
+using Avalonia.Media.TextFormatting;
+using Avalonia.Platform;
+using Avalonia.Utilities;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+using System.Runtime.InteropServices;
+
+#if AVALONIA_SKIA
+namespace Avalonia.Skia.RenderTests
+#else
+
+using Avalonia.Direct2D1.RenderTests;
+
+namespace Avalonia.Direct2D1.RenderTests.Media
+#endif
+{
+ public class TextLayoutTests : TestBase
+ {
+ public TextLayoutTests()
+ : base(@"Media\TextFormatting\TextLayout")
+ {
+ }
+
+ [Fact]
+ public async Task TextLayout_Basic()
+ {
+ // Skip test on OSX: text rendering is subtly different.
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ return;
+
+ var t = new TextLayout(
+ "Avalonia!",
+ new Typeface(TestFontFamily),
+ 24,
+ Brushes.Black);
+
+ var target = new Border
+ {
+ Width = 200,
+ Height = 200,
+ Background = Brushes.White,
+ Child = new DrawnControl(c =>
+ {
+ var textRect = new Rect(t.Size);
+ var bounds = new Rect(0, 0, 200, 200);
+ var rect = bounds.CenterRect(textRect);
+ c.DrawRectangle(Brushes.Yellow, null, rect);
+ t.Draw(c, rect.Position);
+ }),
+ };
+
+ await RenderToFile(target);
+ CompareImages();
+ }
+
+ [Fact]
+ public async Task TextLayout_Rotated()
+ {
+ // Skip test on OSX: text rendering is subtly different.
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ return;
+
+ var t = new TextLayout(
+ "Avalonia!",
+ new Typeface(TestFontFamily),
+ 24,
+ Brushes.Black);
+
+ var target = new Border
+ {
+ Width = 200,
+ Height = 200,
+ Background = Brushes.White,
+ Child = new DrawnControl(c =>
+ {
+ var textRect = new Rect(t.Size);
+ var bounds = new Rect(0, 0, 200, 200);
+ var rect = bounds.CenterRect(textRect);
+ var rotate = Matrix.CreateTranslation(-100, -100) *
+ Matrix.CreateRotation(MathUtilities.Deg2Rad(90)) *
+ Matrix.CreateTranslation(100, 100);
+ using var transform = c.PushPreTransform(rotate);
+ c.DrawRectangle(Brushes.Yellow, null, rect);
+ t.Draw(c, rect.Position);
+ }),
+ };
+
+ await RenderToFile(target);
+ CompareImages();
+ }
+
+ private class DrawnControl : Control
+ {
+ private readonly Action _render;
+ public DrawnControl(Action render) => _render = render;
+ public override void Render(DrawingContext context) => _render(context);
+ }
+ }
+}
diff --git a/tests/TestFiles/Direct2D1/Media/TextFormatting/TextLayout/TextLayout_Basic.expected.png b/tests/TestFiles/Direct2D1/Media/TextFormatting/TextLayout/TextLayout_Basic.expected.png
new file mode 100644
index 0000000000..215e83106f
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Media/TextFormatting/TextLayout/TextLayout_Basic.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Media/TextFormatting/TextLayout/TextLayout_Rotated.expected.png b/tests/TestFiles/Direct2D1/Media/TextFormatting/TextLayout/TextLayout_Rotated.expected.png
new file mode 100644
index 0000000000..237a799224
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Media/TextFormatting/TextLayout/TextLayout_Rotated.expected.png differ
diff --git a/tests/TestFiles/Skia/Media/TextFormatting/TextLayout/TextLayout_Basic.expected.png b/tests/TestFiles/Skia/Media/TextFormatting/TextLayout/TextLayout_Basic.expected.png
new file mode 100644
index 0000000000..220932ff41
Binary files /dev/null and b/tests/TestFiles/Skia/Media/TextFormatting/TextLayout/TextLayout_Basic.expected.png differ
diff --git a/tests/TestFiles/Skia/Media/TextFormatting/TextLayout/TextLayout_Rotated.expected.png b/tests/TestFiles/Skia/Media/TextFormatting/TextLayout/TextLayout_Rotated.expected.png
new file mode 100644
index 0000000000..26fe2b0c91
Binary files /dev/null and b/tests/TestFiles/Skia/Media/TextFormatting/TextLayout/TextLayout_Rotated.expected.png differ