1 #include <precomp.h> 2 3 #define NDEBUG 4 #include <debug.h> 5 6 // 7 // "Windows Graphics Programming: Win32 GDI and DirectDraw", 8 // Chp 9 Areas, Region, Set Operations on Regions, hard copy pg 560. 9 // universal set's bounding box to be [-(1 << 27), -(1 << 27), (1 << 27) -1, (1 << 27) -1]. 10 // 11 #define MIN_COORD (INT_MIN/16) // See also ntgdi/region.c 12 #define MAX_COORD (INT_MAX/16) 13 14 #define INRECT(r, x, y) \ 15 ( ( ((r).right > x)) && \ 16 ( ((r).left <= x)) && \ 17 ( ((r).bottom > y)) && \ 18 ( ((r).top <= y)) ) 19 20 static 21 VOID 22 FASTCALL 23 SortRects(PRECT pRect, INT nCount) 24 { 25 INT i, a, b, c, s; 26 RECT sRect; 27 28 if (nCount > 0) 29 { 30 i = 1; // set index point 31 c = nCount; // set inverse count 32 do 33 { 34 s = i; // set sort count 35 if ( i < nCount ) 36 { 37 a = i - 1; // [0] 38 b = i; // [1] 39 do 40 { 41 if ( pRect[a].top != pRect[b].top ) break; 42 if ( pRect[a].left > pRect[b].left ) 43 { 44 sRect = pRect[a]; 45 pRect[a] = pRect[b]; 46 pRect[b] = sRect; 47 } 48 ++s; 49 b++; 50 } 51 while ( s < nCount ); 52 } 53 ++i; 54 } 55 while ( c-- != 1 ); 56 } 57 } 58 59 /* 60 * I thought it was okay to have this in DeleteObject but~ Speed. (jt) 61 */ 62 BOOL 63 FASTCALL 64 DeleteRegion( 65 _In_ HRGN hrgn) 66 { 67 PRGN_ATTR Rgn_Attr = GdiGetRgnAttr(hrgn); 68 69 if ( Rgn_Attr ) 70 { 71 PGDIBSOBJECT pgO; 72 73 pgO = GdiAllocBatchCommand(NULL, GdiBCDelRgn); 74 if (pgO) 75 { 76 pgO->hgdiobj = hrgn; 77 return TRUE; 78 } 79 } 80 return NtGdiDeleteObjectApp(hrgn); 81 } 82 83 INT 84 FASTCALL 85 MirrorRgnByWidth( 86 _In_ HRGN hrgn, 87 _In_ INT Width, 88 _Out_opt_ HRGN *phrgn) 89 { 90 INT cRgnDSize, Ret = 0; 91 PRGNDATA pRgnData; 92 93 cRgnDSize = NtGdiGetRegionData(hrgn, 0, NULL); 94 95 if (cRgnDSize) 96 { 97 pRgnData = HeapAlloc(GetProcessHeap(), 0, cRgnDSize * sizeof(LONG)); 98 if (pRgnData) 99 { 100 if ( GetRegionData(hrgn, cRgnDSize, pRgnData) ) 101 { 102 HRGN hRgnex; 103 UINT i; 104 INT SaveL = pRgnData->rdh.rcBound.left; 105 pRgnData->rdh.rcBound.left = Width - pRgnData->rdh.rcBound.right; 106 pRgnData->rdh.rcBound.right = Width - SaveL; 107 if (pRgnData->rdh.nCount > 0) 108 { 109 PRECT pRect = (PRECT)&pRgnData->Buffer; 110 for (i = 0; i < pRgnData->rdh.nCount; i++) 111 { 112 SaveL = pRect[i].left; 113 pRect[i].left = Width - pRect[i].right; 114 pRect[i].right = Width - SaveL; 115 } 116 } 117 SortRects((PRECT)&pRgnData->Buffer, pRgnData->rdh.nCount); 118 hRgnex = ExtCreateRegion(NULL, cRgnDSize , pRgnData); 119 if (hRgnex) 120 { 121 if (phrgn) 122 { 123 *phrgn = hRgnex; 124 } 125 else 126 { 127 CombineRgn(hrgn, hRgnex, 0, RGN_COPY); 128 DeleteObject(hRgnex); 129 } 130 Ret = 1; 131 } 132 } 133 HeapFree( GetProcessHeap(), 0, pRgnData); 134 } 135 } 136 return Ret; 137 } 138 139 INT 140 WINAPI 141 MirrorRgnDC( 142 _In_ HDC hdc, 143 _In_ HRGN hrgn, 144 _Out_opt_ HRGN *phrn) 145 { 146 if (!GdiValidateHandle((HGDIOBJ) hdc) || 147 (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC)) 148 return 0; 149 150 return MirrorRgnByWidth(hrgn, NtGdiGetDeviceWidth(hdc), phrn); 151 } 152 153 /* FUNCTIONS *****************************************************************/ 154 155 FORCEINLINE 156 ULONG 157 IntSetNullRgn( 158 _Inout_ PRGN_ATTR prgnattr) 159 { 160 prgnattr->iComplexity = NULLREGION; 161 prgnattr->AttrFlags |= ATTR_RGN_DIRTY; 162 prgnattr->Rect.left = prgnattr->Rect.top = prgnattr->Rect.right = prgnattr->Rect.bottom = 0; 163 return NULLREGION; 164 } 165 166 FORCEINLINE 167 ULONG 168 IntSetRectRgn( 169 _Inout_ PRGN_ATTR prgnattr, 170 _In_ INT xLeft, 171 _In_ INT yTop, 172 _In_ INT xRight, 173 _In_ INT yBottom) 174 { 175 ASSERT(xLeft <= xRight); 176 ASSERT(yTop <= yBottom); 177 178 if ((xLeft == xRight) || (yTop == yBottom)) 179 return IntSetNullRgn(prgnattr); 180 181 prgnattr->iComplexity = SIMPLEREGION; 182 prgnattr->Rect.left = xLeft; 183 prgnattr->Rect.top = yTop; 184 prgnattr->Rect.right = xRight; 185 prgnattr->Rect.bottom = yBottom; 186 prgnattr->AttrFlags |= ATTR_RGN_DIRTY; 187 return SIMPLEREGION; 188 } 189 190 /* 191 * @implemented 192 */ 193 INT 194 WINAPI 195 CombineRgn( 196 _In_ HRGN hrgnDest, 197 _In_ HRGN hrgnSrc1, 198 _In_ HRGN hrgnSrc2, 199 _In_ INT iCombineMode) 200 { 201 PRGN_ATTR prngattrDest = NULL; 202 PRGN_ATTR prngattrSrc1 = NULL; 203 PRGN_ATTR prngattrSrc2 = NULL; 204 RECT rcTemp; 205 206 /* Get the region attribute for dest and source 1 */ 207 prngattrDest = GdiGetRgnAttr(hrgnDest); 208 prngattrSrc1 = GdiGetRgnAttr(hrgnSrc1); 209 210 /* If that failed or if the source 1 region is complex, go to win32k */ 211 if ((prngattrDest == NULL) || (prngattrSrc1 == NULL) || 212 (prngattrSrc1->iComplexity > SIMPLEREGION)) 213 { 214 return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode); 215 } 216 217 /* Handle RGN_COPY first, it needs only hrgnSrc1 */ 218 if (iCombineMode == RGN_COPY) 219 { 220 /* Check if the source region is a NULLREGION */ 221 if (prngattrSrc1->iComplexity == NULLREGION) 222 { 223 /* The dest region is a NULLREGION, too */ 224 return IntSetNullRgn(prngattrDest); 225 } 226 227 /* We already know that the source region cannot be complex, so 228 create a rect region from the bounds of the source rect */ 229 return IntSetRectRgn(prngattrDest, 230 prngattrSrc1->Rect.left, 231 prngattrSrc1->Rect.top, 232 prngattrSrc1->Rect.right, 233 prngattrSrc1->Rect.bottom); 234 } 235 236 /* For all other operations we need hrgnSrc2 */ 237 prngattrSrc2 = GdiGetRgnAttr(hrgnSrc2); 238 239 /* If we got no attribute or the region is complex, go to win32k */ 240 if ((prngattrSrc2 == NULL) || (prngattrSrc2->iComplexity > SIMPLEREGION)) 241 { 242 return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode); 243 } 244 245 /* Handle RGN_AND */ 246 if (iCombineMode == RGN_AND) 247 { 248 /* Check if either of the regions is a NULLREGION */ 249 if ((prngattrSrc1->iComplexity == NULLREGION) || 250 (prngattrSrc2->iComplexity == NULLREGION)) 251 { 252 /* Result is also a NULLREGION */ 253 return IntSetNullRgn(prngattrDest); 254 } 255 256 /* Get the intersection of the 2 rects */ 257 if (!IntersectRect(&rcTemp, &prngattrSrc1->Rect, &prngattrSrc2->Rect)) 258 { 259 /* The rects do not intersect, result is a NULLREGION */ 260 return IntSetNullRgn(prngattrDest); 261 } 262 263 /* Use the intersection of the rects */ 264 return IntSetRectRgn(prngattrDest, 265 rcTemp.left, 266 rcTemp.top, 267 rcTemp.right, 268 rcTemp.bottom); 269 } 270 271 /* Handle RGN_DIFF */ 272 if (iCombineMode == RGN_DIFF) 273 { 274 /* Check if source 1 is a NULLREGION */ 275 if (prngattrSrc1->iComplexity == NULLREGION) 276 { 277 /* The result is a NULLREGION as well */ 278 return IntSetNullRgn(prngattrDest); 279 } 280 281 /* Get the intersection of the 2 rects */ 282 if ((prngattrSrc2->iComplexity == NULLREGION) || 283 !IntersectRect(&rcTemp, &prngattrSrc1->Rect, &prngattrSrc2->Rect)) 284 { 285 /* The rects do not intersect, dest equals source 1 */ 286 return IntSetRectRgn(prngattrDest, 287 prngattrSrc1->Rect.left, 288 prngattrSrc1->Rect.top, 289 prngattrSrc1->Rect.right, 290 prngattrSrc1->Rect.bottom); 291 } 292 293 /* We need to check is whether we can subtract the rects. For that 294 we call SubtractRect, which will give us the bounding box of the 295 subtraction. The function returns FALSE if the resulting rect is 296 empty */ 297 if (!SubtractRect(&rcTemp, &prngattrSrc1->Rect, &rcTemp)) 298 { 299 /* The result is a NULLREGION */ 300 return IntSetNullRgn(prngattrDest); 301 } 302 303 /* Now check if the result of SubtractRect matches the source 1 rect. 304 Since we already know that the rects intersect, the result can 305 only match the source 1 rect, if it could not be "cut" on either 306 side, but the overlapping was on a corner, so the new bounding box 307 equals the previous rect */ 308 if (!EqualRect(&rcTemp, &prngattrSrc1->Rect)) 309 { 310 /* We got a properly subtracted rect, so use it. */ 311 return IntSetRectRgn(prngattrDest, 312 rcTemp.left, 313 rcTemp.top, 314 rcTemp.right, 315 rcTemp.bottom); 316 } 317 318 /* The result would be a complex region, go to win32k */ 319 return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode); 320 } 321 322 /* Handle OR and XOR */ 323 if ((iCombineMode == RGN_OR) || (iCombineMode == RGN_XOR)) 324 { 325 /* Check if source 1 is a NULLREGION */ 326 if (prngattrSrc1->iComplexity == NULLREGION) 327 { 328 /* Check if source 2 is also a NULLREGION */ 329 if (prngattrSrc2->iComplexity == NULLREGION) 330 { 331 /* Both are NULLREGIONs, result is also a NULLREGION */ 332 return IntSetNullRgn(prngattrDest); 333 } 334 335 /* The result is equal to source 2 */ 336 return IntSetRectRgn(prngattrDest, 337 prngattrSrc2->Rect.left, 338 prngattrSrc2->Rect.top, 339 prngattrSrc2->Rect.right, 340 prngattrSrc2->Rect.bottom ); 341 } 342 343 /* Check if only source 2 is a NULLREGION */ 344 if (prngattrSrc2->iComplexity == NULLREGION) 345 { 346 /* The result is equal to source 1 */ 347 return IntSetRectRgn(prngattrDest, 348 prngattrSrc1->Rect.left, 349 prngattrSrc1->Rect.top, 350 prngattrSrc1->Rect.right, 351 prngattrSrc1->Rect.bottom); 352 } 353 354 /* Do the rects have the same x extent */ 355 if ((prngattrSrc1->Rect.left == prngattrSrc2->Rect.left) && 356 (prngattrSrc1->Rect.right == prngattrSrc2->Rect.right)) 357 { 358 /* Do the rects also have the same y extent */ 359 if ((prngattrSrc1->Rect.top == prngattrSrc2->Rect.top) && 360 (prngattrSrc1->Rect.bottom == prngattrSrc2->Rect.bottom)) 361 { 362 /* Rects are equal, if this is RGN_OR, the result is source 1 */ 363 if (iCombineMode == RGN_OR) 364 { 365 /* The result is equal to source 1 */ 366 return IntSetRectRgn(prngattrDest, 367 prngattrSrc1->Rect.left, 368 prngattrSrc1->Rect.top, 369 prngattrSrc1->Rect.right, 370 prngattrSrc1->Rect.bottom ); 371 } 372 else 373 { 374 /* XORing with itself yields an empty region */ 375 return IntSetNullRgn(prngattrDest); 376 } 377 } 378 379 /* Check if the rects are disjoint */ 380 if ((prngattrSrc2->Rect.bottom < prngattrSrc1->Rect.top) || 381 (prngattrSrc2->Rect.top > prngattrSrc1->Rect.bottom)) 382 { 383 /* The result would be a complex region, go to win32k */ 384 return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode); 385 } 386 387 /* Check if this is OR */ 388 if (iCombineMode == RGN_OR) 389 { 390 /* Use the maximum extent of both rects combined */ 391 return IntSetRectRgn(prngattrDest, 392 prngattrSrc1->Rect.left, 393 min(prngattrSrc1->Rect.top, prngattrSrc2->Rect.top), 394 prngattrSrc1->Rect.right, 395 max(prngattrSrc1->Rect.bottom, prngattrSrc2->Rect.bottom)); 396 } 397 398 /* Check if the rects are adjacent */ 399 if (prngattrSrc2->Rect.bottom == prngattrSrc1->Rect.top) 400 { 401 /* The result is the combined rects */ 402 return IntSetRectRgn(prngattrDest, 403 prngattrSrc1->Rect.left, 404 prngattrSrc2->Rect.top, 405 prngattrSrc1->Rect.right, 406 prngattrSrc1->Rect.bottom ); 407 } 408 else if (prngattrSrc2->Rect.top == prngattrSrc1->Rect.bottom) 409 { 410 /* The result is the combined rects */ 411 return IntSetRectRgn(prngattrDest, 412 prngattrSrc1->Rect.left, 413 prngattrSrc1->Rect.top, 414 prngattrSrc1->Rect.right, 415 prngattrSrc2->Rect.bottom ); 416 } 417 418 /* When we are here, this is RGN_XOR and the rects overlap */ 419 return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode); 420 } 421 422 /* Do the rects have the same y extent */ 423 if ((prngattrSrc1->Rect.top == prngattrSrc2->Rect.top) && 424 (prngattrSrc1->Rect.bottom == prngattrSrc2->Rect.bottom)) 425 { 426 /* Check if the rects are disjoint */ 427 if ((prngattrSrc2->Rect.right < prngattrSrc1->Rect.left) || 428 (prngattrSrc2->Rect.left > prngattrSrc1->Rect.right)) 429 { 430 /* The result would be a complex region, go to win32k */ 431 return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode); 432 } 433 434 /* Check if this is OR */ 435 if (iCombineMode == RGN_OR) 436 { 437 /* Use the maximum extent of both rects combined */ 438 return IntSetRectRgn(prngattrDest, 439 min(prngattrSrc1->Rect.left, prngattrSrc2->Rect.left), 440 prngattrSrc1->Rect.top, 441 max(prngattrSrc1->Rect.right, prngattrSrc2->Rect.right), 442 prngattrSrc1->Rect.bottom); 443 } 444 445 /* Check if the rects are adjacent */ 446 if (prngattrSrc2->Rect.right == prngattrSrc1->Rect.left) 447 { 448 /* The result is the combined rects */ 449 return IntSetRectRgn(prngattrDest, 450 prngattrSrc2->Rect.left, 451 prngattrSrc1->Rect.top, 452 prngattrSrc1->Rect.right, 453 prngattrSrc1->Rect.bottom ); 454 } 455 else if (prngattrSrc2->Rect.left == prngattrSrc1->Rect.right) 456 { 457 /* The result is the combined rects */ 458 return IntSetRectRgn(prngattrDest, 459 prngattrSrc1->Rect.left, 460 prngattrSrc1->Rect.top, 461 prngattrSrc2->Rect.right, 462 prngattrSrc1->Rect.bottom ); 463 } 464 465 /* When we are here, this is RGN_XOR and the rects overlap */ 466 return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode); 467 } 468 469 /* Last case: RGN_OR and one rect is completely within the other */ 470 if (iCombineMode == RGN_OR) 471 { 472 /* Check if rect 1 can contain rect 2 */ 473 if (prngattrSrc1->Rect.left <= prngattrSrc2->Rect.left) 474 { 475 /* rect 1 might be the outer one, check of that is true */ 476 if ((prngattrSrc1->Rect.right >= prngattrSrc2->Rect.right) && 477 (prngattrSrc1->Rect.top <= prngattrSrc2->Rect.top) && 478 (prngattrSrc1->Rect.bottom >= prngattrSrc2->Rect.bottom)) 479 { 480 /* Rect 1 contains rect 2, use it */ 481 return IntSetRectRgn(prngattrDest, 482 prngattrSrc1->Rect.left, 483 prngattrSrc1->Rect.top, 484 prngattrSrc1->Rect.right, 485 prngattrSrc1->Rect.bottom ); 486 } 487 } 488 else 489 { 490 /* rect 2 might be the outer one, check of that is true */ 491 if ((prngattrSrc2->Rect.right >= prngattrSrc1->Rect.right) && 492 (prngattrSrc2->Rect.top <= prngattrSrc1->Rect.top) && 493 (prngattrSrc2->Rect.bottom >= prngattrSrc1->Rect.bottom)) 494 { 495 /* Rect 2 contains rect 1, use it */ 496 return IntSetRectRgn(prngattrDest, 497 prngattrSrc2->Rect.left, 498 prngattrSrc2->Rect.top, 499 prngattrSrc2->Rect.right, 500 prngattrSrc2->Rect.bottom ); 501 } 502 } 503 } 504 505 /* We couldn't handle the operation, go to win32k */ 506 return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode); 507 } 508 509 DPRINT1("Invalid iCombineMode %d\n", iCombineMode); 510 SetLastError(ERROR_INVALID_PARAMETER); 511 return ERROR; 512 } 513 514 515 /* 516 * @implemented 517 */ 518 HRGN 519 WINAPI 520 CreateEllipticRgnIndirect( 521 const RECT *prc 522 ) 523 { 524 /* Notes if prc is NULL it will crash on All Windows NT I checked 2000/XP/VISTA */ 525 return NtGdiCreateEllipticRgn(prc->left, prc->top, prc->right, prc->bottom); 526 527 } 528 529 /* 530 * @implemented 531 */ 532 HRGN 533 WINAPI 534 CreatePolygonRgn( const POINT * lppt, int cPoints, int fnPolyFillMode) 535 { 536 return (HRGN) NtGdiPolyPolyDraw( (HDC)UlongToHandle(fnPolyFillMode), (PPOINT) lppt, (PULONG) &cPoints, 1, GdiPolyPolyRgn); 537 } 538 539 /* 540 * @implemented 541 */ 542 HRGN 543 WINAPI 544 CreatePolyPolygonRgn( const POINT* lppt, 545 const INT* lpPolyCounts, 546 int nCount, 547 int fnPolyFillMode) 548 { 549 return (HRGN) NtGdiPolyPolyDraw( (HDC)UlongToHandle(fnPolyFillMode), (PPOINT) lppt, (PULONG) lpPolyCounts, (ULONG) nCount, GdiPolyPolyRgn ); 550 } 551 552 /* 553 * @implemented 554 */ 555 HRGN 556 WINAPI 557 CreateRectRgn(int x1, int y1, int x2, int y2) 558 { 559 PRGN_ATTR pRgn_Attr; 560 HRGN hrgn = NULL; 561 int tmp; 562 563 /* Normalize points, REGION_SetRectRgn does this too. */ 564 if ( x1 > x2 ) 565 { 566 tmp = x1; 567 x1 = x2; 568 x2 = tmp; 569 } 570 571 if ( y1 > y2 ) 572 { 573 tmp = y1; 574 y1 = y2; 575 y2 = tmp; 576 } 577 /* Check outside 28 bit limit for universal set bound box. REGION_SetRectRgn doesn't do this! */ 578 if ( x1 < MIN_COORD || 579 y1 < MIN_COORD || 580 x2 > MAX_COORD || 581 y2 > MAX_COORD ) 582 { 583 SetLastError(ERROR_INVALID_PARAMETER); 584 return NULL; 585 } 586 587 hrgn = hGetPEBHandle(hctRegionHandle, 0); 588 if (hrgn) 589 { 590 DPRINT1("PEB Handle Cache Test return hrgn %p, should be NULL!\n",hrgn); 591 hrgn = NULL; 592 } 593 594 if (!hrgn) 595 hrgn = NtGdiCreateRectRgn(0, 0, 1, 1); 596 597 if (!hrgn) 598 return hrgn; 599 600 if (!(pRgn_Attr = GdiGetRgnAttr(hrgn)) ) 601 { 602 DPRINT1("No Attr for Region handle!!!\n"); 603 DeleteRegion(hrgn); 604 return NULL; 605 } 606 607 pRgn_Attr->AttrFlags = ATTR_RGN_VALID; 608 609 IntSetRectRgn( pRgn_Attr, x1, y1, x2, y2 ); 610 611 return hrgn; 612 } 613 614 /* 615 * @implemented 616 */ 617 HRGN 618 WINAPI 619 CreateRectRgnIndirect( 620 const RECT *prc 621 ) 622 { 623 /* Notes if prc is NULL it will crash on All Windows NT I checked 2000/XP/VISTA */ 624 return CreateRectRgn(prc->left, prc->top, prc->right, prc->bottom); 625 626 } 627 628 /* 629 * @implemented 630 */ 631 INT 632 WINAPI 633 ExcludeClipRect( 634 _In_ HDC hdc, 635 _In_ INT xLeft, 636 _In_ INT yTop, 637 _In_ INT xRight, 638 _In_ INT yBottom) 639 { 640 HANDLE_METADC(INT, ExcludeClipRect, ERROR, hdc, xLeft, yTop, xRight, yBottom); 641 642 return NtGdiExcludeClipRect(hdc, xLeft, yTop, xRight, yBottom); 643 } 644 645 /* 646 * @implemented 647 */ 648 HRGN 649 WINAPI 650 ExtCreateRegion( 651 CONST XFORM * lpXform, 652 DWORD nCount, 653 CONST RGNDATA * lpRgnData 654 ) 655 { 656 if (lpRgnData) 657 { 658 if ((!lpXform) && (lpRgnData->rdh.nCount == 1)) 659 { 660 PRECT pRect = (PRECT)&lpRgnData->Buffer[0]; 661 return CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom); 662 } 663 return NtGdiExtCreateRegion((LPXFORM) lpXform, nCount,(LPRGNDATA) lpRgnData); 664 } 665 SetLastError(ERROR_INVALID_PARAMETER); 666 return NULL; 667 } 668 669 /* 670 * @implemented 671 */ 672 INT 673 WINAPI 674 ExtSelectClipRgn( 675 _In_ HDC hdc, 676 _In_ HRGN hrgn, 677 _In_ INT iMode) 678 { 679 INT Ret; 680 HRGN NewRgn = NULL; 681 682 HANDLE_METADC(INT, ExtSelectClipRgn, 0, hdc, hrgn, iMode); 683 684 #if 0 685 if ( hrgn ) 686 { 687 if ( GetLayout(hdc) & LAYOUT_RTL ) 688 { 689 if ( MirrorRgnDC(hdc, hrgn, &NewRgn) ) 690 { 691 if ( NewRgn ) hrgn = NewRgn; 692 } 693 } 694 } 695 #endif 696 /* Batch handles RGN_COPY only! */ 697 if (iMode == RGN_COPY) 698 { 699 PDC_ATTR pdcattr; 700 PRGN_ATTR pRgn_Attr = NULL; 701 702 /* Get the DC attribute */ 703 pdcattr = GdiGetDcAttr(hdc); 704 if ( pdcattr ) 705 { 706 PGDI_TABLE_ENTRY pEntry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hdc); 707 708 /* hrgn can be NULL unless the RGN_COPY mode is specified. */ 709 if (hrgn) pRgn_Attr = GdiGetRgnAttr(hrgn); 710 711 if ( !(pdcattr->ulDirty_ & DC_DIBSECTION) && 712 !(pEntry->Flags & GDI_ENTRY_VALIDATE_VIS) ) 713 { 714 if (!hrgn || (hrgn && pRgn_Attr && pRgn_Attr->iComplexity <= SIMPLEREGION) ) 715 { 716 PGDIBSEXTSELCLPRGN pgO = GdiAllocBatchCommand(hdc, GdiBCExtSelClipRgn); 717 if (pgO) 718 { 719 pgO->fnMode = iMode; 720 721 if ( hrgn && pRgn_Attr ) 722 { 723 Ret = pRgn_Attr->iComplexity; 724 // Note from ntgdi/dcstate.c : "The VisRectRegion field needs to be set to a valid state." 725 if ( pdcattr->VisRectRegion.Rect.left >= pRgn_Attr->Rect.right || 726 pdcattr->VisRectRegion.Rect.top >= pRgn_Attr->Rect.bottom || 727 pdcattr->VisRectRegion.Rect.right <= pRgn_Attr->Rect.left || 728 pdcattr->VisRectRegion.Rect.bottom <= pRgn_Attr->Rect.top ) 729 Ret = NULLREGION; 730 731 // Pass the rect since this region will go away. 732 pgO->rcl = pRgn_Attr->Rect; 733 } 734 else 735 { 736 Ret = pdcattr->VisRectRegion.iComplexity; 737 pgO->fnMode |= GDIBS_NORECT; // Set no hrgn mode. 738 } 739 if ( NewRgn ) DeleteObject(NewRgn); 740 return Ret; 741 } 742 } 743 } 744 } 745 } 746 Ret = NtGdiExtSelectClipRgn(hdc, hrgn, iMode); 747 748 if ( NewRgn ) DeleteObject(NewRgn); 749 750 return Ret; 751 } 752 753 /* 754 * @implemented 755 */ 756 int 757 WINAPI 758 GetClipRgn( 759 HDC hdc, 760 HRGN hrgn 761 ) 762 { 763 INT Ret; 764 765 /* Check if DC handle is valid */ 766 if (!GdiGetDcAttr(hdc)) 767 { 768 /* Last error code differs from what NtGdiGetRandomRgn returns */ 769 SetLastError(ERROR_INVALID_PARAMETER); 770 return -1; 771 } 772 773 Ret = NtGdiGetRandomRgn(hdc, hrgn, CLIPRGN); 774 775 // if (Ret) 776 // { 777 // if(GetLayout(hdc) & LAYOUT_RTL) MirrorRgnDC(hdc,(HRGN)Ret, NULL); 778 // } 779 return Ret; 780 } 781 782 /* 783 * @implemented 784 */ 785 int 786 WINAPI 787 GetMetaRgn(HDC hdc, 788 HRGN hrgn) 789 { 790 return NtGdiGetRandomRgn(hdc, hrgn, METARGN); 791 } 792 793 /* 794 * @implemented 795 * 796 */ 797 DWORD 798 WINAPI 799 GetRegionData(HRGN hrgn, 800 DWORD nCount, 801 LPRGNDATA lpRgnData) 802 { 803 if (!lpRgnData) 804 { 805 nCount = 0; 806 } 807 808 return NtGdiGetRegionData(hrgn,nCount,lpRgnData); 809 } 810 811 /* 812 * @implemented 813 * 814 */ 815 INT 816 WINAPI 817 GetRgnBox(HRGN hrgn, 818 LPRECT prcOut) 819 { 820 PRGN_ATTR Rgn_Attr; 821 822 if (!(Rgn_Attr = GdiGetRgnAttr(hrgn))) 823 return NtGdiGetRgnBox(hrgn, prcOut); 824 825 if (Rgn_Attr->iComplexity == NULLREGION) 826 { 827 prcOut->left = 0; 828 prcOut->top = 0; 829 prcOut->right = 0; 830 prcOut->bottom = 0; 831 } 832 else 833 { 834 if (Rgn_Attr->iComplexity != SIMPLEREGION) 835 return NtGdiGetRgnBox(hrgn, prcOut); 836 /* WARNING! prcOut is never checked newbies! */ 837 RtlCopyMemory( prcOut, &Rgn_Attr->Rect, sizeof(RECT)); 838 } 839 return Rgn_Attr->iComplexity; 840 } 841 842 /* 843 * @implemented 844 */ 845 INT 846 WINAPI 847 IntersectClipRect( 848 _In_ HDC hdc, 849 _In_ INT nLeft, 850 _In_ INT nTop, 851 _In_ INT nRight, 852 _In_ INT nBottom) 853 { 854 HANDLE_METADC(INT, IntersectClipRect, ERROR, hdc, nLeft, nTop, nRight, nBottom); 855 return NtGdiIntersectClipRect(hdc, nLeft, nTop, nRight, nBottom); 856 } 857 858 /* 859 * @implemented 860 */ 861 BOOL 862 WINAPI 863 MirrorRgn(HWND hwnd, HRGN hrgn) 864 { 865 INT l; 866 RECT Rect; 867 GetWindowRect(hwnd, &Rect); 868 l = Rect.right - Rect.left; 869 Rect.right -= Rect.left; 870 return MirrorRgnByWidth(hrgn, l, NULL); 871 } 872 873 /* 874 * @implemented 875 */ 876 INT 877 WINAPI 878 OffsetClipRgn( 879 HDC hdc, 880 INT nXOffset, 881 INT nYOffset) 882 { 883 HANDLE_METADC(INT, OffsetClipRgn, ERROR, hdc, nXOffset, nYOffset); 884 return NtGdiOffsetClipRgn(hdc, nXOffset, nYOffset); 885 } 886 887 /* 888 * @implemented 889 * 890 */ 891 INT 892 WINAPI 893 OffsetRgn( HRGN hrgn, 894 int nXOffset, 895 int nYOffset) 896 { 897 PRGN_ATTR pRgn_Attr; 898 RECTL rc; 899 900 if (!(pRgn_Attr = GdiGetRgnAttr(hrgn))) 901 return NtGdiOffsetRgn(hrgn,nXOffset,nYOffset); 902 903 if ( pRgn_Attr->iComplexity == NULLREGION) 904 return pRgn_Attr->iComplexity; 905 906 if ( pRgn_Attr->iComplexity != SIMPLEREGION) 907 return NtGdiOffsetRgn(hrgn,nXOffset,nYOffset); 908 909 rc = pRgn_Attr->Rect; 910 911 if (rc.left < rc.right) 912 { 913 if (rc.top < rc.bottom) 914 { 915 rc.left += nXOffset; 916 rc.top += nYOffset; 917 rc.right += nXOffset; 918 rc.bottom += nYOffset; 919 920 /* Make sure the offset is within the legal range */ 921 if ( (rc.left & MIN_COORD && ((rc.left & MIN_COORD) != MIN_COORD)) || 922 (rc.top & MIN_COORD && ((rc.top & MIN_COORD) != MIN_COORD)) || 923 (rc.right & MIN_COORD && ((rc.right & MIN_COORD) != MIN_COORD)) || 924 (rc.bottom & MIN_COORD && ((rc.bottom & MIN_COORD) != MIN_COORD)) ) 925 { 926 DPRINT("OffsetRgn ERROR\n"); 927 return ERROR; 928 } 929 930 pRgn_Attr->Rect = rc; 931 pRgn_Attr->AttrFlags |= ATTR_RGN_DIRTY; 932 } 933 } 934 return pRgn_Attr->iComplexity; 935 } 936 937 /* 938 * @implemented 939 */ 940 BOOL 941 WINAPI 942 PtInRegion(IN HRGN hrgn, 943 int x, 944 int y) 945 { 946 PRGN_ATTR pRgn_Attr; 947 948 if (!(pRgn_Attr = GdiGetRgnAttr(hrgn))) 949 return NtGdiPtInRegion(hrgn,x,y); 950 951 if ( pRgn_Attr->iComplexity == NULLREGION) 952 return FALSE; 953 954 if ( pRgn_Attr->iComplexity != SIMPLEREGION) 955 return NtGdiPtInRegion(hrgn,x,y); 956 957 return INRECT( pRgn_Attr->Rect, x, y); 958 } 959 960 /* 961 * @implemented 962 */ 963 BOOL 964 WINAPI 965 RectInRegion(HRGN hrgn, 966 LPCRECT prcl) 967 { 968 PRGN_ATTR pRgn_Attr; 969 RECTL rc; 970 971 if (!(pRgn_Attr = GdiGetRgnAttr(hrgn))) 972 return NtGdiRectInRegion(hrgn, (LPRECT) prcl); 973 974 if ( pRgn_Attr->iComplexity == NULLREGION) 975 return FALSE; 976 977 if ( pRgn_Attr->iComplexity != SIMPLEREGION) 978 return NtGdiRectInRegion(hrgn, (LPRECT) prcl); 979 980 /* swap the coordinates to make right >= left and bottom >= top */ 981 /* (region building rectangles are normalized the same way) */ 982 if ( prcl->top > prcl->bottom) 983 { 984 rc.top = prcl->bottom; 985 rc.bottom = prcl->top; 986 } 987 else 988 { 989 rc.top = prcl->top; 990 rc.bottom = prcl->bottom; 991 } 992 if ( prcl->right < prcl->left) 993 { 994 rc.right = prcl->left; 995 rc.left = prcl->right; 996 } 997 else 998 { 999 rc.right = prcl->right; 1000 rc.left = prcl->left; 1001 } 1002 1003 if ( ( pRgn_Attr->Rect.left >= rc.right ) || 1004 ( pRgn_Attr->Rect.right <= rc.left ) || 1005 ( pRgn_Attr->Rect.top >= rc.bottom ) || 1006 ( pRgn_Attr->Rect.bottom <= rc.top ) ) 1007 { 1008 return FALSE; 1009 } 1010 1011 return TRUE; 1012 } 1013 1014 /* 1015 * @implemented 1016 */ 1017 int 1018 WINAPI 1019 SelectClipRgn( 1020 _In_ HDC hdc, 1021 _In_ HRGN hrgn) 1022 { 1023 return ExtSelectClipRgn(hdc, hrgn, RGN_COPY); 1024 } 1025 1026 /* 1027 * @implemented 1028 */ 1029 BOOL 1030 WINAPI 1031 SetRectRgn( 1032 _In_ HRGN hrgn, 1033 _In_ INT xLeft, 1034 _In_ INT yTop, 1035 _In_ INT xRight, 1036 _In_ INT yBottom) 1037 { 1038 PRGN_ATTR prngattr; 1039 1040 /* Try to get the region attribute */ 1041 prngattr = GdiGetRgnAttr(hrgn); 1042 if (prngattr == NULL) 1043 { 1044 return NtGdiSetRectRgn(hrgn, xLeft, yTop, xRight, yBottom); 1045 } 1046 1047 /* check for NULL region */ 1048 if ((xLeft == xRight) || (yTop == yBottom)) 1049 { 1050 IntSetNullRgn(prngattr); 1051 return TRUE; 1052 } 1053 1054 if (xLeft > xRight) 1055 { 1056 prngattr->Rect.left = xRight; 1057 prngattr->Rect.right = xLeft; 1058 } 1059 else 1060 { 1061 prngattr->Rect.left = xLeft; 1062 prngattr->Rect.right = xRight; 1063 } 1064 1065 if (yTop > yBottom) 1066 { 1067 prngattr->Rect.top = yBottom; 1068 prngattr->Rect.bottom = yTop; 1069 } 1070 else 1071 { 1072 prngattr->Rect.top = yTop; 1073 prngattr->Rect.bottom = yBottom; 1074 } 1075 1076 prngattr->AttrFlags |= ATTR_RGN_DIRTY ; 1077 prngattr->iComplexity = SIMPLEREGION; 1078 1079 return TRUE; 1080 } 1081 1082 /* 1083 * @implemented 1084 */ 1085 int 1086 WINAPI 1087 SetMetaRgn(HDC hDC) 1088 { 1089 if (GDI_HANDLE_GET_TYPE(hDC) == GDI_OBJECT_TYPE_DC) 1090 return NtGdiSetMetaRgn(hDC); 1091 #if 0 1092 PLDC pLDC = GdiGetLDC(hDC); 1093 if ( pLDC && GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_METADC ) 1094 { 1095 if (pLDC->iType == LDC_EMFLDC || EMFDRV_SetMetaRgn(hDC)) 1096 { 1097 return NtGdiSetMetaRgn(hDC); 1098 } 1099 else 1100 SetLastError(ERROR_INVALID_HANDLE); 1101 } 1102 #endif 1103 return ERROR; 1104 } 1105 1106