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