From 3ca21bb550e3ddecfd66a56d9d880c354f8b1853 Mon Sep 17 00:00:00 2001 From: GitHub Copilot Date: Fri, 6 Feb 2026 16:37:38 +0100 Subject: [PATCH 1/2] [UIKit] Enable nullability and clean up UIGraphics. This is file 11 of 30 files with nullability disabled in UIKit. * Enable nullability (#nullable enable). * Add nullable annotations (UIImage?, CGContext?, NSDictionary?, CGPDFInfo?). * Fix null reference return in UIImage.Scale methods caused by nullable GetImageFromCurrentImageContext return type. * Improve XML documentation comments: remove 'To be added.' placeholders, fix formatting, add missing docs for BeginImageContextWithOptions, EndPDFContext, and other members, add 'see cref' references, remove empty and elements, fix element ordering (summary before param), correct PDF context method remarks to reference EndPDFContext instead of EndImageContext. Contributes towards https://github.com/dotnet/macios/issues/17285. --- src/UIKit/UIGraphics.cs | 242 +++++++++--------- src/UIKit/UIImage.cs | 4 +- .../Documentation.KnownFailures.txt | 2 - 3 files changed, 123 insertions(+), 125 deletions(-) diff --git a/src/UIKit/UIGraphics.cs b/src/UIKit/UIGraphics.cs index 8d14ca843e29..289f6871b91f 100644 --- a/src/UIKit/UIGraphics.cs +++ b/src/UIKit/UIGraphics.cs @@ -10,8 +10,7 @@ using CoreGraphics; using System.ComponentModel; -// Disable until we get around to enable + fix any issues. -#nullable disable +#nullable enable namespace UIKit { @@ -20,9 +19,9 @@ namespace UIKit { #endif /// Helper methods to paint on the screen, PDF context or bitmaps. - /// - /// Methods in this class generally correspond to UIGraphics* and UIRect* methods in Apple's UIKit Framework. - /// + /// + /// Methods in this class generally correspond to UIGraphics* and UIRect* methods in Apple's UIKit Framework. + /// public static class UIGraphics { [DllImport (Constants.UIKitLibrary)] extern static IntPtr UIGraphicsGetCurrentContext (); @@ -33,51 +32,47 @@ public static class UIGraphics { [DllImport (Constants.UIKitLibrary)] extern static void UIGraphicsPopContext (); - /// To be added. - /// To be added. - /// Fills with the current fill color, using . - /// - /// Developers can call this method from any thread. - /// + /// Fills with the current fill color, using . + /// The rectangle to fill. + /// The blend mode to use when filling. + /// + /// Developers can call this method from any thread. + /// [DllImport (Constants.UIKitLibrary, EntryPoint = "UIRectFillUsingBlendMode")] public extern static void RectFillUsingBlendMode (CGRect rect, CGBlendMode blendMode); + /// Fills a rectangle with the current color on the current context. /// The region to fill. - /// Fills a rectangle with the current color on the current context. - /// - /// Developers can call this method from any thread. - /// + /// + /// Developers can call this method from any thread. + /// [DllImport (Constants.UIKitLibrary, EntryPoint = "UIRectFill")] public extern static void RectFill (CGRect rect); - /// To be added. - /// To be added. - /// Draws a frame inside the specified rectangle and blending it with . - /// To be added. + /// Draws a frame inside the specified rectangle and blending it with . + /// The rectangle in which to draw the frame. + /// The blend mode to use when drawing. [DllImport (Constants.UIKitLibrary, EntryPoint = "UIRectFrameUsingBlendMode")] public extern static void RectFrameUsingBlendMode (CGRect rect, CGBlendMode blendMode); + /// Draws a frame inside the specified rectangle. /// Region where the frame will be drawn. - /// Draws a frame inside the specified rectangle. - /// . [DllImport (Constants.UIKitLibrary, EntryPoint = "UIRectFrame")] public extern static void RectFrame (CGRect rect); - /// New clipping path. - /// Intersects the current clipping path with the specified rectangle. - /// - /// + /// Intersects the current clipping path with the specified rectangle. + /// The new clipping path. [DllImport (Constants.UIKitLibrary, EntryPoint = "UIRectClip")] public extern static void RectClip (CGRect rect); + /// Pushes a new image context and makes it the current graphics context. /// Size of the image context. - /// Pushes a new image context and makes it the current graphics context. - /// - /// UIKit keeps a stack of image context, this method creates a new image context, makes it the default and places it at the top of the graphic context stacks. - /// To restore the previous graphics context, call the method. - /// You can get the current context by calling the method. - /// Developers can call this method from any thread. - /// + /// + /// UIKit keeps a stack of image contexts. This method creates a new image context, makes it the default and places it at the top of the graphic context stack. + /// To restore the previous graphics context, call the method. + /// You can get the current context by calling the method. + /// Developers can call this method from any thread. + /// [SupportedOSPlatform ("ios")] [SupportedOSPlatform ("tvos")] [SupportedOSPlatform ("maccatalyst")] @@ -96,6 +91,16 @@ public static class UIGraphics { [DllImport (Constants.UIKitLibrary, EntryPoint = "UIGraphicsBeginImageContextWithOptions")] extern static void BeginImageContextWithOptions (CGSize size, byte opaque, nfloat scale); + /// Pushes a new image context with the specified options and makes it the current graphics context. + /// The size of the image context. + /// Whether the image context is opaque. + /// The scale factor to apply (use 0 for the device's main screen scale). + /// + /// UIKit keeps a stack of image contexts. This method creates a new image context, makes it the default and places it at the top of the graphic context stack. + /// To restore the previous graphics context, call the method. + /// You can get the current context by calling the method. + /// Developers can call this method from any thread. + /// [SupportedOSPlatform ("ios")] [SupportedOSPlatform ("tvos")] [SupportedOSPlatform ("maccatalyst")] @@ -117,12 +122,12 @@ public static void BeginImageContextWithOptions (CGSize size, bool opaque, nfloa static extern IntPtr UIGraphicsGetImageFromCurrentImageContext (); /// Pops the current image context. - /// - /// UIKit keeps a stack of image context, this method pops the current image context, and makes the new context at the top of the stack, the new default context. - /// If the current context was not created using the - /// or - /// this method does nothing. - /// + /// + /// UIKit keeps a stack of image contexts. This method pops the current image context, and makes the new context at the top of the stack the new default context. + /// If the current context was not created using + /// or , + /// this method does nothing. + /// [SupportedOSPlatform ("ios")] [SupportedOSPlatform ("tvos")] [SupportedOSPlatform ("maccatalyst")] @@ -135,10 +140,10 @@ public static void BeginImageContextWithOptions (CGSize size, bool opaque, nfloa [DllImport (Constants.UIKitLibrary)] extern static void UIGraphicsAddPDFContextDestinationAtPoint (IntPtr str, CGPoint point); - /// Name of destination point. - /// A point in the current context. - /// Adds a PDF destination with the given name at the given position. - /// Only valid if the current graphics context is a PDF context + /// Adds a PDF destination with the given name at the given position. + /// Name of the destination point. + /// A point in the current context. + /// Only valid if the current graphics context is a PDF context. public static void AddPDFContextDestination (string str, CGPoint point) { using (var nsstr = new NSString (str)) @@ -148,10 +153,9 @@ public static void AddPDFContextDestination (string str, CGPoint point) [DllImport (Constants.UIKitLibrary)] extern static void UIGraphicsSetPDFContextDestinationForRect (IntPtr str, CGRect rect); - /// To be added. - /// To be added. - /// Sets the PDF destination with the given name at the given position. - /// To be added. + /// Sets the PDF destination with the given name at the given position. + /// The name of the destination. + /// The rectangle to associate with the destination. public static void SetPDFContextDestination (string str, CGRect rect) { using (var nsstr = new NSString (str)) @@ -161,11 +165,8 @@ public static void SetPDFContextDestination (string str, CGRect rect) [DllImport (Constants.UIKitLibrary)] extern static CGRect UIGraphicsGetPDFContextBounds (); - /// Return the current bounds for the PDF page. - /// - /// - /// - /// + /// Returns the current bounds for the PDF page. + /// The bounds of the current PDF page. public static CGRect PDFContextBounds { get { return UIGraphicsGetPDFContextBounds (); @@ -175,11 +176,9 @@ public static CGRect PDFContextBounds { [DllImport (Constants.UIKitLibrary)] extern static void UIGraphicsSetPDFContextURLForRect (IntPtr url, CGRect rect); - /// To be added. - /// To be added. - /// Links the url to the specified rectangle on the PDF page. - /// - /// + /// Links the URL to the specified rectangle on the PDF page. + /// The URL to link. + /// The rectangle on the PDF page to associate with the URL. public static void SetPDFContextURL (NSUrl url, CGRect rect) { UIGraphicsSetPDFContextURLForRect (url.Handle, rect); @@ -190,17 +189,16 @@ public static void SetPDFContextURL (NSUrl url, CGRect rect) extern static void UIGraphicsBeginPDFContextToFile (/* NSString* */ IntPtr path, CGRect bounds, /* NSDictionary * __nullable */ IntPtr documentInfo); - /// To be added. - /// To be added. - /// To be added. - /// Pushes a new PDF rendering context and make it the current graphics context. - /// - /// UIKit keeps a stack of image context, this method creates a new image context, makes it the default and places it at the top of the graphic context stacks. - /// To restore the previous graphics context, call the method. - /// You can get the current context by calling the method. - /// This function can only be invoked from the UI thread. - /// - public static void BeginPDFContext (string file, CGRect bounds, NSDictionary documentInfo) + /// Pushes a new PDF rendering context that writes to a file and makes it the current graphics context. + /// The path to the PDF file to create. + /// The bounds of the PDF page. + /// Optional dictionary containing PDF document metadata, or . + /// + /// UIKit keeps a stack of contexts. This method creates a new PDF context, makes it the default and places it at the top of the graphic context stack. + /// To close the PDF context and restore the previous graphics context, call the method. + /// This function can only be invoked from the UI thread. + /// + public static void BeginPDFContext (string file, CGRect bounds, NSDictionary? documentInfo) { using (var nsstr = new NSString (file)) { UIGraphicsBeginPDFContextToFile (nsstr.Handle, bounds, documentInfo is null ? IntPtr.Zero : documentInfo.Handle); @@ -208,17 +206,16 @@ public static void BeginPDFContext (string file, CGRect bounds, NSDictionary doc } } - /// To be added. - /// To be added. - /// To be added. - /// Pushes a new PDF rendering context and make it the current graphics context. - /// - /// UIKit keeps a stack of image context, this method creates a new image context, makes it the default and places it at the top of the graphic context stacks. - /// To restore the previous graphics context, call the method. - /// You can get the current context by calling the method. - /// This function can only be invoked from the UI thread. - /// - public static void BeginPDFContext (string file, CGRect bounds, CGPDFInfo documentInfo) + /// Pushes a new PDF rendering context that writes to a file and makes it the current graphics context. + /// The path to the PDF file to create. + /// The bounds of the PDF page. + /// Optional containing PDF document metadata, or . + /// + /// UIKit keeps a stack of contexts. This method creates a new PDF context, makes it the default and places it at the top of the graphic context stack. + /// To close the PDF context and restore the previous graphics context, call the method. + /// This function can only be invoked from the UI thread. + /// + public static void BeginPDFContext (string file, CGRect bounds, CGPDFInfo? documentInfo) { using (var dict = documentInfo is null ? null : documentInfo.ToDictionary ()) using (var nsstr = new NSString (file)) { @@ -230,17 +227,16 @@ public static void BeginPDFContext (string file, CGRect bounds, CGPDFInfo docume extern static void UIGraphicsBeginPDFContextToData (/* NSMutableData* */ IntPtr data, CGRect bounds, /* NSDictionary * __nullable */ IntPtr documentInfo); - /// To be added. - /// To be added. - /// To be added. - /// Pushes a new PDF rendering context and make it the current graphics context. - /// - /// UIKit keeps a stack of image context, this method creates a new image context, makes it the default and places it at the top of the graphic context stacks. - /// To restore the previous graphics context, call the method. - /// You can get the current context by calling the method. - /// This function can only be invoked from the UI thread. - /// - public static void BeginPDFContext (NSMutableData data, CGRect bounds, NSDictionary documentInfo) + /// Pushes a new PDF rendering context that writes to an object and makes it the current graphics context. + /// The mutable data object to write PDF output to. + /// The bounds of the PDF page. + /// Optional dictionary containing PDF document metadata, or . + /// + /// UIKit keeps a stack of contexts. This method creates a new PDF context, makes it the default and places it at the top of the graphic context stack. + /// To close the PDF context and restore the previous graphics context, call the method. + /// This function can only be invoked from the UI thread. + /// + public static void BeginPDFContext (NSMutableData data, CGRect bounds, NSDictionary? documentInfo) { UIGraphicsBeginPDFContextToData (data.Handle, bounds, documentInfo is null ? IntPtr.Zero : documentInfo.Handle); GC.KeepAlive (data); @@ -251,7 +247,7 @@ public static void BeginPDFContext (NSMutableData data, CGRect bounds, NSDiction extern static void UIGraphicsBeginPDFPage (); /// Starts a new page using the bounds from the initial PDF context. - /// Does nothing if the current context is not a PDF context + /// Does nothing if the current context is not a PDF context. public static void BeginPDFPage () { UIGraphicsBeginPDFPage (); @@ -260,10 +256,10 @@ public static void BeginPDFPage () [DllImport (Constants.UIKitLibrary)] extern static void UIGraphicsBeginPDFPageWithInfo (CGRect bounds, IntPtr info); - /// To be added. - /// To be added. - /// Starts a new page using the bounds from the initial PDF context. - /// Does nothing if the current context is not a PDF context + /// Starts a new page with the specified bounds and page information in the current PDF context. + /// The bounds of the new PDF page. + /// A dictionary containing page-specific metadata. + /// Does nothing if the current context is not a PDF context. public static void BeginPDFPage (CGRect bounds, NSDictionary pageInfo) { UIGraphicsBeginPDFPageWithInfo (bounds, pageInfo.Handle); @@ -273,6 +269,11 @@ public static void BeginPDFPage (CGRect bounds, NSDictionary pageInfo) [DllImport (Constants.UIKitLibrary)] extern static void UIGraphicsEndPDFContext (); + /// Closes the PDF context and pops it from the stack. + /// + /// UIKit keeps a stack of contexts. This method pops the current PDF context, and makes the new context at the top of the stack the new default context. + /// If the current context was not a PDF context, this method does nothing. + /// public static void EndPDFContext () { UIGraphicsEndPDFContext (); @@ -280,43 +281,42 @@ public static void EndPDFContext () #if !XAMCORE_5_0 /// Closes the PDF context and pops it from the stack. - /// - /// UIKit keeps a stack of contexts, this method pops the current PDF context, and makes the new context at the top of the stack, the new default context. - /// If the current context was not a PDF context this method does nothing. - /// + /// + /// UIKit keeps a stack of contexts. This method pops the current PDF context, and makes the new context at the top of the stack the new default context. + /// If the current context was not a PDF context, this method does nothing. + /// [EditorBrowsable (EditorBrowsableState.Never)] [Obsolete ("Use 'EndPDFContext' instead.")] public static void EndPDFContent () => EndPDFContext (); #endif /// Returns the contents of the current context as an image. - /// An image, or null on error - /// - /// This method is only valid if the current context (the context at the top of the stack) is an image context. - /// Developers can call this method from any thread. - /// + /// An image, or on error. + /// + /// This method is only valid if the current context (the context at the top of the stack) is an image context. + /// Developers can call this method from any thread. + /// [SupportedOSPlatform ("ios")] [SupportedOSPlatform ("tvos")] [SupportedOSPlatform ("maccatalyst")] [UnsupportedOSPlatform ("ios17.0")] [UnsupportedOSPlatform ("tvos17.0")] [UnsupportedOSPlatform ("maccatalyst17.0")] - public static UIImage GetImageFromCurrentImageContext () + public static UIImage? GetImageFromCurrentImageContext () { using (var pool = new NSAutoreleasePool ()) { var handle = UIGraphicsGetImageFromCurrentImageContext (); - return (UIImage) Runtime.GetNSObject (handle); + return Runtime.GetNSObject (handle) as UIImage; } } - /// Returns the current graphics context - /// - /// - /// - /// This returns the current graphics context (the context at the top of the stack). This is only valid after you have pushed a new graphics context with one of the methods in this class. - /// Developers can call this method from any thread. - /// - public static CGContext GetCurrentContext () + /// Returns the current graphics context. + /// The current , or if there is no current context. + /// + /// This returns the current graphics context (the context at the top of the stack). This is only valid after you have pushed a new graphics context with one of the methods in this class. + /// Developers can call this method from any thread. + /// + public static CGContext? GetCurrentContext () { var ctx = UIGraphicsGetCurrentContext (); @@ -326,11 +326,11 @@ public static CGContext GetCurrentContext () return new CGContext (ctx, false); } - /// To be added. - /// Manually pushes a CGContext into the UIKit graphics context stack. - /// - /// Developers can call this method from any thread. - /// + /// Manually pushes a into the UIKit graphics context stack. + /// The graphics context to push onto the stack. + /// + /// Developers can call this method from any thread. + /// public static void PushContext (CGContext ctx) { UIGraphicsPushContext (ctx.Handle); @@ -338,9 +338,9 @@ public static void PushContext (CGContext ctx) } /// Pops the top context and sets the previous context as the default context. - /// - /// Developers can call this method from any thread. - /// + /// + /// Developers can call this method from any thread. + /// public static void PopContext () { UIGraphicsPopContext (); diff --git a/src/UIKit/UIImage.cs b/src/UIKit/UIImage.cs index bd3abcd96401..f1d450beefe4 100644 --- a/src/UIKit/UIImage.cs +++ b/src/UIKit/UIImage.cs @@ -102,7 +102,7 @@ public void SaveToPhotosAlbum (SaveStatus status) [UnsupportedOSPlatform ("ios17.0")] [UnsupportedOSPlatform ("tvos17.0")] [UnsupportedOSPlatform ("maccatalyst17.0")] - public UIImage Scale (CGSize newSize, nfloat scaleFactor) + public UIImage? Scale (CGSize newSize, nfloat scaleFactor) { UIGraphics.BeginImageContextWithOptions (newSize, false, scaleFactor); @@ -126,7 +126,7 @@ public UIImage Scale (CGSize newSize, nfloat scaleFactor) [UnsupportedOSPlatform ("ios17.0")] [UnsupportedOSPlatform ("tvos17.0")] [UnsupportedOSPlatform ("maccatalyst17.0")] - public UIImage Scale (CGSize newSize) + public UIImage? Scale (CGSize newSize) { UIGraphics.BeginImageContext (newSize); diff --git a/tests/cecil-tests/Documentation.KnownFailures.txt b/tests/cecil-tests/Documentation.KnownFailures.txt index a8ec7d1aa4d6..4571f0774294 100644 --- a/tests/cecil-tests/Documentation.KnownFailures.txt +++ b/tests/cecil-tests/Documentation.KnownFailures.txt @@ -17138,8 +17138,6 @@ M:UIKit.UIFontPickerViewControllerDelegate_Extensions.DidCancel(UIKit.IUIFontPic M:UIKit.UIFontPickerViewControllerDelegate_Extensions.DidPickFont(UIKit.IUIFontPickerViewControllerDelegate,UIKit.UIFontPickerViewController) M:UIKit.UIGestureRecognizer.Dispose(System.Boolean) M:UIKit.UIGestureRecognizerDelegate_Extensions.ShouldReceiveEvent(UIKit.IUIGestureRecognizerDelegate,UIKit.UIGestureRecognizer,UIKit.UIEvent) -M:UIKit.UIGraphics.BeginImageContextWithOptions(CoreGraphics.CGSize,System.Boolean,System.Runtime.InteropServices.NFloat) -M:UIKit.UIGraphics.EndPDFContext M:UIKit.UIHoverGestureRecognizer.#ctor(System.Action) M:UIKit.UIHoverGestureRecognizer.#ctor(System.Action{UIKit.UIHoverGestureRecognizer}) M:UIKit.UIImage.AccessibilityActivate From 094b7263c493cd5e7f7cb312ce70572b2e1dac22 Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Tue, 10 Feb 2026 12:26:37 +0100 Subject: [PATCH 2/2] Fix according to reviews, and a couple of other tweaks. --- src/UIKit/UIGraphics.cs | 14 ++++++++------ src/UIKit/UIImage.cs | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/UIKit/UIGraphics.cs b/src/UIKit/UIGraphics.cs index 289f6871b91f..af2774204d76 100644 --- a/src/UIKit/UIGraphics.cs +++ b/src/UIKit/UIGraphics.cs @@ -70,7 +70,7 @@ public static class UIGraphics { /// /// UIKit keeps a stack of image contexts. This method creates a new image context, makes it the default and places it at the top of the graphic context stack. /// To restore the previous graphics context, call the method. - /// You can get the current context by calling the method. + /// You can get the image from the current image context by calling the method. /// Developers can call this method from any thread. /// [SupportedOSPlatform ("ios")] @@ -98,7 +98,7 @@ public static class UIGraphics { /// /// UIKit keeps a stack of image contexts. This method creates a new image context, makes it the default and places it at the top of the graphic context stack. /// To restore the previous graphics context, call the method. - /// You can get the current context by calling the method. + /// You can get the image from the current image context by calling the method. /// Developers can call this method from any thread. /// [SupportedOSPlatform ("ios")] @@ -201,7 +201,7 @@ extern static void UIGraphicsBeginPDFContextToFile (/* NSString* */ IntPtr path, public static void BeginPDFContext (string file, CGRect bounds, NSDictionary? documentInfo) { using (var nsstr = new NSString (file)) { - UIGraphicsBeginPDFContextToFile (nsstr.Handle, bounds, documentInfo is null ? IntPtr.Zero : documentInfo.Handle); + UIGraphicsBeginPDFContextToFile (nsstr.Handle, bounds, documentInfo.GetHandle ()); GC.KeepAlive (documentInfo); } } @@ -217,9 +217,9 @@ public static void BeginPDFContext (string file, CGRect bounds, NSDictionary? do /// public static void BeginPDFContext (string file, CGRect bounds, CGPDFInfo? documentInfo) { - using (var dict = documentInfo is null ? null : documentInfo.ToDictionary ()) + using (var dict = documentInfo?.ToDictionary ()) using (var nsstr = new NSString (file)) { - UIGraphicsBeginPDFContextToFile (nsstr.Handle, bounds, dict is null ? IntPtr.Zero : dict.Handle); + UIGraphicsBeginPDFContextToFile (nsstr.Handle, bounds, dict.GetHandle ()); } } @@ -238,7 +238,9 @@ extern static void UIGraphicsBeginPDFContextToData (/* NSMutableData* */ IntPtr /// public static void BeginPDFContext (NSMutableData data, CGRect bounds, NSDictionary? documentInfo) { - UIGraphicsBeginPDFContextToData (data.Handle, bounds, documentInfo is null ? IntPtr.Zero : documentInfo.Handle); + System.ArgumentNullException.ThrowIfNull (data); + + UIGraphicsBeginPDFContextToData (data.Handle, bounds, documentInfo.GetHandle ()); GC.KeepAlive (data); GC.KeepAlive (documentInfo); } diff --git a/src/UIKit/UIImage.cs b/src/UIKit/UIImage.cs index f1d450beefe4..beefd03dc40b 100644 --- a/src/UIKit/UIImage.cs +++ b/src/UIKit/UIImage.cs @@ -92,7 +92,7 @@ public void SaveToPhotosAlbum (SaveStatus status) /// Scales the image up or down. /// The desired size for the scaled image. /// Scale factor to apply to the scaled image. If the value specified is zero, the device's scale factor is used. - /// The scaled image. + /// The scaled image, or in case of failure. /// /// This can be used from a background thread. /// @@ -116,7 +116,7 @@ public void SaveToPhotosAlbum (SaveStatus status) /// Scales the image up or down. /// The desired size for the scaled image. - /// The scaled image. + /// The scaled image, or in case of failure. /// /// This can be used from a background thread. ///