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