Merge branch 'master' of github.com:mono/mono into masterwork
[mono.git] / mcs / class / System.Drawing / System.Drawing / macFunctions.cs
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         [SuppressUnmanagedCodeSecurity]
38 #if NET_2_0
39         internal static class MacSupport {
40 #else
41         internal sealed class MacSupport {
42 #endif
43                 internal static Hashtable contextReference = new Hashtable ();
44                 internal static object lockobj = new object ();
45
46                 internal static Delegate hwnd_delegate;
47
48 #if DEBUG_CLIPPING
49                 internal static float red = 1.0f;
50                 internal static float green = 0.0f;
51                 internal static float blue = 0.0f;
52                 internal static int debug_threshold = 1;
53 #endif
54
55                 static MacSupport () {
56                         foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies ()) {
57                                 if (String.Equals (asm.GetName ().Name, "System.Windows.Forms")) {
58                                         Type driver_type = asm.GetType ("System.Windows.Forms.XplatUICarbon");
59                                         if (driver_type != null) {
60                                                 hwnd_delegate = (Delegate) driver_type.GetField ("HwndDelegate", BindingFlags.NonPublic | BindingFlags.Static).GetValue (null);
61                                         }
62                                 }
63                         }
64                 }
65
66                 internal static CocoaContext GetCGContextForNSView (IntPtr handle) {
67                         IntPtr graphicsContext = objc_msgSend (objc_getClass ("NSGraphicsContext"), sel_registerName ("currentContext"));
68                         IntPtr ctx = objc_msgSend (graphicsContext, sel_registerName ("graphicsPort"));
69                         Rect bounds = new Rect ();
70
71                         objc_msgSend_stret (ref bounds, handle, sel_registerName ("bounds"));
72
73                         var isFlipped = bool_objc_msgSend (handle, sel_registerName ("isFlipped"));
74                         if (isFlipped) {
75                                 CGContextSaveGState (ctx);
76                                 CGContextTranslateCTM (ctx, bounds.origin.x, bounds.size.height);
77                                 CGContextScaleCTM (ctx,1.0f,-1.0f);
78                         }
79
80                         return new CocoaContext (ctx, (int) bounds.size.width, (int) bounds.size.height);
81                 }
82
83                 internal static CarbonContext GetCGContextForView (IntPtr handle) {
84                         IntPtr context = IntPtr.Zero;
85                         IntPtr port = IntPtr.Zero;
86                         IntPtr window = IntPtr.Zero;
87
88                         window = GetControlOwner (handle);
89
90                         if (handle == IntPtr.Zero || window == IntPtr.Zero) {
91                                 // FIXME: Can we actually get a CGContextRef for the desktop?  this makes context IntPtr.Zero
92                                 port = GetQDGlobalsThePort ();
93                                 CreateCGContextForPort (port, ref context);
94
95                                 Rect desktop_bounds = CGDisplayBounds (CGMainDisplayID ());
96
97                                 return new CarbonContext (port, context, (int)desktop_bounds.size.width, (int)desktop_bounds.size.height);
98                         }
99
100                         QDRect window_bounds = new QDRect ();
101                         Rect view_bounds = new Rect ();
102
103                         port = GetWindowPort (window);
104                         
105                         context = GetContext (port);
106
107                         GetWindowBounds (window, 32, ref window_bounds);
108
109                         HIViewGetBounds (handle, ref view_bounds);
110
111                         HIViewConvertRect (ref view_bounds, handle, IntPtr.Zero);
112                         
113                         if (view_bounds.size.height < 0) view_bounds.size.height = 0;
114                         if (view_bounds.size.width < 0) view_bounds.size.width = 0;
115
116                         CGContextTranslateCTM (context, view_bounds.origin.x, (window_bounds.bottom - window_bounds.top) - (view_bounds.origin.y + view_bounds.size.height));
117
118                         // Create the original rect path and clip to it
119                         Rect rc_clip = new Rect (0, 0, view_bounds.size.width, view_bounds.size.height);
120
121                         CGContextSaveGState (context);
122
123                         Rectangle [] clip_rectangles = (Rectangle []) hwnd_delegate.DynamicInvoke (new object [] {handle});
124                         if (clip_rectangles != null && clip_rectangles.Length > 0) {
125                                 int length = clip_rectangles.Length;
126                                 
127                                 CGContextBeginPath (context);
128                                 CGContextAddRect (context, rc_clip);
129
130                                 for (int i = 0; i < length; i++) {
131                                         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));
132                                 }
133                                 CGContextClosePath (context);
134                                 CGContextEOClip (context);
135 #if DEBUG_CLIPPING
136                                 if (clip_rectangles.Length >= debug_threshold) {
137                                         CGContextSetRGBFillColor (context, red, green, blue, 0.5f);
138                                         CGContextFillRect (context, rc_clip);
139                                         CGContextFlush (context);
140                                         System.Threading.Thread.Sleep (500);
141                                         if (red == 1.0f) { red = 0.0f; blue = 1.0f; } 
142                                         else if (blue == 1.0f) { blue = 0.0f; green = 1.0f; } 
143                                         else if (green == 1.0f) { green = 0.0f; red = 1.0f; } 
144                                 }
145 #endif
146                         } else {
147                                 CGContextBeginPath (context);
148                                 CGContextAddRect (context, rc_clip);
149                                 CGContextClosePath (context);
150                                 CGContextClip (context);
151                         }
152
153                         return new CarbonContext (port, context, (int)view_bounds.size.width, (int)view_bounds.size.height);
154                 }
155
156                 internal static IntPtr GetContext (IntPtr port) {
157                         IntPtr context = IntPtr.Zero;
158
159                         lock (lockobj) { 
160 #if FALSE
161                                 if (contextReference [port] != null) {
162                                         CreateCGContextForPort (port, ref context);
163                                 } else {
164                                         QDBeginCGContext (port, ref context);
165                                         contextReference [port] = context;
166                                 }
167 #else
168                                 CreateCGContextForPort (port, ref context);
169 #endif
170                         }
171
172                         return context;
173                 }
174
175                 internal static void ReleaseContext (IntPtr port, IntPtr context) {
176                         CGContextRestoreGState (context);
177
178                         lock (lockobj) { 
179 #if FALSE
180                                 if (contextReference [port] != null && context == (IntPtr) contextReference [port]) { 
181                                         QDEndCGContext (port, ref context);
182                                         contextReference [port] = null;
183                                 } else {
184                                         CFRelease (context);
185                                 }
186 #else
187                                 CFRelease (context);
188 #endif
189                         }
190                 }
191
192                 #region Cocoa Methods
193                 [DllImport("libobjc.dylib")]
194                 public static extern IntPtr objc_getClass(string className); 
195                 [DllImport("libobjc.dylib")]
196                 public static extern IntPtr objc_msgSend(IntPtr basePtr, IntPtr selector, string argument);  
197                 [DllImport("libobjc.dylib")]
198                 public static extern IntPtr objc_msgSend(IntPtr basePtr, IntPtr selector);        
199                 [DllImport("libobjc.dylib")]
200                 public static extern void objc_msgSend_stret(ref Rect arect, IntPtr basePtr, IntPtr selector);        
201                 [DllImport ("libobjc.dylib", EntryPoint = "objc_msgSend")]
202                 public static extern bool bool_objc_msgSend (IntPtr handle, IntPtr selector);
203                 [DllImport("libobjc.dylib")]
204                 public static extern IntPtr sel_registerName(string selectorName);         
205                 #endregion
206
207                 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
208                 internal static extern IntPtr CGMainDisplayID ();
209                 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
210                 internal static extern Rect CGDisplayBounds (IntPtr display);
211
212                 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
213                 internal static extern int HIViewGetBounds (IntPtr vHnd, ref Rect r);
214                 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
215                 internal static extern int HIViewConvertRect (ref Rect r, IntPtr a, IntPtr b);
216
217                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
218                 internal static extern IntPtr GetControlOwner (IntPtr aView);
219
220                 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
221                 internal static extern int GetWindowBounds (IntPtr wHnd, uint reg, ref QDRect rect);
222                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
223                 internal static extern IntPtr GetWindowPort (IntPtr hWnd);
224                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
225                 internal static extern IntPtr GetQDGlobalsThePort ();
226                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
227                 internal static extern void CreateCGContextForPort (IntPtr port, ref IntPtr context);
228                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
229                 internal static extern void CFRelease (IntPtr context);
230                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
231                 internal static extern void QDBeginCGContext (IntPtr port, ref IntPtr context);
232                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
233                 internal static extern void QDEndCGContext (IntPtr port, ref IntPtr context);
234                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
235                 internal static extern int CGContextClipToRect (IntPtr context, Rect clip);
236                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
237                 internal static extern int CGContextClipToRects (IntPtr context, Rect [] clip_rects, int count);
238                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
239                 internal static extern void CGContextTranslateCTM (IntPtr context, float tx, float ty);
240                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
241                 internal static extern void CGContextScaleCTM (IntPtr context, float x, float y);
242                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
243                 internal static extern void CGContextFlush (IntPtr context);
244                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
245                 internal static extern void CGContextSynchronize (IntPtr context);
246                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
247                 internal static extern IntPtr CGPathCreateMutable ();
248                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
249                 internal static extern void CGPathAddRects (IntPtr path, IntPtr _void, Rect [] rects, int count);
250                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
251                 internal static extern void CGPathAddRect (IntPtr path, IntPtr _void, Rect rect);
252                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
253                 internal static extern void CGContextAddRects (IntPtr context, Rect [] rects, int count);
254                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
255                 internal static extern void CGContextAddRect (IntPtr context, Rect rect);
256                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
257                 internal static extern void CGContextBeginPath (IntPtr context);
258                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
259                 internal static extern void CGContextClosePath (IntPtr context);
260                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
261                 internal static extern void CGContextAddPath (IntPtr context, IntPtr path);
262                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
263                 internal static extern void CGContextClip (IntPtr context);
264                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
265                 internal static extern void CGContextEOClip (IntPtr context);
266                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
267                 internal static extern void CGContextEOFillPath (IntPtr context);
268                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
269                 internal static extern void CGContextSaveGState (IntPtr context);
270                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
271                 internal static extern void CGContextRestoreGState (IntPtr context);
272
273 #if DEBUG_CLIPPING
274                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
275                 internal static extern void CGContextSetRGBFillColor (IntPtr context, float red, float green, float blue, float alpha);
276                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
277                 internal static extern void CGContextFillRect (IntPtr context, Rect rect);
278 #endif
279         }
280
281         internal struct CGSize {
282                 public float width;
283                 public float height;
284         }
285
286         internal struct CGPoint {
287                 public float x;
288                 public float y;
289         }
290
291         internal struct Rect {
292                 public Rect (float x, float y, float width, float height) {
293                         this.origin.x = x;
294                         this.origin.y = y;
295                         this.size.width = width;
296                         this.size.height = height;
297                 }
298
299                 public CGPoint origin;
300                 public CGSize size;
301         }
302
303         internal struct QDRect
304         {
305                 public short top;
306                 public short left;
307                 public short bottom;
308                 public short right;
309         }
310
311         internal struct CarbonContext : IMacContext
312         {
313                 public IntPtr port;
314                 public IntPtr ctx;
315                 public int width;
316                 public int height;
317
318                 public CarbonContext (IntPtr port, IntPtr ctx, int width, int height)
319                 {
320                         this.port = port;
321                         this.ctx = ctx;
322                         this.width = width;
323                         this.height = height;
324                 }
325
326                 public void Synchronize ()
327                 {
328                         MacSupport.CGContextSynchronize (ctx);
329                 }
330
331                 public void Release ()
332                 {
333                         MacSupport.ReleaseContext (port, ctx);
334                 }
335         }
336
337         internal struct CocoaContext : IMacContext
338         {
339                 public IntPtr ctx;
340                 public int width;
341                 public int height;
342
343                 public CocoaContext (IntPtr ctx, int width, int height)
344                 {
345                         this.ctx = ctx;
346                         this.width = width;
347                         this.height = height;
348                 }
349
350                 public void Synchronize ()
351                 {
352                         MacSupport.CGContextSynchronize (ctx);
353                 }
354
355                 public void Release ()
356                 {
357                         MacSupport.CGContextRestoreGState(ctx);
358                 }
359         }
360
361         internal interface IMacContext
362         {
363                 void Synchronize ();
364                 void Release ();
365         }
366 }