Skip to content

Commit

Permalink
Added a test for tracking path closure with missing strokes for vario…
Browse files Browse the repository at this point in the history
…us line caps/joins
  • Loading branch information
kekekeks committed Apr 24, 2024
1 parent 7b2b18e commit c55f6a9
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/Avalonia.Base/Media/LineSegment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public Point Point

internal override void ApplyTo(StreamGeometryContext ctx)
{
ctx.LineTo(Point);
ctx.LineTo(Point, IsStroked);
}

public override string ToString()
Expand Down
9 changes: 9 additions & 0 deletions src/Avalonia.Base/Media/PathSegment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,14 @@ namespace Avalonia.Media
public abstract class PathSegment : AvaloniaObject
{
internal abstract void ApplyTo(StreamGeometryContext ctx);

public static readonly StyledProperty<bool> IsStrokedProperty =
AvaloniaProperty.Register<PathSegment, bool>(nameof(IsStroked), true);

public bool IsStroked
{
get => GetValue(IsStrokedProperty);
set => SetValue(IsStrokedProperty, value);
}
}
}
36 changes: 35 additions & 1 deletion tests/Avalonia.RenderTests.WpfCompare/CrossUI.Wpf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
using WColor = System.Windows.Media.Color;
using WMatrix = System.Windows.Media.Matrix;
using Avalonia.RenderTests.WpfCompare;
using PenLineCap = Avalonia.Media.PenLineCap;
using WPenLineCap = System.Windows.Media.PenLineCap;
using PenLineJoin = Avalonia.Media.PenLineJoin;
using WPenLineJoin = System.Windows.Media.PenLineJoin;

namespace CrossUI
{
Expand Down Expand Up @@ -160,6 +164,16 @@ private static Geometry ConvertGeometry(CrossGeometry g)
return new EllipseGeometry(ellipse.Rect.ToWpf());
else if (g is CrossStreamGeometry streamGeometry)
return (StreamGeometry)streamGeometry.GetContext().GetGeometry();
else if (g is CrossPathGeometry pathGeometry)
return new PathGeometry()
{
Figures = new PathFigureCollection(pathGeometry.Figures.Select(f => new PathFigure(
f.Start.ToWpf(), f.Segments.Select(s =>
s switch
{
CrossPathSegment.Line line => new LineSegment(line.To.ToWpf(), s.IsStroked)
}), f.Closed)))
};
throw new NotSupportedException();
}

Expand Down Expand Up @@ -228,7 +242,27 @@ static Brush SyncGradient(GradientBrush dst, CrossGradientBrush src)
{
if (pen == null)
return null;
return new Pen(ConvertBrush(pen.Brush), pen.Thickness);

var cap = pen.LineCap switch
{
PenLineCap.Flat => WPenLineCap.Flat,
PenLineCap.Round => WPenLineCap.Round,
PenLineCap.Square => WPenLineCap.Square
};
var join = pen.LineJoin switch
{
PenLineJoin.Bevel => WPenLineJoin.Bevel,
PenLineJoin.Miter => WPenLineJoin.Miter,
PenLineJoin.Round => WPenLineJoin.Round
};

return new Pen(ConvertBrush(pen.Brush), pen.Thickness)
{
StartLineCap = cap,
EndLineCap = cap,
DashCap = cap,
LineJoin = join,
};
}

private static ImageSource ConvertImage(CrossImage image)
Expand Down
73 changes: 73 additions & 0 deletions tests/Avalonia.RenderTests/CrossTests/CrossGeometryTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Media;
using CrossUI;
using Xunit;
Expand Down Expand Up @@ -107,4 +109,75 @@ public void Should_Render_Geometry_With_Strokeless_Lines()
Background = brush
});
}

[CrossTheory,
InlineData(PenLineCap.Flat, PenLineJoin.Round),
InlineData(PenLineCap.Flat, PenLineJoin.Bevel),
InlineData(PenLineCap.Flat, PenLineJoin.Miter),
InlineData(PenLineCap.Round, PenLineJoin.Round),
InlineData(PenLineCap.Round, PenLineJoin.Bevel),
InlineData(PenLineCap.Round, PenLineJoin.Miter),
]
public void Should_Properly_CloseFigure(PenLineCap lineCap, PenLineJoin lineJoin)
{
var geometry = new CrossPathGeometry();


var center = new Point(150, 150);
var r = 100d;

var pointCount = 5;
var points = Enumerable.Range(0, pointCount).Select(a => a * Math.PI / pointCount * 2).Select(a =>
new Point(center.X + Math.Sin(a) * r, center.Y + Math.Cos(a) * r)).ToArray();

var figure = new CrossPathFigure() { Start = points[0], Closed = true };
geometry.Figures.Add(figure);
var lineNum = 0;
for (var c = 2; lineNum < pointCount - 1; c = (c + 2) % pointCount, lineNum++)
{
figure.Segments.Add(new CrossPathSegment.Line(points[c], (lineNum) % 3 < 2));
}

var control = new CrossFuncControl(ctx =>
{
ctx.DrawRectangle(new CrossSolidColorBrush(Colors.White), null, new(0, 0, 300, 300));
ctx.DrawGeometry(null,
new CrossPen()
{
Brush = new CrossSolidColorBrush(Colors.Black),
Thickness = 20,
LineJoin = lineJoin,
LineCap = lineCap
}, geometry);
}) { Width = 300, Height = 300 };
/*
var brush = new CrossDrawingBrush()
{
TileMode = TileMode.None,
Drawing = new CrossDrawingGroup()
{
Children = new List<CrossDrawing>()
{
new CrossGeometryDrawing(new CrossRectangleGeometry(new(0, 0, 300, 300)))
{
Brush = new CrossSolidColorBrush(Colors.White)
},
new CrossGeometryDrawing(geometry)
{
Pen = new CrossPen()
{
Brush = new CrossSolidColorBrush(Colors.Black),
Thickness = 40,
LineJoin = lineJoin,
LineCap = lineCap
}
}
}
}
};*/

//RenderAndCompare(new CrossControl() { Width = 300, Height = 300, Background = brush },
RenderAndCompare(control,
$"{nameof(Should_Properly_CloseFigure)}_{lineCap}_{lineJoin}");
}
}
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 @@ -149,8 +149,33 @@ static Geometry ConvertGeometry(CrossGeometry g)
return new EllipseGeometry(ellipse.Rect);
else if(g is CrossStreamGeometry streamGeometry)
return (StreamGeometry)streamGeometry.GetContext().GetGeometry();
else if (g is CrossPathGeometry path)
return new PathGeometry()
{
Figures = RetAddRange(new PathFigures(), path.Figures.Select(f =>
new PathFigure()
{
StartPoint = f.Start,
IsClosed = f.Closed,
Segments = RetAddRange<PathSegments, PathSegment>(new PathSegments(), f.Segments.Select(s =>
s switch
{
CrossPathSegment.Line l => new LineSegment()
{
Point = l.To, IsStroked = l.IsStroked
}
}))
}))
};
throw new NotSupportedException();
}

static TList RetAddRange<TList, T>(TList l, IEnumerable<T> en) where TList : IList<T>
{
foreach(var e in en)
l.Add(e);
return l;
}

static Drawing ConvertDrawing(CrossDrawing src)
{
Expand Down Expand Up @@ -217,7 +242,7 @@ static Brush SyncGradient(GradientBrush dst, CrossGradientBrush src)
{
if (pen == null)
return null;
return new Pen(ConvertBrush(pen.Brush), pen.Thickness);
return new Pen(ConvertBrush(pen.Brush), pen.Thickness) { LineCap = pen.LineCap, LineJoin = pen.LineJoin };
}

static IImage ConvertImage(CrossImage image)
Expand Down
19 changes: 19 additions & 0 deletions tests/Avalonia.RenderTests/CrossUI/CrossUI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,23 @@ public CrossRectangleGeometry(Rect rect)
}
}

public class CrossPathGeometry : CrossGeometry
{
public List<CrossPathFigure> Figures { get; set; } = new();
}

public class CrossPathFigure
{
public Point Start { get; set; }
public List<CrossPathSegment> Segments { get; set; } = new();
public bool Closed { get; set; }
}

public abstract record class CrossPathSegment(bool IsStroked)
{
public record Line(Point To, bool IsStroked) : CrossPathSegment(IsStroked);
}

public class CrossDrawingBrush : CrossTileBrush
{
public CrossDrawing Drawing;
Expand All @@ -149,6 +166,8 @@ public class CrossPen
{
public CrossBrush Brush;
public double Thickness = 1;
public PenLineJoin LineJoin { get; set; } = PenLineJoin.Miter;
public PenLineCap LineCap { get; set; } = PenLineCap.Flat;
}

public interface ICrossStreamGeometryContextImpl : IDisposable
Expand Down
2 changes: 1 addition & 1 deletion tests/Avalonia.Skia.RenderTests/CrossTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class CrossFactAttribute : FactAttribute

}

class CrossThreoryAttribute : TheoryAttribute
class CrossTheoryAttribute : TheoryAttribute
{

}
Expand Down

0 comments on commit c55f6a9

Please sign in to comment.