2 // System.Drawing.Region.cs
5 // Miguel de Icaza (miguel@ximian.com)
6 // Jordi Mas i Hernandez (jordi@ximian.com)
8 // Copyright (C) 2003 Ximian, Inc. http://www.ximian.com
9 // Copyright (C) 2004,2006 Novell, Inc. http://www.novell.com
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:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
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.
31 using System.Drawing.Drawing2D;
32 using System.Runtime.InteropServices;
34 namespace System.Drawing
36 public sealed class Region : MarshalByRefObject, IDisposable
38 private IntPtr nativeRegion = IntPtr.Zero;
42 Status status = GDIPlus.GdipCreateRegion (out nativeRegion);
43 GDIPlus.CheckStatus (status);
46 internal Region(IntPtr native)
48 nativeRegion = native;
51 public Region (GraphicsPath path)
54 throw new ArgumentNullException ("path");
55 Status status = GDIPlus.GdipCreateRegionPath (path.nativePath, out nativeRegion);
56 GDIPlus.CheckStatus (status);
59 public Region (Rectangle rect)
61 Status status = GDIPlus.GdipCreateRegionRectI (ref rect, out nativeRegion);
62 GDIPlus.CheckStatus (status);
65 public Region (RectangleF rect)
67 Status status = GDIPlus.GdipCreateRegionRect (ref rect, out nativeRegion);
68 GDIPlus.CheckStatus (status);
71 public Region (RegionData rgnData)
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);
86 public void Union (GraphicsPath path)
89 throw new ArgumentNullException ("path");
90 Status status = GDIPlus.GdipCombineRegionPath (nativeRegion, path.nativePath, CombineMode.Union);
91 GDIPlus.CheckStatus (status);
95 public void Union (Rectangle rect)
97 Status status = GDIPlus.GdipCombineRegionRectI (nativeRegion, ref rect, CombineMode.Union);
98 GDIPlus.CheckStatus (status);
101 public void Union (RectangleF rect)
103 Status status = GDIPlus.GdipCombineRegionRect (nativeRegion, ref rect, CombineMode.Union);
104 GDIPlus.CheckStatus (status);
107 public void Union (Region region)
110 throw new ArgumentNullException ("region");
111 Status status = GDIPlus.GdipCombineRegionRegion (nativeRegion, region.NativeObject, CombineMode.Union);
112 GDIPlus.CheckStatus (status);
119 public void Intersect (GraphicsPath path)
122 throw new ArgumentNullException ("path");
123 Status status = GDIPlus.GdipCombineRegionPath (nativeRegion, path.nativePath, CombineMode.Intersect);
124 GDIPlus.CheckStatus (status);
127 public void Intersect (Rectangle rect)
129 Status status = GDIPlus.GdipCombineRegionRectI (nativeRegion, ref rect, CombineMode.Intersect);
130 GDIPlus.CheckStatus (status);
133 public void Intersect (RectangleF rect)
135 Status status = GDIPlus.GdipCombineRegionRect (nativeRegion, ref rect, CombineMode.Intersect);
136 GDIPlus.CheckStatus (status);
139 public void Intersect (Region region)
142 throw new ArgumentNullException ("region");
143 Status status = GDIPlus.GdipCombineRegionRegion (nativeRegion, region.NativeObject, CombineMode.Intersect);
144 GDIPlus.CheckStatus (status);
150 public void Complement (GraphicsPath path)
153 throw new ArgumentNullException ("path");
154 Status status = GDIPlus.GdipCombineRegionPath (nativeRegion, path.nativePath, CombineMode.Complement);
155 GDIPlus.CheckStatus (status);
158 public void Complement (Rectangle rect)
160 Status status = GDIPlus.GdipCombineRegionRectI (nativeRegion, ref rect, CombineMode.Complement);
161 GDIPlus.CheckStatus (status);
164 public void Complement (RectangleF rect)
166 Status status = GDIPlus.GdipCombineRegionRect (nativeRegion, ref rect, CombineMode.Complement);
167 GDIPlus.CheckStatus (status);
170 public void Complement (Region region)
173 throw new ArgumentNullException ("region");
174 Status status = GDIPlus.GdipCombineRegionRegion (nativeRegion, region.NativeObject, CombineMode.Complement);
175 GDIPlus.CheckStatus (status);
181 public void Exclude (GraphicsPath path)
184 throw new ArgumentNullException ("path");
185 Status status = GDIPlus.GdipCombineRegionPath (nativeRegion, path.nativePath, CombineMode.Exclude);
186 GDIPlus.CheckStatus (status);
189 public void Exclude (Rectangle rect)
191 Status status = GDIPlus.GdipCombineRegionRectI (nativeRegion, ref rect, CombineMode.Exclude);
192 GDIPlus.CheckStatus (status);
195 public void Exclude (RectangleF rect)
197 Status status = GDIPlus.GdipCombineRegionRect (nativeRegion, ref rect, CombineMode.Exclude);
198 GDIPlus.CheckStatus (status);
201 public void Exclude (Region region)
204 throw new ArgumentNullException ("region");
205 Status status = GDIPlus.GdipCombineRegionRegion (nativeRegion, region.NativeObject, CombineMode.Exclude);
206 GDIPlus.CheckStatus (status);
212 public void Xor (GraphicsPath path)
215 throw new ArgumentNullException ("path");
216 Status status = GDIPlus.GdipCombineRegionPath (nativeRegion, path.nativePath, CombineMode.Xor);
217 GDIPlus.CheckStatus (status);
220 public void Xor (Rectangle rect)
222 Status status = GDIPlus.GdipCombineRegionRectI (nativeRegion, ref rect, CombineMode.Xor);
223 GDIPlus.CheckStatus (status);
226 public void Xor (RectangleF rect)
228 Status status = GDIPlus.GdipCombineRegionRect (nativeRegion, ref rect, CombineMode.Xor);
229 GDIPlus.CheckStatus (status);
232 public void Xor (Region region)
235 throw new ArgumentNullException ("region");
236 Status status = GDIPlus.GdipCombineRegionRegion (nativeRegion, region.NativeObject, CombineMode.Xor);
237 GDIPlus.CheckStatus (status);
243 public RectangleF GetBounds (Graphics g)
246 throw new ArgumentNullException ("g");
248 RectangleF rect = new Rectangle();
250 Status status = GDIPlus.GdipGetRegionBounds (nativeRegion, g.NativeObject, ref rect);
251 GDIPlus.CheckStatus (status);
259 public void Translate (int dx, int dy)
261 Status status = GDIPlus.GdipTranslateRegionI (nativeRegion, dx, dy);
262 GDIPlus.CheckStatus (status);
265 public void Translate (float dx, float dy)
267 Status status = GDIPlus.GdipTranslateRegion (nativeRegion, dx, dy);
268 GDIPlus.CheckStatus (status);
274 public bool IsVisible (int x, int y, Graphics g)
276 IntPtr ptr = (g == null) ? IntPtr.Zero : g.NativeObject;
279 Status status = GDIPlus.GdipIsVisibleRegionPointI (nativeRegion, x, y, ptr, out result);
280 GDIPlus.CheckStatus (status);
285 public bool IsVisible (int x, int y, int width, int height)
289 Status status = GDIPlus.GdipIsVisibleRegionRectI (nativeRegion, x, y,
290 width, height, IntPtr.Zero, out result);
292 GDIPlus.CheckStatus (status);
297 public bool IsVisible (int x, int y, int width, int height, Graphics g)
299 IntPtr ptr = (g == null) ? IntPtr.Zero : g.NativeObject;
302 Status status = GDIPlus.GdipIsVisibleRegionRectI (nativeRegion, x, y,
303 width, height, ptr, out result);
305 GDIPlus.CheckStatus (status);
310 public bool IsVisible (Point point)
314 Status status = GDIPlus.GdipIsVisibleRegionPointI (nativeRegion, point.X, point.Y,
315 IntPtr.Zero, out result);
317 GDIPlus.CheckStatus (status);
322 public bool IsVisible (PointF point)
326 Status status = GDIPlus.GdipIsVisibleRegionPoint (nativeRegion, point.X, point.Y,
327 IntPtr.Zero, out result);
329 GDIPlus.CheckStatus (status);
334 public bool IsVisible (Point point, Graphics g)
336 IntPtr ptr = (g == null) ? IntPtr.Zero : g.NativeObject;
339 Status status = GDIPlus.GdipIsVisibleRegionPointI (nativeRegion, point.X, point.Y,
342 GDIPlus.CheckStatus (status);
347 public bool IsVisible (PointF point, Graphics g)
349 IntPtr ptr = (g == null) ? IntPtr.Zero : g.NativeObject;
352 Status status = GDIPlus.GdipIsVisibleRegionPoint (nativeRegion, point.X, point.Y,
355 GDIPlus.CheckStatus (status);
360 public bool IsVisible (Rectangle rect)
364 Status status = GDIPlus.GdipIsVisibleRegionRectI (nativeRegion, rect.X, rect.Y,
365 rect.Width, rect.Height, IntPtr.Zero, out result);
367 GDIPlus.CheckStatus (status);
372 public bool IsVisible (RectangleF rect)
376 Status status = GDIPlus.GdipIsVisibleRegionRect (nativeRegion, rect.X, rect.Y,
377 rect.Width, rect.Height, IntPtr.Zero, out result);
379 GDIPlus.CheckStatus (status);
384 public bool IsVisible (Rectangle rect, Graphics g)
386 IntPtr ptr = (g == null) ? IntPtr.Zero : g.NativeObject;
389 Status status = GDIPlus.GdipIsVisibleRegionRectI (nativeRegion, rect.X, rect.Y,
390 rect.Width, rect.Height, ptr, out result);
392 GDIPlus.CheckStatus (status);
397 public bool IsVisible (RectangleF rect, Graphics g)
399 IntPtr ptr = (g == null) ? IntPtr.Zero : g.NativeObject;
402 Status status = GDIPlus.GdipIsVisibleRegionRect (nativeRegion, rect.X, rect.Y,
403 rect.Width, rect.Height, ptr, out result);
405 GDIPlus.CheckStatus (status);
410 public bool IsVisible (float x, float y)
414 Status status = GDIPlus.GdipIsVisibleRegionPoint (nativeRegion, x, y, IntPtr.Zero, out result);
415 GDIPlus.CheckStatus (status);
420 public bool IsVisible (float x, float y, Graphics g)
422 IntPtr ptr = (g == null) ? IntPtr.Zero : g.NativeObject;
425 Status status = GDIPlus.GdipIsVisibleRegionPoint (nativeRegion, x, y, ptr, out result);
426 GDIPlus.CheckStatus (status);
431 public bool IsVisible (float x, float y, float width, float height)
435 Status status = GDIPlus.GdipIsVisibleRegionRect (nativeRegion, x, y, width, height, IntPtr.Zero, out result);
436 GDIPlus.CheckStatus (status);
441 public bool IsVisible (float x, float y, float width, float height, Graphics g)
443 IntPtr ptr = (g == null) ? IntPtr.Zero : g.NativeObject;
446 Status status = GDIPlus.GdipIsVisibleRegionRect (nativeRegion, x, y, width, height, ptr, out result);
447 GDIPlus.CheckStatus (status);
457 public bool IsEmpty(Graphics g)
460 throw new ArgumentNullException ("g");
464 Status status = GDIPlus.GdipIsEmptyRegion (nativeRegion, g.NativeObject, out result);
465 GDIPlus.CheckStatus (status);
470 public bool IsInfinite(Graphics g)
473 throw new ArgumentNullException ("g");
477 Status status = GDIPlus.GdipIsInfiniteRegion (nativeRegion, g.NativeObject, out result);
478 GDIPlus.CheckStatus (status);
483 public void MakeEmpty()
485 Status status = GDIPlus.GdipSetEmpty (nativeRegion);
486 GDIPlus.CheckStatus (status);
489 public void MakeInfinite()
491 Status status = GDIPlus.GdipSetInfinite (nativeRegion);
492 GDIPlus.CheckStatus (status);
495 public bool Equals(Region region, Graphics g)
498 throw new ArgumentNullException ("region");
500 throw new ArgumentNullException ("g");
504 Status status = GDIPlus.GdipIsEqualRegion (nativeRegion, region.NativeObject,
505 g.NativeObject, out result);
507 GDIPlus.CheckStatus (status);
512 public static Region FromHrgn (IntPtr hrgn)
514 if (hrgn == IntPtr.Zero)
515 throw new ArgumentException ("hrgn");
518 Status status = GDIPlus.GdipCreateRegionHrgn (hrgn, out handle);
519 GDIPlus.CheckStatus (status);
521 return new Region (handle);
525 public IntPtr GetHrgn (Graphics g)
527 // Our WindowsForms implementation uses null to avoid
528 // creating a Graphics context when not needed
530 // this is MS behaviour
532 throw new ArgumentNullException ("g");
534 // this is an hack for MWF (libgdiplus would reject that)
538 IntPtr handle = IntPtr.Zero;
539 Status status = GDIPlus.GdipGetRegionHRgn (nativeRegion, g.NativeObject, ref handle);
540 GDIPlus.CheckStatus (status);
545 public RegionData GetRegionData()
549 Status status = GDIPlus.GdipGetRegionDataSize (nativeRegion, out size);
550 GDIPlus.CheckStatus (status);
552 byte[] buff = new byte [size];
554 status = GDIPlus.GdipGetRegionData (nativeRegion, buff, size, out filled);
555 GDIPlus.CheckStatus (status);
557 RegionData rgndata = new RegionData (buff);
563 public RectangleF[] GetRegionScans(Matrix matrix)
566 throw new ArgumentNullException ("matrix");
570 Status status = GDIPlus.GdipGetRegionScansCount (nativeRegion, out cnt, matrix.NativeObject);
571 GDIPlus.CheckStatus (status);
574 return new RectangleF[0];
576 RectangleF[] rects = new RectangleF [cnt];
577 int size = Marshal.SizeOf (rects[0]);
579 IntPtr dest = Marshal.AllocHGlobal (size * cnt);
581 status = GDIPlus.GdipGetRegionScans (nativeRegion, dest, out cnt, matrix.NativeObject);
582 GDIPlus.CheckStatus (status);
585 // note: Marshal.FreeHGlobal is called from GDIPlus.FromUnManagedMemoryToRectangles
586 GDIPlus.FromUnManagedMemoryToRectangles (dest, rects);
591 public void Transform(Matrix matrix)
594 throw new ArgumentNullException ("matrix");
596 Status status = GDIPlus.GdipTransformRegion (nativeRegion, matrix.NativeObject);
597 GDIPlus.CheckStatus (status);
600 public Region Clone()
604 Status status = GDIPlus.GdipCloneRegion (nativeRegion, out cloned);
605 GDIPlus.CheckStatus (status);
607 return new Region (cloned);
610 public void Dispose ()
613 System.GC.SuppressFinalize (this);
616 private void DisposeHandle ()
618 if (nativeRegion != IntPtr.Zero) {
619 GDIPlus.GdipDeleteRegion (nativeRegion);
620 nativeRegion = IntPtr.Zero;
629 internal IntPtr NativeObject
635 nativeRegion = value;
638 // why is this a instance method ? and not static ?
639 public void ReleaseHrgn (IntPtr regionHandle)
641 if (regionHandle == IntPtr.Zero)
642 throw new ArgumentNullException ("regionHandle");
644 Status status = Status.Ok;
645 if (GDIPlus.RunningOnUnix ()) {
646 // for libgdiplus HRGN == GpRegion*
647 status = GDIPlus.GdipDeleteRegion (regionHandle);
649 // ... but on Windows HRGN are (old) GDI objects
650 if (!GDIPlus.DeleteObject (regionHandle))
651 status = Status.InvalidParameter;
653 GDIPlus.CheckStatus (status);