Skip to content

Commit

Permalink
Fix transform desync (#16363)
Browse files Browse the repository at this point in the history
* Make sure wrapper and platform DrawingContext have the same transform after Flush

* Add some tests

* Update Avalonia.RenderTests.WpfCompare.csproj

* Remove comments

* Use test font
  • Loading branch information
Gillibald authored Sep 12, 2024
1 parent ad8e67c commit 7da58ba
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -148,5 +148,10 @@ public void Flush()
ExecCommand(ref commands[index]);

_commands.Clear();

if (Transform != _impl.Transform)
{
_impl.Transform = Transform;
}
}
}
}
17 changes: 16 additions & 1 deletion tests/Avalonia.RenderTests.WpfCompare/CrossUI.Wpf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,22 @@ private static ImageSource ConvertImage(CrossImage image)
return new DrawingImage(ConvertDrawing(di.Drawing));
throw new NotSupportedException();
}


public void PushTransform(Matrix matrix)
{
_ctx.PushTransform(new MatrixTransform(matrix.ToWpf()));
}

public void Pop()
{
_ctx.Pop();
}

public void DrawLine(CrossPen pen, Point p1, Point p2)
{
_ctx.DrawLine(ConvertPen(pen), p1.ToWpf(), p2.ToWpf());
}

public void DrawRectangle(CrossBrush? brush, CrossPen? pen, Rect rc) => _ctx.DrawRectangle(ConvertBrush(brush), ConvertPen(pen), rc.ToWpf());
public void DrawGeometry(CrossBrush? brush, CrossPen? pen, CrossGeometry geo) =>
_ctx.DrawGeometry(ConvertBrush(brush), ConvertPen(pen), ConvertGeometry(geo));
Expand Down
51 changes: 51 additions & 0 deletions tests/Avalonia.RenderTests/CrossTests/Media/DrawingContextTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using Avalonia.Media;
using CrossUI;

#if AVALONIA_SKIA
namespace Avalonia.Skia.RenderTests.CrossTests;
#elif AVALONIA_D2D
namespace Avalonia.Direct2D1.RenderTests.CrossTests;
#else
namespace Avalonia.RenderTests.WpfCompare.CrossTests;
#endif


public class DrawingContextTests : CrossTestBase
{
public DrawingContextTests() : base("Media/DrawingContext")
{
}

[CrossFact]
public void Transform_Should_Work_As_Expected()
{
RenderAndCompare(

new CrossFuncControl(ctx =>
{
ctx.PushTransform(Matrix.CreateTranslation(100, 100));
ctx.DrawLine(new CrossPen { Brush = new CrossSolidColorBrush(Colors.Red), Thickness = 1 },
new Point(0, 0), new Point(100, 0));
ctx.Pop();
ctx.PushTransform(Matrix.CreateTranslation(200, 100));
ctx.DrawLine(new CrossPen { Brush = new CrossSolidColorBrush(Colors.Orange), Thickness = 1 },
new Point(0, 0), new Point(0, 100));
ctx.Pop();
ctx.PushTransform(Matrix.CreateTranslation(200, 200));
ctx.DrawLine(
new CrossPen { Brush = new CrossSolidColorBrush(Colors.Yellow), Thickness = 1 },
new Point(0, 0), new Point(-100, 0));
ctx.Pop();
ctx.PushTransform(Matrix.CreateTranslation(100, 200));
ctx.DrawLine(new CrossPen { Brush = new CrossSolidColorBrush(Colors.Green), Thickness = 1 },
new Point(0, 0), new Point(0, -100));
ctx.Pop();
}) { Width = 300, Height = 300 }

);

}
}
27 changes: 26 additions & 1 deletion tests/Avalonia.RenderTests/CrossUI/CrossUI.Avalonia.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ public override void Render(DrawingContext context)
class AvaloniaCrossDrawingContext : ICrossDrawingContext
{
private readonly DrawingContext _ctx;
private readonly Stack<DrawingContext.PushedState> _stack = new();

public AvaloniaCrossDrawingContext(DrawingContext ctx)
{
Expand Down Expand Up @@ -303,7 +304,31 @@ static IImage ConvertImage(CrossImage image)
return new DrawingImage(ConvertDrawing(di.Drawing));
throw new NotSupportedException();
}


public void PushTransform(Matrix matrix)
{
_stack.Push(_ctx.PushTransform(matrix));
}

public void Pop()
{
var state = _stack.Pop();

state.Dispose();
}

public void DrawLine(CrossPen pen, Point p1, Point p2)
{
var avPen = ConvertPen(pen);

if (avPen == null)
{
return;
}

_ctx.DrawLine(avPen, p1, p2);
}

public void DrawRectangle(CrossBrush? brush, CrossPen? pen, Rect rc) => _ctx.DrawRectangle(ConvertBrush(brush), ConvertPen(pen), rc);
public void DrawGeometry(CrossBrush? brush, CrossPen? pen, CrossGeometry geometry) =>
_ctx.DrawGeometry(ConvertBrush(brush), ConvertPen(pen), ConvertGeometry(geometry));
Expand Down
3 changes: 3 additions & 0 deletions tests/Avalonia.RenderTests/CrossUI/CrossUI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ public interface ICrossStreamGeometryContextImplProvider

public interface ICrossDrawingContext
{
void PushTransform(Matrix matrix);
void Pop();
void DrawLine(CrossPen pen, Point p1, Point p2);
void DrawRectangle(CrossBrush? brush, CrossPen? pen, Rect rc);
void DrawGeometry(CrossBrush? brush, CrossPen? pen, CrossGeometry geometry);
void DrawImage(CrossImage image, Rect rc);
Expand Down
69 changes: 69 additions & 0 deletions tests/Avalonia.RenderTests/Media/DrawingContextTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System.Globalization;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Media;
using Xunit;
#pragma warning disable CS0649

#if AVALONIA_SKIA
namespace Avalonia.Skia.RenderTests;

public class DrawingContextTests : TestBase
{
public DrawingContextTests() : base(@"Media\DrawingContext")
{
}

[Fact]
public async Task Should_Render_LinesAndText()
{
var target = new Border
{
Width = 300,
Height = 300,
Background = Brushes.White,
Child = new RenderControl()
};

await RenderToFile(target);
CompareImages(skipImmediate: true);
}

internal class RenderControl : Control
{
private static readonly Typeface s_typeface = new Typeface(TestFontFamily);

public override void Render(DrawingContext context)
{
var pen = new Pen(Brushes.LightGray, 10);
RenderLine1(context, pen);
RenderLine2(context, pen);
RenderLine3(context, pen);
RenderLine4(context, pen);

RenderLine1(context, new Pen(Brushes.Red));
RenderAText(context, new Point(50, 20));
RenderLine2(context, new Pen(Brushes.Orange));
RenderAText(context, new Point(50, -50));
RenderLine3(context, new Pen(Brushes.Yellow));
RenderAText(context, new Point(0, 0));
RenderLine4(context, new Pen(Brushes.Green));
}

private static void RenderLine1(DrawingContext context, IPen pen) => context.DrawLine(pen, new Point(100, 100), new Point(200, 100));
private static void RenderLine2(DrawingContext context, IPen pen) => context.DrawLine(pen, new Point(200, 100), new Point(200, 200));
private static void RenderLine3(DrawingContext context, IPen pen) => context.DrawLine(pen, new Point(200, 200), new Point(100, 200));
private static void RenderLine4(DrawingContext context, IPen pen) => context.DrawLine(pen, new Point(100, 200), new Point(100, 100));

private static void RenderAText(DrawingContext context, Point point)
{
using (context.PushOpacity(0.7))
{
context.DrawText(
new FormattedText("any text to render", CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
s_typeface, 12, Brushes.Black), point);
}
}
}
}
#endif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 7da58ba

Please sign in to comment.