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)