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