From fae80cac37fbd07149c5010661a36bb095f32d77 Mon Sep 17 00:00:00 2001 From: h3xds1nz Date: Sun, 13 Oct 2024 23:27:07 +0200 Subject: [PATCH 01/13] Remove PathGeometry/PathFigure related allocations --- .../System/Windows/Media/EllipseGeometry.cs | 23 +++------ .../System/Windows/Media/LineGeometry.cs | 11 +--- .../System/Windows/Media/PathFigure.cs | 15 ++++-- .../System/Windows/Media/PathGeometry.cs | 8 +++ .../System/Windows/Media/RectangleGeometry.cs | 50 +++++-------------- .../Windows/Controls/Primitives/TickBar.cs | 32 +++--------- 6 files changed, 47 insertions(+), 92 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/EllipseGeometry.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/EllipseGeometry.cs index b67934e4b30..f2162582ecf 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/EllipseGeometry.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/EllipseGeometry.cs @@ -267,32 +267,23 @@ public override double GetArea(double tolerance, ToleranceType type) internal override PathFigureCollection GetTransformedFigureCollection(Transform transform) { - Point [] points = GetPointList(); + Point[] points = GetPointList(); // Get the combined transform argument with the internal transform Matrix matrix = GetCombinedMatrix(transform); if (!matrix.IsIdentity) { - for (int i=0; i diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/LineGeometry.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/LineGeometry.cs index 93e1d68afe4..c6bcfe44456 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/LineGeometry.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/LineGeometry.cs @@ -230,16 +230,7 @@ internal override PathFigureCollection GetTransformedFigureCollection(Transform endPoint *= matrix; } - PathFigureCollection collection = new PathFigureCollection(); - collection.Add( - new PathFigure( - startPoint, - new PathSegment[]{new LineSegment(endPoint, true)}, - false // ==> not closed - ) - ); - - return collection; + return new PathFigureCollection(1) { new PathFigure(startPoint, [new LineSegment(endPoint, true)], false) }; // ==> not closed; } /// diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/PathFigure.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/PathFigure.cs index 06b2596be8a..da7024829d9 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/PathFigure.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/PathFigure.cs @@ -50,15 +50,24 @@ public PathFigure() /// Indicates whether the figure is closed public PathFigure(Point start, IEnumerable segments, bool closed) { + ArgumentNullException.ThrowIfNull(segments); + StartPoint = start; PathSegmentCollection mySegments = Segments; - ArgumentNullException.ThrowIfNull(segments); + foreach (PathSegment item in segments) + mySegments.Add(item); + + IsClosed = closed; + } + + internal PathFigure(Point start, ReadOnlySpan segments, bool closed) + { + StartPoint = start; + PathSegmentCollection mySegments = Segments; foreach (PathSegment item in segments) - { mySegments.Add(item); - } IsClosed = closed; } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/PathGeometry.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/PathGeometry.cs index 12a800b80bf..f9f6891a0ce 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/PathGeometry.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/PathGeometry.cs @@ -76,6 +76,14 @@ public PathGeometry(IEnumerable figures) SetDirty(); } + internal PathGeometry(params ReadOnlySpan figures) + { + foreach (PathFigure item in figures) + Figures.Add(item); + + SetDirty(); + } + /// /// Constructor /// diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs index 5c6316dc425..f7249f358ad 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs @@ -332,50 +332,26 @@ internal override PathFigureCollection GetTransformedFigureCollection(Transform // Transform if applicable. if (!matrix.IsIdentity) { - for (int i=0; i Date: Sun, 13 Oct 2024 23:30:39 +0200 Subject: [PATCH 02/13] Mark GetPointCount/GetSegmentCount static --- .../System/Windows/Media/RectangleGeometry.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs index f7249f358ad..79e3e8062d3 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs @@ -502,7 +502,7 @@ private static ReadOnlySpan GetTypeList(Rect rect, double radiusX, double } } - private uint GetPointCount(Rect rect, double radiusX, double radiusY) + private static uint GetPointCount(Rect rect, double radiusX, double radiusY) { if (rect.IsEmpty) { @@ -518,7 +518,7 @@ private uint GetPointCount(Rect rect, double radiusX, double radiusY) } } - private uint GetSegmentCount(Rect rect, double radiusX, double radiusY) + private static uint GetSegmentCount(Rect rect, double radiusX, double radiusY) { if (rect.IsEmpty) { From c979ea9b7a4662e4cf9e40cd72cb5fb69eedec3c Mon Sep 17 00:00:00 2001 From: h3xds1nz Date: Mon, 21 Oct 2024 21:57:48 +0200 Subject: [PATCH 03/13] Remove unnecessary heap Point allocations and pinning in EllipseGeometry --- .../System/Windows/Media/EllipseGeometry.cs | 45 +++++++++---------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/EllipseGeometry.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/EllipseGeometry.cs index f2162582ecf..01c34360d0a 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/EllipseGeometry.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/EllipseGeometry.cs @@ -159,8 +159,7 @@ internal static Rect GetBoundsHelper(Pen pen, Matrix worldMatrix, Point center, { Rect rect; - if ( (pen == null || pen.DoesNotContainGaps) && - worldMatrix.IsIdentity && geometryMatrix.IsIdentity) + if ((pen == null || pen.DoesNotContainGaps) && worldMatrix.IsIdentity && geometryMatrix.IsIdentity) { double strokeThickness = 0.0; @@ -179,10 +178,10 @@ internal static Rect GetBoundsHelper(Pen pen, Matrix worldMatrix, Point center, { unsafe { - Point* pPoints = stackalloc Point[(int)c_pointCount]; - EllipseGeometry.GetPointList(pPoints, c_pointCount, center, radiusX, radiusY); + Point* pPoints = stackalloc Point[(int)GetPointCount()]; + EllipseGeometry.InitializePointList(pPoints, (int)GetPointCount(), center, radiusX, radiusY); - fixed (byte* pTypes = RoundedPathTypes) //Merely retrieves the pointer to static PE data, no actual pinning occurs + fixed (byte* pTypes = RoundedPathTypes) // Merely retrieves the pointer to static PE data, no actual pinning occurs { rect = Geometry.GetBoundsHelper( pen, @@ -207,9 +206,9 @@ internal override bool ContainsInternal(Pen pen, Point hitPoint, double toleranc unsafe { Point* pPoints = stackalloc Point[(int)GetPointCount()]; - EllipseGeometry.GetPointList(pPoints, GetPointCount(), Center, RadiusX, RadiusY); + EllipseGeometry.InitializePointList(pPoints, (int)GetPointCount(), Center, RadiusX, RadiusY); - fixed (byte* pTypes = RoundedPathTypes) //Merely retrieves the pointer to static PE data, no actual pinning occurs + fixed (byte* pTypes = RoundedPathTypes) // Merely retrieves the pointer to static PE data, no actual pinning occurs { return ContainsInternal( pen, @@ -267,7 +266,9 @@ public override double GetArea(double tolerance, ToleranceType type) internal override PathFigureCollection GetTransformedFigureCollection(Transform transform) { - Point[] points = GetPointList(); + // Initialize the point list + Span points = stackalloc Point[(int)GetPointCount()]; + InitializePointList(points); // Get the combined transform argument with the internal transform Matrix matrix = GetCombinedMatrix(transform); @@ -308,11 +309,11 @@ internal override PathGeometryData GetPathGeometryData() return Geometry.GetEmptyPathGeometryData(); } - PathGeometryData data = new PathGeometryData(); - data.FillRule = FillRule.EvenOdd; - data.Matrix = CompositionResourceManager.TransformToMilMatrix3x2D(Transform); + PathGeometryData data = new() { FillRule = FillRule.EvenOdd, Matrix = CompositionResourceManager.TransformToMilMatrix3x2D(Transform) }; - Point[] points = GetPointList(); + // Initialize the point list + Span points = stackalloc Point[(int)GetPointCount()]; + InitializePointList(points); ByteStreamGeometryContext ctx = new ByteStreamGeometryContext(); @@ -331,24 +332,20 @@ internal override PathGeometryData GetPathGeometryData() } /// + /// Initializes the point list into . Optionally pins the source if not stack-allocated. /// - /// - private Point[] GetPointList() + private unsafe void InitializePointList(Span destination) { - Point[] points = new Point[GetPointCount()]; - - unsafe + fixed (Point* ptrPoints = destination) // In case this is stackallocated, it's a no-op { - fixed(Point *pPoints = points) - { - EllipseGeometry.GetPointList(pPoints, GetPointCount(), Center, RadiusX, RadiusY); - } + EllipseGeometry.InitializePointList(ptrPoints, destination.Length, Center, RadiusX, RadiusY); } - - return points; } - private unsafe static void GetPointList(Point * points, uint pointsCount, Point center, double radiusX, double radiusY) + /// + /// Initializes the point list specified by . The pointer must be pinned. + /// + private unsafe static void InitializePointList(Point* points, int pointsCount, Point center, double radiusX, double radiusY) { Invariant.Assert(pointsCount >= c_pointCount); From 6bf76f061269ccfdc7da7aaba5310e1ab0e548af Mon Sep 17 00:00:00 2001 From: h3xds1nz Date: Mon, 21 Oct 2024 22:15:45 +0200 Subject: [PATCH 04/13] Remove redundant usigns in EllipseGeometry --- .../System/Windows/Media/EllipseGeometry.cs | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/EllipseGeometry.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/EllipseGeometry.cs index 01c34360d0a..6fb976d2585 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/EllipseGeometry.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/EllipseGeometry.cs @@ -2,25 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -// - -using System; using MS.Internal; -using System.ComponentModel; -using System.ComponentModel.Design.Serialization; -using System.Reflection; -using System.Collections; -using System.Text; -using System.Globalization; -using System.Windows.Media; using System.Windows.Media.Composition; -using System.Windows; -using System.Text.RegularExpressions; -using System.Windows.Media.Animation; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Security; -using SR=MS.Internal.PresentationCore.SR; + +using SR = MS.Internal.PresentationCore.SR; namespace System.Windows.Media { From 5abb317a424d628edf008bb669d8aafca8357294 Mon Sep 17 00:00:00 2001 From: h3xds1nz Date: Mon, 21 Oct 2024 22:18:51 +0200 Subject: [PATCH 05/13] Use proper naming conventions, remove GetPointCount/GetSegmentCount, inline vars --- .../System/Windows/Media/EllipseGeometry.cs | 156 ++++++------------ .../System/Windows/Media/RectangleGeometry.cs | 4 +- 2 files changed, 51 insertions(+), 109 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/EllipseGeometry.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/EllipseGeometry.cs index 6fb976d2585..40a36bf9f1d 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/EllipseGeometry.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/EllipseGeometry.cs @@ -19,9 +19,7 @@ public sealed partial class EllipseGeometry : Geometry /// /// /// - public EllipseGeometry() - { - } + public EllipseGeometry() { } /// /// Constructor - sets the ellipse to the paramters with the given transformation @@ -30,7 +28,7 @@ public EllipseGeometry(Rect rect) { if (rect.IsEmpty) { - throw new System.ArgumentException(SR.Format(SR.Rect_Empty, "rect")); + throw new ArgumentException(SR.Format(SR.Rect_Empty, nameof(rect))); } RadiusX = (rect.Right - rect.X) * (1.0 / 2.0); @@ -41,10 +39,7 @@ public EllipseGeometry(Rect rect) /// /// Constructor - sets the ellipse to the parameters /// - public EllipseGeometry( - Point center, - double radiusX, - double radiusY) + public EllipseGeometry(Point center, double radiusX, double radiusY) { Center = center; RadiusX = radiusX; @@ -54,11 +49,7 @@ public EllipseGeometry( /// /// Constructor - sets the ellipse to the parameters /// - public EllipseGeometry( - Point center, - double radiusX, - double radiusY, - Transform transform) : this(center, radiusX, radiusY) + public EllipseGeometry(Point center, double radiusX, double radiusY, Transform transform) : this(center, radiusX, radiusY) { Transform = transform; } @@ -81,14 +72,13 @@ public override Rect Bounds if (transform == null || transform.IsIdentity) { Point currentCenter = Center; - Double currentRadiusX = RadiusX; - Double currentRadiusY = RadiusY; - - boundsRect = new Rect( - currentCenter.X - Math.Abs(currentRadiusX), - currentCenter.Y - Math.Abs(currentRadiusY), - 2.0 * Math.Abs(currentRadiusX), - 2.0 * Math.Abs(currentRadiusY)); + double currentRadiusX = RadiusX; + double currentRadiusY = RadiusY; + + boundsRect = new Rect(currentCenter.X - Math.Abs(currentRadiusX), + currentCenter.Y - Math.Abs(currentRadiusY), + 2.0 * Math.Abs(currentRadiusX), + 2.0 * Math.Abs(currentRadiusY)); } else { @@ -99,9 +89,7 @@ public override Rect Bounds // it's easier to let unmanaged code do the work for us. // - Matrix geometryMatrix; - - Transform.GetTransformValue(transform, out geometryMatrix); + Transform.GetTransformValue(transform, out Matrix geometryMatrix); boundsRect = EllipseGeometry.GetBoundsHelper( null /* no pen */, @@ -124,86 +112,44 @@ public override Rect Bounds /// internal override Rect GetBoundsInternal(Pen pen, Matrix matrix, double tolerance, ToleranceType type) { - Matrix geometryMatrix; - - Transform.GetTransformValue(Transform, out geometryMatrix); - - return EllipseGeometry.GetBoundsHelper( - pen, - matrix, - Center, - RadiusX, - RadiusY, - geometryMatrix, - tolerance, - type); + Transform.GetTransformValue(Transform, out Matrix geometryMatrix); + + return EllipseGeometry.GetBoundsHelper(pen, matrix, Center, RadiusX, RadiusY, geometryMatrix, tolerance, type); } - internal static Rect GetBoundsHelper(Pen pen, Matrix worldMatrix, Point center, double radiusX, double radiusY, - Matrix geometryMatrix, double tolerance, ToleranceType type) + internal static unsafe Rect GetBoundsHelper(Pen pen, Matrix worldMatrix, Point center, double radiusX, double radiusY, + Matrix geometryMatrix, double tolerance, ToleranceType type) { - Rect rect; - if ((pen == null || pen.DoesNotContainGaps) && worldMatrix.IsIdentity && geometryMatrix.IsIdentity) { - double strokeThickness = 0.0; - - if (Pen.ContributesToBounds(pen)) - { - strokeThickness = Math.Abs(pen.Thickness); - } + double strokeThickness = Pen.ContributesToBounds(pen) ? Math.Abs(pen.Thickness) : 0.0; - rect = new Rect( - center.X - Math.Abs(radiusX)-0.5*strokeThickness, - center.Y - Math.Abs(radiusY)-0.5*strokeThickness, - 2.0 * Math.Abs(radiusX)+strokeThickness, - 2.0 * Math.Abs(radiusY)+strokeThickness); + return new Rect(center.X - Math.Abs(radiusX) - 0.5 * strokeThickness, + center.Y - Math.Abs(radiusY) - 0.5 * strokeThickness, + 2.0 * Math.Abs(radiusX) + strokeThickness, + 2.0 * Math.Abs(radiusY) + strokeThickness); } - else + + Point* ptrPoints = stackalloc Point[(int)PointCount]; + EllipseGeometry.InitializePointList(ptrPoints, (int)PointCount, center, radiusX, radiusY); + + fixed (byte* ptrTypes = RoundedPathTypes) // Merely retrieves the pointer to static PE data, no actual pinning occurs { - unsafe - { - Point* pPoints = stackalloc Point[(int)GetPointCount()]; - EllipseGeometry.InitializePointList(pPoints, (int)GetPointCount(), center, radiusX, radiusY); - - fixed (byte* pTypes = RoundedPathTypes) // Merely retrieves the pointer to static PE data, no actual pinning occurs - { - rect = Geometry.GetBoundsHelper( - pen, - &worldMatrix, - pPoints, - pTypes, - c_pointCount, - c_segmentCount, - &geometryMatrix, - tolerance, - type, - false); // skip hollows - meaningless here, this is never a hollow - } - } + return Geometry.GetBoundsHelper(pen, &worldMatrix, ptrPoints, ptrTypes, PointCount, SegmentCount, &geometryMatrix, + tolerance, type, false); // skip hollows - meaningless here, this is never a hollow } - - return rect; } internal override bool ContainsInternal(Pen pen, Point hitPoint, double tolerance, ToleranceType type) { unsafe { - Point* pPoints = stackalloc Point[(int)GetPointCount()]; - EllipseGeometry.InitializePointList(pPoints, (int)GetPointCount(), Center, RadiusX, RadiusY); + Point* ptrPoints = stackalloc Point[(int)PointCount]; + EllipseGeometry.InitializePointList(ptrPoints, (int)PointCount, Center, RadiusX, RadiusY); - fixed (byte* pTypes = RoundedPathTypes) // Merely retrieves the pointer to static PE data, no actual pinning occurs + fixed (byte* ptrTypes = RoundedPathTypes) // Merely retrieves the pointer to static PE data, no actual pinning occurs { - return ContainsInternal( - pen, - hitPoint, - tolerance, - type, - pPoints, - GetPointCount(), - pTypes, - GetSegmentCount()); + return ContainsInternal(pen, hitPoint, tolerance, type, ptrPoints, PointCount, ptrTypes, SegmentCount); } } } @@ -252,7 +198,7 @@ public override double GetArea(double tolerance, ToleranceType type) internal override PathFigureCollection GetTransformedFigureCollection(Transform transform) { // Initialize the point list - Span points = stackalloc Point[(int)GetPointCount()]; + Span points = stackalloc Point[(int)PointCount]; InitializePointList(points); // Get the combined transform argument with the internal transform @@ -277,7 +223,7 @@ internal override PathFigureCollection GetTransformedFigureCollection(Transform /// internal override PathGeometry GetAsPathGeometry() { - PathStreamGeometryContext ctx = new PathStreamGeometryContext(FillRule.EvenOdd, Transform); + PathStreamGeometryContext ctx = new(FillRule.EvenOdd, Transform); PathGeometry.ParsePathGeometryData(GetPathGeometryData(), ctx); return ctx.GetPathGeometry(); @@ -297,11 +243,10 @@ internal override PathGeometryData GetPathGeometryData() PathGeometryData data = new() { FillRule = FillRule.EvenOdd, Matrix = CompositionResourceManager.TransformToMilMatrix3x2D(Transform) }; // Initialize the point list - Span points = stackalloc Point[(int)GetPointCount()]; + Span points = stackalloc Point[(int)PointCount]; InitializePointList(points); - ByteStreamGeometryContext ctx = new ByteStreamGeometryContext(); - + ByteStreamGeometryContext ctx = new(); ctx.BeginFigure(points[0], true /* is filled */, true /* is closed */); // i == 0, 3, 6, 9 @@ -332,13 +277,13 @@ private unsafe void InitializePointList(Span destination) /// private unsafe static void InitializePointList(Point* points, int pointsCount, Point center, double radiusX, double radiusY) { - Invariant.Assert(pointsCount >= c_pointCount); + Invariant.Assert((uint)pointsCount >= PointCount); radiusX = Math.Abs(radiusX); radiusY = Math.Abs(radiusY); // Set the X coordinates - double mid = radiusX * c_arcAsBezier; + double mid = radiusX * ArcAsBezier; points[0].X = points[1].X = points[11].X = points[12].X = center.X + radiusX; points[2].X = points[10].X = center.X + mid; @@ -347,7 +292,7 @@ private unsafe static void InitializePointList(Point* points, int pointsCount, P points[5].X = points[6].X = points[7].X = center.X - radiusX; // Set the Y coordinates - mid = radiusY * c_arcAsBezier; + mid = radiusY * ArcAsBezier; points[2].Y = points[3].Y = points[4].Y = center.Y + radiusY; points[1].Y = points[5].Y = center.Y + mid; @@ -355,29 +300,26 @@ private unsafe static void InitializePointList(Point* points, int pointsCount, P points[7].Y = points[11].Y = center.Y - mid; points[8].Y = points[9].Y = points[10].Y = center.Y - radiusY; } - - private static uint GetPointCount() { return c_pointCount; } - private static uint GetSegmentCount() { return c_segmentCount; } #region Static Data // Approximating a 1/4 circle with a Bezier curve _ - internal const double c_arcAsBezier = 0.5522847498307933984; // =( \/2 - 1)*4/3 + internal const double ArcAsBezier = 0.5522847498307933984; // =( \/2 - 1)*4/3 - private const UInt32 c_segmentCount = 4; - private const UInt32 c_pointCount = 13; + private const uint SegmentCount = 4; + private const uint PointCount = 13; - private const byte c_smoothBezier = (byte)MILCoreSegFlags.SegTypeBezier | - (byte)MILCoreSegFlags.SegIsCurved | - (byte)MILCoreSegFlags.SegSmoothJoin; + private const byte SmoothBezier = (byte)MILCoreSegFlags.SegTypeBezier | + (byte)MILCoreSegFlags.SegIsCurved | + (byte)MILCoreSegFlags.SegSmoothJoin; private static ReadOnlySpan RoundedPathTypes => [(byte)MILCoreSegFlags.SegTypeBezier | (byte)MILCoreSegFlags.SegIsCurved | (byte)MILCoreSegFlags.SegSmoothJoin | (byte)MILCoreSegFlags.SegClosed, - c_smoothBezier, - c_smoothBezier, - c_smoothBezier]; + SmoothBezier, + SmoothBezier, + SmoothBezier]; #endregion } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs index 79e3e8062d3..0cde1db0dda 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs @@ -454,8 +454,8 @@ private unsafe static void GetPointList(Point * points, uint pointsCount, Rect r radiusX = Math.Min(rect.Width * (1.0 / 2.0), Math.Abs(radiusX)); radiusY = Math.Min(rect.Height * (1.0 / 2.0), Math.Abs(radiusY)); - double bezierX = ((1.0 - EllipseGeometry.c_arcAsBezier) * radiusX); - double bezierY = ((1.0 - EllipseGeometry.c_arcAsBezier) * radiusY); + double bezierX = ((1.0 - EllipseGeometry.ArcAsBezier) * radiusX); + double bezierY = ((1.0 - EllipseGeometry.ArcAsBezier) * radiusY); points[1].X = points[0].X = points[15].X = points[14].X = rect.X; points[2].X = points[13].X = rect.X + bezierX; From 39dedeb9615f1f1ac83ea06fe577816cf97d084c Mon Sep 17 00:00:00 2001 From: h3xds1nz Date: Mon, 21 Oct 2024 22:42:50 +0200 Subject: [PATCH 06/13] Remove regression from #9230 that shouldn't pass review, turn static byte fields into constants --- .../System/Windows/Media/RectangleGeometry.cs | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs index 0cde1db0dda..c4a20a78e11 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs @@ -580,25 +580,23 @@ public override bool MayHaveCurves() static private UInt32 c_roundedSegmentCount = 8; static private UInt32 c_roundedPointCount = 17; - static private byte smoothBezier = (byte)MILCoreSegFlags.SegTypeBezier | - (byte)MILCoreSegFlags.SegIsCurved | - (byte)MILCoreSegFlags.SegSmoothJoin; - - static private byte smoothLine = (byte)MILCoreSegFlags.SegTypeLine | (byte)MILCoreSegFlags.SegSmoothJoin; - - private static ReadOnlySpan RoundedPathTypes => new byte[] { - (byte)MILCoreSegFlags.SegTypeBezier | - (byte)MILCoreSegFlags.SegIsCurved | - (byte)MILCoreSegFlags.SegSmoothJoin | - (byte)MILCoreSegFlags.SegClosed, - smoothLine, - smoothBezier, - smoothLine, - smoothBezier, - smoothLine, - smoothBezier, - smoothLine - }; + private const byte SmoothBezier = (byte)MILCoreSegFlags.SegTypeBezier | + (byte)MILCoreSegFlags.SegIsCurved | + (byte)MILCoreSegFlags.SegSmoothJoin; + + private const byte SmoothLine = (byte)MILCoreSegFlags.SegTypeLine | (byte)MILCoreSegFlags.SegSmoothJoin; + + private static ReadOnlySpan RoundedPathTypes => [(byte)MILCoreSegFlags.SegTypeBezier | + (byte)MILCoreSegFlags.SegIsCurved | + (byte)MILCoreSegFlags.SegSmoothJoin | + (byte)MILCoreSegFlags.SegClosed, + SmoothLine, + SmoothBezier, + SmoothLine, + SmoothBezier, + SmoothLine, + SmoothBezier, + SmoothLine]; // Squared private const UInt32 c_squaredSegmentCount = 4; From 2762b3f08bcce44bde884ac10d3220e0b06ed6d6 Mon Sep 17 00:00:00 2001 From: h3xds1nz Date: Mon, 21 Oct 2024 22:52:32 +0200 Subject: [PATCH 07/13] Finish up with the rest of the constant names --- .../System/Windows/Media/RectangleGeometry.cs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs index c4a20a78e11..cec6dd4be4e 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs @@ -449,7 +449,7 @@ private unsafe static void GetPointList(Point * points, uint pointsCount, Rect r if (IsRounded(radiusX, radiusY)) { // It is a rounded rectangle - Invariant.Assert(pointsCount >= c_roundedPointCount); + Invariant.Assert(pointsCount >= RoundedPointCount); radiusX = Math.Min(rect.Width * (1.0 / 2.0), Math.Abs(radiusX)); radiusY = Math.Min(rect.Height * (1.0 / 2.0), Math.Abs(radiusY)); @@ -476,7 +476,7 @@ private unsafe static void GetPointList(Point * points, uint pointsCount, Rect r else { // The rectangle is not rounded - Invariant.Assert(pointsCount >= c_squaredPointCount); + Invariant.Assert(pointsCount >= SquaredPointCount); points[0].X = points[3].X = points[4].X = rect.X; points[1].X = points[2].X = rect.Right; @@ -510,11 +510,11 @@ private static uint GetPointCount(Rect rect, double radiusX, double radiusY) } else if (IsRounded(radiusX, radiusY)) { - return c_roundedPointCount; + return RoundedPointCount; } else { - return c_squaredPointCount; + return SquaredPointCount; } } @@ -526,11 +526,11 @@ private static uint GetSegmentCount(Rect rect, double radiusX, double radiusY) } else if (IsRounded(radiusX, radiusY)) { - return c_roundedSegmentCount; + return RoundedSegmentCount; } else { - return c_squaredSegmentCount; + return SquaredSegmentCount; } } @@ -544,13 +544,13 @@ private static void GetCounts(Rect rect, double radiusX, double radiusY, out uin else if (IsRounded(radiusX, radiusY)) { // The rectangle is rounded - pointCount = c_roundedPointCount; - segmentCount = c_roundedSegmentCount; + pointCount = RoundedPointCount; + segmentCount = RoundedSegmentCount; } else { - pointCount = c_squaredPointCount; - segmentCount = c_squaredSegmentCount; + pointCount = SquaredPointCount; + segmentCount = SquaredSegmentCount; } } @@ -577,8 +577,8 @@ public override bool MayHaveCurves() #region InstanceData // Rouneded - static private UInt32 c_roundedSegmentCount = 8; - static private UInt32 c_roundedPointCount = 17; + private const uint RoundedSegmentCount = 8; + private const uint RoundedPointCount = 17; private const byte SmoothBezier = (byte)MILCoreSegFlags.SegTypeBezier | (byte)MILCoreSegFlags.SegIsCurved | @@ -599,8 +599,8 @@ public override bool MayHaveCurves() SmoothLine]; // Squared - private const UInt32 c_squaredSegmentCount = 4; - private const UInt32 c_squaredPointCount = 5; + private const uint SquaredSegmentCount = 4; + private const uint SquaredPointCount = 5; private static ReadOnlySpan SquaredPathTypes => [(byte)MILCoreSegFlags.SegTypeLine | (byte)MILCoreSegFlags.SegClosed, (byte)MILCoreSegFlags.SegTypeLine, From 97f7fe352156764a6faa4cd37a644ed038433012 Mon Sep 17 00:00:00 2001 From: h3xds1nz Date: Mon, 21 Oct 2024 23:11:42 +0200 Subject: [PATCH 08/13] Remove Point allocations in RectangleGeometry --- .../System/Windows/Media/RectangleGeometry.cs | 48 +++++++++---------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs index cec6dd4be4e..c24ab01d545 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs @@ -214,16 +214,15 @@ internal static Rect GetBoundsHelper(Pen pen, Matrix worldMatrix, Rect rect, dou { unsafe { - uint pointCount, segmentCount; - GetCounts(rect, radiusX, radiusY, out pointCount, out segmentCount); + GetCounts(rect, radiusX, radiusY, out uint pointCount, out uint segmentCount); // We've checked that rect isn't empty above Invariant.Assert(pointCount != 0); Point* pPoints = stackalloc Point[(int)pointCount]; - RectangleGeometry.GetPointList(pPoints, pointCount, rect, radiusX, radiusY); + RectangleGeometry.InitializePointList(pPoints, (int)pointCount, rect, radiusX, radiusY); - fixed (byte* pTypes = GetTypeList(rect, radiusX, radiusY)) //Merely retrieves the pointer to static PE data, no actual pinning occurs + fixed (byte* pTypes = GetTypeList(rect, radiusX, radiusY)) // Merely retrieves the pointer to static PE data, no actual pinning occurs { boundingRect = Geometry.GetBoundsHelper( pen, @@ -260,9 +259,9 @@ internal override bool ContainsInternal(Pen pen, Point hitPoint, double toleranc unsafe { Point* pPoints = stackalloc Point[(int)pointCount]; - RectangleGeometry.GetPointList(pPoints, pointCount, rect, radiusX, radiusY); + RectangleGeometry.InitializePointList(pPoints, (int)pointCount, rect, radiusX, radiusY); - fixed (byte* pTypes = GetTypeList(rect, radiusX, radiusY)) //Merely retrieves the pointer to static PE data, no actual pinning occurs + fixed (byte* pTypes = GetTypeList(rect, radiusX, radiusY)) // Merely retrieves the pointer to static PE data, no actual pinning occurs { return ContainsInternal( pen, @@ -327,7 +326,9 @@ internal override PathFigureCollection GetTransformedFigureCollection(Transform if (IsRounded(radiusX, radiusY)) { - Point[] points = GetPointList(rect, radiusX, radiusY); + // Initialize the point list + Span points = stackalloc Point[(int)GetPointCount(rect, radiusX, radiusY)]; + InitializePointList(points, rect, radiusX, radiusY); // Transform if applicable. if (!matrix.IsIdentity) @@ -388,9 +389,7 @@ internal override PathGeometryData GetPathGeometryData() return Geometry.GetEmptyPathGeometryData(); } - PathGeometryData data = new PathGeometryData(); - data.FillRule = FillRule.EvenOdd; - data.Matrix = CompositionResourceManager.TransformToMilMatrix3x2D(Transform); + PathGeometryData data = new() { FillRule = FillRule.EvenOdd, Matrix = CompositionResourceManager.TransformToMilMatrix3x2D(Transform) }; double radiusX = RadiusX; double radiusY = RadiusY; @@ -400,7 +399,9 @@ internal override PathGeometryData GetPathGeometryData() if (IsRounded(radiusX, radiusY)) { - Point[] points = GetPointList(rect, radiusX, radiusY); + // Initialize the point list + Span points = stackalloc Point[(int)GetPointCount(rect, radiusX, radiusY)]; + InitializePointList(points, rect, radiusX, radiusY); ctx.BeginFigure(points[0], true /* is filled */, true /* is closed */); ctx.BezierTo(points[1], points[2], points[3], true /* is stroked */, false /* is smooth join */); @@ -426,30 +427,25 @@ internal override PathGeometryData GetPathGeometryData() } /// + /// Initializes the point list into . Optionally pins the source if not stack-allocated. /// - /// - private Point[] GetPointList(Rect rect, double radiusX, double radiusY) + private unsafe void InitializePointList(Span destination, ref readonly Rect rect, double radiusX, double radiusY) { - uint pointCount = GetPointCount(rect, radiusX, radiusY); - Point[] points = new Point[pointCount]; - - unsafe + fixed (Point* ptrPoints = destination) // In case this is stackallocated, it's a no-op { - fixed(Point *pPoints = points) - { - RectangleGeometry.GetPointList(pPoints, pointCount, rect, radiusX, radiusY); - } + RectangleGeometry.InitializePointList(ptrPoints, destination.Length, rect, radiusX, radiusY); } - - return points; } - private unsafe static void GetPointList(Point * points, uint pointsCount, Rect rect, double radiusX, double radiusY) + /// + /// Initializes the point list specified by . The pointer must be pinned. + /// + private unsafe static void InitializePointList(Point* points, int pointsCount, Rect rect, double radiusX, double radiusY) { if (IsRounded(radiusX, radiusY)) { // It is a rounded rectangle - Invariant.Assert(pointsCount >= RoundedPointCount); + Invariant.Assert((uint)pointsCount >= RoundedPointCount); radiusX = Math.Min(rect.Width * (1.0 / 2.0), Math.Abs(radiusX)); radiusY = Math.Min(rect.Height * (1.0 / 2.0), Math.Abs(radiusY)); @@ -476,7 +472,7 @@ private unsafe static void GetPointList(Point * points, uint pointsCount, Rect r else { // The rectangle is not rounded - Invariant.Assert(pointsCount >= SquaredPointCount); + Invariant.Assert((uint)pointsCount >= SquaredPointCount); points[0].X = points[3].X = points[4].X = rect.X; points[1].X = points[2].X = rect.Right; From 50451ca3716f996c22e5b1dd6696b63c3951bf96 Mon Sep 17 00:00:00 2001 From: h3xds1nz Date: Mon, 21 Oct 2024 23:21:58 +0200 Subject: [PATCH 09/13] Remove redundant usings in RectangleGeometry --- .../System/Windows/Media/RectangleGeometry.cs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs index c24ab01d545..d2e18110158 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs @@ -2,25 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -// - -using System; using MS.Internal; -using System.ComponentModel.Design.Serialization; -using System.Reflection; -using System.Collections; -using System.Text; -using System.Globalization; -using System.Windows.Media; using System.Windows.Media.Composition; -using System.Windows; -using System.Text.RegularExpressions; -using System.Windows.Media.Animation; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Security; - -using SR=MS.Internal.PresentationCore.SR; namespace System.Windows.Media { From 1aa52d315164eb5afa514c1da0820f886c9972a6 Mon Sep 17 00:00:00 2001 From: h3xds1nz Date: Mon, 21 Oct 2024 23:31:46 +0200 Subject: [PATCH 10/13] Simplify code, inline vars, use pattern matching --- .../System/Windows/Media/EllipseGeometry.cs | 18 ++- .../System/Windows/Media/RectangleGeometry.cs | 137 ++++++------------ 2 files changed, 54 insertions(+), 101 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/EllipseGeometry.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/EllipseGeometry.cs index 40a36bf9f1d..0329104e024 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/EllipseGeometry.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/EllipseGeometry.cs @@ -120,7 +120,7 @@ internal override Rect GetBoundsInternal(Pen pen, Matrix matrix, double toleranc internal static unsafe Rect GetBoundsHelper(Pen pen, Matrix worldMatrix, Point center, double radiusX, double radiusY, Matrix geometryMatrix, double tolerance, ToleranceType type) { - if ((pen == null || pen.DoesNotContainGaps) && worldMatrix.IsIdentity && geometryMatrix.IsIdentity) + if ((pen is null || pen.DoesNotContainGaps) && worldMatrix.IsIdentity && geometryMatrix.IsIdentity) { double strokeThickness = Pen.ContributesToBounds(pen) ? Math.Abs(pen.Thickness) : 0.0; @@ -129,14 +129,16 @@ internal static unsafe Rect GetBoundsHelper(Pen pen, Matrix worldMatrix, Point c 2.0 * Math.Abs(radiusX) + strokeThickness, 2.0 * Math.Abs(radiusY) + strokeThickness); } - - Point* ptrPoints = stackalloc Point[(int)PointCount]; - EllipseGeometry.InitializePointList(ptrPoints, (int)PointCount, center, radiusX, radiusY); - - fixed (byte* ptrTypes = RoundedPathTypes) // Merely retrieves the pointer to static PE data, no actual pinning occurs + else { - return Geometry.GetBoundsHelper(pen, &worldMatrix, ptrPoints, ptrTypes, PointCount, SegmentCount, &geometryMatrix, - tolerance, type, false); // skip hollows - meaningless here, this is never a hollow + Point* ptrPoints = stackalloc Point[(int)PointCount]; + EllipseGeometry.InitializePointList(ptrPoints, (int)PointCount, center, radiusX, radiusY); + + fixed (byte* ptrTypes = RoundedPathTypes) // Merely retrieves the pointer to static PE data, no actual pinning occurs + { + return Geometry.GetBoundsHelper(pen, &worldMatrix, ptrPoints, ptrTypes, PointCount, SegmentCount, &geometryMatrix, + tolerance, type, false); // skip hollows - meaningless here, this is never a hollow + } } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs index d2e18110158..ab9c5a2d456 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs @@ -17,9 +17,7 @@ public sealed partial class RectangleGeometry : Geometry /// /// /// - public RectangleGeometry() - { - } + public RectangleGeometry() { } /// /// Constructor - sets the rounded rectangle to equal the passed in parameters @@ -32,9 +30,7 @@ public RectangleGeometry(Rect rect) /// /// Constructor - sets the rounded rectangle to equal the passed in parameters /// - public RectangleGeometry(Rect rect, - double radiusX, - double radiusY) : this(rect) + public RectangleGeometry(Rect rect, double radiusX, double radiusY) : this(rect) { RadiusX = radiusX; RadiusY = radiusY; @@ -47,11 +43,7 @@ public RectangleGeometry(Rect rect, /// /// /// - public RectangleGeometry( - Rect rect, - double radiusX, - double radiusY, - Transform transform) : this(rect, radiusX, radiusY) + public RectangleGeometry(Rect rect, double radiusX, double radiusY, Transform transform) : this(rect, radiusX, radiusY) { Transform = transform; } @@ -101,9 +93,7 @@ public override Rect Bounds // it's easier to let unmanaged code do the work for us. // - Matrix geometryMatrix; - - Transform.GetTransformValue(transform, out geometryMatrix); + Transform.GetTransformValue(transform, out Matrix geometryMatrix); boundsRect = RectangleGeometry.GetBoundsHelper( null /* no pen */, @@ -123,24 +113,20 @@ public override Rect Bounds internal override bool AreClose(Geometry geometry) { - RectangleGeometry rectGeometry2 = geometry as RectangleGeometry; - - if (rectGeometry2 != null) + if (geometry is RectangleGeometry rectGeometry2) { RectangleGeometry rectGeometry1 = this; Rect rect1 = rectGeometry1.Rect; Rect rect2 = rectGeometry2.Rect; - - return ( - DoubleUtil.AreClose(rect1.X, rect2.X) && - DoubleUtil.AreClose(rect1.Y, rect2.Y) && - DoubleUtil.AreClose(rect1.Width, rect2.Width) && - DoubleUtil.AreClose(rect1.Height, rect2.Height) && - DoubleUtil.AreClose(rectGeometry1.RadiusX, rectGeometry2.RadiusX) && - DoubleUtil.AreClose(rectGeometry1.RadiusY, rectGeometry2.RadiusY) && - (rectGeometry1.Transform == rectGeometry2.Transform) && - (rectGeometry1.IsFrozen == rectGeometry2.IsFrozen) - ); + + return DoubleUtil.AreClose(rect1.X, rect2.X) && + DoubleUtil.AreClose(rect1.Y, rect2.Y) && + DoubleUtil.AreClose(rect1.Width, rect2.Width) && + DoubleUtil.AreClose(rect1.Height, rect2.Height) && + DoubleUtil.AreClose(rectGeometry1.RadiusX, rectGeometry2.RadiusX) && + DoubleUtil.AreClose(rectGeometry1.RadiusY, rectGeometry2.RadiusY) && + (rectGeometry1.Transform == rectGeometry2.Transform) && + (rectGeometry1.IsFrozen == rectGeometry2.IsFrozen); } return base.AreClose(geometry); @@ -152,77 +138,51 @@ internal override bool AreClose(Geometry geometry) /// internal override Rect GetBoundsInternal(Pen pen, Matrix worldMatrix, double tolerance, ToleranceType type) { - Matrix geometryMatrix; - - Transform.GetTransformValue(Transform, out geometryMatrix); - - return RectangleGeometry.GetBoundsHelper( - pen, - worldMatrix, - Rect, - RadiusX, - RadiusY, - geometryMatrix, - tolerance, - type); + Transform.GetTransformValue(Transform, out Matrix geometryMatrix); + + return RectangleGeometry.GetBoundsHelper(pen, worldMatrix, Rect, RadiusX, RadiusY, geometryMatrix, tolerance, type); } - internal static Rect GetBoundsHelper(Pen pen, Matrix worldMatrix, Rect rect, double radiusX, double radiusY, + internal static unsafe Rect GetBoundsHelper(Pen pen, Matrix worldMatrix, Rect rect, double radiusX, double radiusY, Matrix geometryMatrix, double tolerance, ToleranceType type) { - Rect boundingRect; - if (rect.IsEmpty) - { - boundingRect = Rect.Empty; - } - else if ( (pen == null || pen.DoesNotContainGaps) && - geometryMatrix.IsIdentity && worldMatrix.IsIdentity) + return Rect.Empty; + + if ((pen is null || pen.DoesNotContainGaps) && geometryMatrix.IsIdentity && worldMatrix.IsIdentity) { double strokeThickness = 0.0; - boundingRect = rect; + Rect boundingRect = rect; if (Pen.ContributesToBounds(pen)) { strokeThickness = Math.Abs(pen.Thickness); - boundingRect.X -= 0.5*strokeThickness; - boundingRect.Y -= 0.5*strokeThickness; + boundingRect.X -= 0.5 * strokeThickness; + boundingRect.Y -= 0.5 * strokeThickness; boundingRect.Width += strokeThickness; boundingRect.Height += strokeThickness; } + + return boundingRect; } else { - unsafe - { - GetCounts(rect, radiusX, radiusY, out uint pointCount, out uint segmentCount); + GetCounts(rect, radiusX, radiusY, out uint pointCount, out uint segmentCount); - // We've checked that rect isn't empty above - Invariant.Assert(pointCount != 0); + // We've checked that rect isn't empty above + Invariant.Assert(pointCount != 0); - Point* pPoints = stackalloc Point[(int)pointCount]; - RectangleGeometry.InitializePointList(pPoints, (int)pointCount, rect, radiusX, radiusY); + Point* ptrPoints = stackalloc Point[(int)pointCount]; + RectangleGeometry.InitializePointList(ptrPoints, (int)pointCount, rect, radiusX, radiusY); - fixed (byte* pTypes = GetTypeList(rect, radiusX, radiusY)) // Merely retrieves the pointer to static PE data, no actual pinning occurs - { - boundingRect = Geometry.GetBoundsHelper( - pen, - &worldMatrix, - pPoints, - pTypes, - pointCount, - segmentCount, - &geometryMatrix, - tolerance, - type, - false); // skip hollows - meaningless here, this is never a hollow - } + fixed (byte* ptrTypes = GetTypeList(rect, radiusX, radiusY)) // Merely retrieves the pointer to static PE data, no actual pinning occurs + { + return Geometry.GetBoundsHelper(pen, &worldMatrix, ptrPoints, ptrTypes, pointCount, segmentCount, + &geometryMatrix, tolerance, type, false); // skip hollows - meaningless here, this is never a hollow } } - - return boundingRect; } internal override bool ContainsInternal(Pen pen, Point hitPoint, double tolerance, ToleranceType type) @@ -241,20 +201,12 @@ internal override bool ContainsInternal(Pen pen, Point hitPoint, double toleranc unsafe { - Point* pPoints = stackalloc Point[(int)pointCount]; - RectangleGeometry.InitializePointList(pPoints, (int)pointCount, rect, radiusX, radiusY); + Point* ptrPoints = stackalloc Point[(int)pointCount]; + RectangleGeometry.InitializePointList(ptrPoints, (int)pointCount, rect, radiusX, radiusY); - fixed (byte* pTypes = GetTypeList(rect, radiusX, radiusY)) // Merely retrieves the pointer to static PE data, no actual pinning occurs + fixed (byte* ptrTypes = GetTypeList(rect, radiusX, radiusY)) // Merely retrieves the pointer to static PE data, no actual pinning occurs { - return ContainsInternal( - pen, - hitPoint, - tolerance, - type, - pPoints, - pointCount, - pTypes, - segmentCount); + return ContainsInternal(pen, hitPoint, tolerance, type, ptrPoints, pointCount, ptrTypes, segmentCount); } } } @@ -329,7 +281,7 @@ internal override PathFigureCollection GetTransformedFigureCollection(Transform new BezierSegment(points[9], points[10], points[11], true, true), new LineSegment(points[12], true, true), new BezierSegment(points[13], points[14], points[15], true, true)], - closed: true) }; // closed + closed: true) }; } else { @@ -346,8 +298,7 @@ internal static bool IsRounded(double radiusX, double radiusY) internal bool IsRounded() { - return RadiusX != 0.0 - && RadiusY != 0.0; + return RadiusX != 0.0 && RadiusY != 0.0; } /// @@ -355,7 +306,7 @@ internal bool IsRounded() /// internal override PathGeometry GetAsPathGeometry() { - PathStreamGeometryContext ctx = new PathStreamGeometryContext(FillRule.EvenOdd, Transform); + PathStreamGeometryContext ctx = new(FillRule.EvenOdd, Transform); PathGeometry.ParsePathGeometryData(GetPathGeometryData(), ctx); return ctx.GetPathGeometry(); @@ -378,7 +329,7 @@ internal override PathGeometryData GetPathGeometryData() double radiusY = RadiusY; Rect rect = Rect; - ByteStreamGeometryContext ctx = new ByteStreamGeometryContext(); + ByteStreamGeometryContext ctx = new(); if (IsRounded(radiusX, radiusY)) { @@ -412,7 +363,7 @@ internal override PathGeometryData GetPathGeometryData() /// /// Initializes the point list into . Optionally pins the source if not stack-allocated. /// - private unsafe void InitializePointList(Span destination, ref readonly Rect rect, double radiusX, double radiusY) + private unsafe void InitializePointList(Span destination, Rect rect, double radiusX, double radiusY) { fixed (Point* ptrPoints = destination) // In case this is stackallocated, it's a no-op { From 77dadd4b7baad1042d2245d82eee0d89475e7eee Mon Sep 17 00:00:00 2001 From: h3xds1nz Date: Mon, 21 Oct 2024 23:36:09 +0200 Subject: [PATCH 11/13] Use constants in LineGeometry --- .../System/Windows/Media/LineGeometry.cs | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/LineGeometry.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/LineGeometry.cs index c6bcfe44456..59f7be05458 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/LineGeometry.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/LineGeometry.cs @@ -114,19 +114,19 @@ internal static Rect GetBoundsHelper(Pen pen, Matrix worldMatrix, Point pt1, Poi { unsafe { - Point* pPoints = stackalloc Point[2]; + Point* pPoints = stackalloc Point[(int)PointCount]; pPoints[0] = pt1; pPoints[1] = pt2; - fixed (byte* pTypes = LineTypes) //Merely retrieves the pointer to static PE data, no actual pinning occurs + fixed (byte* pTypes = LineTypes) // Merely retrieves the pointer to static PE data, no actual pinning occurs { return Geometry.GetBoundsHelper( pen, &worldMatrix, pPoints, - pTypes, - c_pointCount, - c_segmentCount, + pTypes, + PointCount, + SegmentCount, &geometryMatrix, tolerance, type, @@ -140,11 +140,11 @@ internal override bool ContainsInternal(Pen pen, Point hitPoint, double toleranc { unsafe { - Point* pPoints = stackalloc Point[2]; + Point* pPoints = stackalloc Point[(int)PointCount]; pPoints[0] = StartPoint; pPoints[1] = EndPoint; - fixed (byte* pTypes = LineTypes) //Merely retrieves the pointer to static PE data, no actual pinning occurs + fixed (byte* pTypes = LineTypes) // Merely retrieves the pointer to static PE data, no actual pinning occurs { return ContainsInternal( pen, @@ -152,9 +152,9 @@ internal override bool ContainsInternal(Pen pen, Point hitPoint, double toleranc tolerance, type, pPoints, - GetPointCount(), + PointCount, pTypes, - GetSegmentCount()); + SegmentCount); } } } @@ -185,12 +185,6 @@ public override double GetArea(double tolerance, ToleranceType type) return 0.0; } - private static ReadOnlySpan LineTypes => [(byte)MILCoreSegFlags.SegTypeLine]; - - private static uint GetPointCount() { return c_pointCount; } - - private static uint GetSegmentCount() { return c_segmentCount; } - /// /// GetAsPathGeometry - return a PathGeometry version of this Geometry /// @@ -261,8 +255,10 @@ internal override PathGeometryData GetPathGeometryData() #region Static Data - private const UInt32 c_segmentCount = 1; - private const UInt32 c_pointCount = 2; + private const uint SegmentCount = 1; + private const uint PointCount = 2; + + private static ReadOnlySpan LineTypes => [(byte)MILCoreSegFlags.SegTypeLine]; #endregion } From 13d2fad721f74723b2c3689a7c3e857ac4e13125 Mon Sep 17 00:00:00 2001 From: h3xds1nz Date: Mon, 21 Oct 2024 23:36:44 +0200 Subject: [PATCH 12/13] Remove redundant usings in LineGeometry --- .../System/Windows/Media/LineGeometry.cs | 23 ++----------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/LineGeometry.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/LineGeometry.cs index 59f7be05458..747b0a19231 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/LineGeometry.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/LineGeometry.cs @@ -1,27 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -// - -using System; -using MS.Internal; -using System.ComponentModel; -using System.ComponentModel.Design.Serialization; -using System.Reflection; -using System.Collections; -using System.Text; -using System.Globalization; -using System.Windows.Media; -using System.Windows; -using System.Text.RegularExpressions; -using System.Windows.Media.Animation; -using System.Windows.Media.Composition; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Security; +// See the LICENSE file in the project root for more information. -using SR=MS.Internal.PresentationCore.SR; +using System.Windows.Media.Composition; namespace System.Windows.Media { From f63ec0bb18e4d73af59d09ae913ef049695d24a8 Mon Sep 17 00:00:00 2001 From: h3xds1nz Date: Mon, 21 Oct 2024 23:41:07 +0200 Subject: [PATCH 13/13] Simplify code in LineGeometry, inline vars --- .../System/Windows/Media/LineGeometry.cs | 89 +++++-------------- 1 file changed, 24 insertions(+), 65 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/LineGeometry.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/LineGeometry.cs index 747b0a19231..502511cfc6d 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/LineGeometry.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/LineGeometry.cs @@ -16,9 +16,7 @@ public sealed partial class LineGeometry : Geometry /// /// /// - public LineGeometry() - { - } + public LineGeometry() { } /// /// @@ -32,10 +30,7 @@ public LineGeometry(Point startPoint, Point endPoint) /// /// /// - public LineGeometry( - Point startPoint, - Point endPoint, - Transform transform) : this(startPoint, endPoint) + public LineGeometry(Point startPoint, Point endPoint, Transform transform) : this(startPoint, endPoint) { Transform = transform; } @@ -70,50 +65,25 @@ public override Rect Bounds /// internal override Rect GetBoundsInternal(Pen pen, Matrix worldMatrix, double tolerance, ToleranceType type) { - Matrix geometryMatrix; - - Transform.GetTransformValue(Transform, out geometryMatrix); - - return LineGeometry.GetBoundsHelper( - pen, - worldMatrix, - StartPoint, - EndPoint, - geometryMatrix, - tolerance, - type); + Transform.GetTransformValue(Transform, out Matrix geometryMatrix); + + return LineGeometry.GetBoundsHelper(pen, worldMatrix, StartPoint, EndPoint, geometryMatrix, tolerance, type); } - internal static Rect GetBoundsHelper(Pen pen, Matrix worldMatrix, Point pt1, Point pt2, - Matrix geometryMatrix, double tolerance, ToleranceType type) + internal static unsafe Rect GetBoundsHelper(Pen pen, Matrix worldMatrix, Point pt1, Point pt2, + Matrix geometryMatrix, double tolerance, ToleranceType type) { - if (pen == null && worldMatrix.IsIdentity && geometryMatrix.IsIdentity) - { + if (pen is null && worldMatrix.IsIdentity && geometryMatrix.IsIdentity) return new Rect(pt1, pt2); - } - else + + Point* ptrPoints = stackalloc Point[(int)PointCount]; + ptrPoints[0] = pt1; + ptrPoints[1] = pt2; + + fixed (byte* ptrTypes = LineTypes) // Merely retrieves the pointer to static PE data, no actual pinning occurs { - unsafe - { - Point* pPoints = stackalloc Point[(int)PointCount]; - pPoints[0] = pt1; - pPoints[1] = pt2; - - fixed (byte* pTypes = LineTypes) // Merely retrieves the pointer to static PE data, no actual pinning occurs - { - return Geometry.GetBoundsHelper( - pen, - &worldMatrix, - pPoints, - pTypes, - PointCount, - SegmentCount, - &geometryMatrix, - tolerance, - type, - false); // skip hollows - meaningless here, this is never a hollow - } - } + return Geometry.GetBoundsHelper(pen, &worldMatrix, ptrPoints, ptrTypes, PointCount, SegmentCount, + &geometryMatrix, tolerance, type, false); // skip hollows - meaningless here, this is never a hollow } } @@ -121,21 +91,13 @@ internal override bool ContainsInternal(Pen pen, Point hitPoint, double toleranc { unsafe { - Point* pPoints = stackalloc Point[(int)PointCount]; - pPoints[0] = StartPoint; - pPoints[1] = EndPoint; + Point* ptrPoints = stackalloc Point[(int)PointCount]; + ptrPoints[0] = StartPoint; + ptrPoints[1] = EndPoint; - fixed (byte* pTypes = LineTypes) // Merely retrieves the pointer to static PE data, no actual pinning occurs + fixed (byte* ptrTypes = LineTypes) // Merely retrieves the pointer to static PE data, no actual pinning occurs { - return ContainsInternal( - pen, - hitPoint, - tolerance, - type, - pPoints, - PointCount, - pTypes, - SegmentCount); + return ContainsInternal(pen, hitPoint, tolerance, type, ptrPoints, PointCount, ptrTypes, SegmentCount); } } } @@ -171,7 +133,7 @@ public override double GetArea(double tolerance, ToleranceType type) /// internal override PathGeometry GetAsPathGeometry() { - PathStreamGeometryContext ctx = new PathStreamGeometryContext(FillRule.EvenOdd, Transform); + PathStreamGeometryContext ctx = new(FillRule.EvenOdd, Transform); PathGeometry.ParsePathGeometryData(GetPathGeometryData(), ctx); return ctx.GetPathGeometry(); @@ -219,12 +181,9 @@ internal override PathGeometryData GetPathGeometryData() return Geometry.GetEmptyPathGeometryData(); } - PathGeometryData data = new PathGeometryData(); - data.FillRule = FillRule.EvenOdd; - data.Matrix = CompositionResourceManager.TransformToMilMatrix3x2D(Transform); - - ByteStreamGeometryContext ctx = new ByteStreamGeometryContext(); + PathGeometryData data = new() { FillRule = FillRule.EvenOdd, Matrix = CompositionResourceManager.TransformToMilMatrix3x2D(Transform) }; + ByteStreamGeometryContext ctx = new(); ctx.BeginFigure(StartPoint, true /* is filled */, false /* is closed */); ctx.LineTo(EndPoint, true /* is stroked */, false /* is smooth join */);