diff options
author | Filip Navara <filip.navara@gmail.com> | 2018-08-01 13:47:47 +0300 |
---|---|---|
committer | Alexander Köplinger <alex.koeplinger@outlook.com> | 2018-08-01 13:47:47 +0300 |
commit | 60b95ba08d3373377a24a608ea9983471a7eeb3c (patch) | |
tree | f97b384685aac51ed07c8a40ae831630b285b008 /mcs/class/System.Drawing | |
parent | 92d567c89baf698e4abc7ed4a152ed8a6e1e243a (diff) |
Fix System.Drawing on 64-bit macOS. (#9824)
Carbon implementation now throws exception instead of crashing in the mismatched p/invoke calls.
Cocoa implementation now support 64-bit mode and uses the handle of `NSView` that is passed in instead of relying on `NSGraphicsContext.CurrentContext`. It also fixes handling of flipped views.
Requires up to date libgdiplus.
Diffstat (limited to 'mcs/class/System.Drawing')
-rw-r--r-- | mcs/class/System.Drawing/System.Drawing/Graphics.cs | 4 | ||||
-rw-r--r-- | mcs/class/System.Drawing/System.Drawing/macFunctions.cs | 150 |
2 files changed, 107 insertions, 47 deletions
diff --git a/mcs/class/System.Drawing/System.Drawing/Graphics.cs b/mcs/class/System.Drawing/System.Drawing/Graphics.cs index 15df9cd343c..eb2a8836150 100644 --- a/mcs/class/System.Drawing/System.Drawing/Graphics.cs +++ b/mcs/class/System.Drawing/System.Drawing/Graphics.cs @@ -1710,6 +1710,10 @@ namespace System.Drawing IntPtr graphics; if (GDIPlus.UseCocoaDrawable) { + if (hwnd == IntPtr.Zero) { + throw new NotSupportedException ("Opening display graphics is not supported"); + } + CocoaContext context = MacSupport.GetCGContextForNSView (hwnd); GDIPlus.GdipCreateFromContext_macosx (context.ctx, context.width, context.height, out graphics); diff --git a/mcs/class/System.Drawing/System.Drawing/macFunctions.cs b/mcs/class/System.Drawing/System.Drawing/macFunctions.cs index 623bc06a30e..fa990f3b51a 100644 --- a/mcs/class/System.Drawing/System.Drawing/macFunctions.cs +++ b/mcs/class/System.Drawing/System.Drawing/macFunctions.cs @@ -61,21 +61,46 @@ namespace System.Drawing { } internal static CocoaContext GetCGContextForNSView (IntPtr handle) { - IntPtr graphicsContext = objc_msgSend (objc_getClass ("NSGraphicsContext"), sel_registerName ("currentContext")); + if (handle == IntPtr.Zero) { + return null; + } + + IntPtr focusView = objc_msgSend (objc_getClass ("NSView"), sel_registerName ("focusView")); + IntPtr focusHandle = IntPtr.Zero; + if (focusView != handle) { + if (!bool_objc_msgSend (handle, sel_registerName ("lockFocusIfCanDraw"))) + return null; + + focusHandle = handle; + } + + IntPtr windowHandle = objc_msgSend (handle, sel_registerName ("window")); + IntPtr graphicsContext = objc_msgSend (windowHandle, sel_registerName ("graphicsContext")); IntPtr ctx = objc_msgSend (graphicsContext, sel_registerName ("graphicsPort")); - Rect bounds = new Rect (); + bool isFlipped = bool_objc_msgSend (handle, sel_registerName ("isFlipped")); + Size size; CGContextSaveGState (ctx); - objc_msgSend_stret (ref bounds, handle, sel_registerName ("bounds")); - - var isFlipped = bool_objc_msgSend (handle, sel_registerName ("isFlipped")); - if (isFlipped) { - CGContextTranslateCTM (ctx, bounds.origin.x, bounds.size.height); - CGContextScaleCTM (ctx,1.0f,-1.0f); + if (IntPtr.Size == 4) { + CGRect32 bounds = new CGRect32 (); + objc_msgSend_stret (ref bounds, handle, sel_registerName ("bounds")); + if (isFlipped) { + CGContextTranslateCTM32 (ctx, bounds.origin.x, bounds.size.height); + CGContextScaleCTM32 (ctx, 1.0f, -1.0f); + } + size = new Size ((int) bounds.size.width, (int) bounds.size.height); + } else { + CGRect64 bounds = new CGRect64 (); + objc_msgSend_stret (ref bounds, handle, sel_registerName ("bounds")); + if (isFlipped) { + CGContextTranslateCTM64 (ctx, bounds.origin.x, bounds.size.height); + CGContextScaleCTM64 (ctx, 1.0f, -1.0f); + } + size = new Size ((int) bounds.size.width, (int) bounds.size.height); } - return new CocoaContext (ctx, (int) bounds.size.width, (int) bounds.size.height); + return new CocoaContext (focusHandle, ctx, size.Width, size.Height); } internal static CarbonContext GetCGContextForView (IntPtr handle) { @@ -83,6 +108,9 @@ namespace System.Drawing { IntPtr port = IntPtr.Zero; IntPtr window = IntPtr.Zero; + if (IntPtr.Size == 8) + throw new NotSupportedException (); + window = GetControlOwner (handle); if (handle == IntPtr.Zero || window == IntPtr.Zero) { @@ -90,13 +118,13 @@ namespace System.Drawing { port = GetQDGlobalsThePort (); CreateCGContextForPort (port, ref context); - Rect desktop_bounds = CGDisplayBounds (CGMainDisplayID ()); + CGRect32 desktop_bounds = CGDisplayBounds32 (CGMainDisplayID ()); return new CarbonContext (port, context, (int)desktop_bounds.size.width, (int)desktop_bounds.size.height); } QDRect window_bounds = new QDRect (); - Rect view_bounds = new Rect (); + CGRect32 view_bounds = new CGRect32 (); port = GetWindowPort (window); @@ -111,10 +139,10 @@ namespace System.Drawing { if (view_bounds.size.height < 0) view_bounds.size.height = 0; if (view_bounds.size.width < 0) view_bounds.size.width = 0; - CGContextTranslateCTM (context, view_bounds.origin.x, (window_bounds.bottom - window_bounds.top) - (view_bounds.origin.y + view_bounds.size.height)); + CGContextTranslateCTM32 (context, view_bounds.origin.x, (window_bounds.bottom - window_bounds.top) - (view_bounds.origin.y + view_bounds.size.height)); // Create the original rect path and clip to it - Rect rc_clip = new Rect (0, 0, view_bounds.size.width, view_bounds.size.height); + CGRect32 rc_clip = new CGRect32 (0, 0, view_bounds.size.width, view_bounds.size.height); CGContextSaveGState (context); @@ -123,10 +151,10 @@ namespace System.Drawing { int length = clip_rectangles.Length; CGContextBeginPath (context); - CGContextAddRect (context, rc_clip); + CGContextAddRect32 (context, rc_clip); for (int i = 0; i < length; i++) { - CGContextAddRect (context, new Rect (clip_rectangles [i].X, view_bounds.size.height - clip_rectangles [i].Y - clip_rectangles [i].Height, clip_rectangles [i].Width, clip_rectangles [i].Height)); + CGContextAddRect32 (context, new CGRect32 (clip_rectangles [i].X, view_bounds.size.height - clip_rectangles [i].Y - clip_rectangles [i].Height, clip_rectangles [i].Width, clip_rectangles [i].Height)); } CGContextClosePath (context); CGContextEOClip (context); @@ -143,7 +171,7 @@ namespace System.Drawing { #endif } else { CGContextBeginPath (context); - CGContextAddRect (context, rc_clip); + CGContextAddRect32 (context, rc_clip); CGContextClosePath (context); CGContextClip (context); } @@ -195,22 +223,26 @@ namespace System.Drawing { [DllImport("libobjc.dylib")] public static extern IntPtr objc_msgSend(IntPtr basePtr, IntPtr selector); [DllImport("libobjc.dylib")] - public static extern void objc_msgSend_stret(ref Rect arect, IntPtr basePtr, IntPtr selector); + public static extern void objc_msgSend_stret(ref CGRect32 arect, IntPtr basePtr, IntPtr selector); + [DllImport("libobjc.dylib")] + public static extern void objc_msgSend_stret(ref CGRect64 arect, IntPtr basePtr, IntPtr selector); [DllImport ("libobjc.dylib", EntryPoint = "objc_msgSend")] public static extern bool bool_objc_msgSend (IntPtr handle, IntPtr selector); + [DllImport ("libobjc.dylib", EntryPoint = "objc_msgSend")] + public static extern bool bool_objc_msgSend_IntPtr (IntPtr handle, IntPtr selector, IntPtr argument); [DllImport("libobjc.dylib")] public static extern IntPtr sel_registerName(string selectorName); #endregion [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] internal static extern IntPtr CGMainDisplayID (); - [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] - internal static extern Rect CGDisplayBounds (IntPtr display); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon", EntryPoint = "CGDisplayBounds")] + internal static extern CGRect32 CGDisplayBounds32 (IntPtr display); [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] - internal static extern int HIViewGetBounds (IntPtr vHnd, ref Rect r); + internal static extern int HIViewGetBounds (IntPtr vHnd, ref CGRect32 r); [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] - internal static extern int HIViewConvertRect (ref Rect r, IntPtr a, IntPtr b); + internal static extern int HIViewConvertRect (ref CGRect32 r, IntPtr a, IntPtr b); [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] internal static extern IntPtr GetControlOwner (IntPtr aView); @@ -229,28 +261,22 @@ namespace System.Drawing { internal static extern void QDBeginCGContext (IntPtr port, ref IntPtr context); [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] internal static extern void QDEndCGContext (IntPtr port, ref IntPtr context); - [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] - internal static extern int CGContextClipToRect (IntPtr context, Rect clip); - [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] - internal static extern int CGContextClipToRects (IntPtr context, Rect [] clip_rects, int count); - [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] - internal static extern void CGContextTranslateCTM (IntPtr context, float tx, float ty); - [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] - internal static extern void CGContextScaleCTM (IntPtr context, float x, float y); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon", EntryPoint = "CGContextTranslateCTM")] + internal static extern void CGContextTranslateCTM32 (IntPtr context, float tx, float ty); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon", EntryPoint = "CGContextScaleCTM")] + internal static extern void CGContextScaleCTM32 (IntPtr context, float x, float y); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon", EntryPoint = "CGContextTranslateCTM")] + internal static extern void CGContextTranslateCTM64 (IntPtr context, double tx, double ty); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon", EntryPoint = "CGContextScaleCTM")] + internal static extern void CGContextScaleCTM64 (IntPtr context, double x, double y); [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] internal static extern void CGContextFlush (IntPtr context); [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] internal static extern void CGContextSynchronize (IntPtr context); [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] internal static extern IntPtr CGPathCreateMutable (); - [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] - internal static extern void CGPathAddRects (IntPtr path, IntPtr _void, Rect [] rects, int count); - [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] - internal static extern void CGPathAddRect (IntPtr path, IntPtr _void, Rect rect); - [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] - internal static extern void CGContextAddRects (IntPtr context, Rect [] rects, int count); - [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] - internal static extern void CGContextAddRect (IntPtr context, Rect rect); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon", EntryPoint = "CGContextAddRect")] + internal static extern void CGContextAddRect32 (IntPtr context, CGRect32 rect); [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] internal static extern void CGContextBeginPath (IntPtr context); [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] @@ -272,30 +298,52 @@ namespace System.Drawing { [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] internal static extern void CGContextSetRGBFillColor (IntPtr context, float red, float green, float blue, float alpha); [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] - internal static extern void CGContextFillRect (IntPtr context, Rect rect); + internal static extern void CGContextFillRect (IntPtr context, CGRect32 rect); #endif } - internal struct CGSize { + internal struct CGSize32 { public float width; public float height; } - internal struct CGPoint { + internal struct CGPoint32 { public float x; public float y; } - internal struct Rect { - public Rect (float x, float y, float width, float height) { + internal struct CGRect32 { + public CGRect32 (float x, float y, float width, float height) { this.origin.x = x; this.origin.y = y; this.size.width = width; this.size.height = height; } - public CGPoint origin; - public CGSize size; + public CGPoint32 origin; + public CGSize32 size; + } + + internal struct CGSize64 { + public double width; + public double height; + } + + internal struct CGPoint64 { + public double x; + public double y; + } + + internal struct CGRect64 { + public CGRect64 (double x, double y, double width, double height) { + this.origin.x = x; + this.origin.y = y; + this.size.width = width; + this.size.height = height; + } + + public CGPoint64 origin; + public CGSize64 size; } internal struct QDRect @@ -332,14 +380,16 @@ namespace System.Drawing { } } - internal struct CocoaContext : IMacContext + internal class CocoaContext : IMacContext { + public IntPtr focusHandle; public IntPtr ctx; public int width; public int height; - public CocoaContext (IntPtr ctx, int width, int height) + public CocoaContext (IntPtr focusHandle, IntPtr ctx, int width, int height) { + this.focusHandle = focusHandle; this.ctx = ctx; this.width = width; this.height = height; @@ -352,7 +402,13 @@ namespace System.Drawing { public void Release () { - MacSupport.CGContextRestoreGState(ctx); + if (IntPtr.Zero != focusHandle) + MacSupport.CGContextFlush (ctx); + + MacSupport.CGContextRestoreGState (ctx); + + if (IntPtr.Zero != focusHandle) + MacSupport.objc_msgSend (focusHandle, MacSupport.sel_registerName ("unlockFocus")); } } |