diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutablePen.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutablePen.cs
index bcfec5dccf..326083dec1 100644
--- a/src/Avalonia.Visuals/Media/Immutable/ImmutablePen.cs
+++ b/src/Avalonia.Visuals/Media/Immutable/ImmutablePen.cs
@@ -1,12 +1,14 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
+using System;
+
namespace Avalonia.Media.Immutable
{
///
/// Describes how a stroke is drawn.
///
- public class ImmutablePen : IPen
+ public class ImmutablePen : IPen, IEquatable
{
///
/// Initializes a new instance of the class.
@@ -81,5 +83,14 @@ namespace Avalonia.Media.Immutable
/// The limit on the ratio of the miter length to half this pen's Thickness.
///
public double MiterLimit { get; }
+
+ ///
+ public override bool Equals(object obj) => Pen.PenEquals(this, obj as IPen);
+
+ ///
+ public bool Equals(IPen other) => Pen.PenEquals(this, other);
+
+ ///
+ public override int GetHashCode() => Pen.GetHashCode(this);
}
}
diff --git a/src/Avalonia.Visuals/Media/Pen.cs b/src/Avalonia.Visuals/Media/Pen.cs
index d609335d68..b89ca15a0e 100644
--- a/src/Avalonia.Visuals/Media/Pen.cs
+++ b/src/Avalonia.Visuals/Media/Pen.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
+using System.Collections.Generic;
using Avalonia.Media.Immutable;
using Avalonia.Utilities;
@@ -10,7 +11,7 @@ namespace Avalonia.Media
///
/// Describes how a stroke is drawn.
///
- public class Pen : AvaloniaObject, IMutablePen
+ public class Pen : AvaloniaObject, IMutablePen, IEquatable
{
///
/// Defines the property.
@@ -170,6 +171,15 @@ namespace Avalonia.Media
///
public event EventHandler Invalidated;
+ ///
+ public override bool Equals(object obj) => PenEquals(this, obj as IPen);
+
+ ///
+ public bool Equals(IPen other) => PenEquals(this, other);
+
+ ///
+ public override int GetHashCode() => GetHashCode(this);
+
///
/// Creates an immutable clone of the brush.
///
@@ -232,6 +242,37 @@ namespace Avalonia.Media
/// The event args.
protected void RaiseInvalidated(EventArgs e) => Invalidated?.Invoke(this, e);
+ internal static int GetHashCode(IPen pen)
+ {
+ var hashCode = 1181807663;
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(pen.Brush);
+ hashCode = hashCode * -1521134295 + pen.Thickness.GetHashCode();
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(pen.DashStyle);
+ hashCode = hashCode * -1521134295 + pen.LineCap.GetHashCode();
+ hashCode = hashCode * -1521134295 + pen.LineJoin.GetHashCode();
+ hashCode = hashCode * -1521134295 + pen.MiterLimit.GetHashCode();
+ return hashCode;
+ }
+
+ internal static bool PenEquals(IPen a, IPen b)
+ {
+ if (ReferenceEquals(a, b))
+ {
+ return true;
+ }
+ else if (a is null && !(b is null) || (b is null && !(a is null)))
+ {
+ return false;
+ }
+
+ return EqualityComparer.Default.Equals(a.Brush, b.Brush) &&
+ a.Thickness == b.Thickness &&
+ EqualityComparer.Default.Equals(a.DashStyle, b.DashStyle) &&
+ a.LineCap == b.LineCap &&
+ a.LineJoin == b.LineJoin &&
+ a.MiterLimit == b.MiterLimit;
+ }
+
private void AffectsRenderInvalidated(object sender, EventArgs e) => RaiseInvalidated(EventArgs.Empty);
}
}
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs
index 0781a233f7..ff97ced349 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs
@@ -74,7 +74,7 @@ namespace Avalonia.Rendering.SceneGraph
///
public bool Equals(Matrix transform, IPen pen, Point p1, Point p2)
{
- return transform == Transform && pen == Pen && p1 == P1 && p2 == P2;
+ return transform == Transform && Equals(pen, Pen) && p1 == P1 && p2 == P2;
}
public override void Render(IDrawingContextImpl context)