Merge branch 'master' of github.com:mono/mono into masterwork
[mono.git] / mcs / class / System.Drawing / System.Drawing / Region.cs
1 //
2 // System.Drawing.Region.cs
3 //
4 // Author:
5 //      Miguel de Icaza (miguel@ximian.com)
6 //      Jordi Mas i Hernandez (jordi@ximian.com)
7 //
8 // Copyright (C) 2003 Ximian, Inc. http://www.ximian.com
9 // Copyright (C) 2004,2006 Novell, Inc. http://www.novell.com
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System.Drawing.Drawing2D;
32 using System.Runtime.InteropServices;
33 using System.Security.Permissions;
34
35 namespace System.Drawing
36 {
37 #if !NET_2_0
38         [ComVisible (false)]
39 #endif
40         public sealed class Region : MarshalByRefObject, IDisposable
41         {
42                 private IntPtr nativeRegion = IntPtr.Zero;
43                 
44                 public Region()
45                 {
46                         Status status = GDIPlus.GdipCreateRegion (out nativeRegion);
47                         GDIPlus.CheckStatus (status);
48                 }
49
50                 internal Region(IntPtr native)
51                 {
52                         nativeRegion = native; 
53                 }
54                 
55                 public Region (GraphicsPath path)
56                 {
57                         if (path == null)
58                                 throw new ArgumentNullException ("path");
59                         Status status = GDIPlus.GdipCreateRegionPath (path.NativeObject, out nativeRegion);
60                         GDIPlus.CheckStatus (status);
61                 }
62
63                 public Region (Rectangle rect)                
64                 {
65                         Status status = GDIPlus.GdipCreateRegionRectI (ref rect, out nativeRegion);
66                         GDIPlus.CheckStatus (status);
67                 }
68
69                 public Region (RectangleF rect)
70                 {
71                         Status status = GDIPlus.GdipCreateRegionRect (ref rect, out nativeRegion);
72                         GDIPlus.CheckStatus (status);
73                 }
74
75                 public Region (RegionData rgnData)
76                 {
77                         if (rgnData == null)
78                                 throw new ArgumentNullException ("rgnData");
79                         // a NullReferenceException can be throw for rgnData.Data.Length (if rgnData.Data is null) just like MS
80                         if (rgnData.Data.Length == 0)
81                                 throw new ArgumentException ("rgnData");
82                         Status status = GDIPlus.GdipCreateRegionRgnData (rgnData.Data, rgnData.Data.Length, out nativeRegion);
83                         GDIPlus.CheckStatus (status);
84                 }
85                 
86                 //                                                                                                     
87                 // Union
88                 //
89
90                 public void Union (GraphicsPath path)
91                 {
92                         if (path == null)
93                                 throw new ArgumentNullException ("path");
94                         Status status = GDIPlus.GdipCombineRegionPath (nativeRegion, path.NativeObject, CombineMode.Union);
95                         GDIPlus.CheckStatus (status);                        
96                 }
97
98
99                 public void Union (Rectangle rect)
100                 {                                    
101                         Status status = GDIPlus.GdipCombineRegionRectI (nativeRegion, ref rect, CombineMode.Union);
102                         GDIPlus.CheckStatus (status);
103                 }
104
105                 public void Union (RectangleF rect)
106                 {
107                         Status status = GDIPlus.GdipCombineRegionRect (nativeRegion, ref rect, CombineMode.Union);
108                         GDIPlus.CheckStatus (status);
109                 }
110
111                 public void Union (Region region)
112                 {
113                         if (region == null)
114                                 throw new ArgumentNullException ("region");
115                         Status status = GDIPlus.GdipCombineRegionRegion (nativeRegion, region.NativeObject, CombineMode.Union);
116                         GDIPlus.CheckStatus (status);
117                 }                                                                                         
118
119                 
120                 //
121                 // Intersect
122                 //
123                 public void Intersect (GraphicsPath path)
124                 {
125                         if (path == null)
126                                 throw new ArgumentNullException ("path");
127                         Status status = GDIPlus.GdipCombineRegionPath (nativeRegion, path.NativeObject, CombineMode.Intersect);
128                         GDIPlus.CheckStatus (status);  
129                 }
130
131                 public void Intersect (Rectangle rect)
132                 {
133                         Status status = GDIPlus.GdipCombineRegionRectI (nativeRegion, ref rect, CombineMode.Intersect);
134                         GDIPlus.CheckStatus (status);
135                 }
136
137                 public void Intersect (RectangleF rect)
138                 {
139                         Status status = GDIPlus.GdipCombineRegionRect (nativeRegion, ref rect, CombineMode.Intersect);
140                         GDIPlus.CheckStatus (status);
141                 }
142
143                 public void Intersect (Region region)
144                 {
145                         if (region == null)
146                                 throw new ArgumentNullException ("region");
147                         Status status = GDIPlus.GdipCombineRegionRegion (nativeRegion, region.NativeObject, CombineMode.Intersect);
148                         GDIPlus.CheckStatus (status);
149                 }
150
151                 //
152                 // Complement
153                 //
154                 public void Complement (GraphicsPath path)
155                 {
156                         if (path == null)
157                                 throw new ArgumentNullException ("path");
158                         Status status = GDIPlus.GdipCombineRegionPath (nativeRegion, path.NativeObject, CombineMode.Complement);
159                         GDIPlus.CheckStatus (status);  
160                 }
161
162                 public void Complement (Rectangle rect)
163                 {
164                         Status status = GDIPlus.GdipCombineRegionRectI (nativeRegion, ref rect, CombineMode.Complement);
165                         GDIPlus.CheckStatus (status);
166                 }
167
168                 public void Complement (RectangleF rect)
169                 {
170                         Status status = GDIPlus.GdipCombineRegionRect (nativeRegion, ref rect, CombineMode.Complement);
171                         GDIPlus.CheckStatus (status);
172                 }
173
174                 public void Complement (Region region)
175                 {
176                         if (region == null)
177                                 throw new ArgumentNullException ("region");
178                         Status status = GDIPlus.GdipCombineRegionRegion (nativeRegion, region.NativeObject, CombineMode.Complement);
179                         GDIPlus.CheckStatus (status);
180                 }
181
182                 //
183                 // Exclude
184                 //
185                 public void Exclude (GraphicsPath path)
186                 {
187                         if (path == null)
188                                 throw new ArgumentNullException ("path");
189                         Status status = GDIPlus.GdipCombineRegionPath (nativeRegion, path.NativeObject, CombineMode.Exclude);
190                         GDIPlus.CheckStatus (status);                                                   
191                 }
192
193                 public void Exclude (Rectangle rect)
194                 {
195                         Status status = GDIPlus.GdipCombineRegionRectI (nativeRegion, ref rect, CombineMode.Exclude);
196                         GDIPlus.CheckStatus (status);
197                 }
198
199                 public void Exclude (RectangleF rect)
200                 {
201                         Status status = GDIPlus.GdipCombineRegionRect (nativeRegion, ref rect, CombineMode.Exclude);
202                         GDIPlus.CheckStatus (status);
203                 }
204
205                 public void Exclude (Region region)
206                 {
207                         if (region == null)
208                                 throw new ArgumentNullException ("region");
209                         Status status = GDIPlus.GdipCombineRegionRegion (nativeRegion, region.NativeObject, CombineMode.Exclude);
210                         GDIPlus.CheckStatus (status);
211                 }
212
213                 //
214                 // Xor
215                 //
216                 public void Xor (GraphicsPath path)
217                 {
218                         if (path == null)
219                                 throw new ArgumentNullException ("path");
220                         Status status = GDIPlus.GdipCombineRegionPath (nativeRegion, path.NativeObject, CombineMode.Xor);
221                         GDIPlus.CheckStatus (status);  
222                 }
223
224                 public void Xor (Rectangle rect)
225                 {
226                         Status status = GDIPlus.GdipCombineRegionRectI (nativeRegion, ref rect, CombineMode.Xor);
227                         GDIPlus.CheckStatus (status);
228                 }
229
230                 public void Xor (RectangleF rect)
231                 {
232                         Status status = GDIPlus.GdipCombineRegionRect (nativeRegion, ref rect, CombineMode.Xor);
233                         GDIPlus.CheckStatus (status);
234                 }
235
236                 public void Xor (Region region)
237                 {
238                         if (region == null)
239                                 throw new ArgumentNullException ("region");
240                         Status status = GDIPlus.GdipCombineRegionRegion (nativeRegion, region.NativeObject, CombineMode.Xor);
241                         GDIPlus.CheckStatus (status); 
242                 }
243
244                 //
245                 // GetBounds
246                 //
247                 public RectangleF GetBounds (Graphics g)
248                 {
249                         if (g == null)
250                                 throw new ArgumentNullException ("g");
251
252                         RectangleF rect = new Rectangle();
253                         
254                         Status status = GDIPlus.GdipGetRegionBounds (nativeRegion, g.NativeObject, ref rect);
255                         GDIPlus.CheckStatus (status);
256
257                         return rect;
258                 }
259
260                 //
261                 // Translate
262                 //
263                 public void Translate (int dx, int dy)
264                 {
265                         Status status = GDIPlus.GdipTranslateRegionI (nativeRegion, dx, dy);
266                         GDIPlus.CheckStatus (status);   
267                 }
268
269                 public void Translate (float dx, float dy)
270                 {
271                         Status status = GDIPlus.GdipTranslateRegion (nativeRegion, dx, dy);
272                         GDIPlus.CheckStatus (status);
273                 }
274
275                 //
276                 // IsVisible
277                 //
278                 public bool IsVisible (int x, int y, Graphics g)
279                 {
280                         IntPtr ptr = (g == null) ? IntPtr.Zero : g.NativeObject;
281                         bool result;
282                         
283                         Status status = GDIPlus.GdipIsVisibleRegionPointI (nativeRegion, x, y, ptr, out result);
284                         GDIPlus.CheckStatus (status);
285
286                         return result;
287                 }
288
289                 public bool IsVisible (int x, int y, int width, int height)
290                 {
291                         bool result;
292
293                         Status status = GDIPlus.GdipIsVisibleRegionRectI (nativeRegion, x, y,
294                                 width, height, IntPtr.Zero, out result);
295
296                         GDIPlus.CheckStatus (status);
297
298                         return result;
299                 }
300
301                 public bool IsVisible (int x, int y, int width, int height, Graphics g)
302                 {
303                         IntPtr ptr = (g == null) ? IntPtr.Zero : g.NativeObject;
304                         bool result;
305
306                         Status status = GDIPlus.GdipIsVisibleRegionRectI (nativeRegion, x, y,
307                                 width, height, ptr, out result);
308
309                         GDIPlus.CheckStatus (status);
310
311                         return result;
312                 }
313
314                 public bool IsVisible (Point point)
315                 {
316                         bool result;
317
318                         Status status = GDIPlus.GdipIsVisibleRegionPointI (nativeRegion, point.X, point.Y,
319                                 IntPtr.Zero, out result);
320                                 
321                         GDIPlus.CheckStatus (status);
322
323                         return result;
324                 }
325
326                 public bool IsVisible (PointF point)
327                 {
328                        bool result;
329
330                         Status status = GDIPlus.GdipIsVisibleRegionPoint (nativeRegion, point.X, point.Y,
331                                 IntPtr.Zero, out result);
332
333                         GDIPlus.CheckStatus (status);
334
335                         return result;
336                 }
337
338                 public bool IsVisible (Point point, Graphics g)
339                 {
340                         IntPtr ptr = (g == null) ? IntPtr.Zero : g.NativeObject;
341                         bool result;
342
343                         Status status = GDIPlus.GdipIsVisibleRegionPointI (nativeRegion, point.X, point.Y,
344                                 ptr, out result);
345
346                         GDIPlus.CheckStatus (status);
347
348                         return result;                                                      
349                 }
350
351                 public bool IsVisible (PointF point, Graphics g)
352                 {
353                         IntPtr ptr = (g == null) ? IntPtr.Zero : g.NativeObject;
354                         bool result;
355
356                         Status status = GDIPlus.GdipIsVisibleRegionPoint (nativeRegion, point.X, point.Y,
357                                 ptr, out result);
358
359                         GDIPlus.CheckStatus (status);
360
361                         return result;
362                 }
363
364                 public bool IsVisible (Rectangle rect)
365                 {
366                         bool result;
367
368                         Status status = GDIPlus.GdipIsVisibleRegionRectI (nativeRegion, rect.X, rect.Y,
369                                 rect.Width, rect.Height, IntPtr.Zero, out result);
370
371                         GDIPlus.CheckStatus (status);
372
373                         return result;
374                 }
375
376                 public bool IsVisible (RectangleF rect)
377                 {
378                         bool result;
379
380                         Status status = GDIPlus.GdipIsVisibleRegionRect (nativeRegion, rect.X, rect.Y,
381                                 rect.Width, rect.Height, IntPtr.Zero, out result);
382
383                         GDIPlus.CheckStatus (status);
384
385                         return result;
386                 }
387
388                 public bool IsVisible (Rectangle rect, Graphics g)
389                 {
390                         IntPtr ptr = (g == null) ? IntPtr.Zero : g.NativeObject;
391                         bool result;
392
393                         Status status = GDIPlus.GdipIsVisibleRegionRectI (nativeRegion, rect.X, rect.Y,
394                                 rect.Width, rect.Height, ptr, out result);
395                         
396                         GDIPlus.CheckStatus (status);
397
398                         return result;
399                 }
400
401                 public bool IsVisible (RectangleF rect, Graphics g)
402                 {
403                         IntPtr ptr = (g == null) ? IntPtr.Zero : g.NativeObject;
404                         bool result;
405
406                         Status status = GDIPlus.GdipIsVisibleRegionRect (nativeRegion, rect.X, rect.Y,
407                                 rect.Width, rect.Height, ptr, out result);
408                                 
409                         GDIPlus.CheckStatus (status);
410
411                         return result;
412                 }
413
414                 public bool IsVisible (float x, float y)
415                 {
416                         bool result;
417
418                         Status status = GDIPlus.GdipIsVisibleRegionPoint (nativeRegion, x, y, IntPtr.Zero, out result);
419                         GDIPlus.CheckStatus (status);
420
421                         return result;
422                 }
423
424                 public bool IsVisible (float x, float y, Graphics g)
425                 {
426                         IntPtr ptr = (g == null) ? IntPtr.Zero : g.NativeObject;
427                         bool result;
428
429                         Status status = GDIPlus.GdipIsVisibleRegionPoint (nativeRegion, x, y, ptr, out result);
430                         GDIPlus.CheckStatus (status);
431
432                         return result;
433                 }
434
435                 public bool IsVisible (float x, float y, float width, float height)
436                 {
437                         bool result;
438                         
439                         Status status = GDIPlus.GdipIsVisibleRegionRect (nativeRegion, x, y, width, height, IntPtr.Zero, out result);
440                         GDIPlus.CheckStatus (status);
441
442                         return result;
443                 }
444
445                 public bool IsVisible (float x, float y, float width, float height, Graphics g) 
446                 {
447                         IntPtr ptr = (g == null) ? IntPtr.Zero : g.NativeObject;
448                         bool result;
449
450                         Status status = GDIPlus.GdipIsVisibleRegionRect (nativeRegion, x, y, width, height, ptr, out result);
451                         GDIPlus.CheckStatus (status);
452
453                         return result;
454                 }
455
456
457                 //
458                 // Miscellaneous
459                 //
460
461                 public bool IsEmpty(Graphics g)
462                 {
463                         if (g == null)
464                                 throw new ArgumentNullException ("g");
465
466                         bool result;               
467
468                         Status status = GDIPlus.GdipIsEmptyRegion (nativeRegion, g.NativeObject, out result);
469                         GDIPlus.CheckStatus (status);
470
471                         return result;                        
472                 }
473
474                 public bool IsInfinite(Graphics g)
475                 {
476                         if (g == null)
477                                 throw new ArgumentNullException ("g");
478
479                         bool result;
480
481                         Status status = GDIPlus.GdipIsInfiniteRegion (nativeRegion, g.NativeObject, out result);
482                         GDIPlus.CheckStatus (status);
483
484                         return result;  
485                 }
486
487                 public void MakeEmpty()
488                 {
489                         Status status = GDIPlus.GdipSetEmpty (nativeRegion);
490                         GDIPlus.CheckStatus (status);               
491                 }
492
493                 public void MakeInfinite()
494                 {
495                         Status status = GDIPlus.GdipSetInfinite (nativeRegion);
496                         GDIPlus.CheckStatus (status);                      
497                 }
498                 
499                 public bool Equals(Region region, Graphics g)
500                 {
501                         if (region == null)
502                                 throw new ArgumentNullException ("region");
503                         if (g == null)
504                                 throw new ArgumentNullException ("g");
505
506                         bool result;
507                         
508                         Status status = GDIPlus.GdipIsEqualRegion (nativeRegion, region.NativeObject,
509                            g.NativeObject, out result);                                   
510                            
511                         GDIPlus.CheckStatus (status);                      
512                         
513                         return result;                  
514                 }
515                 
516                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
517                 public static Region FromHrgn (IntPtr hrgn)
518                 {
519                         if (hrgn == IntPtr.Zero)
520                                 throw new ArgumentException ("hrgn");
521
522                         IntPtr handle;
523                         Status status = GDIPlus.GdipCreateRegionHrgn (hrgn, out handle);
524                         GDIPlus.CheckStatus (status);
525
526                         return new Region (handle);
527                 }
528                 
529                 
530                 public IntPtr GetHrgn (Graphics g)
531                 {
532                         // Our WindowsForms implementation uses null to avoid
533                         // creating a Graphics context when not needed
534 #if false
535                         // this is MS behaviour
536                         if (g == null)
537                                 throw new ArgumentNullException ("g");
538 #else
539                         // this is an hack for MWF (libgdiplus would reject that)
540                         if (g == null)
541                                 return nativeRegion;
542 #endif
543                         IntPtr handle = IntPtr.Zero;
544                         Status status = GDIPlus.GdipGetRegionHRgn (nativeRegion, g.NativeObject, ref handle);
545                         GDIPlus.CheckStatus (status);
546                         return handle;
547                 }
548                 
549                 
550                 public RegionData GetRegionData()
551                 {
552                         int size, filled;                       
553                         
554                         Status status = GDIPlus.GdipGetRegionDataSize (nativeRegion, out size);                  
555                         GDIPlus.CheckStatus (status);                      
556                         
557                         byte[] buff = new byte [size];                  
558                         
559                         status = GDIPlus.GdipGetRegionData (nativeRegion, buff, size, out filled);
560                         GDIPlus.CheckStatus (status);                      
561                         
562                         RegionData rgndata = new RegionData();
563                         rgndata.Data = buff;
564                         
565                         return rgndata;
566                 }
567                 
568                 
569                 public RectangleF[] GetRegionScans(Matrix matrix)
570                 {
571                         if (matrix == null)
572                                 throw new ArgumentNullException ("matrix");
573
574                         int cnt;
575                         
576                         Status status = GDIPlus.GdipGetRegionScansCount (nativeRegion, out cnt, matrix.NativeObject);                  
577                         GDIPlus.CheckStatus (status);                                 
578                         
579                         if (cnt == 0)
580                                 return new RectangleF[0];
581                                                 
582                         RectangleF[] rects = new RectangleF [cnt];                                      
583                         int size = Marshal.SizeOf (rects[0]);                  
584                         
585                         IntPtr dest = Marshal.AllocHGlobal (size * cnt);                        
586                         try {
587                                 status = GDIPlus.GdipGetRegionScans (nativeRegion, dest, out cnt, matrix.NativeObject);
588                                 GDIPlus.CheckStatus (status);
589                         }
590                         finally {
591                                 // note: Marshal.FreeHGlobal is called from GDIPlus.FromUnManagedMemoryToRectangles
592                                 GDIPlus.FromUnManagedMemoryToRectangles (dest, rects);
593                         }
594                         return rects;                   
595                 }               
596
597                 public void Transform(Matrix matrix)
598                 {
599                         if (matrix == null)
600                                 throw new ArgumentNullException ("matrix");
601
602                         Status status = GDIPlus.GdipTransformRegion (nativeRegion, matrix.NativeObject);
603                         GDIPlus.CheckStatus (status);                                                   
604                 }               
605                 
606                 public Region Clone()
607                 {
608                         IntPtr cloned;
609                                 
610                         Status status = GDIPlus.GdipCloneRegion (nativeRegion, out cloned);
611                         GDIPlus.CheckStatus (status);
612                                 
613                         return new Region (cloned); 
614                 }
615
616                 public void Dispose ()
617                 {
618                         DisposeHandle ();
619                         System.GC.SuppressFinalize (this);
620                 }
621
622                 private void DisposeHandle ()
623                 {
624                         if (nativeRegion != IntPtr.Zero) {
625                                 GDIPlus.GdipDeleteRegion (nativeRegion);
626                                 nativeRegion = IntPtr.Zero;
627                         }
628                 }
629
630                 ~Region ()
631                 {
632                         DisposeHandle ();
633                 }
634
635                 internal IntPtr NativeObject
636                 {
637                         get{
638                                 return nativeRegion;
639                         }
640                         set     {
641                                 nativeRegion = value;
642                         }
643                 }
644 #if NET_2_0
645                 // why is this a instance method ? and not static ?
646                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
647                 public void ReleaseHrgn (IntPtr regionHandle)           
648                 {
649                         if (regionHandle == IntPtr.Zero) 
650                                 throw new ArgumentNullException ("regionHandle");
651
652                         Status status = Status.Ok;
653                         if (GDIPlus.RunningOnUnix ()) {
654                                 // for libgdiplus HRGN == GpRegion* 
655                                 status = GDIPlus.GdipDeleteRegion (regionHandle);
656                         } else {
657                                 // ... but on Windows HRGN are (old) GDI objects
658                                 if (!GDIPlus.DeleteObject (regionHandle))
659                                         status = Status.InvalidParameter;
660                         }
661                         GDIPlus.CheckStatus (status);
662                 }
663 #endif
664         }
665 }