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