1 /* 2 * COPYRIGHT: GNU GPL, See COPYING in the top level directory 3 * PROJECT: ReactOS Win32k subsystem 4 * PURPOSE: Clip region functions 5 * FILE: win32ss/gdi/ntgdi/cliprgn.c 6 * PROGRAMER: Unknown 7 */ 8 9 #include <win32k.h> 10 11 #define NDEBUG 12 #include <debug.h> 13 14 VOID 15 FASTCALL 16 IntGdiReleaseRaoRgn(PDC pDC) 17 { 18 INT Index = GDI_HANDLE_GET_INDEX(pDC->BaseObject.hHmgr); 19 PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index]; 20 pDC->fs |= DC_FLAG_DIRTY_RAO; 21 Entry->Flags |= GDI_ENTRY_VALIDATE_VIS; 22 RECTL_vSetEmptyRect(&pDC->erclClip); 23 REGION_Delete(pDC->prgnRao); 24 pDC->prgnRao = NULL; 25 } 26 27 VOID 28 FASTCALL 29 IntGdiReleaseVisRgn(PDC pDC) 30 { 31 INT Index = GDI_HANDLE_GET_INDEX(pDC->BaseObject.hHmgr); 32 PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index]; 33 pDC->fs |= DC_FLAG_DIRTY_RAO; 34 Entry->Flags |= GDI_ENTRY_VALIDATE_VIS; 35 RECTL_vSetEmptyRect(&pDC->erclClip); 36 REGION_Delete(pDC->prgnVis); 37 pDC->prgnVis = prgnDefault; 38 } 39 40 VOID 41 FASTCALL 42 GdiSelectVisRgn( 43 HDC hdc, 44 PREGION prgn) 45 { 46 DC *dc; 47 48 if (!(dc = DC_LockDc(hdc))) 49 { 50 EngSetLastError(ERROR_INVALID_HANDLE); 51 return; 52 } 53 54 dc->fs |= DC_FLAG_DIRTY_RAO; 55 56 ASSERT(dc->prgnVis != NULL); 57 ASSERT(prgn != NULL); 58 59 IntGdiCombineRgn(dc->prgnVis, prgn, NULL, RGN_COPY); 60 REGION_bOffsetRgn(dc->prgnVis, -dc->ptlDCOrig.x, -dc->ptlDCOrig.y); 61 62 DC_UnlockDc(dc); 63 } 64 65 66 int 67 FASTCALL 68 IntGdiExtSelectClipRgn( 69 PDC dc, 70 PREGION prgn, 71 int fnMode) 72 { 73 if (fnMode == RGN_COPY) 74 { 75 if (!prgn) 76 { 77 if (dc->dclevel.prgnClip != NULL) 78 { 79 REGION_Delete(dc->dclevel.prgnClip); 80 dc->dclevel.prgnClip = NULL; 81 dc->fs |= DC_FLAG_DIRTY_RAO; 82 } 83 return SIMPLEREGION; 84 } 85 86 if (!dc->dclevel.prgnClip) 87 dc->dclevel.prgnClip = IntSysCreateRectpRgn(0, 0, 0, 0); 88 89 dc->fs |= DC_FLAG_DIRTY_RAO; 90 91 return IntGdiCombineRgn(dc->dclevel.prgnClip, prgn, NULL, RGN_COPY); 92 } 93 94 ASSERT(prgn != NULL); 95 96 if (!dc->dclevel.prgnClip) 97 { 98 RECTL rect; 99 100 REGION_GetRgnBox(dc->prgnVis, &rect); 101 dc->dclevel.prgnClip = IntSysCreateRectpRgnIndirect(&rect); 102 } 103 104 dc->fs |= DC_FLAG_DIRTY_RAO; 105 106 return IntGdiCombineRgn(dc->dclevel.prgnClip, dc->dclevel.prgnClip, prgn, fnMode); 107 } 108 109 110 int 111 APIENTRY 112 NtGdiExtSelectClipRgn( 113 HDC hDC, 114 HRGN hrgn, 115 int fnMode) 116 { 117 int retval; 118 DC *dc; 119 PREGION prgn; 120 121 if (!(dc = DC_LockDc(hDC))) 122 { 123 EngSetLastError(ERROR_INVALID_HANDLE); 124 return ERROR; 125 } 126 127 prgn = REGION_LockRgn(hrgn); 128 129 if ((prgn == NULL) && (fnMode != RGN_COPY)) 130 { 131 EngSetLastError(ERROR_INVALID_HANDLE); 132 retval = ERROR; 133 } 134 else 135 { 136 retval = IntGdiExtSelectClipRgn(dc, prgn, fnMode); 137 } 138 139 if (prgn) 140 REGION_UnlockRgn(prgn); 141 142 DC_UnlockDc(dc); 143 return retval; 144 } 145 146 _Success_(return!=ERROR) 147 INT 148 FASTCALL 149 GdiGetClipBox( 150 _In_ HDC hdc, 151 _Out_ LPRECT prc) 152 { 153 PDC pdc; 154 INT iComplexity; 155 156 /* Lock the DC */ 157 pdc = DC_LockDc(hdc); 158 if (!pdc) 159 { 160 return ERROR; 161 } 162 163 /* Update RAO region if necessary */ 164 if (pdc->fs & DC_FLAG_DIRTY_RAO) 165 CLIPPING_UpdateGCRegion(pdc); 166 167 /* Check if we have a RAO region (intersection of API and VIS region) */ 168 if (pdc->prgnRao) 169 { 170 /* We have a RAO region, use it */ 171 iComplexity = REGION_GetRgnBox(pdc->prgnRao, prc); 172 } 173 else 174 { 175 /* No RAO region means no API region, so use the VIS region */ 176 ASSERT(pdc->prgnVis); 177 iComplexity = REGION_GetRgnBox(pdc->prgnVis, prc); 178 } 179 180 /* Unlock the DC */ 181 DC_UnlockDc(pdc); 182 183 /* Convert the rect to logical coordinates */ 184 IntDPtoLP(pdc, (LPPOINT)prc, 2); 185 186 /* Return the complexity */ 187 return iComplexity; 188 } 189 190 _Success_(return!=ERROR) 191 INT 192 APIENTRY 193 NtGdiGetAppClipBox( 194 _In_ HDC hdc, 195 _Out_ LPRECT prc) 196 { 197 RECT rect; 198 INT iComplexity; 199 200 /* Call the internal function */ 201 iComplexity = GdiGetClipBox(hdc, &rect); 202 203 if (iComplexity != ERROR) 204 { 205 _SEH2_TRY 206 { 207 ProbeForWrite(prc, sizeof(RECT), 1); 208 *prc = rect; 209 } 210 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 211 { 212 iComplexity = ERROR; 213 } 214 _SEH2_END 215 } 216 217 /* Return the complexity */ 218 return iComplexity; 219 } 220 221 INT 222 APIENTRY 223 NtGdiExcludeClipRect( 224 _In_ HDC hdc, 225 _In_ INT xLeft, 226 _In_ INT yTop, 227 _In_ INT xRight, 228 _In_ INT yBottom) 229 { 230 INT iComplexity; 231 RECTL rect; 232 PDC pdc; 233 234 /* Lock the DC */ 235 pdc = DC_LockDc(hdc); 236 if (pdc == NULL) 237 { 238 EngSetLastError(ERROR_INVALID_HANDLE); 239 return ERROR; 240 } 241 242 /* Convert coordinates to device space */ 243 rect.left = xLeft; 244 rect.top = yTop; 245 rect.right = xRight; 246 rect.bottom = yBottom; 247 RECTL_vMakeWellOrdered(&rect); 248 IntLPtoDP(pdc, (LPPOINT)&rect, 2); 249 250 /* Check if we already have a clip region */ 251 if (pdc->dclevel.prgnClip != NULL) 252 { 253 /* We have a region, subtract the rect */ 254 iComplexity = REGION_SubtractRectFromRgn(pdc->dclevel.prgnClip, 255 pdc->dclevel.prgnClip, 256 &rect); 257 } 258 else 259 { 260 /* We don't have a clip region yet, create an empty region */ 261 pdc->dclevel.prgnClip = IntSysCreateRectpRgn(0, 0, 0, 0); 262 if (pdc->dclevel.prgnClip == NULL) 263 { 264 iComplexity = ERROR; 265 } 266 else 267 { 268 /* Subtract the rect from the VIS region */ 269 iComplexity = REGION_SubtractRectFromRgn(pdc->dclevel.prgnClip, 270 pdc->prgnVis, 271 &rect); 272 } 273 } 274 275 /* Emulate Windows behavior */ 276 if (iComplexity == SIMPLEREGION) 277 iComplexity = COMPLEXREGION; 278 279 /* If we succeeded, mark the RAO region as dirty */ 280 if (iComplexity != ERROR) 281 pdc->fs |= DC_FLAG_DIRTY_RAO; 282 283 /* Unlock the DC */ 284 DC_UnlockDc(pdc); 285 286 return iComplexity; 287 } 288 289 INT 290 APIENTRY 291 NtGdiIntersectClipRect( 292 _In_ HDC hdc, 293 _In_ INT xLeft, 294 _In_ INT yTop, 295 _In_ INT xRight, 296 _In_ INT yBottom) 297 { 298 INT iComplexity; 299 RECTL rect; 300 PREGION prgnNew; 301 PDC pdc; 302 303 DPRINT("NtGdiIntersectClipRect(%p, %d,%d-%d,%d)\n", 304 hdc, xLeft, yTop, xRight, yBottom); 305 306 /* Lock the DC */ 307 pdc = DC_LockDc(hdc); 308 if (!pdc) 309 { 310 EngSetLastError(ERROR_INVALID_HANDLE); 311 return ERROR; 312 } 313 314 /* Convert coordinates to device space */ 315 rect.left = xLeft; 316 rect.top = yTop; 317 rect.right = xRight; 318 rect.bottom = yBottom; 319 IntLPtoDP(pdc, (LPPOINT)&rect, 2); 320 321 /* Check if we already have a clip region */ 322 if (pdc->dclevel.prgnClip != NULL) 323 { 324 /* We have a region, crop it */ 325 iComplexity = REGION_CropRegion(pdc->dclevel.prgnClip, 326 pdc->dclevel.prgnClip, 327 &rect); 328 } 329 else 330 { 331 /* We don't have a region yet, allocate a new one */ 332 prgnNew = IntSysCreateRectpRgnIndirect(&rect); 333 if (prgnNew == NULL) 334 { 335 iComplexity = ERROR; 336 } 337 else 338 { 339 /* Set the new region */ 340 pdc->dclevel.prgnClip = prgnNew; 341 iComplexity = SIMPLEREGION; 342 } 343 } 344 345 /* If we succeeded, mark the RAO region as dirty */ 346 if (iComplexity != ERROR) 347 pdc->fs |= DC_FLAG_DIRTY_RAO; 348 349 /* Unlock the DC */ 350 DC_UnlockDc(pdc); 351 352 return iComplexity; 353 } 354 355 INT 356 APIENTRY 357 NtGdiOffsetClipRgn( 358 _In_ HDC hdc, 359 _In_ INT xOffset, 360 _In_ INT yOffset) 361 { 362 INT iComplexity; 363 PDC pdc; 364 POINTL apt[2]; 365 366 /* Lock the DC */ 367 pdc = DC_LockDc(hdc); 368 if (pdc == NULL) 369 { 370 return ERROR; 371 } 372 373 /* Check if we have a clip region */ 374 if (pdc->dclevel.prgnClip != NULL) 375 { 376 /* Convert coordinates into device space. Note that we need to convert 377 2 coordinates to account for rotation / shear / offset */ 378 apt[0].x = 0; 379 apt[0].y = 0; 380 apt[1].x = xOffset; 381 apt[1].y = yOffset; 382 IntLPtoDP(pdc, &apt, 2); 383 384 /* Offset the clip region */ 385 if (!REGION_bOffsetRgn(pdc->dclevel.prgnClip, 386 apt[1].x - apt[0].x, 387 apt[1].y - apt[0].y)) 388 { 389 iComplexity = ERROR; 390 } 391 else 392 { 393 iComplexity = REGION_Complexity(pdc->dclevel.prgnClip); 394 } 395 396 /* Mark the RAO region as dirty */ 397 pdc->fs |= DC_FLAG_DIRTY_RAO; 398 } 399 else 400 { 401 /* NULL means no clipping, i.e. the "whole" region */ 402 iComplexity = SIMPLEREGION; 403 } 404 405 /* Unlock the DC and return the complexity */ 406 DC_UnlockDc(pdc); 407 return iComplexity; 408 } 409 410 BOOL APIENTRY NtGdiPtVisible(HDC hDC, 411 int X, 412 int Y) 413 { 414 BOOL ret = FALSE; 415 PDC dc; 416 417 if(!(dc = DC_LockDc(hDC))) 418 { 419 EngSetLastError(ERROR_INVALID_HANDLE); 420 return FALSE; 421 } 422 423 if (dc->prgnRao) 424 { 425 POINT pt = {X, Y}; 426 IntLPtoDP(dc, &pt, 1); 427 ret = REGION_PtInRegion(dc->prgnRao, pt.x, pt.y); 428 } 429 430 DC_UnlockDc(dc); 431 432 return ret; 433 } 434 435 BOOL 436 APIENTRY 437 NtGdiRectVisible( 438 HDC hDC, 439 LPRECT UnsafeRect) 440 { 441 NTSTATUS Status = STATUS_SUCCESS; 442 PDC dc = DC_LockDc(hDC); 443 BOOL Result = FALSE; 444 RECTL Rect; 445 446 if (!dc) 447 { 448 EngSetLastError(ERROR_INVALID_HANDLE); 449 return FALSE; 450 } 451 452 _SEH2_TRY 453 { 454 ProbeForRead(UnsafeRect, 455 sizeof(RECT), 456 1); 457 Rect = *UnsafeRect; 458 } 459 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 460 { 461 Status = _SEH2_GetExceptionCode(); 462 } 463 _SEH2_END; 464 465 if(!NT_SUCCESS(Status)) 466 { 467 DC_UnlockDc(dc); 468 SetLastNtError(Status); 469 return FALSE; 470 } 471 472 if (dc->fs & DC_FLAG_DIRTY_RAO) 473 CLIPPING_UpdateGCRegion(dc); 474 475 if (dc->prgnRao) 476 { 477 IntLPtoDP(dc, (LPPOINT)&Rect, 2); 478 Result = REGION_RectInRegion(dc->prgnRao, &Rect); 479 } 480 DC_UnlockDc(dc); 481 482 return Result; 483 } 484 485 int 486 FASTCALL 487 IntGdiSetMetaRgn(PDC pDC) 488 { 489 INT Ret = ERROR; 490 491 if ( pDC->dclevel.prgnMeta ) 492 { 493 if ( pDC->dclevel.prgnClip ) 494 { 495 // preferably REGION_IntersectRegion 496 Ret = IntGdiCombineRgn(pDC->dclevel.prgnMeta, pDC->dclevel.prgnMeta, pDC->dclevel.prgnClip, RGN_AND); 497 if (Ret != ERROR) 498 { 499 REGION_Delete(pDC->dclevel.prgnClip); 500 pDC->dclevel.prgnClip = NULL; 501 IntGdiReleaseRaoRgn(pDC); 502 } 503 } 504 else 505 Ret = REGION_Complexity(pDC->dclevel.prgnMeta); 506 } 507 else 508 { 509 if ( pDC->dclevel.prgnClip ) 510 { 511 Ret = REGION_Complexity(pDC->dclevel.prgnClip); 512 pDC->dclevel.prgnMeta = pDC->dclevel.prgnClip; 513 pDC->dclevel.prgnClip = NULL; 514 } 515 else 516 Ret = SIMPLEREGION; 517 } 518 519 if (Ret != ERROR) 520 pDC->fs |= DC_FLAG_DIRTY_RAO; 521 522 return Ret; 523 } 524 525 526 int APIENTRY NtGdiSetMetaRgn(HDC hDC) 527 { 528 INT Ret; 529 PDC pDC = DC_LockDc(hDC); 530 531 if (!pDC) 532 { 533 EngSetLastError(ERROR_INVALID_PARAMETER); 534 return ERROR; 535 } 536 Ret = IntGdiSetMetaRgn(pDC); 537 538 DC_UnlockDc(pDC); 539 return Ret; 540 } 541 542 VOID 543 FASTCALL 544 CLIPPING_UpdateGCRegion(PDC pDC) 545 { 546 /* Must have VisRgn set to a valid state! */ 547 ASSERT (pDC->prgnVis); 548 549 if (pDC->prgnAPI) 550 { 551 REGION_Delete(pDC->prgnAPI); 552 pDC->prgnAPI = NULL; 553 } 554 555 if (pDC->prgnRao) 556 REGION_Delete(pDC->prgnRao); 557 558 pDC->prgnRao = IntSysCreateRectpRgn(0,0,0,0); 559 560 ASSERT(pDC->prgnRao); 561 562 if (pDC->dclevel.prgnMeta || pDC->dclevel.prgnClip) 563 { 564 pDC->prgnAPI = IntSysCreateRectpRgn(0,0,0,0); 565 if (!pDC->dclevel.prgnMeta) 566 { 567 IntGdiCombineRgn(pDC->prgnAPI, 568 pDC->dclevel.prgnClip, 569 NULL, 570 RGN_COPY); 571 } 572 else if (!pDC->dclevel.prgnClip) 573 { 574 IntGdiCombineRgn(pDC->prgnAPI, 575 pDC->dclevel.prgnMeta, 576 NULL, 577 RGN_COPY); 578 } 579 else 580 { 581 IntGdiCombineRgn(pDC->prgnAPI, 582 pDC->dclevel.prgnClip, 583 pDC->dclevel.prgnMeta, 584 RGN_AND); 585 } 586 } 587 588 if (pDC->prgnAPI) 589 { 590 IntGdiCombineRgn(pDC->prgnRao, 591 pDC->prgnVis, 592 pDC->prgnAPI, 593 RGN_AND); 594 } 595 else 596 { 597 IntGdiCombineRgn(pDC->prgnRao, 598 pDC->prgnVis, 599 NULL, 600 RGN_COPY); 601 } 602 603 604 REGION_bOffsetRgn(pDC->prgnRao, pDC->ptlDCOrig.x, pDC->ptlDCOrig.y); 605 606 RtlCopyMemory(&pDC->erclClip, 607 &pDC->prgnRao->rdh.rcBound, 608 sizeof(RECTL)); 609 610 pDC->fs &= ~DC_FLAG_DIRTY_RAO; 611 612 // pDC->co should be used. Example, CLIPOBJ_cEnumStart uses XCLIPOBJ to build 613 // the rects from region objects rects in pClipRgn->Buffer. 614 // With pDC->co.pClipRgn->Buffer, 615 // pDC->co.pClipRgn = pDC->prgnRao ? pDC->prgnRao : pDC->prgnVis; 616 617 IntEngUpdateClipRegion(&pDC->co, 618 pDC->prgnRao->rdh.nCount, 619 pDC->prgnRao->Buffer, 620 &pDC->erclClip); 621 622 REGION_bOffsetRgn(pDC->prgnRao, -pDC->ptlDCOrig.x, -pDC->ptlDCOrig.y); 623 } 624 625 /* EOF */ 626