diff --git a/api/Avalonia.nupkg.xml b/api/Avalonia.nupkg.xml
index af46d2fb2ea..992944cec56 100644
--- a/api/Avalonia.nupkg.xml
+++ b/api/Avalonia.nupkg.xml
@@ -1,4 +1,4 @@
-
+
@@ -43,12 +43,174 @@
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
+
+ CP0002
+ M:Avalonia.Media.PolylineGeometry.#ctor(System.Collections.Generic.IEnumerable{Avalonia.Point},System.Boolean)
+ baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
+ current/Avalonia/lib/net10.0/Avalonia.Base.dll
+
CP0002
M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
+
+ CP0002
+ F:Avalonia.Controls.Documents.TextElement.LetterSpacingProperty
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ F:Avalonia.Controls.Presenters.ContentPresenter.LetterSpacingProperty
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ F:Avalonia.Controls.Primitives.TemplatedControl.LetterSpacingProperty
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ F:Avalonia.Controls.Shapes.Shape.StrokeMiterLimitProperty
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ F:Avalonia.Controls.TextBlock.LetterSpacingProperty
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Design.CreatePreviewWithControl(System.Object)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Design.GetDataContext(Avalonia.Controls.Templates.IDataTemplate)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Design.GetPreviewWith(Avalonia.Controls.Templates.IDataTemplate)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Design.GetPreviewWith(Avalonia.Styling.IStyle)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Design.SetDataContext(Avalonia.Controls.Templates.IDataTemplate,System.Object)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.AvaloniaObject,Avalonia.Controls.ITemplate{Avalonia.Controls.Control})
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.Controls.ResourceDictionary,Avalonia.Controls.ITemplate{Avalonia.Controls.Control})
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.Controls.Templates.IDataTemplate,Avalonia.Controls.Control)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.Controls.Templates.IDataTemplate,Avalonia.Controls.ITemplate{Avalonia.Controls.Control})
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.Styling.IStyle,Avalonia.Controls.Control)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.Styling.IStyle,Avalonia.Controls.ITemplate{Avalonia.Controls.Control})
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Documents.TextElement.get_LetterSpacing
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Documents.TextElement.GetLetterSpacing(Avalonia.Controls.Control)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Documents.TextElement.set_LetterSpacing(System.Double)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Documents.TextElement.SetLetterSpacing(Avalonia.Controls.Control,System.Double)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Presenters.ContentPresenter.get_LetterSpacing
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Presenters.ContentPresenter.set_LetterSpacing(System.Double)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Primitives.TemplatedControl.get_LetterSpacing
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Primitives.TemplatedControl.set_LetterSpacing(System.Double)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Shapes.Shape.get_StrokeMiterLimit
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Shapes.Shape.set_StrokeMiterLimit(System.Double)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
+
CP0002
F:Avalonia.Media.Fonts.FontCollectionBase._glyphTypefaceCache
@@ -97,12 +259,174 @@
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
+
+ CP0002
+ M:Avalonia.Media.PolylineGeometry.#ctor(System.Collections.Generic.IEnumerable{Avalonia.Point},System.Boolean)
+ baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
+ current/Avalonia/lib/net8.0/Avalonia.Base.dll
+
CP0002
M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
+
+ CP0002
+ F:Avalonia.Controls.Documents.TextElement.LetterSpacingProperty
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ F:Avalonia.Controls.Presenters.ContentPresenter.LetterSpacingProperty
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ F:Avalonia.Controls.Primitives.TemplatedControl.LetterSpacingProperty
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ F:Avalonia.Controls.Shapes.Shape.StrokeMiterLimitProperty
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ F:Avalonia.Controls.TextBlock.LetterSpacingProperty
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Design.CreatePreviewWithControl(System.Object)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Design.GetDataContext(Avalonia.Controls.Templates.IDataTemplate)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Design.GetPreviewWith(Avalonia.Controls.Templates.IDataTemplate)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Design.GetPreviewWith(Avalonia.Styling.IStyle)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Design.SetDataContext(Avalonia.Controls.Templates.IDataTemplate,System.Object)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.AvaloniaObject,Avalonia.Controls.ITemplate{Avalonia.Controls.Control})
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.Controls.ResourceDictionary,Avalonia.Controls.ITemplate{Avalonia.Controls.Control})
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.Controls.Templates.IDataTemplate,Avalonia.Controls.Control)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.Controls.Templates.IDataTemplate,Avalonia.Controls.ITemplate{Avalonia.Controls.Control})
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.Styling.IStyle,Avalonia.Controls.Control)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.Styling.IStyle,Avalonia.Controls.ITemplate{Avalonia.Controls.Control})
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Documents.TextElement.get_LetterSpacing
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Documents.TextElement.GetLetterSpacing(Avalonia.Controls.Control)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Documents.TextElement.set_LetterSpacing(System.Double)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Documents.TextElement.SetLetterSpacing(Avalonia.Controls.Control,System.Double)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Presenters.ContentPresenter.get_LetterSpacing
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Presenters.ContentPresenter.set_LetterSpacing(System.Double)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Primitives.TemplatedControl.get_LetterSpacing
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Primitives.TemplatedControl.set_LetterSpacing(System.Double)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Shapes.Shape.get_StrokeMiterLimit
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
+
+ CP0002
+ M:Avalonia.Controls.Shapes.Shape.set_StrokeMiterLimit(System.Double)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
+
CP0002
M:Avalonia.Dialogs.Internal.ManagedFileChooserFilterViewModel.#ctor(Avalonia.Platform.Storage.FilePickerFileType)
@@ -445,4 +769,4 @@
baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
-
+
\ No newline at end of file
diff --git a/src/Avalonia.Base/Media/PolylineGeometry.cs b/src/Avalonia.Base/Media/PolylineGeometry.cs
index 13b11d84445..f9b9c24be96 100644
--- a/src/Avalonia.Base/Media/PolylineGeometry.cs
+++ b/src/Avalonia.Base/Media/PolylineGeometry.cs
@@ -27,6 +27,7 @@ public class PolylineGeometry : Geometry
private IList _points;
private IDisposable? _pointsObserver;
+ private readonly FillRule _fillRule;
static PolylineGeometry()
{
@@ -40,8 +41,10 @@ static PolylineGeometry()
public PolylineGeometry()
{
_points = new Points();
+ _fillRule = FillRule.EvenOdd;
}
+ ///
///
/// Initializes a new instance of the class.
///
@@ -49,6 +52,17 @@ public PolylineGeometry(IEnumerable points, bool isFilled)
{
_points = new Points(points);
IsFilled = isFilled;
+ _fillRule = FillRule.EvenOdd;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PolylineGeometry(IEnumerable points, bool isFilled, FillRule fillRule)
+ {
+ _points = new Points(points);
+ IsFilled = isFilled;
+ _fillRule = fillRule;
}
///
@@ -70,10 +84,18 @@ public bool IsFilled
set => SetValue(IsFilledProperty, value);
}
+ ///
+ /// Gets how the intersecting areas of the polyline are combined.
+ ///
+ public FillRule FillRule => _fillRule;
+
///
public override Geometry Clone()
{
- return new PolylineGeometry(Points, IsFilled);
+ return new PolylineGeometry(Points, IsFilled, _fillRule)
+ {
+ Transform = Transform
+ };
}
private protected sealed override IGeometryImpl? CreateDefiningGeometry()
@@ -83,6 +105,7 @@ public override Geometry Clone()
using (var context = geometry.Open())
{
+ context.SetFillRule(_fillRule);
var points = Points;
var isFilled = IsFilled;
if (points.Count > 0)
diff --git a/src/Avalonia.Controls/Shapes/Polygon.cs b/src/Avalonia.Controls/Shapes/Polygon.cs
index 48530432f02..d6fdcafa565 100644
--- a/src/Avalonia.Controls/Shapes/Polygon.cs
+++ b/src/Avalonia.Controls/Shapes/Polygon.cs
@@ -9,9 +9,12 @@ public class Polygon : Shape
public static readonly StyledProperty> PointsProperty =
AvaloniaProperty.Register>("Points");
+ public static readonly StyledProperty FillRuleProperty =
+ AvaloniaProperty.Register(nameof(FillRule));
+
static Polygon()
{
- AffectsGeometry(PointsProperty);
+ AffectsGeometry(PointsProperty, FillRuleProperty);
}
public Polygon()
@@ -25,9 +28,18 @@ public IList Points
set => SetValue(PointsProperty, value);
}
+ ///
+ /// Gets or sets how the interior of the polygon is determined when a is applied.
+ ///
+ public FillRule FillRule
+ {
+ get => GetValue(FillRuleProperty);
+ set => SetValue(FillRuleProperty, value);
+ }
+
protected override Geometry CreateDefiningGeometry()
{
- return new PolylineGeometry { Points = Points, IsFilled = true };
+ return new PolylineGeometry(Points, isFilled: true, fillRule: FillRule);
}
}
}
diff --git a/src/Avalonia.Controls/Shapes/Polyline.cs b/src/Avalonia.Controls/Shapes/Polyline.cs
index 628fc70e1d9..a0675202733 100644
--- a/src/Avalonia.Controls/Shapes/Polyline.cs
+++ b/src/Avalonia.Controls/Shapes/Polyline.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using Avalonia;
using Avalonia.Media;
using Avalonia.Data;
@@ -10,10 +11,13 @@ public class Polyline : Shape
public static readonly StyledProperty> PointsProperty =
AvaloniaProperty.Register>("Points");
+ public static readonly StyledProperty FillRuleProperty =
+ AvaloniaProperty.Register(nameof(FillRule));
+
static Polyline()
{
StrokeThicknessProperty.OverrideDefaultValue(1);
- AffectsGeometry(PointsProperty);
+ AffectsGeometry(PointsProperty, FillRuleProperty);
}
public Polyline()
@@ -27,9 +31,19 @@ public IList Points
set => SetValue(PointsProperty, value);
}
+ ///
+ /// Gets or sets how the interior of the polyline is determined when a is applied.
+ ///
+ public FillRule FillRule
+ {
+ get => GetValue(FillRuleProperty);
+ set => SetValue(FillRuleProperty, value);
+ }
+
protected override Geometry CreateDefiningGeometry()
{
- return new PolylineGeometry { Points = Points, IsFilled = false };
+ var isFilled = Fill != null;
+ return new PolylineGeometry(Points, isFilled, FillRule);
}
}
}
diff --git a/tests/Avalonia.Controls.UnitTests/Shapes/PolygonTests.cs b/tests/Avalonia.Controls.UnitTests/Shapes/PolygonTests.cs
index 1775a01cd3d..ccb04fa4986 100644
--- a/tests/Avalonia.Controls.UnitTests/Shapes/PolygonTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/Shapes/PolygonTests.cs
@@ -1,5 +1,6 @@
using System.Collections.ObjectModel;
using Avalonia.Controls.Shapes;
+using Avalonia.Media;
using Avalonia.UnitTests;
using Xunit;
@@ -25,4 +26,51 @@ public void Polygon_Will_Update_Geometry_On_Shapes_Collection_Content_Change()
root.Child = null;
}
+
+ [Fact]
+ public void FillRule_On_Polygon_Is_Applied_To_DefiningGeometry()
+ {
+ using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface);
+
+ var target = new Polygon
+ {
+ Points = new Points { new Point(0, 0), new Point(10, 10), new Point(20, 0) },
+ FillRule = FillRule.NonZero
+ };
+
+ target.Measure(Size.Infinity);
+
+ var geometry = Assert.IsType(target.DefiningGeometry);
+ Assert.Equal(FillRule.NonZero, geometry.FillRule);
+ }
+
+ [Fact]
+ public void Polygon_Equals_Closed_Polyline_Bounds()
+ {
+ using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface);
+
+ var polyline = new Polyline
+ {
+ Points = new Points
+ {
+ new Point(0, 0),
+ new Point(10, 0),
+ new Point(10, 10),
+ new Point(0, 10),
+ new Point(0, 0)
+ },
+ FillRule = FillRule.NonZero
+ };
+
+ var polygon = new Polygon
+ {
+ Points = new Points { new Point(0, 0), new Point(10, 0), new Point(10, 10), new Point(0, 10) },
+ FillRule = FillRule.NonZero
+ };
+
+ polyline.Measure(Size.Infinity);
+ polygon.Measure(Size.Infinity);
+
+ Assert.Equal(polygon.DefiningGeometry!.Bounds, polyline.DefiningGeometry!.Bounds);
+ }
}
diff --git a/tests/Avalonia.Controls.UnitTests/Shapes/PolylineTests.cs b/tests/Avalonia.Controls.UnitTests/Shapes/PolylineTests.cs
index 971cd81f4a6..2b73ec21a51 100644
--- a/tests/Avalonia.Controls.UnitTests/Shapes/PolylineTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/Shapes/PolylineTests.cs
@@ -1,5 +1,6 @@
using System.Collections.ObjectModel;
using Avalonia.Controls.Shapes;
+using Avalonia.Media;
using Avalonia.UnitTests;
using Xunit;
@@ -25,4 +26,66 @@ public void Polyline_Will_Update_Geometry_On_Shapes_Collection_Content_Change()
root.Child = null;
}
+
+ [Fact]
+ public void FillRule_On_Polyline_Is_Applied_To_DefiningGeometry()
+ {
+ using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface);
+
+ var target = new Polyline
+ {
+ Points = new Points { new Point(0, 0), new Point(10, 10), new Point(20, 0) },
+ Fill = Brushes.Red,
+ FillRule = FillRule.NonZero
+ };
+
+ target.Measure(Size.Infinity);
+
+ var geometry = Assert.IsType(target.DefiningGeometry);
+ Assert.Equal(FillRule.NonZero, geometry.FillRule);
+ Assert.True(geometry.IsFilled);
+ }
+
+ [Fact]
+ public void FillRule_Differs_Between_EvenOdd_And_NonZero()
+ {
+ using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface);
+
+ var evenOdd = new Polyline
+ {
+ Points = new Points { new Point(0, 0), new Point(10, 10), new Point(20, 0) },
+ Fill = Brushes.Red,
+ FillRule = FillRule.EvenOdd
+ };
+
+ var nonZero = new Polyline
+ {
+ Points = new Points { new Point(0, 0), new Point(10, 10), new Point(20, 0) },
+ Fill = Brushes.Red,
+ FillRule = FillRule.NonZero
+ };
+
+ evenOdd.Measure(Size.Infinity);
+ nonZero.Measure(Size.Infinity);
+
+ Assert.Equal(FillRule.EvenOdd, Assert.IsType(evenOdd.DefiningGeometry).FillRule);
+ Assert.Equal(FillRule.NonZero, Assert.IsType(nonZero.DefiningGeometry).FillRule);
+ }
+
+ [Fact]
+ public void When_Fill_Is_Null_Polyline_Geometry_Is_Not_Filled()
+ {
+ using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface);
+
+ var target = new Polyline
+ {
+ Points = new Points { new Point(0, 0), new Point(10, 10), new Point(20, 0) },
+ FillRule = FillRule.NonZero,
+ Fill = null
+ };
+
+ target.Measure(Size.Infinity);
+ var geometry = Assert.IsType(target.DefiningGeometry);
+ Assert.False(geometry.IsFilled);
+ }
}
diff --git a/tests/Avalonia.RenderTests/Shapes/PolygonTests.cs b/tests/Avalonia.RenderTests/Shapes/PolygonTests.cs
index 301ee46cf7d..f2b9ec31a94 100644
--- a/tests/Avalonia.RenderTests/Shapes/PolygonTests.cs
+++ b/tests/Avalonia.RenderTests/Shapes/PolygonTests.cs
@@ -13,6 +13,39 @@ public PolygonTests()
{
}
+ [Theory]
+ [InlineData(FillRule.EvenOdd)]
+ [InlineData(FillRule.NonZero)]
+ public async Task Polygon_FillRule(FillRule fillRule)
+ {
+ var target = new Decorator
+ {
+ Padding = new Thickness(8),
+ Width = 220,
+ Height = 220,
+ Child = new Polygon
+ {
+ Stroke = Brushes.Black,
+ StrokeThickness = 2,
+ Fill = Brushes.Gold,
+ Points = new Points
+ {
+ new Point(50, 0),
+ new Point(21, 90),
+ new Point(98, 35),
+ new Point(2, 35),
+ new Point(79, 90)
+ },
+ Stretch = Stretch.Uniform,
+ FillRule = fillRule
+ }
+ };
+
+ var testName = $"{nameof(Polygon_FillRule)}_{fillRule}";
+ await RenderToFile(target, testName);
+ CompareImages(testName);
+ }
+
[Fact]
public async Task Polygon_1px_Stroke()
{
diff --git a/tests/Avalonia.RenderTests/Shapes/PolylineTests.cs b/tests/Avalonia.RenderTests/Shapes/PolylineTests.cs
index e110b4e30e8..dd4f6828dd1 100644
--- a/tests/Avalonia.RenderTests/Shapes/PolylineTests.cs
+++ b/tests/Avalonia.RenderTests/Shapes/PolylineTests.cs
@@ -13,6 +13,75 @@ public PolylineTests()
{
}
+ [Theory]
+ [InlineData(FillRule.EvenOdd)]
+ [InlineData(FillRule.NonZero)]
+ public async Task Polyline_FillRule(FillRule fillRule)
+ {
+ var target = new Decorator
+ {
+ Padding = new Thickness(8),
+ Width = 260,
+ Height = 180,
+ Child = new Polyline
+ {
+ Stroke = Brushes.Black,
+ StrokeThickness = 2,
+ Fill = Brushes.OrangeRed,
+ Points = new Points
+ {
+ new Point(10, 170),
+ new Point(60, 20),
+ new Point(110, 170),
+ new Point(20, 70),
+ new Point(240, 70),
+ new Point(130, 170),
+ new Point(190, 20),
+ new Point(10, 170),
+ },
+ Stretch = Stretch.Uniform,
+ FillRule = fillRule
+ }
+ };
+
+ var testName = $"{nameof(Polyline_FillRule)}_{fillRule}";
+ await RenderToFile(target, testName);
+ CompareImages(testName);
+ }
+
+ [Fact]
+ public async Task Polyline_FillRule_NoFill()
+ {
+ var target = new Decorator
+ {
+ Padding = new Thickness(8),
+ Width = 260,
+ Height = 180,
+ Child = new Polyline
+ {
+ Stroke = Brushes.Black,
+ StrokeThickness = 2,
+ Fill = null,
+ Points = new Points
+ {
+ new Point(10, 170),
+ new Point(60, 20),
+ new Point(110, 170),
+ new Point(20, 70),
+ new Point(240, 70),
+ new Point(130, 170),
+ new Point(190, 20),
+ new Point(10, 170),
+ },
+ Stretch = Stretch.Uniform,
+ FillRule = FillRule.EvenOdd
+ }
+ };
+
+ await RenderToFile(target);
+ CompareImages();
+ }
+
[Fact]
public async Task Polyline_1px_Stroke()
{
diff --git a/tests/TestFiles/Skia/Shapes/Polygon/Polygon_FillRule_EvenOdd.expected.png b/tests/TestFiles/Skia/Shapes/Polygon/Polygon_FillRule_EvenOdd.expected.png
new file mode 100644
index 00000000000..db832be43b3
Binary files /dev/null and b/tests/TestFiles/Skia/Shapes/Polygon/Polygon_FillRule_EvenOdd.expected.png differ
diff --git a/tests/TestFiles/Skia/Shapes/Polygon/Polygon_FillRule_NonZero.expected.png b/tests/TestFiles/Skia/Shapes/Polygon/Polygon_FillRule_NonZero.expected.png
new file mode 100644
index 00000000000..152f959fd94
Binary files /dev/null and b/tests/TestFiles/Skia/Shapes/Polygon/Polygon_FillRule_NonZero.expected.png differ
diff --git a/tests/TestFiles/Skia/Shapes/Polyline/Polyline_FillRule_EvenOdd.expected.png b/tests/TestFiles/Skia/Shapes/Polyline/Polyline_FillRule_EvenOdd.expected.png
new file mode 100644
index 00000000000..4b1348f5b63
Binary files /dev/null and b/tests/TestFiles/Skia/Shapes/Polyline/Polyline_FillRule_EvenOdd.expected.png differ
diff --git a/tests/TestFiles/Skia/Shapes/Polyline/Polyline_FillRule_NoFill.expected.png b/tests/TestFiles/Skia/Shapes/Polyline/Polyline_FillRule_NoFill.expected.png
new file mode 100644
index 00000000000..5837133ef4b
Binary files /dev/null and b/tests/TestFiles/Skia/Shapes/Polyline/Polyline_FillRule_NoFill.expected.png differ
diff --git a/tests/TestFiles/Skia/Shapes/Polyline/Polyline_FillRule_NonZero.expected.png b/tests/TestFiles/Skia/Shapes/Polyline/Polyline_FillRule_NonZero.expected.png
new file mode 100644
index 00000000000..b697dc80355
Binary files /dev/null and b/tests/TestFiles/Skia/Shapes/Polyline/Polyline_FillRule_NonZero.expected.png differ