1 // 2 // System.Drawing.carbonFunctions.cs 3 // 4 // Authors: 5 // Geoff Norton (gnorton@customerdna.com> 6 // 7 // Copyright (C) 2007 Novell, Inc. (http://www.novell.com) 8 // 9 // Permission is hereby granted, free of charge, to any person obtaining 10 // a copy of this software and associated documentation files (the 11 // "Software"), to deal in the Software without restriction, including 12 // without limitation the rights to use, copy, modify, merge, publish, 13 // distribute, sublicense, and/or sell copies of the Software, and to 14 // permit persons to whom the Software is furnished to do so, subject to 15 // the following conditions: 16 // 17 // The above copyright notice and this permission notice shall be 18 // included in all copies or substantial portions of the Software. 19 // 20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 // 28 #undef DEBUG_CLIPPING 29 30 using System.Collections; 31 using System.Reflection; 32 using System.Runtime.InteropServices; 33 using System.Security; 34 35 namespace System.Drawing { 36 37 internal static class MacSupport { 38 internal static Hashtable contextReference = new Hashtable (); 39 internal static object lockobj = new object (); 40 41 internal static Delegate hwnd_delegate; 42 43 #if DEBUG_CLIPPING 44 internal static float red = 1.0f; 45 internal static float green = 0.0f; 46 internal static float blue = 0.0f; 47 internal static int debug_threshold = 1; 48 #endif 49 MacSupport()50 static MacSupport () { 51 #if !NETSTANDARD1_6 52 foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies ()) { 53 if (String.Equals (asm.GetName ().Name, "System.Windows.Forms")) { 54 Type driver_type = asm.GetType ("System.Windows.Forms.XplatUICarbon"); 55 if (driver_type != null) { 56 hwnd_delegate = (Delegate) driver_type.GetTypeInfo() .GetField ("HwndDelegate", BindingFlags.NonPublic | BindingFlags.Static).GetValue (null); 57 } 58 } 59 } 60 #endif 61 } 62 GetCGContextForNSView(IntPtr handle)63 internal static CocoaContext GetCGContextForNSView (IntPtr handle) { 64 IntPtr graphicsContext = objc_msgSend (objc_getClass ("NSGraphicsContext"), sel_registerName ("currentContext")); 65 IntPtr ctx = objc_msgSend (graphicsContext, sel_registerName ("graphicsPort")); 66 Rect bounds = new Rect (); 67 68 CGContextSaveGState (ctx); 69 70 objc_msgSend_stret (ref bounds, handle, sel_registerName ("bounds")); 71 72 var isFlipped = bool_objc_msgSend (handle, sel_registerName ("isFlipped")); 73 if (isFlipped) { 74 CGContextTranslateCTM (ctx, bounds.origin.x, bounds.size.height); 75 CGContextScaleCTM (ctx,1.0f,-1.0f); 76 } 77 78 return new CocoaContext (ctx, (int) bounds.size.width, (int) bounds.size.height); 79 } 80 GetCGContextForView(IntPtr handle)81 internal static CarbonContext GetCGContextForView (IntPtr handle) { 82 IntPtr context = IntPtr.Zero; 83 IntPtr port = IntPtr.Zero; 84 IntPtr window = IntPtr.Zero; 85 86 window = GetControlOwner (handle); 87 88 if (handle == IntPtr.Zero || window == IntPtr.Zero) { 89 // FIXME: Can we actually get a CGContextRef for the desktop? this makes context IntPtr.Zero 90 port = GetQDGlobalsThePort (); 91 CreateCGContextForPort (port, ref context); 92 93 Rect desktop_bounds = CGDisplayBounds (CGMainDisplayID ()); 94 95 return new CarbonContext (port, context, (int)desktop_bounds.size.width, (int)desktop_bounds.size.height); 96 } 97 98 QDRect window_bounds = new QDRect (); 99 Rect view_bounds = new Rect (); 100 101 port = GetWindowPort (window); 102 103 context = GetContext (port); 104 105 GetWindowBounds (window, 32, ref window_bounds); 106 107 HIViewGetBounds (handle, ref view_bounds); 108 109 HIViewConvertRect (ref view_bounds, handle, IntPtr.Zero); 110 111 if (view_bounds.size.height < 0) view_bounds.size.height = 0; 112 if (view_bounds.size.width < 0) view_bounds.size.width = 0; 113 114 CGContextTranslateCTM (context, view_bounds.origin.x, (window_bounds.bottom - window_bounds.top) - (view_bounds.origin.y + view_bounds.size.height)); 115 116 // Create the original rect path and clip to it 117 Rect rc_clip = new Rect (0, 0, view_bounds.size.width, view_bounds.size.height); 118 119 CGContextSaveGState (context); 120 121 Rectangle [] clip_rectangles = (Rectangle []) hwnd_delegate.DynamicInvoke (new object [] {handle}); 122 if (clip_rectangles != null && clip_rectangles.Length > 0) { 123 int length = clip_rectangles.Length; 124 125 CGContextBeginPath (context); 126 CGContextAddRect (context, rc_clip); 127 128 for (int i = 0; i < length; i++) { 129 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)); 130 } 131 CGContextClosePath (context); 132 CGContextEOClip (context); 133 #if DEBUG_CLIPPING 134 if (clip_rectangles.Length >= debug_threshold) { 135 CGContextSetRGBFillColor (context, red, green, blue, 0.5f); 136 CGContextFillRect (context, rc_clip); 137 CGContextFlush (context); 138 System.Threading.Thread.Sleep (500); 139 if (red == 1.0f) { red = 0.0f; blue = 1.0f; } 140 else if (blue == 1.0f) { blue = 0.0f; green = 1.0f; } 141 else if (green == 1.0f) { green = 0.0f; red = 1.0f; } 142 } 143 #endif 144 } else { 145 CGContextBeginPath (context); 146 CGContextAddRect (context, rc_clip); 147 CGContextClosePath (context); 148 CGContextClip (context); 149 } 150 151 return new CarbonContext (port, context, (int)view_bounds.size.width, (int)view_bounds.size.height); 152 } 153 GetContext(IntPtr port)154 internal static IntPtr GetContext (IntPtr port) { 155 IntPtr context = IntPtr.Zero; 156 157 lock (lockobj) { 158 #if FALSE 159 if (contextReference [port] != null) { 160 CreateCGContextForPort (port, ref context); 161 } else { 162 QDBeginCGContext (port, ref context); 163 contextReference [port] = context; 164 } 165 #else 166 CreateCGContextForPort (port, ref context); 167 #endif 168 } 169 170 return context; 171 } 172 ReleaseContext(IntPtr port, IntPtr context)173 internal static void ReleaseContext (IntPtr port, IntPtr context) { 174 CGContextRestoreGState (context); 175 176 lock (lockobj) { 177 #if FALSE 178 if (contextReference [port] != null && context == (IntPtr) contextReference [port]) { 179 QDEndCGContext (port, ref context); 180 contextReference [port] = null; 181 } else { 182 CFRelease (context); 183 } 184 #else 185 CFRelease (context); 186 #endif 187 } 188 } 189 190 #region Cocoa Methods 191 [DllImport("libobjc.dylib")] objc_getClass(string className)192 public static extern IntPtr objc_getClass(string className); 193 [DllImport("libobjc.dylib")] objc_msgSend(IntPtr basePtr, IntPtr selector, string argument)194 public static extern IntPtr objc_msgSend(IntPtr basePtr, IntPtr selector, string argument); 195 [DllImport("libobjc.dylib")] objc_msgSend(IntPtr basePtr, IntPtr selector)196 public static extern IntPtr objc_msgSend(IntPtr basePtr, IntPtr selector); 197 [DllImport("libobjc.dylib")] objc_msgSend_stret(ref Rect arect, IntPtr basePtr, IntPtr selector)198 public static extern void objc_msgSend_stret(ref Rect arect, IntPtr basePtr, IntPtr selector); 199 [DllImport ("libobjc.dylib", EntryPoint = "objc_msgSend")] bool_objc_msgSend(IntPtr handle, IntPtr selector)200 public static extern bool bool_objc_msgSend (IntPtr handle, IntPtr selector); 201 [DllImport("libobjc.dylib")] sel_registerName(string selectorName)202 public static extern IntPtr sel_registerName(string selectorName); 203 #endregion 204 205 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGMainDisplayID()206 internal static extern IntPtr CGMainDisplayID (); 207 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGDisplayBounds(IntPtr display)208 internal static extern Rect CGDisplayBounds (IntPtr display); 209 210 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] HIViewGetBounds(IntPtr vHnd, ref Rect r)211 internal static extern int HIViewGetBounds (IntPtr vHnd, ref Rect r); 212 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] HIViewConvertRect(ref Rect r, IntPtr a, IntPtr b)213 internal static extern int HIViewConvertRect (ref Rect r, IntPtr a, IntPtr b); 214 215 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] GetControlOwner(IntPtr aView)216 internal static extern IntPtr GetControlOwner (IntPtr aView); 217 218 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] GetWindowBounds(IntPtr wHnd, uint reg, ref QDRect rect)219 internal static extern int GetWindowBounds (IntPtr wHnd, uint reg, ref QDRect rect); 220 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] GetWindowPort(IntPtr hWnd)221 internal static extern IntPtr GetWindowPort (IntPtr hWnd); 222 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] GetQDGlobalsThePort()223 internal static extern IntPtr GetQDGlobalsThePort (); 224 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CreateCGContextForPort(IntPtr port, ref IntPtr context)225 internal static extern void CreateCGContextForPort (IntPtr port, ref IntPtr context); 226 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CFRelease(IntPtr context)227 internal static extern void CFRelease (IntPtr context); 228 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] QDBeginCGContext(IntPtr port, ref IntPtr context)229 internal static extern void QDBeginCGContext (IntPtr port, ref IntPtr context); 230 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] QDEndCGContext(IntPtr port, ref IntPtr context)231 internal static extern void QDEndCGContext (IntPtr port, ref IntPtr context); 232 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGContextClipToRect(IntPtr context, Rect clip)233 internal static extern int CGContextClipToRect (IntPtr context, Rect clip); 234 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGContextClipToRects(IntPtr context, Rect [] clip_rects, int count)235 internal static extern int CGContextClipToRects (IntPtr context, Rect [] clip_rects, int count); 236 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGContextTranslateCTM(IntPtr context, float tx, float ty)237 internal static extern void CGContextTranslateCTM (IntPtr context, float tx, float ty); 238 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGContextScaleCTM(IntPtr context, float x, float y)239 internal static extern void CGContextScaleCTM (IntPtr context, float x, float y); 240 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGContextFlush(IntPtr context)241 internal static extern void CGContextFlush (IntPtr context); 242 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGContextSynchronize(IntPtr context)243 internal static extern void CGContextSynchronize (IntPtr context); 244 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGPathCreateMutable()245 internal static extern IntPtr CGPathCreateMutable (); 246 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGPathAddRects(IntPtr path, IntPtr _void, Rect [] rects, int count)247 internal static extern void CGPathAddRects (IntPtr path, IntPtr _void, Rect [] rects, int count); 248 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGPathAddRect(IntPtr path, IntPtr _void, Rect rect)249 internal static extern void CGPathAddRect (IntPtr path, IntPtr _void, Rect rect); 250 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGContextAddRects(IntPtr context, Rect [] rects, int count)251 internal static extern void CGContextAddRects (IntPtr context, Rect [] rects, int count); 252 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGContextAddRect(IntPtr context, Rect rect)253 internal static extern void CGContextAddRect (IntPtr context, Rect rect); 254 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGContextBeginPath(IntPtr context)255 internal static extern void CGContextBeginPath (IntPtr context); 256 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGContextClosePath(IntPtr context)257 internal static extern void CGContextClosePath (IntPtr context); 258 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGContextAddPath(IntPtr context, IntPtr path)259 internal static extern void CGContextAddPath (IntPtr context, IntPtr path); 260 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGContextClip(IntPtr context)261 internal static extern void CGContextClip (IntPtr context); 262 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGContextEOClip(IntPtr context)263 internal static extern void CGContextEOClip (IntPtr context); 264 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGContextEOFillPath(IntPtr context)265 internal static extern void CGContextEOFillPath (IntPtr context); 266 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGContextSaveGState(IntPtr context)267 internal static extern void CGContextSaveGState (IntPtr context); 268 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGContextRestoreGState(IntPtr context)269 internal static extern void CGContextRestoreGState (IntPtr context); 270 271 #if DEBUG_CLIPPING 272 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGContextSetRGBFillColor(IntPtr context, float red, float green, float blue, float alpha)273 internal static extern void CGContextSetRGBFillColor (IntPtr context, float red, float green, float blue, float alpha); 274 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] CGContextFillRect(IntPtr context, Rect rect)275 internal static extern void CGContextFillRect (IntPtr context, Rect rect); 276 #endif 277 } 278 279 internal struct CGSize { 280 public float width; 281 public float height; 282 } 283 284 internal struct CGPoint { 285 public float x; 286 public float y; 287 } 288 289 internal struct Rect { RectSystem.Drawing.Rect290 public Rect (float x, float y, float width, float height) { 291 this.origin.x = x; 292 this.origin.y = y; 293 this.size.width = width; 294 this.size.height = height; 295 } 296 297 public CGPoint origin; 298 public CGSize size; 299 } 300 301 internal struct QDRect 302 { 303 public short top; 304 public short left; 305 public short bottom; 306 public short right; 307 } 308 309 internal struct CarbonContext : IMacContext 310 { 311 public IntPtr port; 312 public IntPtr ctx; 313 public int width; 314 public int height; 315 CarbonContextSystem.Drawing.CarbonContext316 public CarbonContext (IntPtr port, IntPtr ctx, int width, int height) 317 { 318 this.port = port; 319 this.ctx = ctx; 320 this.width = width; 321 this.height = height; 322 } 323 SynchronizeSystem.Drawing.CarbonContext324 public void Synchronize () 325 { 326 MacSupport.CGContextSynchronize (ctx); 327 } 328 ReleaseSystem.Drawing.CarbonContext329 public void Release () 330 { 331 MacSupport.ReleaseContext (port, ctx); 332 } 333 } 334 335 internal struct CocoaContext : IMacContext 336 { 337 public IntPtr ctx; 338 public int width; 339 public int height; 340 CocoaContextSystem.Drawing.CocoaContext341 public CocoaContext (IntPtr ctx, int width, int height) 342 { 343 this.ctx = ctx; 344 this.width = width; 345 this.height = height; 346 } 347 SynchronizeSystem.Drawing.CocoaContext348 public void Synchronize () 349 { 350 MacSupport.CGContextSynchronize (ctx); 351 } 352 ReleaseSystem.Drawing.CocoaContext353 public void Release () 354 { 355 MacSupport.CGContextRestoreGState(ctx); 356 } 357 } 358 359 internal interface IMacContext 360 { Synchronize()361 void Synchronize (); Release()362 void Release (); 363 } 364 } 365