From db05a293b8f435dc665d54c44477b5da4734e55a Mon Sep 17 00:00:00 2001 From: Jeremy Kuhne Date: Thu, 4 Mar 2021 13:46:37 -0800 Subject: [PATCH 01/11] Add basic GetContextInfo regression tests. --- .../Common/tests/System/Drawing/Helpers.cs | 3 + .../tests/Graphics_GetContextTests.cs | 166 ++++++++++++++++++ .../tests/System.Drawing.Common.Tests.csproj | 10 +- 3 files changed, 173 insertions(+), 6 deletions(-) create mode 100644 src/libraries/System.Drawing.Common/tests/Graphics_GetContextTests.cs diff --git a/src/libraries/Common/tests/System/Drawing/Helpers.cs b/src/libraries/Common/tests/System/Drawing/Helpers.cs index 162cf6abcb072..fc68b4e6e124a 100644 --- a/src/libraries/Common/tests/System/Drawing/Helpers.cs +++ b/src/libraries/Common/tests/System/Drawing/Helpers.cs @@ -20,6 +20,7 @@ public static class Helpers public const string GdiPlusIsAvailableNotWindows7 = nameof(Helpers) + "." + nameof(GetGdiPlusIsAvailableNotWindows7); public const string AnyInstalledPrinters = nameof(Helpers) + "." + nameof(IsAnyInstalledPrinters); public const string WindowsRS3OrEarlier = nameof(Helpers) + "." + nameof(IsWindowsRS3OrEarlier); + public const string IsWindows = nameof(Helpers) + "." + nameof(GetIsWindows); public static bool GetIsDrawingSupported() => PlatformDetection.IsDrawingSupported; @@ -53,6 +54,8 @@ public static bool GetIsWindowsOrAtLeastLibgdiplus6() return installedVersion.Major >= 6; } + public static bool GetIsWindows() => PlatformDetection.IsWindows; + public static bool IsNotUnix => PlatformDetection.IsWindows; public static bool IsWindowsRS3OrEarlier => !PlatformDetection.IsWindows10Version1803OrGreater; diff --git a/src/libraries/System.Drawing.Common/tests/Graphics_GetContextTests.cs b/src/libraries/System.Drawing.Common/tests/Graphics_GetContextTests.cs new file mode 100644 index 0000000000000..3eb940d75da69 --- /dev/null +++ b/src/libraries/System.Drawing.Common/tests/Graphics_GetContextTests.cs @@ -0,0 +1,166 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Drawing.Drawing2D; +using Xunit; + +namespace System.Drawing.Tests +{ + public class Graphics_GetContextTests : DrawingTest + { + [ConditionalFact(Helpers.IsWindows)] + public void GetContextInfo_DefaultGraphics() + { + using (var image = new Bitmap(10, 10)) + using (Graphics graphics = Graphics.FromImage(image)) + { + object info = graphics.GetContextInfo(); + Assert.IsType(info); + object[] infoArray = (object[])info; + Assert.Equal(2, infoArray.Length); + Assert.IsType(infoArray[0]); + Assert.IsType(infoArray[1]); + using (Region region = (Region)infoArray[0]) + using (Matrix matrix = (Matrix)infoArray[1]) + { + Assert.True(region.IsInfinite(graphics)); + Assert.True(matrix.IsIdentity); + } + } + } + + [ConditionalFact(Helpers.IsWindows)] + public void GetContextInfo_Clipping() + { + using (var image = new Bitmap(10, 10)) + using (Graphics graphics = Graphics.FromImage(image)) + using (Region initialClip = new Region(new Rectangle(1, 2, 9, 10))) + { + graphics.Clip = initialClip; + + object[] info = (object[])graphics.GetContextInfo(); + using (Region region = (Region)info[0]) + using (Matrix matrix = (Matrix)info[1]) + { + Assert.Equal(initialClip.GetBounds(graphics), region.GetBounds(graphics)); + Assert.True(matrix.IsIdentity); + } + } + } + + [ConditionalFact(Helpers.IsWindows)] + public void GetContextInfo_Transform() + { + using (var image = new Bitmap(10, 10)) + using (Graphics graphics = Graphics.FromImage(image)) + using (Matrix initialTransform = new Matrix()) + { + initialTransform.Translate(1, 2); + graphics.Transform = initialTransform; + + object[] info = (object[])graphics.GetContextInfo(); + using (Region region = (Region)info[0]) + using (Matrix matrix = (Matrix)info[1]) + { + Assert.True(region.IsInfinite(graphics)); + Assert.Equal(initialTransform, matrix); + } + } + } + + [ConditionalFact(Helpers.IsWindows)] + public void GetContextInfo_ClipAndTransform() + { + using (var image = new Bitmap(10, 10)) + using (Graphics graphics = Graphics.FromImage(image)) + using (Matrix initialTransform = new Matrix()) + using (Region initialClip = new Region(new Rectangle(1, 2, 9, 10))) + { + graphics.Clip = initialClip; + initialTransform.Translate(1, 2); + graphics.Transform = initialTransform; + + object[] info = (object[])graphics.GetContextInfo(); + using (Region region = (Region)info[0]) + using (Matrix matrix = (Matrix)info[1]) + { + Assert.Equal(new RectangleF(0, 0, 9, 10), region.GetBounds(graphics)); + Assert.Equal(initialTransform, matrix); + } + } + } + + [ConditionalFact(Helpers.IsWindows)] + public void GetContextInfo_TransformAndClip() + { + using (var image = new Bitmap(10, 10)) + using (Graphics graphics = Graphics.FromImage(image)) + using (Matrix initialTransform = new Matrix()) + using (Region initialClip = new Region(new Rectangle(1, 2, 9, 10))) + { + initialTransform.Translate(1, 2); + graphics.Transform = initialTransform; + graphics.Clip = initialClip; + + object[] info = (object[])graphics.GetContextInfo(); + using (Region region = (Region)info[0]) + using (Matrix matrix = (Matrix)info[1]) + { + Assert.Equal(new RectangleF(1, 2, 9, 10), region.GetBounds(graphics)); + Assert.Equal(initialTransform, matrix); + } + } + } + + [ConditionalFact(Helpers.IsWindows)] + public void GetContextInfo_ClipAndTransformSaveState() + { + using (var image = new Bitmap(10, 10)) + using (Graphics graphics = Graphics.FromImage(image)) + using (Matrix initialTransform = new Matrix()) + using (Region initialClip = new Region(new Rectangle(1, 2, 9, 10))) + { + graphics.Clip = initialClip; + initialTransform.Translate(1, 2); + graphics.Transform = initialTransform; + + GraphicsState state = graphics.Save(); + object[] info = (object[])graphics.GetContextInfo(); + + using (Region region = (Region)info[0]) + using (Matrix matrix = (Matrix)info[1]) + { + initialTransform.Translate(1, 2); + Assert.Equal(new RectangleF(0, 0, 8, 8), region.GetBounds(graphics)); + Assert.Equal(initialTransform, matrix); + } + } + } + + [ConditionalFact(Helpers.IsWindows)] + public void GetContextInfo_ClipAndTransformSaveAndRestoreState() + { + using (var image = new Bitmap(10, 10)) + using (Graphics graphics = Graphics.FromImage(image)) + using (Matrix initialTransform = new Matrix()) + using (Region initialClip = new Region(new Rectangle(1, 2, 9, 10))) + { + graphics.Clip = initialClip; + initialTransform.Translate(1, 2); + graphics.Transform = initialTransform; + + GraphicsState state = graphics.Save(); + object[] info = (object[])graphics.GetContextInfo(); + graphics.Restore(state); + + using (Region region = (Region)info[0]) + using (Matrix matrix = (Matrix)info[1]) + { + initialTransform.Translate(1, 2); + Assert.Equal(new RectangleF(0, 0, 8, 8), region.GetBounds(graphics)); + Assert.Equal(initialTransform, matrix); + } + } + } + } +} diff --git a/src/libraries/System.Drawing.Common/tests/System.Drawing.Common.Tests.csproj b/src/libraries/System.Drawing.Common/tests/System.Drawing.Common.Tests.csproj index 9d0c15dec7797..baa169e969831 100644 --- a/src/libraries/System.Drawing.Common/tests/System.Drawing.Common.Tests.csproj +++ b/src/libraries/System.Drawing.Common/tests/System.Drawing.Common.Tests.csproj @@ -28,6 +28,7 @@ + @@ -87,12 +88,9 @@ - - - + + + From 8f221aacf08661bfc47bfdbc9d39e8631e8f44cc Mon Sep 17 00:00:00 2001 From: Jeremy Kuhne Date: Thu, 4 Mar 2021 18:37:28 -0800 Subject: [PATCH 02/11] Implement new GetContextInfo API overloads Implements #47880, adding new, more performant overloads for GetContextInfo. - Add helper for only creating a region if it isn't infinite - Start an internal extensions class for easier mapping of System.Drawing concepts to System.Numerics types - Simplify GraphicsContext --- .../ref/System.Drawing.Common.cs | 3 + .../src/System.Drawing.Common.csproj | 1 + .../src/System/Drawing/Graphics.Unix.cs | 12 ++ .../src/System/Drawing/Graphics.Windows.cs | 80 +++++++--- .../src/System/Drawing/Graphics.cs | 33 ++++ .../src/System/Drawing/GraphicsContext.cs | 142 +++-------------- .../src/System/Drawing/NumericsExtensions.cs | 27 ++++ .../tests/Graphics_GetContextTests.Core.cs | 149 ++++++++++++++++++ .../tests/Graphics_GetContextTests.cs | 4 +- .../tests/System.Drawing.Common.Tests.csproj | 3 +- 10 files changed, 312 insertions(+), 142 deletions(-) create mode 100644 src/libraries/System.Drawing.Common/src/System/Drawing/NumericsExtensions.cs create mode 100644 src/libraries/System.Drawing.Common/tests/Graphics_GetContextTests.Core.cs diff --git a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs index 157484d8543ff..b1831da81a241 100644 --- a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs +++ b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs @@ -595,7 +595,10 @@ public void Flush(System.Drawing.Drawing2D.FlushIntention intention) { } public static System.Drawing.Graphics FromHwndInternal(System.IntPtr hwnd) { throw null; } public static System.Drawing.Graphics FromImage(System.Drawing.Image image) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + [Obsolete("Use one of the other overloads.")] public object GetContextInfo() { throw null; } + public void GetContextInfo(out PointF offset) { throw null; } + public void GetContextInfo(out PointF offset, out Region? clip) { throw null; } public static System.IntPtr GetHalftonePalette() { throw null; } public System.IntPtr GetHdc() { throw null; } public System.Drawing.Color GetNearestColor(System.Drawing.Color color) { throw null; } diff --git a/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj b/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj index 153bbc77f97fc..ced08e350ecc3 100644 --- a/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj +++ b/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj @@ -30,6 +30,7 @@ + diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Unix.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Unix.cs index 3da1617e5979b..d0b123621b8f9 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Unix.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Unix.cs @@ -581,6 +581,18 @@ public object GetContextInfo() throw new NotImplementedException(); } + [EditorBrowsable(EditorBrowsableState.Never)] + public void GetContextInfo(out PointF offset) + { + throw new PlatformNotSupportedException(); + } + + [EditorBrowsable(EditorBrowsableState.Never)] + public void GetContextInfo(out PointF offset, out Region? clip) + { + throw new PlatformNotSupportedException(); + } + private void CheckErrorStatus(int status) { Gdip.CheckStatus(status); diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs index f523e1c4e58b5..d414246121164 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs @@ -8,6 +8,7 @@ using System.Drawing.Imaging; using System.Drawing.Internal; using System.Globalization; +using System.Numerics; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using Gdip = System.Drawing.SafeNativeMethods.Gdip; @@ -682,40 +683,58 @@ public unsafe void EnumerateMetafile( /// WARNING: This method is for internal FX support only. /// [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("Use one of the other overloads.")] public object GetContextInfo() { - Region cumulClip = Clip; // current context clip. - Matrix cumulTransform = Transform; // current context transform. - PointF currentOffset = PointF.Empty; // offset of current context. - PointF totalOffset = PointF.Empty; // absolute coord offset of top context. + GetContextInfo(out Matrix3x2 cumulativeTransform, calculateClip: true, out Region? cumulativeClip); + return new object[] { cumulativeClip ?? new Region(), new Matrix(cumulativeTransform) }; + } - if (!cumulTransform.IsIdentity) - { - currentOffset = cumulTransform.Offset; - } + private void GetContextInfo(out Matrix3x2 cumulativeTransform, bool calculateClip, out Region? cumulativeClip) + { + cumulativeClip = calculateClip ? GetRegionIfNotInfinite() : null; // Current context clip. + cumulativeTransform = TransformElements; // Current context transform. + Vector2 currentOffset = default; // Offset of current context. + Vector2 totalOffset = default; // Absolute coordinate offset of top context. GraphicsContext? context = _previousContext; - while (context != null) + if (!cumulativeTransform.IsIdentity) { - if (!context.TransformOffset.IsEmpty) + currentOffset = cumulativeTransform.Translation; + } + + while (context is not null) + { + if (!context.TransformOffset.IsEmpty()) { - cumulTransform.Translate(context.TransformOffset.X, context.TransformOffset.Y); + cumulativeTransform.Translate(context.TransformOffset); } - if (!currentOffset.IsEmpty) + if (!currentOffset.IsEmpty()) { // The location of the GDI+ clip region is relative to the coordinate origin after any translate transform // has been applied. We need to intersect regions using the same coordinate origin relative to the previous // context. - cumulClip.Translate(currentOffset.X, currentOffset.Y); + + // If we don't have a cumulative clip, we're infinite, and translation on infinite regions is a no-op. + cumulativeClip?.Translate(currentOffset.X, currentOffset.Y); totalOffset.X += currentOffset.X; totalOffset.Y += currentOffset.Y; } - if (context.Clip != null) + // Context only stores clips if they are not infinite. Intersecting a clip with an infinite clip is a no-op. + if (calculateClip && context.Clip is not null) { - cumulClip.Intersect(context.Clip); + // Intersecting an infinite clip with another is just a copy of the second clip. + if (cumulativeClip is null) + { + cumulativeClip = context.Clip; + } + else + { + cumulativeClip.Intersect(context.Clip); + } } currentOffset = context.TransformOffset; @@ -732,14 +751,39 @@ public object GetContextInfo() } while (context.IsCumulative); } - if (!totalOffset.IsEmpty) + if (!totalOffset.IsEmpty()) { // We need now to reset the total transform in the region so when calling Region.GetHRgn(Graphics) // the HRegion is properly offset by GDI+ based on the total offset of the graphics object. - cumulClip.Translate(-totalOffset.X, -totalOffset.Y); + + // If we don't have a cumulative clip, we're infinite, and translation on infinite regions is a no-op. + cumulativeClip?.Translate(-totalOffset.X, -totalOffset.Y); } + } + + /// + /// Gets the cumulative offset. + /// + /// The cumulative offset. + [EditorBrowsable(EditorBrowsableState.Never)] + public void GetContextInfo(out PointF offset) + { + GetContextInfo(out Matrix3x2 cumulativeTransform, calculateClip: false, out _); + Vector2 translation = cumulativeTransform.Translation; + offset = new PointF(translation.X, translation.Y); + } - return new object[] { cumulClip, cumulTransform }; + /// + /// Gets the cumulative offset and clip region. + /// + /// The cumulative offset. + /// The cumulative clip region or null if the clip region is infinite. + [EditorBrowsable(EditorBrowsableState.Never)] + public void GetContextInfo(out PointF offset, out Region? clip) + { + GetContextInfo(out Matrix3x2 cumulativeTransform, calculateClip: true, out clip); + Vector2 translation = cumulativeTransform.Translation; + offset = new PointF(translation.X, translation.Y); } public RectangleF VisibleClipBounds diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.cs index 9ab0ebe423784..4917e8f33d831 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.cs @@ -2465,5 +2465,38 @@ private void IgnoreMetafileErrors(Image image, ref int errorStatus) if (errorStatus != Gdip.Ok && image.RawFormat.Equals(ImageFormat.Emf)) errorStatus = Gdip.Ok; } + + /// + /// Creates a Region class only if the native region is not infinite. + /// + internal Region? GetRegionIfNotInfinite() + { + Gdip.CheckStatus(Gdip.GdipCreateRegion(out IntPtr regionHandle)); + try + { + Gdip.GdipGetClip(new HandleRef(this, NativeGraphics), new HandleRef(null, regionHandle)); + Gdip.CheckStatus(Gdip.GdipIsInfiniteRegion( + new HandleRef(null, regionHandle), + new HandleRef(this, NativeGraphics), + out int isInfinite)); + + if (isInfinite != 0) + { + // Infinite + return null; + } + + Region region = new Region(regionHandle); + regionHandle = IntPtr.Zero; + return region; + } + finally + { + if (regionHandle != IntPtr.Zero) + { + Gdip.GdipDeleteRegion(new HandleRef(null, regionHandle)); + } + } + } } } diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/GraphicsContext.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/GraphicsContext.cs index 82340aa17020f..c1587d0e383a6 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/GraphicsContext.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/GraphicsContext.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Drawing.Drawing2D; +using System.Numerics; namespace System.Drawing { @@ -10,58 +10,10 @@ namespace System.Drawing /// internal sealed class GraphicsContext : IDisposable { - /// - /// The state that identifies the context. - /// - private int _contextState; - - /// - /// The context's translate transform. - /// - private PointF _transformOffset; - - /// - /// The context's clip region. - /// - private Region? _clipRegion; - - /// - /// The next context up the stack. - /// - private GraphicsContext? _nextContext; - - /// - /// The previous context down the stack. - /// - private GraphicsContext? _prevContext; - - /// - /// Flags that determines whether the context was created for a Graphics.Save() operation. - /// This kind of contexts are cumulative across subsequent Save() calls so the top context - /// info is cumulative. This is not the same for contexts created for a Graphics.BeginContainer() - /// operation, in this case the new context information is reset. See Graphics.BeginContainer() - /// and Graphics.Save() for more information. - /// - private bool _isCumulative; - public GraphicsContext(Graphics g) { - Matrix transform = g.Transform; - if (!transform.IsIdentity) - { - _transformOffset = transform.Offset; - } - transform.Dispose(); - - Region clip = g.Clip; - if (clip.IsInfinite(g)) - { - clip.Dispose(); - } - else - { - _clipRegion = clip; - } + TransformOffset = g.TransformElements.Translation; + Clip = g.GetRegionIfNotInfinite(); } /// @@ -78,100 +30,46 @@ public void Dispose() /// public void Dispose(bool disposing) { - if (_nextContext != null) - { - // Dispose all contexts up the stack since they are relative to this one and its state will be invalid. - _nextContext.Dispose(); - _nextContext = null; - } + // Dispose all contexts up the stack since they are relative to this one and its state will be invalid. + Next?.Dispose(); + Next = null; - if (_clipRegion != null) - { - _clipRegion.Dispose(); - _clipRegion = null; - } + Clip?.Dispose(); + Clip = null; } /// /// The state id representing the GraphicsContext. /// - public int State - { - get - { - return _contextState; - } - set - { - _contextState = value; - } - } + public int State { get; set; } /// /// The translate transform in the GraphicsContext. /// - public PointF TransformOffset - { - get - { - return _transformOffset; - } - } + public Vector2 TransformOffset { get; private set; } /// - /// The clipping region the GraphicsContext. + /// The clipping region the GraphicsContext. /// - public Region? Clip - { - get - { - return _clipRegion; - } - } + public Region? Clip { get; private set; } /// /// The next GraphicsContext object in the stack. /// - public GraphicsContext? Next - { - get - { - return _nextContext; - } - set - { - _nextContext = value; - } - } + public GraphicsContext? Next { get; set; } /// /// The previous GraphicsContext object in the stack. /// - public GraphicsContext? Previous - { - get - { - return _prevContext; - } - set - { - _prevContext = value; - } - } + public GraphicsContext? Previous { get; set; } /// - /// Determines whether this context is cumulative or not. See filed for more info. + /// Flag that determines whether the context was created for a Graphics.Save() operation. + /// This kind of contexts are cumulative across subsequent Save() calls so the top context + /// info is cumulative. This is not the same for contexts created for a Graphics.BeginContainer() + /// operation, in this case the new context information is reset. See Graphics.BeginContainer() + /// and Graphics.Save() for more information. /// - public bool IsCumulative - { - get - { - return _isCumulative; - } - set - { - _isCumulative = value; - } - } + public bool IsCumulative { get; set; } } } diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/NumericsExtensions.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/NumericsExtensions.cs new file mode 100644 index 0000000000000..1f468afdae269 --- /dev/null +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/NumericsExtensions.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; + +namespace System.Drawing +{ + /// + /// Helpers to allow using System.Numerics types like the System.Drawing equivalents. + /// + internal static class NumericsExtensions + { + internal static void Translate(this ref Matrix3x2 matrix, Vector2 offset) + { + // Replicating what Matrix.Translate(float offsetX, float offsetY) does. + matrix.M31 += (offset.X * matrix.M11) + (offset.Y * matrix.M21); + matrix.M32 += (offset.X * matrix.M12) + (offset.Y * matrix.M22); + } + + internal static bool IsEmpty(this Vector2 vector) => vector.X == 0 && vector.Y == 0; + } +} diff --git a/src/libraries/System.Drawing.Common/tests/Graphics_GetContextTests.Core.cs b/src/libraries/System.Drawing.Common/tests/Graphics_GetContextTests.Core.cs new file mode 100644 index 0000000000000..0e09cef317868 --- /dev/null +++ b/src/libraries/System.Drawing.Common/tests/Graphics_GetContextTests.Core.cs @@ -0,0 +1,149 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Drawing.Drawing2D; +using System.Numerics; +using Xunit; + +namespace System.Drawing.Tests +{ + public partial class Graphics_GetContextTests + { + [ConditionalFact(Helpers.IsWindows)] + public void GetContextInfo_New_DefaultGraphics() + { + using (var image = new Bitmap(10, 10)) + using (Graphics graphics = Graphics.FromImage(image)) + { + graphics.GetContextInfo(out PointF offset); + Assert.True(offset.IsEmpty); + + graphics.GetContextInfo(out offset, out Region? clip); + Assert.True(offset.IsEmpty); + Assert.Null(clip); + } + } + + [ConditionalFact(Helpers.IsWindows)] + public void GetContextInfo_New_Clipping() + { + using (var image = new Bitmap(10, 10)) + using (Graphics graphics = Graphics.FromImage(image)) + using (Region initialClip = new Region(new Rectangle(1, 2, 9, 10))) + { + graphics.Clip = initialClip; + + graphics.GetContextInfo(out PointF offset); + Assert.True(offset.IsEmpty); + + graphics.GetContextInfo(out offset, out Region? clip); + Assert.True(offset.IsEmpty); + Assert.NotNull(clip); + Assert.Equal(initialClip.GetBounds(graphics), clip.GetBounds(graphics)); + clip.Dispose(); + } + } + + [ConditionalFact(Helpers.IsWindows)] + public void GetContextInfo_New_Transform() + { + using (var image = new Bitmap(10, 10)) + using (Graphics graphics = Graphics.FromImage(image)) + { + graphics.TransformElements = Matrix3x2.CreateTranslation(1, 2); + + graphics.GetContextInfo(out PointF offset); + Assert.Equal(new PointF(1, 2), offset); + + graphics.GetContextInfo(out offset, out Region? clip); + Assert.Null(clip); + Assert.Equal(new PointF(1, 2), offset); + } + } + + [ConditionalFact(Helpers.IsWindows)] + public void GetContextInfo_New_ClipAndTransform() + { + using (var image = new Bitmap(10, 10)) + using (Graphics graphics = Graphics.FromImage(image)) + using (Region initialClip = new Region(new Rectangle(1, 2, 9, 10))) + { + graphics.Clip = initialClip; + graphics.TransformElements = Matrix3x2.CreateTranslation(1, 2); + + graphics.GetContextInfo(out PointF offset); + Assert.Equal(new PointF(1, 2), offset); + + graphics.GetContextInfo(out offset, out Region? clip); + Assert.NotNull(clip); + Assert.Equal(new RectangleF(0, 0, 9, 10), clip.GetBounds(graphics)); + Assert.Equal(new PointF(1, 2), offset); + clip.Dispose(); + } + } + + [ConditionalFact(Helpers.IsWindows)] + public void GetContextInfo_New_TransformAndClip() + { + using (var image = new Bitmap(10, 10)) + using (Graphics graphics = Graphics.FromImage(image)) + using (Region initialClip = new Region(new Rectangle(1, 2, 9, 10))) + { + graphics.TransformElements = Matrix3x2.CreateTranslation(1, 2); + graphics.Clip = initialClip; + + graphics.GetContextInfo(out PointF offset); + Assert.Equal(new PointF(1, 2), offset); + + graphics.GetContextInfo(out offset, out Region? clip); + Assert.NotNull(clip); + Assert.Equal(new RectangleF(1, 2, 9, 10), clip.GetBounds(graphics)); + Assert.Equal(new PointF(1, 2), offset); + clip.Dispose(); + } + } + + [ConditionalFact(Helpers.IsWindows)] + public void GetContextInfo_New_ClipAndTransformSaveState() + { + using (var image = new Bitmap(10, 10)) + using (Graphics graphics = Graphics.FromImage(image)) + using (Region initialClip = new Region(new Rectangle(1, 2, 9, 10))) + { + graphics.Clip = initialClip; + graphics.TransformElements = Matrix3x2.CreateTranslation(1, 2); + + GraphicsState state = graphics.Save(); + + graphics.GetContextInfo(out PointF offset); + Assert.Equal(new PointF(2, 4), offset); + + graphics.GetContextInfo(out offset, out Region? clip); + Assert.NotNull(clip); + Assert.Equal(new RectangleF(0, 0, 8, 8), clip.GetBounds(graphics)); + Assert.Equal(new PointF(2, 4), offset); + clip.Dispose(); + } + } + + [ConditionalFact(Helpers.IsWindows)] + public void GetContextInfo_New_ClipAndTransformSaveAndRestoreState() + { + using (var image = new Bitmap(10, 10)) + using (Graphics graphics = Graphics.FromImage(image)) + { + graphics.SetClip(new Rectangle(1, 2, 9, 10)); + graphics.TransformElements = Matrix3x2.CreateTranslation(1, 2); + + GraphicsState state = graphics.Save(); + graphics.GetContextInfo(out PointF offset, out Region? clip); + graphics.Restore(state); + + Assert.NotNull(clip); + Assert.Equal(new RectangleF(0, 0, 8, 8), clip.GetBounds(graphics)); + Assert.Equal(new PointF(2, 4), offset); + clip.Dispose(); + } + } + } +} diff --git a/src/libraries/System.Drawing.Common/tests/Graphics_GetContextTests.cs b/src/libraries/System.Drawing.Common/tests/Graphics_GetContextTests.cs index 3eb940d75da69..9dd8d4e389993 100644 --- a/src/libraries/System.Drawing.Common/tests/Graphics_GetContextTests.cs +++ b/src/libraries/System.Drawing.Common/tests/Graphics_GetContextTests.cs @@ -6,7 +6,8 @@ namespace System.Drawing.Tests { - public class Graphics_GetContextTests : DrawingTest +#pragma warning disable CS0618 // Type or member is obsolete + public partial class Graphics_GetContextTests : DrawingTest { [ConditionalFact(Helpers.IsWindows)] public void GetContextInfo_DefaultGraphics() @@ -163,4 +164,5 @@ public void GetContextInfo_ClipAndTransformSaveAndRestoreState() } } } +#pragma warning restore CS0618 // Type or member is obsolete } diff --git a/src/libraries/System.Drawing.Common/tests/System.Drawing.Common.Tests.csproj b/src/libraries/System.Drawing.Common/tests/System.Drawing.Common.Tests.csproj index baa169e969831..e8f4d68133f0d 100644 --- a/src/libraries/System.Drawing.Common/tests/System.Drawing.Common.Tests.csproj +++ b/src/libraries/System.Drawing.Common/tests/System.Drawing.Common.Tests.csproj @@ -1,4 +1,4 @@ - + true true @@ -117,6 +117,7 @@ + From cc4c154e9ea165778fb9fe50b4c9cb53feaa000f Mon Sep 17 00:00:00 2001 From: Jeremy Kuhne Date: Fri, 5 Mar 2021 11:10:21 -0800 Subject: [PATCH 03/11] Update WindowsGraphics to use new overloads. --- .../src/misc/GDI/WindowsGraphics.cs | 45 +++++++------------ 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/src/libraries/System.Drawing.Common/src/misc/GDI/WindowsGraphics.cs b/src/libraries/System.Drawing.Common/src/misc/GDI/WindowsGraphics.cs index d6f876ceee5a7..6257a8219199b 100644 --- a/src/libraries/System.Drawing.Common/src/misc/GDI/WindowsGraphics.cs +++ b/src/libraries/System.Drawing.Common/src/misc/GDI/WindowsGraphics.cs @@ -57,42 +57,29 @@ public static WindowsGraphics FromGraphics(Graphics g, ApplyGraphicsProperties p PointF offset = default; - Region? clipRgn = null; - Matrix? worldTransf = null; - - if ((properties & ApplyGraphicsProperties.TranslateTransform) != 0 || (properties & ApplyGraphicsProperties.Clipping) != 0) + if (properties != ApplyGraphicsProperties.None) { - if (g.GetContextInfo() is object[] data && data.Length == 2) + Region? clip = null; + + if (properties.HasFlag(ApplyGraphicsProperties.Clipping)) { - clipRgn = data[0] as Region; - worldTransf = data[1] as Matrix; + g.GetContextInfo(out offset, out clip); } - - if (worldTransf != null) + else { - if ((properties & ApplyGraphicsProperties.TranslateTransform) != 0) - { - offset = worldTransf.Offset; - } - - worldTransf.Dispose(); + g.GetContextInfo(out offset); } - if (clipRgn != null) + if (clip is not null) { - if ((properties & ApplyGraphicsProperties.Clipping) != 0) - { - // We have to create the WindowsRegion and dipose the Region object before locking the Graphics object, - // in case of an unlikely exception before releasing the WindowsRegion, the finalizer will do it for us. - // (no try-finally block since this method is used frequently - perf). - // If the Graphics.Clip has not been set (Region.IsInfinite) we don't need to apply it to the DC. - if (!clipRgn.IsInfinite(g)) - { - wr = WindowsRegion.FromRegion(clipRgn, g); // WindowsRegion will take ownership of the hRegion. - } - } + // We have to create the WindowsRegion and dipose the Region object before locking the Graphics object, + // in case of an unlikely exception before releasing the WindowsRegion, the finalizer will do it for us. + // (no try-finally block since this method is used frequently - perf). + + // If clipping has not been set (Region.IsInfinite) GetContextInfo will return a null Region. - clipRgn.Dispose(); // Disposing the Region object doesn't destroy the hRegion. + wr = WindowsRegion.FromRegion(clip, g); // WindowsRegion will take ownership of the hRegion. + clip.Dispose(); // Disposing the Region object doesn't destroy the hRegion. } } @@ -100,7 +87,7 @@ public static WindowsGraphics FromGraphics(Graphics g, ApplyGraphicsProperties p wg._graphics = g; // Apply transform and clip - if (wr != null) + if (wr is not null) { using (wr) { From ee03c701be4c0a829734c392d40d69e30278675e Mon Sep 17 00:00:00 2001 From: Jeremy Kuhne Date: Fri, 5 Mar 2021 12:43:04 -0800 Subject: [PATCH 04/11] Skip tests when GDI+ isn't available. --- src/libraries/Common/tests/System/Drawing/Helpers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Common/tests/System/Drawing/Helpers.cs b/src/libraries/Common/tests/System/Drawing/Helpers.cs index fc68b4e6e124a..a4567ab687831 100644 --- a/src/libraries/Common/tests/System/Drawing/Helpers.cs +++ b/src/libraries/Common/tests/System/Drawing/Helpers.cs @@ -54,7 +54,7 @@ public static bool GetIsWindowsOrAtLeastLibgdiplus6() return installedVersion.Major >= 6; } - public static bool GetIsWindows() => PlatformDetection.IsWindows; + public static bool GetIsWindows() => PlatformDetection.IsDrawingSupported && PlatformDetection.IsWindows; public static bool IsNotUnix => PlatformDetection.IsWindows; From ade74ec8da2a05902888525343a16ea18f8eb70a Mon Sep 17 00:00:00 2001 From: Jeremy Kuhne Date: Fri, 5 Mar 2021 17:13:13 -0800 Subject: [PATCH 05/11] Add `[SupportedOSPlatform("windows")]` --- .../System.Drawing.Common/ref/System.Drawing.Common.cs | 3 +++ .../System.Drawing.Common/src/System/Drawing/Graphics.Unix.cs | 4 ++++ .../src/System/Drawing/Graphics.Windows.cs | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs index b1831da81a241..aa8a29b1e38d5 100644 --- a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs +++ b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs @@ -595,9 +595,12 @@ public void Flush(System.Drawing.Drawing2D.FlushIntention intention) { } public static System.Drawing.Graphics FromHwndInternal(System.IntPtr hwnd) { throw null; } public static System.Drawing.Graphics FromImage(System.Drawing.Image image) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + [System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")] [Obsolete("Use one of the other overloads.")] public object GetContextInfo() { throw null; } + [System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")] public void GetContextInfo(out PointF offset) { throw null; } + [System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")] public void GetContextInfo(out PointF offset, out Region? clip) { throw null; } public static System.IntPtr GetHalftonePalette() { throw null; } public System.IntPtr GetHdc() { throw null; } diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Unix.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Unix.cs index d0b123621b8f9..cba7e4aab0a55 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Unix.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Unix.cs @@ -41,6 +41,7 @@ using System.Runtime.InteropServices; using System.Text; using Gdip = System.Drawing.SafeNativeMethods.Gdip; +using System.Runtime.Versioning; namespace System.Drawing { @@ -576,18 +577,21 @@ public RectangleF VisibleClipBounds } [EditorBrowsable(EditorBrowsableState.Never)] + [SupportedOSPlatform("windows")] public object GetContextInfo() { throw new NotImplementedException(); } [EditorBrowsable(EditorBrowsableState.Never)] + [SupportedOSPlatform("windows")] public void GetContextInfo(out PointF offset) { throw new PlatformNotSupportedException(); } [EditorBrowsable(EditorBrowsableState.Never)] + [SupportedOSPlatform("windows")] public void GetContextInfo(out PointF offset, out Region? clip) { throw new PlatformNotSupportedException(); diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs index d414246121164..028eb342e377e 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs @@ -11,6 +11,7 @@ using System.Numerics; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; +using System.Runtime.Versioning; using Gdip = System.Drawing.SafeNativeMethods.Gdip; namespace System.Drawing @@ -684,6 +685,7 @@ public unsafe void EnumerateMetafile( /// [EditorBrowsable(EditorBrowsableState.Never)] [Obsolete("Use one of the other overloads.")] + [SupportedOSPlatform("windows")] public object GetContextInfo() { GetContextInfo(out Matrix3x2 cumulativeTransform, calculateClip: true, out Region? cumulativeClip); @@ -766,6 +768,7 @@ private void GetContextInfo(out Matrix3x2 cumulativeTransform, bool calculateCli /// /// The cumulative offset. [EditorBrowsable(EditorBrowsableState.Never)] + [SupportedOSPlatform("windows")] public void GetContextInfo(out PointF offset) { GetContextInfo(out Matrix3x2 cumulativeTransform, calculateClip: false, out _); @@ -779,6 +782,7 @@ public void GetContextInfo(out PointF offset) /// The cumulative offset. /// The cumulative clip region or null if the clip region is infinite. [EditorBrowsable(EditorBrowsableState.Never)] + [SupportedOSPlatform("windows")] public void GetContextInfo(out PointF offset, out Region? clip) { GetContextInfo(out Matrix3x2 cumulativeTransform, calculateClip: true, out clip); From e4455f7d9f8bb911679a4af401f37fe34bf5ecfe Mon Sep 17 00:00:00 2001 From: Jeremy Kuhne Date: Thu, 15 Apr 2021 12:12:20 -0700 Subject: [PATCH 06/11] Use new Obsolete attribute pattern. --- docs/project/list-of-obsoletions.md | 3 ++- .../System.Drawing.Common/ref/System.Drawing.Common.cs | 2 +- .../src/System/Drawing/Graphics.Windows.cs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/project/list-of-obsoletions.md b/docs/project/list-of-obsoletions.md index cb094673111ec..3e51736867d24 100644 --- a/docs/project/list-of-obsoletions.md +++ b/docs/project/list-of-obsoletions.md @@ -26,4 +26,5 @@ Currently the identifiers `SYSLIB0001` through `SYSLIB0999` are carved out for o | __`SYSLIB0011`__ | `BinaryFormatter` serialization is obsolete and should not be used. See https://aka.ms/binaryformatter for recommended alternatives. | | __`SYSLIB0012`__ | Assembly.CodeBase and Assembly.EscapedCodeBase are only included for .NET Framework compatibility. Use Assembly.Location instead. | | __`SYSLIB0013`__ | Uri.EscapeUriString can corrupt the Uri string in some cases. Consider using Uri.EscapeDataString for query string components instead. | -| __`SYSLIB0015`__ | DisablePrivateReflectionAttribute has no effect in .NET 6.0+ applications. | \ No newline at end of file +| __`SYSLIB0015`__ | DisablePrivateReflectionAttribute has no effect in .NET 6.0+ applications. | +| __`SYSLIB0016`__ | Use the other GetContextInfo overloads for better performance and fewer allocations. | diff --git a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs index aa8a29b1e38d5..2c6044aed54cf 100644 --- a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs +++ b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs @@ -596,7 +596,7 @@ public void Flush(System.Drawing.Drawing2D.FlushIntention intention) { } public static System.Drawing.Graphics FromImage(System.Drawing.Image image) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] [System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")] - [Obsolete("Use one of the other overloads.")] + [System.ObsoleteAttribute(DiagnosticId = "SYSLIB0016", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public object GetContextInfo() { throw null; } [System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")] public void GetContextInfo(out PointF offset) { throw null; } diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs index 028eb342e377e..271154e093dc8 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs @@ -684,7 +684,7 @@ public unsafe void EnumerateMetafile( /// WARNING: This method is for internal FX support only. /// [EditorBrowsable(EditorBrowsableState.Never)] - [Obsolete("Use one of the other overloads.")] + [Obsolete(DiagnosticId = "SYSLIB0016", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] [SupportedOSPlatform("windows")] public object GetContextInfo() { From 9293cd731687d4aaeab31e8214cb6fac61de7e3b Mon Sep 17 00:00:00 2001 From: Jeremy Kuhne Date: Thu, 15 Apr 2021 12:51:50 -0700 Subject: [PATCH 07/11] Use Obsoletions.cs and conditionalize in ref. --- docs/project/list-of-obsoletions.md | 2 +- src/libraries/Common/src/System/Obsoletions.cs | 3 +++ .../System.Drawing.Common/ref/System.Drawing.Common.cs | 6 +++++- .../ref/System.Drawing.Common.csproj | 8 +++++++- .../src/System.Drawing.Common.csproj | 2 ++ .../src/System/Drawing/Graphics.Windows.cs | 2 +- 6 files changed, 19 insertions(+), 4 deletions(-) diff --git a/docs/project/list-of-obsoletions.md b/docs/project/list-of-obsoletions.md index 3e51736867d24..9fdfabcb40a38 100644 --- a/docs/project/list-of-obsoletions.md +++ b/docs/project/list-of-obsoletions.md @@ -27,4 +27,4 @@ Currently the identifiers `SYSLIB0001` through `SYSLIB0999` are carved out for o | __`SYSLIB0012`__ | Assembly.CodeBase and Assembly.EscapedCodeBase are only included for .NET Framework compatibility. Use Assembly.Location instead. | | __`SYSLIB0013`__ | Uri.EscapeUriString can corrupt the Uri string in some cases. Consider using Uri.EscapeDataString for query string components instead. | | __`SYSLIB0015`__ | DisablePrivateReflectionAttribute has no effect in .NET 6.0+ applications. | -| __`SYSLIB0016`__ | Use the other GetContextInfo overloads for better performance and fewer allocations. | +| __`SYSLIB0016`__ | Use the Graphics.GetContextInfo overloads that accept arguments for better performance and fewer allocations. | diff --git a/src/libraries/Common/src/System/Obsoletions.cs b/src/libraries/Common/src/System/Obsoletions.cs index a4f6fb66e1f75..0c81d883e6439 100644 --- a/src/libraries/Common/src/System/Obsoletions.cs +++ b/src/libraries/Common/src/System/Obsoletions.cs @@ -51,5 +51,8 @@ internal static class Obsoletions internal const string DisablePrivateReflectionAttributeMessage = "DisablePrivateReflectionAttribute has no effect in .NET 6.0+ applications."; internal const string DisablePrivateReflectionAttributeDiagId = "SYSLIB0015"; + + internal const string GetContextInfoMessage = "Use the Graphics.GetContextInfo overloads that accept arguments for better performance and fewer allocations."; + internal const string GetContextInfoId = "SYSLIB0016"; } } diff --git a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs index 2c6044aed54cf..a521ba066feca 100644 --- a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs +++ b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs @@ -596,7 +596,11 @@ public void Flush(System.Drawing.Drawing2D.FlushIntention intention) { } public static System.Drawing.Graphics FromImage(System.Drawing.Image image) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] [System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")] - [System.ObsoleteAttribute(DiagnosticId = "SYSLIB0016", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] +#if NET50_OBSOLETIONS + [System.ObsoleteAttribute(Obsoletions.GetContextInfoMessage, DiagnosticId = Obsoletions.GetContextInfoId, UrlFormat = Obsoletions.SharedUrlFormat)] +#else + [System.ObsoleteAttribute(Obsoletions.GetContextInfoMessage)] +#endif public object GetContextInfo() { throw null; } [System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")] public void GetContextInfo(out PointF offset) { throw null; } diff --git a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.csproj b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.csproj index 5e56a68614b59..9a9bdb7178273 100644 --- a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.csproj +++ b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.csproj @@ -1,12 +1,18 @@ - + $(NetCoreAppCurrent);netcoreapp3.0 true enable + + + $(DefineConstants);NET50_OBSOLETIONS + + diff --git a/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj b/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj index ced08e350ecc3..4d37cf7ead080 100644 --- a/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj +++ b/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj @@ -165,6 +165,8 @@ Link="Common\Interop\Windows\Gdi32\Interop.RasterOp.cs" /> + System.Drawing.DefaultComponent.bmp diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs index 271154e093dc8..a2fe30b6b5fb9 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs @@ -684,7 +684,7 @@ public unsafe void EnumerateMetafile( /// WARNING: This method is for internal FX support only. /// [EditorBrowsable(EditorBrowsableState.Never)] - [Obsolete(DiagnosticId = "SYSLIB0016", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [Obsolete(Obsoletions.GetContextInfoMessage, DiagnosticId = Obsoletions.GetContextInfoId, UrlFormat = Obsoletions.SharedUrlFormat)] [SupportedOSPlatform("windows")] public object GetContextInfo() { From 7bb81556ae514485418458e838597526997a68c5 Mon Sep 17 00:00:00 2001 From: Jeremy Kuhne Date: Thu, 15 Apr 2021 13:26:14 -0700 Subject: [PATCH 08/11] Address feedback --- src/libraries/Common/src/System/Obsoletions.cs | 2 +- .../System.Drawing.Common/ref/System.Drawing.Common.cs | 4 +--- .../System.Drawing.Common/ref/System.Drawing.Common.csproj | 2 -- .../src/System/Drawing/Graphics.Windows.cs | 2 +- 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/libraries/Common/src/System/Obsoletions.cs b/src/libraries/Common/src/System/Obsoletions.cs index 0c81d883e6439..52c8042c9bee0 100644 --- a/src/libraries/Common/src/System/Obsoletions.cs +++ b/src/libraries/Common/src/System/Obsoletions.cs @@ -53,6 +53,6 @@ internal static class Obsoletions internal const string DisablePrivateReflectionAttributeDiagId = "SYSLIB0015"; internal const string GetContextInfoMessage = "Use the Graphics.GetContextInfo overloads that accept arguments for better performance and fewer allocations."; - internal const string GetContextInfoId = "SYSLIB0016"; + internal const string GetContextInfoDiagId = "SYSLIB0016"; } } diff --git a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs index a521ba066feca..f5dbadbd7f023 100644 --- a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs +++ b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs @@ -597,9 +597,7 @@ public void Flush(System.Drawing.Drawing2D.FlushIntention intention) { } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] [System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")] #if NET50_OBSOLETIONS - [System.ObsoleteAttribute(Obsoletions.GetContextInfoMessage, DiagnosticId = Obsoletions.GetContextInfoId, UrlFormat = Obsoletions.SharedUrlFormat)] -#else - [System.ObsoleteAttribute(Obsoletions.GetContextInfoMessage)] + [System.ObsoleteAttribute("Use the Graphics.GetContextInfo overloads that accept arguments for better performance and fewer allocations.", DiagnosticId = "SYSLIB0016", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] #endif public object GetContextInfo() { throw null; } [System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")] diff --git a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.csproj b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.csproj index 9a9bdb7178273..3b16ac683caaf 100644 --- a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.csproj +++ b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.csproj @@ -11,8 +11,6 @@ - diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs index a2fe30b6b5fb9..929ea19c4fad8 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs @@ -684,7 +684,7 @@ public unsafe void EnumerateMetafile( /// WARNING: This method is for internal FX support only. /// [EditorBrowsable(EditorBrowsableState.Never)] - [Obsolete(Obsoletions.GetContextInfoMessage, DiagnosticId = Obsoletions.GetContextInfoId, UrlFormat = Obsoletions.SharedUrlFormat)] + [Obsolete(Obsoletions.GetContextInfoMessage, DiagnosticId = Obsoletions.GetContextInfoDiagId, UrlFormat = Obsoletions.SharedUrlFormat)] [SupportedOSPlatform("windows")] public object GetContextInfo() { From ddbf284c14dd44bf304543cfe675d42ff417b00f Mon Sep 17 00:00:00 2001 From: Jeremy Kuhne Date: Thu, 15 Apr 2021 14:04:19 -0700 Subject: [PATCH 09/11] Conditionalize the obsoletion in the src --- .../System.Drawing.Common/src/System.Drawing.Common.csproj | 4 ++++ .../src/System/Drawing/Graphics.Windows.cs | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj b/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj index 4d37cf7ead080..7942b0edb95de 100644 --- a/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj +++ b/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj @@ -12,6 +12,10 @@ SR.SystemDrawingCommon_PlatformNotSupported + + + $(DefineConstants);NET50_OBSOLETIONS + diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs index 929ea19c4fad8..e63b02039066d 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs @@ -684,7 +684,9 @@ public unsafe void EnumerateMetafile( /// WARNING: This method is for internal FX support only. /// [EditorBrowsable(EditorBrowsableState.Never)] +#if NET50_OBSOLETIONS [Obsolete(Obsoletions.GetContextInfoMessage, DiagnosticId = Obsoletions.GetContextInfoDiagId, UrlFormat = Obsoletions.SharedUrlFormat)] +#endif [SupportedOSPlatform("windows")] public object GetContextInfo() { From fd0cc66ea14fc3468f38cde09fabeef96f7e0484 Mon Sep 17 00:00:00 2001 From: Jeremy Kuhne Date: Thu, 15 Apr 2021 14:46:50 -0700 Subject: [PATCH 10/11] Update suppression in tests --- .../System.Drawing.Common/tests/Graphics_GetContextTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Drawing.Common/tests/Graphics_GetContextTests.cs b/src/libraries/System.Drawing.Common/tests/Graphics_GetContextTests.cs index 9dd8d4e389993..deb05c2a03977 100644 --- a/src/libraries/System.Drawing.Common/tests/Graphics_GetContextTests.cs +++ b/src/libraries/System.Drawing.Common/tests/Graphics_GetContextTests.cs @@ -6,7 +6,7 @@ namespace System.Drawing.Tests { -#pragma warning disable CS0618 // Type or member is obsolete +#pragma warning disable SYSLIB0016 // Type or member is obsolete public partial class Graphics_GetContextTests : DrawingTest { [ConditionalFact(Helpers.IsWindows)] @@ -164,5 +164,5 @@ public void GetContextInfo_ClipAndTransformSaveAndRestoreState() } } } -#pragma warning restore CS0618 // Type or member is obsolete +#pragma warning restore SYSLIB0016 // Type or member is obsolete } From 5dd6c193ea2646262c081ea1ccb1d6ebe55bca08 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Thu, 15 Apr 2021 16:13:45 -0700 Subject: [PATCH 11/11] Apply obsoletions downlevel using an internal ObsoleteAttribute --- .../System.Drawing.Common/ref/System.Drawing.Common.cs | 2 -- .../System.Drawing.Common/ref/System.Drawing.Common.csproj | 5 +---- .../System.Drawing.Common/src/System.Drawing.Common.csproj | 5 +---- .../src/System/Drawing/Graphics.Windows.cs | 2 -- 4 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs index f5dbadbd7f023..e8531366f99be 100644 --- a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs +++ b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs @@ -596,9 +596,7 @@ public void Flush(System.Drawing.Drawing2D.FlushIntention intention) { } public static System.Drawing.Graphics FromImage(System.Drawing.Image image) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] [System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")] -#if NET50_OBSOLETIONS [System.ObsoleteAttribute("Use the Graphics.GetContextInfo overloads that accept arguments for better performance and fewer allocations.", DiagnosticId = "SYSLIB0016", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] -#endif public object GetContextInfo() { throw null; } [System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")] public void GetContextInfo(out PointF offset) { throw null; } diff --git a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.csproj b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.csproj index 3b16ac683caaf..c5678ab357925 100644 --- a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.csproj +++ b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.csproj @@ -2,12 +2,9 @@ $(NetCoreAppCurrent);netcoreapp3.0 true + true enable - - - $(DefineConstants);NET50_OBSOLETIONS - diff --git a/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj b/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj index 7942b0edb95de..a0e1544cb8be0 100644 --- a/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj +++ b/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj @@ -7,15 +7,12 @@ true $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent);netcoreapp3.0-windows;netcoreapp3.0-Unix;netcoreapp3.0 true + true enable SR.SystemDrawingCommon_PlatformNotSupported - - - $(DefineConstants);NET50_OBSOLETIONS - diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs index e63b02039066d..929ea19c4fad8 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Graphics.Windows.cs @@ -684,9 +684,7 @@ public unsafe void EnumerateMetafile( /// WARNING: This method is for internal FX support only. /// [EditorBrowsable(EditorBrowsableState.Never)] -#if NET50_OBSOLETIONS [Obsolete(Obsoletions.GetContextInfoMessage, DiagnosticId = Obsoletions.GetContextInfoDiagId, UrlFormat = Obsoletions.SharedUrlFormat)] -#endif [SupportedOSPlatform("windows")] public object GetContextInfo() {