diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/PresentationCore.csproj b/src/Microsoft.DotNet.Wpf/src/PresentationCore/PresentationCore.csproj index 5b9fe95541a..3b8b307afa9 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/PresentationCore.csproj +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/PresentationCore.csproj @@ -747,6 +747,7 @@ + diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/DoubleCollection.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/DoubleCollection.cs new file mode 100644 index 00000000000..f4a965d79e8 --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/DoubleCollection.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using MS.Utility; + +namespace System.Windows.Media; + +public sealed partial class DoubleCollection +{ + /// + /// Initializes a new instance using a . Elements are copied. + /// + /// + internal DoubleCollection(params ReadOnlySpan values) + { + _collection = new FrugalStructList(values.Length); + + foreach (double item in values) + { + _collection.Add(item); + } + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/DrawingDrawingContext.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/DrawingDrawingContext.cs index 83bf679df99..b7e0da92bb7 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/DrawingDrawingContext.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/DrawingDrawingContext.cs @@ -931,11 +931,10 @@ internal override void PushGuidelineY1( // Convert compact record to generic GuidelineSet. // - GuidelineSet guidelineCollection = new GuidelineSet( - null, // x guidelines - new double[] { coordinate, 0 }, // y guidelines - true // dynamic flag - ); + GuidelineSet guidelineCollection = new(guidelinesX: ReadOnlySpan.Empty, + guidelinesY: [coordinate, 0], + isDynamic: true); + guidelineCollection.Freeze(); // @@ -977,15 +976,9 @@ internal override void PushGuidelineY2( // Convert compact record to generic GuidelineSet. // - GuidelineSet guidelineCollection = new GuidelineSet( - null, // x guidelines - new double[] - { - leadingCoordinate, - offsetToDrivenCoordinate - }, // y guidelines - true // dynamic flag - ); + GuidelineSet guidelineCollection = new(guidelinesX: ReadOnlySpan.Empty, + guidelinesY: [leadingCoordinate, offsetToDrivenCoordinate], + isDynamic: true); guidelineCollection.Freeze(); // diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/DoubleCollection.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/DoubleCollection.cs index 00ed4afa61d..2acc631ef70 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/DoubleCollection.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/DoubleCollection.cs @@ -13,8 +13,6 @@ using System.Windows.Markup; using System.Windows.Media.Converters; -// These types are aliased to match the unamanaged names used in interop - namespace System.Windows.Media { /// @@ -878,7 +876,6 @@ public double Current // //------------------------------------------------------ - /// /// Initializes a new instance that is empty. /// @@ -934,12 +931,6 @@ public DoubleCollection(IEnumerable collection) } } - - - - - - WritePostscript(); } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/GuidelineCollection.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/GuidelineCollection.cs index 31b407ac04b..8c4bc6d425e 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/GuidelineCollection.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/GuidelineCollection.cs @@ -40,21 +40,42 @@ public GuidelineSet() /// Array of X coordinates that defines a set of vertical guidelines. /// Array of Y coordinates that defines a set of horizontal guidelines. /// Usage flag: when true then rendering machine will detect animation state and apply subpixel animation behavior. - internal GuidelineSet(double[] guidelinesX, double[] guidelinesY, bool isDynamic) + internal GuidelineSet(ReadOnlySpan guidelinesX, ReadOnlySpan guidelinesY) { - if (guidelinesX != null) + if (!guidelinesX.IsEmpty) { - // Dynamic guideline is defined by a pair of numbers: (coordinate, shift), - // so the legnth of array should be even. + GuidelinesX = new DoubleCollection(guidelinesX); + } + + if (!guidelinesY.IsEmpty) + { + GuidelinesY = new DoubleCollection(guidelinesY); + } + } + + /// + /// Constructs a new GuidelineSet object. + /// This constructor is internal for now, till we'll find a solution + /// for multi-path dynamic guideline implementation. If/when it'll happen, + /// it should become "public" so that the next constructor (without "isDynamic' + /// argument) may go away. + /// + /// Array of X coordinates that defines a set of vertical guidelines. + /// Array of Y coordinates that defines a set of horizontal guidelines. + /// Usage flag: when true then rendering machine will detect animation state and apply subpixel animation behavior. + internal GuidelineSet(ReadOnlySpan guidelinesX, ReadOnlySpan guidelinesY, bool isDynamic) + { + if (!guidelinesX.IsEmpty) + { + // Dynamic guideline is defined by a pair of numbers: (coordinate, shift), so the length of array should be even. Debug.Assert(!isDynamic || guidelinesX.Length % 2 == 0); GuidelinesX = new DoubleCollection(guidelinesX); } - if (guidelinesY != null) + if (!guidelinesY.IsEmpty) { - // Dynamic guideline is defined by a pair of numbers: (coordinate, shift), - // so the legnth of array should be even. + // Dynamic guideline is defined by a pair of numbers: (coordinate, shift), so the length of array should be even. Debug.Assert(!isDynamic || guidelinesY.Length % 2 == 0); GuidelinesY = new DoubleCollection(guidelinesY); @@ -70,14 +91,14 @@ internal GuidelineSet(double[] guidelinesX, double[] guidelinesY, bool isDynamic /// Array of Y coordinates that defines a set of horizontal guidelines. public GuidelineSet(double[] guidelinesX, double[] guidelinesY) { - if (guidelinesX != null) + if (guidelinesX is not null) { - GuidelinesX = new DoubleCollection(guidelinesX); + GuidelinesX = new DoubleCollection(guidelinesX.AsSpan()); } - if (guidelinesY != null) + if (guidelinesY is not null) { - GuidelinesY = new DoubleCollection(guidelinesY); + GuidelinesY = new DoubleCollection(guidelinesY.AsSpan()); } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/UIElement.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/UIElement.cs index 196a9614f6f..8107256468a 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/UIElement.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/UIElement.cs @@ -979,14 +979,13 @@ private void updatePixelSnappingGuidelines() } else { - DoubleCollection xLines = this.VisualXSnappingGuidelines; + DoubleCollection xLines = VisualXSnappingGuidelines; - if(xLines == null) + if (xLines is null) { - xLines = new DoubleCollection(); - xLines.Add(0d); - xLines.Add(this.RenderSize.Width); - this.VisualXSnappingGuidelines = xLines; + xLines = new DoubleCollection(0d, RenderSize.Width); + + VisualXSnappingGuidelines = xLines; } else { @@ -997,13 +996,12 @@ private void updatePixelSnappingGuidelines() xLines[lastGuideline] = this.RenderSize.Width; } - DoubleCollection yLines = this.VisualYSnappingGuidelines; - if(yLines == null) + DoubleCollection yLines = VisualYSnappingGuidelines; + if (yLines is null) { - yLines = new DoubleCollection(); - yLines.Add(0d); - yLines.Add(this.RenderSize.Height); - this.VisualYSnappingGuidelines = yLines; + yLines = new DoubleCollection(0d, RenderSize.Height); + + VisualYSnappingGuidelines = yLines; } else { diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Controls/InkCanvasFeedbackAdorner.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Controls/InkCanvasFeedbackAdorner.cs index a0f118b5c72..9f68328bdc1 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Controls/InkCanvasFeedbackAdorner.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Controls/InkCanvasFeedbackAdorner.cs @@ -34,12 +34,12 @@ internal InkCanvasFeedbackAdorner(InkCanvas inkCanvas) // Initialize the internal data _inkCanvas = inkCanvas; - _adornerBorderPen = new Pen(Brushes.Black, 1.0); - DoubleCollection dashes = new DoubleCollection(); - dashes.Add(4.5); - dashes.Add(4.5); - _adornerBorderPen.DashStyle = new DashStyle(dashes, 2.25); - _adornerBorderPen.DashCap = PenLineCap.Flat; + _adornerBorderPen = new Pen(Brushes.Black, 1.0) + { + DashStyle = new DashStyle(new DoubleCollection(4.5, 4.5), 2.25), + DashCap = PenLineCap.Flat + }; + _adornerBorderPen.Freeze(); } /// @@ -167,7 +167,7 @@ internal void UpdateBounds(Rect rect) private double _offsetX = 0; private double _offsetY = 0; - private Pen _adornerBorderPen; + private readonly Pen _adornerBorderPen; private const int CornerResizeHandleSize = 8; private const double BorderMargin = 8f; diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Controls/InkCanvasSelectionAdorner.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Controls/InkCanvasSelectionAdorner.cs index 7cf65defd42..6a81ac31c82 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Controls/InkCanvasSelectionAdorner.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Controls/InkCanvasSelectionAdorner.cs @@ -30,12 +30,11 @@ internal InkCanvasSelectionAdorner(UIElement adornedElement) "InkCanvasSelectionAdorner only should be used by InkCanvas internally"); // Initialize the internal data. - _adornerBorderPen = new Pen(Brushes.Black, 1.0); - DoubleCollection dashes = new DoubleCollection(); - dashes.Add(4.5); - dashes.Add(4.5); - _adornerBorderPen.DashStyle = new DashStyle(dashes, 2.25); - _adornerBorderPen.DashCap = PenLineCap.Flat; + _adornerBorderPen = new Pen(Brushes.Black, 1.0) + { + DashStyle = new DashStyle(new DoubleCollection(4.5, 4.5), 2.25), + DashCap = PenLineCap.Flat + }; _adornerBorderPen.Freeze(); _adornerPenBrush = new Pen(new SolidColorBrush(Color.FromRgb(132, 146, 222)), 1); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/Grid.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/Grid.cs index 094eb22b5b7..cdcb876f708 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/Grid.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/Grid.cs @@ -3963,20 +3963,20 @@ internal class GridLinesRenderer : DrawingVisual /// static GridLinesRenderer() { - s_oddDashPen = new Pen(Brushes.Blue, c_penWidth); - DoubleCollection oddDashArray = new DoubleCollection(); - oddDashArray.Add(c_dashLength); - oddDashArray.Add(c_dashLength); - s_oddDashPen.DashStyle = new DashStyle(oddDashArray, 0); - s_oddDashPen.DashCap = PenLineCap.Flat; + DoubleCollection dashArray = new DoubleCollection(DashLength, DashLength); + + s_oddDashPen = new Pen(Brushes.Blue, PenWidth) + { + DashStyle = new DashStyle(dashArray, 0), + DashCap = PenLineCap.Flat + }; s_oddDashPen.Freeze(); - s_evenDashPen = new Pen(Brushes.Yellow, c_penWidth); - DoubleCollection evenDashArray = new DoubleCollection(); - evenDashArray.Add(c_dashLength); - evenDashArray.Add(c_dashLength); - s_evenDashPen.DashStyle = new DashStyle(evenDashArray, c_dashLength); - s_evenDashPen.DashCap = PenLineCap.Flat; + s_evenDashPen = new Pen(Brushes.Yellow, PenWidth) + { + DashStyle = new DashStyle(dashArray, DashLength), + DashCap = PenLineCap.Flat + }; s_evenDashPen.Freeze(); } @@ -4029,11 +4029,10 @@ private static void DrawGridLine( drawingContext.DrawLine(s_evenDashPen, start, end); } - private const double c_dashLength = 4.0; // - private const double c_penWidth = 1.0; // + private const double DashLength = 4.0; // + private const double PenWidth = 1.0; // private static readonly Pen s_oddDashPen; // first pen to draw dash private static readonly Pen s_evenDashPen; // second pen to draw dash - private static readonly Point c_zeroPoint = new Point(0, 0); } #endregion Private Structures Classes diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/Primitives/TickBar.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/Primitives/TickBar.cs index 59c50dd102d..96571b630d4 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/Primitives/TickBar.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/Primitives/TickBar.cs @@ -430,11 +430,11 @@ protected override void OnRender(DrawingContext dc) Pen pen = new Pen(Fill, 1.0d); bool snapsToDevicePixels = SnapsToDevicePixels; - DoubleCollection xLines = snapsToDevicePixels ? new DoubleCollection() : null; - DoubleCollection yLines = snapsToDevicePixels ? new DoubleCollection() : null; + DoubleCollection xLines = snapsToDevicePixels ? new DoubleCollection(4) : null; + DoubleCollection yLines = snapsToDevicePixels ? new DoubleCollection(6) : null; // Is it Vertical? - if ((Placement == TickBarPlacement.Left) || (Placement == TickBarPlacement.Right)) + if (Placement is TickBarPlacement.Left or TickBarPlacement.Right) { // Reduce tick interval if it is more than would be visible on the screen double interval = TickFrequency; diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/CaretElement.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/CaretElement.cs index dda1e5c2cbb..bb2eaeed5e9 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/CaretElement.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/CaretElement.cs @@ -683,7 +683,9 @@ internal void OnRenderCaretSubElement(DrawingContext context) // Snap the caret to device pixels. if (!_italic || threadLocalStore.Bidi) { - GuidelineSet guidelineSet = new GuidelineSet(new double[] { -(_systemCaretWidth / 2), _systemCaretWidth / 2 }, null); + GuidelineSet guidelineSet = new(guidelinesX: [-(_systemCaretWidth / 2), _systemCaretWidth / 2], + guidelinesY: ReadOnlySpan.Empty); + context.PushGuidelineSet(guidelineSet); contextPushedCount++; } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/CompositionAdorner.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/CompositionAdorner.cs index d6377ca7507..8331e525e80 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/CompositionAdorner.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/CompositionAdorner.cs @@ -146,8 +146,6 @@ protected override void OnRender(DrawingContext drawingContext) // Render the each of the composition string attribute from the attribute ranges. for (int i = 0; i < _attributeRanges.Count; i++) { - DoubleCollection dashArray; - // Get the composition attribute range from the attribute range lists AttributeRange attributeRange = (AttributeRange)_attributeRanges[i]; @@ -186,14 +184,10 @@ protected override void OnRender(DrawingContext drawingContext) { case UnsafeNativeMethods.TF_DA_LINESTYLE.TF_LS_DOT: // Add the dot length and specify the start/end line cap as the round - dashArray = new DoubleCollection(); - dashArray.Add(DotLength); - dashArray.Add(DotLength); - - pen.DashStyle = new DashStyle(dashArray, 0); - pen.DashCap = System.Windows.Media.PenLineCap.Round; - pen.StartLineCap = System.Windows.Media.PenLineCap.Round; - pen.EndLineCap = System.Windows.Media.PenLineCap.Round; + pen.DashStyle = new DashStyle(new DoubleCollection(DotLength, DotLength), 0); + pen.DashCap = PenLineCap.Round; + pen.StartLineCap = PenLineCap.Round; + pen.EndLineCap = PenLineCap.Round; // Update the line height for the dot line. Dot line will be more thickness than // other line to show it clearly. @@ -205,21 +199,17 @@ protected override void OnRender(DrawingContext drawingContext) double dashLength = height * (lineBold ? BoldDashRatio : NormalDashRatio); double dashGapLength = height * (lineBold ? BoldDashGapRatio : NormalDashGapRatio); - // Add the dash and dash gap legth - dashArray = new DoubleCollection(); - dashArray.Add(dashLength); - dashArray.Add(dashGapLength); - - pen.DashStyle = new DashStyle(dashArray, 0); - pen.DashCap = System.Windows.Media.PenLineCap.Round; - pen.StartLineCap = System.Windows.Media.PenLineCap.Round; - pen.EndLineCap = System.Windows.Media.PenLineCap.Round; + // Add the dash and dash gap length + pen.DashStyle = new DashStyle(new DoubleCollection(dashLength, dashGapLength), 0); + pen.DashCap = PenLineCap.Round; + pen.StartLineCap = PenLineCap.Round; + pen.EndLineCap = PenLineCap.Round; break; case UnsafeNativeMethods.TF_DA_LINESTYLE.TF_LS_SOLID: - pen.StartLineCap = System.Windows.Media.PenLineCap.Round; - pen.EndLineCap = System.Windows.Media.PenLineCap.Round; + pen.StartLineCap = PenLineCap.Round; + pen.EndLineCap = PenLineCap.Round; break; diff --git a/src/Microsoft.DotNet.Wpf/src/ReachFramework/AlphaFlattener/Primitive.cs b/src/Microsoft.DotNet.Wpf/src/ReachFramework/AlphaFlattener/Primitive.cs index 96676c6073d..9fe25907d40 100644 --- a/src/Microsoft.DotNet.Wpf/src/ReachFramework/AlphaFlattener/Primitive.cs +++ b/src/Microsoft.DotNet.Wpf/src/ReachFramework/AlphaFlattener/Primitive.cs @@ -560,10 +560,10 @@ protected int PushAll(DrawingContext dc) { Rect bounds = GetRectBounds(true); - double[] snapx = new double[] { bounds.Left, bounds.Right }; - double[] snapy = new double[] { bounds.Top, bounds.Bottom }; + ReadOnlySpan snapX = [bounds.Left, bounds.Right]; + ReadOnlySpan snapY = [bounds.Top, bounds.Bottom]; - dc.PushGuidelineSet(new GuidelineSet(snapx, snapy)); + dc.PushGuidelineSet(new GuidelineSet(snapX, snapY)); level++; }