1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.Diagnostics; 6 using System.Diagnostics.CodeAnalysis; 7 using System.Drawing.Drawing2D; 8 using System.Drawing.Internal; 9 using System.Globalization; 10 using System.Runtime.InteropServices; 11 12 namespace System.Drawing 13 { 14 public sealed partial class Region : MarshalByRefObject, IDisposable 15 { 16 #if FINALIZATION_WATCH 17 private string allocationSite = Graphics.GetAllocationStack(); 18 #endif 19 Region()20 public Region() 21 { 22 IntPtr region = IntPtr.Zero; 23 int status = SafeNativeMethods.Gdip.GdipCreateRegion(out region); 24 SafeNativeMethods.Gdip.CheckStatus(status); 25 26 SetNativeRegion(region); 27 } 28 Region(RectangleF rect)29 public Region(RectangleF rect) 30 { 31 IntPtr region = IntPtr.Zero; 32 var gprectf = new GPRECTF(rect); 33 int status = SafeNativeMethods.Gdip.GdipCreateRegionRect(ref gprectf, out region); 34 SafeNativeMethods.Gdip.CheckStatus(status); 35 36 SetNativeRegion(region); 37 } 38 Region(Rectangle rect)39 public Region(Rectangle rect) 40 { 41 IntPtr region = IntPtr.Zero; 42 var gprect = new GPRECT(rect); 43 int status = SafeNativeMethods.Gdip.GdipCreateRegionRectI(ref gprect, out region); 44 SafeNativeMethods.Gdip.CheckStatus(status); 45 46 SetNativeRegion(region); 47 } 48 Region(GraphicsPath path)49 public Region(GraphicsPath path) 50 { 51 if (path == null) 52 { 53 throw new ArgumentNullException(nameof(path)); 54 } 55 56 IntPtr region = IntPtr.Zero; 57 int status = SafeNativeMethods.Gdip.GdipCreateRegionPath(new HandleRef(path, path.nativePath), out region); 58 SafeNativeMethods.Gdip.CheckStatus(status); 59 60 SetNativeRegion(region); 61 } 62 Region(RegionData rgnData)63 public Region(RegionData rgnData) 64 { 65 if (rgnData == null) 66 { 67 throw new ArgumentNullException(nameof(rgnData)); 68 } 69 70 IntPtr region = IntPtr.Zero; 71 int status = SafeNativeMethods.Gdip.GdipCreateRegionRgnData(rgnData.Data, 72 rgnData.Data.Length, 73 out region); 74 SafeNativeMethods.Gdip.CheckStatus(status); 75 76 SetNativeRegion(region); 77 } 78 79 internal Region(IntPtr nativeRegion) => SetNativeRegion(nativeRegion); 80 FromHrgn(IntPtr hrgn)81 public static Region FromHrgn(IntPtr hrgn) 82 { 83 IntPtr region = IntPtr.Zero; 84 int status = SafeNativeMethods.Gdip.GdipCreateRegionHrgn(new HandleRef(null, hrgn), out region); 85 SafeNativeMethods.Gdip.CheckStatus(status); 86 87 return new Region(region); 88 } 89 SetNativeRegion(IntPtr nativeRegion)90 private void SetNativeRegion(IntPtr nativeRegion) 91 { 92 if (nativeRegion == IntPtr.Zero) 93 { 94 throw new ArgumentNullException(nameof(nativeRegion)); 95 } 96 97 this._nativeRegion = nativeRegion; 98 } 99 Clone()100 public Region Clone() 101 { 102 IntPtr region = IntPtr.Zero; 103 int status = SafeNativeMethods.Gdip.GdipCloneRegion(new HandleRef(this, _nativeRegion), out region); 104 SafeNativeMethods.Gdip.CheckStatus(status); 105 106 return new Region(region); 107 } 108 Dispose()109 public void Dispose() 110 { 111 Dispose(true); 112 GC.SuppressFinalize(this); 113 } 114 Dispose(bool disposing)115 private void Dispose(bool disposing) 116 { 117 #if FINALIZATION_WATCH 118 if (!disposing && nativeRegion != IntPtr.Zero) 119 Debug.WriteLine("**********************\nDisposed through finalization:\n" + allocationSite); 120 #endif 121 if (_nativeRegion != IntPtr.Zero) 122 { 123 try 124 { 125 #if DEBUG 126 int status = 127 #endif 128 SafeNativeMethods.Gdip.GdipDeleteRegion(new HandleRef(this, _nativeRegion)); 129 #if DEBUG 130 Debug.Assert(status == SafeNativeMethods.Gdip.Ok, "GDI+ returned an error status: " + status.ToString(CultureInfo.InvariantCulture)); 131 #endif 132 } 133 catch (Exception ex) when (!ClientUtils.IsSecurityOrCriticalException(ex)) 134 { 135 } 136 finally 137 { 138 _nativeRegion = IntPtr.Zero; 139 } 140 } 141 } 142 ~Region()143 ~Region() => Dispose(false); 144 MakeInfinite()145 public void MakeInfinite() 146 { 147 int status = SafeNativeMethods.Gdip.GdipSetInfinite(new HandleRef(this, _nativeRegion)); 148 SafeNativeMethods.Gdip.CheckStatus(status); 149 } 150 MakeEmpty()151 public void MakeEmpty() 152 { 153 int status = SafeNativeMethods.Gdip.GdipSetEmpty(new HandleRef(this, _nativeRegion)); 154 SafeNativeMethods.Gdip.CheckStatus(status); 155 } 156 Intersect(RectangleF rect)157 public void Intersect(RectangleF rect) 158 { 159 var gprectf = new GPRECTF(rect); 160 int status = SafeNativeMethods.Gdip.GdipCombineRegionRect(new HandleRef(this, _nativeRegion), ref gprectf, CombineMode.Intersect); 161 SafeNativeMethods.Gdip.CheckStatus(status); 162 } 163 Intersect(Rectangle rect)164 public void Intersect(Rectangle rect) 165 { 166 var gprect = new GPRECT(rect); 167 int status = SafeNativeMethods.Gdip.GdipCombineRegionRectI(new HandleRef(this, _nativeRegion), ref gprect, CombineMode.Intersect); 168 SafeNativeMethods.Gdip.CheckStatus(status); 169 } 170 Intersect(GraphicsPath path)171 public void Intersect(GraphicsPath path) 172 { 173 if (path == null) 174 { 175 throw new ArgumentNullException(nameof(path)); 176 } 177 178 int status = SafeNativeMethods.Gdip.GdipCombineRegionPath(new HandleRef(this, _nativeRegion), new HandleRef(path, path.nativePath), CombineMode.Intersect); 179 SafeNativeMethods.Gdip.CheckStatus(status); 180 } 181 Intersect(Region region)182 public void Intersect(Region region) 183 { 184 if (region == null) 185 { 186 throw new ArgumentNullException(nameof(region)); 187 } 188 189 int status = SafeNativeMethods.Gdip.GdipCombineRegionRegion(new HandleRef(this, _nativeRegion), new HandleRef(region, region._nativeRegion), CombineMode.Intersect); 190 SafeNativeMethods.Gdip.CheckStatus(status); 191 } 192 Union(RectangleF rect)193 public void Union(RectangleF rect) 194 { 195 var gprectf = new GPRECTF(rect); 196 int status = SafeNativeMethods.Gdip.GdipCombineRegionRect(new HandleRef(this, _nativeRegion), ref gprectf, CombineMode.Union); 197 SafeNativeMethods.Gdip.CheckStatus(status); 198 } 199 Union(Rectangle rect)200 public void Union(Rectangle rect) 201 { 202 var gprect = new GPRECT(rect); 203 int status = SafeNativeMethods.Gdip.GdipCombineRegionRectI(new HandleRef(this, _nativeRegion), ref gprect, CombineMode.Union); 204 SafeNativeMethods.Gdip.CheckStatus(status); 205 } 206 Union(GraphicsPath path)207 public void Union(GraphicsPath path) 208 { 209 if (path == null) 210 { 211 throw new ArgumentNullException(nameof(path)); 212 } 213 214 int status = SafeNativeMethods.Gdip.GdipCombineRegionPath(new HandleRef(this, _nativeRegion), new HandleRef(path, path.nativePath), CombineMode.Union); 215 SafeNativeMethods.Gdip.CheckStatus(status); 216 } 217 Union(Region region)218 public void Union(Region region) 219 { 220 if (region == null) 221 { 222 throw new ArgumentNullException(nameof(region)); 223 } 224 225 int status = SafeNativeMethods.Gdip.GdipCombineRegionRegion(new HandleRef(this, _nativeRegion), new HandleRef(region, region._nativeRegion), CombineMode.Union); 226 SafeNativeMethods.Gdip.CheckStatus(status); 227 } 228 Xor(RectangleF rect)229 public void Xor(RectangleF rect) 230 { 231 var gprectf = new GPRECTF(rect); 232 int status = SafeNativeMethods.Gdip.GdipCombineRegionRect(new HandleRef(this, _nativeRegion), ref gprectf, CombineMode.Xor); 233 SafeNativeMethods.Gdip.CheckStatus(status); 234 } 235 Xor(Rectangle rect)236 public void Xor(Rectangle rect) 237 { 238 var gprect = new GPRECT(rect); 239 int status = SafeNativeMethods.Gdip.GdipCombineRegionRectI(new HandleRef(this, _nativeRegion), ref gprect, CombineMode.Xor); 240 SafeNativeMethods.Gdip.CheckStatus(status); 241 } 242 Xor(GraphicsPath path)243 public void Xor(GraphicsPath path) 244 { 245 if (path == null) 246 { 247 throw new ArgumentNullException(nameof(path)); 248 } 249 250 int status = SafeNativeMethods.Gdip.GdipCombineRegionPath(new HandleRef(this, _nativeRegion), new HandleRef(path, path.nativePath), CombineMode.Xor); 251 SafeNativeMethods.Gdip.CheckStatus(status); 252 } 253 Xor(Region region)254 public void Xor(Region region) 255 { 256 if (region == null) 257 { 258 throw new ArgumentNullException(nameof(region)); 259 } 260 261 int status = SafeNativeMethods.Gdip.GdipCombineRegionRegion(new HandleRef(this, _nativeRegion), new HandleRef(region, region._nativeRegion), CombineMode.Xor); 262 SafeNativeMethods.Gdip.CheckStatus(status); 263 } 264 Exclude(RectangleF rect)265 public void Exclude(RectangleF rect) 266 { 267 var gprectf = new GPRECTF(rect); 268 int status = SafeNativeMethods.Gdip.GdipCombineRegionRect(new HandleRef(this, _nativeRegion), ref gprectf, CombineMode.Exclude); 269 SafeNativeMethods.Gdip.CheckStatus(status); 270 } 271 Exclude(Rectangle rect)272 public void Exclude(Rectangle rect) 273 { 274 var gprect = new GPRECT(rect); 275 int status = SafeNativeMethods.Gdip.GdipCombineRegionRectI(new HandleRef(this, _nativeRegion), ref gprect, CombineMode.Exclude); 276 SafeNativeMethods.Gdip.CheckStatus(status); 277 } 278 Exclude(GraphicsPath path)279 public void Exclude(GraphicsPath path) 280 { 281 if (path == null) 282 { 283 throw new ArgumentNullException(nameof(path)); 284 } 285 286 int status = SafeNativeMethods.Gdip.GdipCombineRegionPath(new HandleRef(this, _nativeRegion), new HandleRef(path, path.nativePath), 287 CombineMode.Exclude); 288 SafeNativeMethods.Gdip.CheckStatus(status); 289 } 290 Exclude(Region region)291 public void Exclude(Region region) 292 { 293 if (region == null) 294 { 295 throw new ArgumentNullException(nameof(region)); 296 } 297 298 int status = SafeNativeMethods.Gdip.GdipCombineRegionRegion(new HandleRef(this, _nativeRegion), new HandleRef(region, region._nativeRegion), 299 CombineMode.Exclude); 300 SafeNativeMethods.Gdip.CheckStatus(status); 301 } 302 Complement(RectangleF rect)303 public void Complement(RectangleF rect) 304 { 305 var gprectf = new GPRECTF(rect); 306 int status = SafeNativeMethods.Gdip.GdipCombineRegionRect(new HandleRef(this, _nativeRegion), ref gprectf, CombineMode.Complement); 307 SafeNativeMethods.Gdip.CheckStatus(status); 308 } 309 Complement(Rectangle rect)310 public void Complement(Rectangle rect) 311 { 312 var gprect = new GPRECT(rect); 313 int status = SafeNativeMethods.Gdip.GdipCombineRegionRectI(new HandleRef(this, _nativeRegion), ref gprect, CombineMode.Complement); 314 SafeNativeMethods.Gdip.CheckStatus(status); 315 } 316 Complement(GraphicsPath path)317 public void Complement(GraphicsPath path) 318 { 319 if (path == null) 320 { 321 throw new ArgumentNullException(nameof(path)); 322 } 323 324 int status = SafeNativeMethods.Gdip.GdipCombineRegionPath(new HandleRef(this, _nativeRegion), new HandleRef(path, path.nativePath), CombineMode.Complement); 325 SafeNativeMethods.Gdip.CheckStatus(status); 326 } 327 Complement(Region region)328 public void Complement(Region region) 329 { 330 if (region == null) 331 { 332 throw new ArgumentNullException(nameof(region)); 333 } 334 335 int status = SafeNativeMethods.Gdip.GdipCombineRegionRegion(new HandleRef(this, _nativeRegion), new HandleRef(region, region._nativeRegion), CombineMode.Complement); 336 SafeNativeMethods.Gdip.CheckStatus(status); 337 } 338 Translate(float dx, float dy)339 public void Translate(float dx, float dy) 340 { 341 int status = SafeNativeMethods.Gdip.GdipTranslateRegion(new HandleRef(this, _nativeRegion), dx, dy); 342 SafeNativeMethods.Gdip.CheckStatus(status); 343 } 344 Translate(int dx, int dy)345 public void Translate(int dx, int dy) 346 { 347 int status = SafeNativeMethods.Gdip.GdipTranslateRegionI(new HandleRef(this, _nativeRegion), dx, dy); 348 SafeNativeMethods.Gdip.CheckStatus(status); 349 } 350 Transform(Matrix matrix)351 public void Transform(Matrix matrix) 352 { 353 if (matrix == null) 354 { 355 throw new ArgumentNullException(nameof(matrix)); 356 } 357 358 int status = SafeNativeMethods.Gdip.GdipTransformRegion(new HandleRef(this, _nativeRegion), 359 new HandleRef(matrix, matrix.nativeMatrix)); 360 SafeNativeMethods.Gdip.CheckStatus(status); 361 } 362 GetBounds(Graphics g)363 public RectangleF GetBounds(Graphics g) 364 { 365 if (g == null) 366 { 367 throw new ArgumentNullException(nameof(g)); 368 } 369 370 var gprectf = new GPRECTF(); 371 int status = SafeNativeMethods.Gdip.GdipGetRegionBounds(new HandleRef(this, _nativeRegion), new HandleRef(g, g.NativeGraphics), ref gprectf); 372 SafeNativeMethods.Gdip.CheckStatus(status); 373 374 return gprectf.ToRectangleF(); 375 } 376 GetHrgn(Graphics g)377 public IntPtr GetHrgn(Graphics g) 378 { 379 if (g == null) 380 { 381 throw new ArgumentNullException(nameof(g)); 382 } 383 384 IntPtr hrgn = IntPtr.Zero; 385 int status = SafeNativeMethods.Gdip.GdipGetRegionHRgn(new HandleRef(this, _nativeRegion), new HandleRef(g, g.NativeGraphics), out hrgn); 386 SafeNativeMethods.Gdip.CheckStatus(status); 387 388 return hrgn; 389 } 390 IsEmpty(Graphics g)391 public bool IsEmpty(Graphics g) 392 { 393 if (g == null) 394 { 395 throw new ArgumentNullException(nameof(g)); 396 } 397 398 int isEmpty; 399 int status = SafeNativeMethods.Gdip.GdipIsEmptyRegion(new HandleRef(this, _nativeRegion), new HandleRef(g, g.NativeGraphics), out isEmpty); 400 SafeNativeMethods.Gdip.CheckStatus(status); 401 402 return isEmpty != 0; 403 } 404 IsInfinite(Graphics g)405 public bool IsInfinite(Graphics g) 406 { 407 if (g == null) 408 { 409 throw new ArgumentNullException(nameof(g)); 410 } 411 412 int isInfinite; 413 int status = SafeNativeMethods.Gdip.GdipIsInfiniteRegion(new HandleRef(this, _nativeRegion), new HandleRef(g, g.NativeGraphics), out isInfinite); 414 SafeNativeMethods.Gdip.CheckStatus(status); 415 416 return isInfinite != 0; 417 } 418 Equals(Region region, Graphics g)419 public bool Equals(Region region, Graphics g) 420 { 421 if (g == null) 422 { 423 throw new ArgumentNullException(nameof(g)); 424 } 425 426 if (region == null) 427 { 428 throw new ArgumentNullException(nameof(region)); 429 } 430 431 int isEqual; 432 int status = SafeNativeMethods.Gdip.GdipIsEqualRegion(new HandleRef(this, _nativeRegion), new HandleRef(region, region._nativeRegion), new HandleRef(g, g.NativeGraphics), out isEqual); 433 SafeNativeMethods.Gdip.CheckStatus(status); 434 435 return isEqual != 0; 436 } 437 GetRegionData()438 public RegionData GetRegionData() 439 { 440 int regionSize = 0; 441 int status = SafeNativeMethods.Gdip.GdipGetRegionDataSize(new HandleRef(this, _nativeRegion), out regionSize); 442 SafeNativeMethods.Gdip.CheckStatus(status); 443 444 if (regionSize == 0) 445 { 446 return null; 447 } 448 449 byte[] regionData = new byte[regionSize]; 450 status = SafeNativeMethods.Gdip.GdipGetRegionData(new HandleRef(this, _nativeRegion), regionData, regionSize, out regionSize); 451 SafeNativeMethods.Gdip.CheckStatus(status); 452 453 return new RegionData(regionData); 454 } 455 IsVisible(float x, float y)456 public bool IsVisible(float x, float y) => IsVisible(new PointF(x, y), null); 457 458 public bool IsVisible(PointF point) => IsVisible(point, null); 459 IsVisible(float x, float y, Graphics g)460 public bool IsVisible(float x, float y, Graphics g) => IsVisible(new PointF(x, y), g); 461 IsVisible(PointF point, Graphics g)462 public bool IsVisible(PointF point, Graphics g) 463 { 464 int isVisible; 465 int status = SafeNativeMethods.Gdip.GdipIsVisibleRegionPoint(new HandleRef(this, _nativeRegion), point.X, point.Y, 466 new HandleRef(g, (g == null) ? IntPtr.Zero : g.NativeGraphics), 467 out isVisible); 468 SafeNativeMethods.Gdip.CheckStatus(status); 469 470 return isVisible != 0; 471 } 472 IsVisible(float x, float y, float width, float height)473 public bool IsVisible(float x, float y, float width, float height) => IsVisible(new RectangleF(x, y, width, height), null); 474 475 public bool IsVisible(RectangleF rect) => IsVisible(rect, null); 476 IsVisible(float x, float y, float width, float height, Graphics g)477 public bool IsVisible(float x, float y, float width, float height, Graphics g) => IsVisible(new RectangleF(x, y, width, height), g); 478 IsVisible(RectangleF rect, Graphics g)479 public bool IsVisible(RectangleF rect, Graphics g) 480 { 481 int isVisible = 0; 482 int status = SafeNativeMethods.Gdip.GdipIsVisibleRegionRect(new HandleRef(this, _nativeRegion), rect.X, rect.Y, 483 rect.Width, rect.Height, 484 new HandleRef(g, (g == null) ? IntPtr.Zero : g.NativeGraphics), 485 out isVisible); 486 SafeNativeMethods.Gdip.CheckStatus(status); 487 488 return isVisible != 0; 489 } 490 IsVisible(int x, int y, Graphics g)491 public bool IsVisible(int x, int y, Graphics g) => IsVisible(new Point(x, y), g); 492 493 public bool IsVisible(Point point) => IsVisible(point, null); 494 IsVisible(Point point, Graphics g)495 public bool IsVisible(Point point, Graphics g) 496 { 497 int isVisible = 0; 498 int status = SafeNativeMethods.Gdip.GdipIsVisibleRegionPointI(new HandleRef(this, _nativeRegion), point.X, point.Y, 499 new HandleRef(g, (g == null) ? IntPtr.Zero : g.NativeGraphics), 500 out isVisible); 501 SafeNativeMethods.Gdip.CheckStatus(status); 502 503 return isVisible != 0; 504 } 505 IsVisible(int x, int y, int width, int height)506 public bool IsVisible(int x, int y, int width, int height) => IsVisible(new Rectangle(x, y, width, height), null); 507 508 public bool IsVisible(Rectangle rect) => IsVisible(rect, null); 509 IsVisible(int x, int y, int width, int height, Graphics g)510 public bool IsVisible(int x, int y, int width, int height, Graphics g) => IsVisible(new Rectangle(x, y, width, height), g); 511 IsVisible(Rectangle rect, Graphics g)512 public bool IsVisible(Rectangle rect, Graphics g) 513 { 514 int isVisible = 0; 515 int status = SafeNativeMethods.Gdip.GdipIsVisibleRegionRectI(new HandleRef(this, _nativeRegion), rect.X, rect.Y, 516 rect.Width, rect.Height, 517 new HandleRef(g, (g == null) ? IntPtr.Zero : g.NativeGraphics), 518 out isVisible); 519 SafeNativeMethods.Gdip.CheckStatus(status); 520 521 return isVisible != 0; 522 } 523 GetRegionScans(Matrix matrix)524 public RectangleF[] GetRegionScans(Matrix matrix) 525 { 526 if (matrix == null) 527 { 528 throw new ArgumentNullException(nameof(matrix)); 529 } 530 531 int count = 0; 532 int status = SafeNativeMethods.Gdip.GdipGetRegionScansCount(new HandleRef(this, _nativeRegion), 533 out count, 534 new HandleRef(matrix, matrix.nativeMatrix)); 535 SafeNativeMethods.Gdip.CheckStatus(status); 536 537 int rectsize = (int)Marshal.SizeOf(typeof(GPRECTF)); 538 IntPtr memoryRects = Marshal.AllocHGlobal(checked(rectsize * count)); 539 540 try 541 { 542 status = SafeNativeMethods.Gdip.GdipGetRegionScans(new HandleRef(this, _nativeRegion), 543 memoryRects, 544 out count, 545 new HandleRef(matrix, matrix.nativeMatrix)); 546 SafeNativeMethods.Gdip.CheckStatus(status); 547 548 var gprectf = new GPRECTF(); 549 550 var rectangles = new RectangleF[count]; 551 for (int index = 0; index < count; index++) 552 { 553 gprectf = (GPRECTF)Marshal.PtrToStructure((IntPtr)(checked((long)memoryRects + rectsize * index)), typeof(GPRECTF)); 554 rectangles[index] = gprectf.ToRectangleF(); 555 } 556 557 return rectangles; 558 } 559 finally 560 { 561 Marshal.FreeHGlobal(memoryRects); 562 } 563 } 564 565 internal IntPtr _nativeRegion; 566 } 567 } 568