1 /* 2 * COPYRIGHT: GNU GPL, See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * PURPOSE: Bit blit functions 5 * FILE: win32ss/gdi/ntgdi/bitblt.c 6 * PROGRAMER: Unknown 7 */ 8 9 #include <win32k.h> 10 #define NDEBUG 11 #include <debug.h> 12 DBG_DEFAULT_CHANNEL(GdiBlt); 13 14 BOOL APIENTRY 15 NtGdiAlphaBlend( 16 HDC hDCDest, 17 LONG XOriginDest, 18 LONG YOriginDest, 19 LONG WidthDest, 20 LONG HeightDest, 21 HDC hDCSrc, 22 LONG XOriginSrc, 23 LONG YOriginSrc, 24 LONG WidthSrc, 25 LONG HeightSrc, 26 BLENDFUNCTION BlendFunc, 27 HANDLE hcmXform) 28 { 29 PDC DCDest; 30 PDC DCSrc; 31 HDC ahDC[2]; 32 PGDIOBJ apObj[2]; 33 SURFACE *BitmapDest, *BitmapSrc; 34 RECTL DestRect, SourceRect; 35 BOOL bResult; 36 EXLATEOBJ exlo; 37 BLENDOBJ BlendObj; 38 BlendObj.BlendFunction = BlendFunc; 39 40 if (WidthDest < 0 || HeightDest < 0 || WidthSrc < 0 || HeightSrc < 0) 41 { 42 EngSetLastError(ERROR_INVALID_PARAMETER); 43 return FALSE; 44 } 45 46 if ((hDCDest == NULL) || (hDCSrc == NULL)) 47 { 48 EngSetLastError(ERROR_INVALID_PARAMETER); 49 return FALSE; 50 } 51 52 TRACE("Locking DCs\n"); 53 ahDC[0] = hDCDest; 54 ahDC[1] = hDCSrc ; 55 if (!GDIOBJ_bLockMultipleObjects(2, (HGDIOBJ*)ahDC, apObj, GDIObjType_DC_TYPE)) 56 { 57 WARN("Invalid dc handle (dest=0x%p, src=0x%p) passed to NtGdiAlphaBlend\n", hDCDest, hDCSrc); 58 EngSetLastError(ERROR_INVALID_HANDLE); 59 return FALSE; 60 } 61 DCDest = apObj[0]; 62 DCSrc = apObj[1]; 63 64 if (DCDest->dctype == DC_TYPE_INFO || DCDest->dctype == DCTYPE_INFO) 65 { 66 GDIOBJ_vUnlockObject(&DCSrc->BaseObject); 67 GDIOBJ_vUnlockObject(&DCDest->BaseObject); 68 /* Yes, Windows really returns TRUE in this case */ 69 return TRUE; 70 } 71 72 DestRect.left = XOriginDest; 73 DestRect.top = YOriginDest; 74 DestRect.right = XOriginDest + WidthDest; 75 DestRect.bottom = YOriginDest + HeightDest; 76 IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2); 77 78 DestRect.left += DCDest->ptlDCOrig.x; 79 DestRect.top += DCDest->ptlDCOrig.y; 80 DestRect.right += DCDest->ptlDCOrig.x; 81 DestRect.bottom += DCDest->ptlDCOrig.y; 82 83 if (DCDest->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 84 { 85 IntUpdateBoundsRect(DCDest, &DestRect); 86 } 87 88 SourceRect.left = XOriginSrc; 89 SourceRect.top = YOriginSrc; 90 SourceRect.right = XOriginSrc + WidthSrc; 91 SourceRect.bottom = YOriginSrc + HeightSrc; 92 IntLPtoDP(DCSrc, (LPPOINT)&SourceRect, 2); 93 94 SourceRect.left += DCSrc->ptlDCOrig.x; 95 SourceRect.top += DCSrc->ptlDCOrig.y; 96 SourceRect.right += DCSrc->ptlDCOrig.x; 97 SourceRect.bottom += DCSrc->ptlDCOrig.y; 98 99 if (!DestRect.right || 100 !DestRect.bottom || 101 !SourceRect.right || 102 !SourceRect.bottom) 103 { 104 GDIOBJ_vUnlockObject(&DCSrc->BaseObject); 105 GDIOBJ_vUnlockObject(&DCDest->BaseObject); 106 return TRUE; 107 } 108 109 /* Prepare DCs for blit */ 110 TRACE("Preparing DCs for blit\n"); 111 DC_vPrepareDCsForBlit(DCDest, &DestRect, DCSrc, &SourceRect); 112 113 /* Determine surfaces to be used in the bitblt */ 114 BitmapDest = DCDest->dclevel.pSurface; 115 if (!BitmapDest) 116 { 117 bResult = FALSE ; 118 goto leave ; 119 } 120 121 BitmapSrc = DCSrc->dclevel.pSurface; 122 if (!BitmapSrc) 123 { 124 bResult = FALSE; 125 goto leave; 126 } 127 128 /* Create the XLATEOBJ. */ 129 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest); 130 131 /* Perform the alpha blend operation */ 132 TRACE("Performing the alpha blend\n"); 133 bResult = IntEngAlphaBlend(&BitmapDest->SurfObj, 134 &BitmapSrc->SurfObj, 135 (CLIPOBJ *)&DCDest->co, 136 &exlo.xlo, 137 &DestRect, 138 &SourceRect, 139 &BlendObj); 140 141 EXLATEOBJ_vCleanup(&exlo); 142 leave : 143 TRACE("Finishing blit\n"); 144 DC_vFinishBlit(DCDest, DCSrc); 145 GDIOBJ_vUnlockObject(&DCSrc->BaseObject); 146 GDIOBJ_vUnlockObject(&DCDest->BaseObject); 147 148 return bResult; 149 } 150 151 BOOL APIENTRY 152 NtGdiBitBlt( 153 HDC hDCDest, 154 INT XDest, 155 INT YDest, 156 INT Width, 157 INT Height, 158 HDC hDCSrc, 159 INT XSrc, 160 INT YSrc, 161 DWORD dwRop, 162 IN DWORD crBackColor, 163 IN FLONG fl) 164 { 165 166 if (dwRop & CAPTUREBLT) 167 { 168 return NtGdiStretchBlt(hDCDest, 169 XDest, 170 YDest, 171 Width, 172 Height, 173 hDCSrc, 174 XSrc, 175 YSrc, 176 Width, 177 Height, 178 dwRop, 179 crBackColor); 180 } 181 182 dwRop = dwRop & ~(NOMIRRORBITMAP|CAPTUREBLT); 183 184 /* Forward to NtGdiMaskBlt */ 185 // TODO: What's fl for? LOL not to send this to MaskBit! 186 return NtGdiMaskBlt(hDCDest, 187 XDest, 188 YDest, 189 Width, 190 Height, 191 hDCSrc, 192 XSrc, 193 YSrc, 194 NULL, 195 0, 196 0, 197 MAKEROP4(dwRop, dwRop), 198 crBackColor); 199 } 200 201 BOOL APIENTRY 202 NtGdiTransparentBlt( 203 HDC hdcDst, 204 INT xDst, 205 INT yDst, 206 INT cxDst, 207 INT cyDst, 208 HDC hdcSrc, 209 INT xSrc, 210 INT ySrc, 211 INT cxSrc, 212 INT cySrc, 213 COLORREF TransColor) 214 { 215 PDC DCDest, DCSrc; 216 HDC ahDC[2]; 217 PGDIOBJ apObj[2]; 218 RECTL rcDest, rcSrc; 219 SURFACE *BitmapDest, *BitmapSrc = NULL; 220 ULONG TransparentColor = 0; 221 BOOL Ret = FALSE; 222 EXLATEOBJ exlo; 223 224 if ((hdcDst == NULL) || (hdcSrc == NULL)) 225 { 226 EngSetLastError(ERROR_INVALID_PARAMETER); 227 return FALSE; 228 } 229 230 TRACE("Locking DCs\n"); 231 ahDC[0] = hdcDst; 232 ahDC[1] = hdcSrc ; 233 if (!GDIOBJ_bLockMultipleObjects(2, (HGDIOBJ*)ahDC, apObj, GDIObjType_DC_TYPE)) 234 { 235 WARN("Invalid dc handle (dest=0x%p, src=0x%p) passed to NtGdiAlphaBlend\n", hdcDst, hdcSrc); 236 EngSetLastError(ERROR_INVALID_HANDLE); 237 return FALSE; 238 } 239 DCDest = apObj[0]; 240 DCSrc = apObj[1]; 241 242 if (DCDest->dctype == DC_TYPE_INFO || DCDest->dctype == DCTYPE_INFO) 243 { 244 GDIOBJ_vUnlockObject(&DCSrc->BaseObject); 245 GDIOBJ_vUnlockObject(&DCDest->BaseObject); 246 /* Yes, Windows really returns TRUE in this case */ 247 return TRUE; 248 } 249 250 rcDest.left = xDst; 251 rcDest.top = yDst; 252 rcDest.right = rcDest.left + cxDst; 253 rcDest.bottom = rcDest.top + cyDst; 254 IntLPtoDP(DCDest, (LPPOINT)&rcDest, 2); 255 256 rcDest.left += DCDest->ptlDCOrig.x; 257 rcDest.top += DCDest->ptlDCOrig.y; 258 rcDest.right += DCDest->ptlDCOrig.x; 259 rcDest.bottom += DCDest->ptlDCOrig.y; 260 261 rcSrc.left = xSrc; 262 rcSrc.top = ySrc; 263 rcSrc.right = rcSrc.left + cxSrc; 264 rcSrc.bottom = rcSrc.top + cySrc; 265 IntLPtoDP(DCSrc, (LPPOINT)&rcSrc, 2); 266 267 rcSrc.left += DCSrc->ptlDCOrig.x; 268 rcSrc.top += DCSrc->ptlDCOrig.y; 269 rcSrc.right += DCSrc->ptlDCOrig.x; 270 rcSrc.bottom += DCSrc->ptlDCOrig.y; 271 272 if (DCDest->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 273 { 274 IntUpdateBoundsRect(DCDest, &rcDest); 275 } 276 277 /* Prepare for blit */ 278 DC_vPrepareDCsForBlit(DCDest, &rcDest, DCSrc, &rcSrc); 279 280 BitmapDest = DCDest->dclevel.pSurface; 281 if (!BitmapDest) 282 { 283 goto done; 284 } 285 286 BitmapSrc = DCSrc->dclevel.pSurface; 287 if (!BitmapSrc) 288 { 289 goto done; 290 } 291 292 /* Translate Transparent (RGB) Color to the source palette */ 293 EXLATEOBJ_vInitialize(&exlo, &gpalRGB, BitmapSrc->ppal, 0, 0, 0); 294 TransparentColor = XLATEOBJ_iXlate(&exlo.xlo, (ULONG)TransColor); 295 EXLATEOBJ_vCleanup(&exlo); 296 297 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest); 298 299 Ret = IntEngTransparentBlt(&BitmapDest->SurfObj, &BitmapSrc->SurfObj, 300 (CLIPOBJ *)&DCDest->co, &exlo.xlo, &rcDest, &rcSrc, 301 TransparentColor, 0); 302 303 EXLATEOBJ_vCleanup(&exlo); 304 305 done: 306 DC_vFinishBlit(DCDest, DCSrc); 307 GDIOBJ_vUnlockObject(&DCDest->BaseObject); 308 GDIOBJ_vUnlockObject(&DCSrc->BaseObject); 309 310 return Ret; 311 } 312 313 BOOL APIENTRY 314 NtGdiMaskBlt( 315 HDC hdcDest, 316 INT nXDest, 317 INT nYDest, 318 INT nWidth, 319 INT nHeight, 320 HDC hdcSrc, 321 INT nXSrc, 322 INT nYSrc, 323 HBITMAP hbmMask, 324 INT xMask, 325 INT yMask, 326 DWORD dwRop4, 327 IN DWORD crBackColor) 328 { 329 PDC DCDest; 330 PDC DCSrc = NULL; 331 HDC ahDC[2]; 332 PGDIOBJ apObj[2]; 333 PDC_ATTR pdcattr = NULL; 334 SURFACE *BitmapDest, *BitmapSrc = NULL, *psurfMask = NULL; 335 RECTL DestRect, SourceRect; 336 POINTL SourcePoint, MaskPoint; 337 BOOL Status = FALSE; 338 EXLATEOBJ exlo; 339 XLATEOBJ *XlateObj = NULL; 340 BOOL UsesSource; 341 ROP4 rop4; 342 343 rop4 = WIN32_ROP4_TO_ENG_ROP4(dwRop4); 344 345 UsesSource = ROP4_USES_SOURCE(rop4); 346 if (!hdcDest || (UsesSource && !hdcSrc)) 347 { 348 EngSetLastError(ERROR_INVALID_PARAMETER); 349 return FALSE; 350 } 351 352 /* Check if we need a mask and have a mask bitmap */ 353 if (ROP4_USES_MASK(rop4) && (hbmMask != NULL)) 354 { 355 /* Reference the mask bitmap */ 356 psurfMask = SURFACE_ShareLockSurface(hbmMask); 357 if (psurfMask == NULL) 358 { 359 EngSetLastError(ERROR_INVALID_HANDLE); 360 return FALSE; 361 } 362 363 /* Make sure the mask bitmap is 1 BPP */ 364 if (gajBitsPerFormat[psurfMask->SurfObj.iBitmapFormat] != 1) 365 { 366 EngSetLastError(ERROR_INVALID_PARAMETER); 367 SURFACE_ShareUnlockSurface(psurfMask); 368 return FALSE; 369 } 370 } 371 else 372 { 373 /* We use NULL, if we need a mask, the Eng function will take care of 374 that and use the brushobject to get a mask */ 375 psurfMask = NULL; 376 } 377 378 MaskPoint.x = xMask; 379 MaskPoint.y = yMask; 380 381 /* Take care of source and destination bitmap */ 382 TRACE("Locking DCs\n"); 383 ahDC[0] = hdcDest; 384 ahDC[1] = UsesSource ? hdcSrc : NULL; 385 if (!GDIOBJ_bLockMultipleObjects(2, (HGDIOBJ*)ahDC, apObj, GDIObjType_DC_TYPE)) 386 { 387 WARN("Invalid dc handle (dest=0x%p, src=0x%p) passed to NtGdiMaskBlt\n", hdcDest, hdcSrc); 388 EngSetLastError(ERROR_INVALID_HANDLE); 389 return FALSE; 390 } 391 DCDest = apObj[0]; 392 DCSrc = apObj[1]; 393 394 ASSERT(DCDest); 395 if (NULL == DCDest) 396 { 397 if(DCSrc) DC_UnlockDc(DCSrc); 398 WARN("Invalid destination dc handle (0x%p) passed to NtGdiMaskBlt\n", hdcDest); 399 return FALSE; 400 } 401 402 if (DCDest->dctype == DC_TYPE_INFO) 403 { 404 if(DCSrc) DC_UnlockDc(DCSrc); 405 DC_UnlockDc(DCDest); 406 /* Yes, Windows really returns TRUE in this case */ 407 return TRUE; 408 } 409 410 if (UsesSource) 411 { 412 ASSERT(DCSrc); 413 if (DCSrc->dctype == DC_TYPE_INFO) 414 { 415 DC_UnlockDc(DCDest); 416 DC_UnlockDc(DCSrc); 417 /* Yes, Windows really returns TRUE in this case */ 418 return TRUE; 419 } 420 } 421 422 pdcattr = DCDest->pdcattr; 423 424 DestRect.left = nXDest; 425 DestRect.top = nYDest; 426 DestRect.right = nXDest + nWidth; 427 DestRect.bottom = nYDest + nHeight; 428 IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2); 429 430 DestRect.left += DCDest->ptlDCOrig.x; 431 DestRect.top += DCDest->ptlDCOrig.y; 432 DestRect.right += DCDest->ptlDCOrig.x; 433 DestRect.bottom += DCDest->ptlDCOrig.y; 434 435 if (DCDest->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 436 { 437 IntUpdateBoundsRect(DCDest, &DestRect); 438 } 439 440 SourcePoint.x = nXSrc; 441 SourcePoint.y = nYSrc; 442 443 if (UsesSource) 444 { 445 IntLPtoDP(DCSrc, (LPPOINT)&SourcePoint, 1); 446 447 SourcePoint.x += DCSrc->ptlDCOrig.x; 448 SourcePoint.y += DCSrc->ptlDCOrig.y; 449 /* Calculate Source Rect */ 450 SourceRect.left = SourcePoint.x; 451 SourceRect.top = SourcePoint.y; 452 SourceRect.right = SourcePoint.x + DestRect.right - DestRect.left; 453 SourceRect.bottom = SourcePoint.y + DestRect.bottom - DestRect.top ; 454 } 455 else 456 { 457 SourceRect.left = 0; 458 SourceRect.top = 0; 459 SourceRect.right = 0; 460 SourceRect.bottom = 0; 461 } 462 463 /* Prepare blit */ 464 DC_vPrepareDCsForBlit(DCDest, &DestRect, DCSrc, &SourceRect); 465 466 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) 467 DC_vUpdateFillBrush(DCDest); 468 469 /* Determine surfaces to be used in the bitblt */ 470 BitmapDest = DCDest->dclevel.pSurface; 471 if (!BitmapDest) 472 goto cleanup; 473 474 if (UsesSource) 475 { 476 BitmapSrc = DCSrc->dclevel.pSurface; 477 if (!BitmapSrc) 478 goto cleanup; 479 480 /* Create the XLATEOBJ. */ 481 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest); 482 XlateObj = &exlo.xlo; 483 } 484 485 DPRINT("DestRect: (%d,%d)-(%d,%d) and SourcePoint is (%d,%d)\n", 486 DestRect.left, DestRect.top, DestRect.right, DestRect.bottom, 487 SourcePoint.x, SourcePoint.y); 488 489 DPRINT("nWidth is '%d' and nHeight is '%d'.\n", nWidth, nHeight); 490 491 /* Fix BitBlt so that it will not flip left to right */ 492 if ((DestRect.left > DestRect.right) && (nWidth < 0)) 493 { 494 SourcePoint.x += nWidth; 495 nWidth = -nWidth; 496 } 497 498 /* Fix BitBlt so that it will not flip top to bottom */ 499 if ((DestRect.top > DestRect.bottom) && (nHeight < 0)) 500 { 501 SourcePoint.y += nHeight; 502 nHeight = -nHeight; 503 } 504 505 /* Make Well Ordered so that we don't flip either way */ 506 RECTL_vMakeWellOrdered(&DestRect); 507 508 /* Perform the bitblt operation */ 509 Status = IntEngBitBlt(&BitmapDest->SurfObj, 510 BitmapSrc ? &BitmapSrc->SurfObj : NULL, 511 psurfMask ? &psurfMask->SurfObj : NULL, 512 (CLIPOBJ *)&DCDest->co, 513 XlateObj, 514 &DestRect, 515 &SourcePoint, 516 &MaskPoint, 517 &DCDest->eboFill.BrushObject, 518 &DCDest->dclevel.pbrFill->ptOrigin, 519 rop4); 520 521 if (UsesSource) 522 EXLATEOBJ_vCleanup(&exlo); 523 cleanup: 524 DC_vFinishBlit(DCDest, DCSrc); 525 if (UsesSource) 526 { 527 DC_UnlockDc(DCSrc); 528 } 529 DC_UnlockDc(DCDest); 530 if(psurfMask) SURFACE_ShareUnlockSurface(psurfMask); 531 532 return Status; 533 } 534 535 BOOL 536 APIENTRY 537 NtGdiPlgBlt( 538 IN HDC hdcTrg, 539 IN LPPOINT pptlTrg, 540 IN HDC hdcSrc, 541 IN INT xSrc, 542 IN INT ySrc, 543 IN INT cxSrc, 544 IN INT cySrc, 545 IN HBITMAP hbmMask, 546 IN INT xMask, 547 IN INT yMask, 548 IN DWORD crBackColor) 549 { 550 FIXME("NtGdiPlgBlt: unimplemented.\n"); 551 return FALSE; 552 } 553 554 BOOL 555 NTAPI 556 GreStretchBltMask( 557 HDC hDCDest, 558 INT XOriginDest, 559 INT YOriginDest, 560 INT WidthDest, 561 INT HeightDest, 562 HDC hDCSrc, 563 INT XOriginSrc, 564 INT YOriginSrc, 565 INT WidthSrc, 566 INT HeightSrc, 567 DWORD dwRop4, 568 IN DWORD dwBackColor, 569 HDC hDCMask, 570 INT XOriginMask, 571 INT YOriginMask) 572 { 573 PDC DCDest; 574 PDC DCSrc = NULL; 575 PDC DCMask = NULL; 576 HDC ahDC[3]; 577 PGDIOBJ apObj[3]; 578 PDC_ATTR pdcattr; 579 SURFACE *BitmapDest, *BitmapSrc = NULL; 580 SURFACE *BitmapMask = NULL; 581 RECTL DestRect; 582 RECTL SourceRect; 583 POINTL MaskPoint; 584 BOOL Status = FALSE; 585 EXLATEOBJ exlo; 586 XLATEOBJ *XlateObj = NULL; 587 POINTL BrushOrigin; 588 BOOL UsesSource; 589 BOOL UsesMask; 590 ROP4 rop4; 591 BOOL Case0000, Case0101, Case1010, CaseExcept; 592 593 rop4 = WIN32_ROP4_TO_ENG_ROP4(dwRop4); 594 595 UsesSource = ROP4_USES_SOURCE(rop4); 596 UsesMask = ROP4_USES_MASK(rop4); 597 598 if (0 == WidthDest || 0 == HeightDest || 0 == WidthSrc || 0 == HeightSrc) 599 { 600 EngSetLastError(ERROR_INVALID_PARAMETER); 601 return TRUE; 602 } 603 604 if (!hDCDest || (UsesSource && !hDCSrc) || (UsesMask && !hDCMask)) 605 { 606 EngSetLastError(ERROR_INVALID_PARAMETER); 607 return FALSE; 608 } 609 610 ahDC[0] = hDCDest; 611 ahDC[1] = UsesSource ? hDCSrc : NULL; 612 ahDC[2] = UsesMask ? hDCMask : NULL; 613 if (!GDIOBJ_bLockMultipleObjects(3, (HGDIOBJ*)ahDC, apObj, GDIObjType_DC_TYPE)) 614 { 615 WARN("Invalid dc handle (dest=0x%p, src=0x%p) passed to GreStretchBltMask\n", hDCDest, hDCSrc); 616 EngSetLastError(ERROR_INVALID_HANDLE); 617 return FALSE; 618 } 619 DCDest = apObj[0]; 620 DCSrc = apObj[1]; 621 DCMask = apObj[2]; 622 623 if (DCDest->dctype == DC_TYPE_INFO) 624 { 625 if(DCSrc) GDIOBJ_vUnlockObject(&DCSrc->BaseObject); 626 if(DCMask) GDIOBJ_vUnlockObject(&DCMask->BaseObject); 627 GDIOBJ_vUnlockObject(&DCDest->BaseObject); 628 /* Yes, Windows really returns TRUE in this case */ 629 return TRUE; 630 } 631 632 if (UsesSource) 633 { 634 if (DCSrc->dctype == DC_TYPE_INFO) 635 { 636 GDIOBJ_vUnlockObject(&DCDest->BaseObject); 637 GDIOBJ_vUnlockObject(&DCSrc->BaseObject); 638 if(DCMask) GDIOBJ_vUnlockObject(&DCMask->BaseObject); 639 /* Yes, Windows really returns TRUE in this case */ 640 return TRUE; 641 } 642 } 643 644 645 Case0000 = ((WidthDest < 0) && (HeightDest < 0) && (WidthSrc < 0) && (HeightSrc < 0)); 646 Case0101 = ((WidthDest < 0) && (HeightDest > 0) && (WidthSrc < 0) && (HeightSrc > 0)); 647 Case1010 = ((WidthDest > 0) && (HeightDest < 0) && (WidthSrc > 0) && (HeightSrc < 0)); 648 CaseExcept = (Case0000 || Case0101 || Case1010); 649 650 pdcattr = DCDest->pdcattr; 651 652 DestRect.left = XOriginDest; 653 DestRect.top = YOriginDest; 654 DestRect.right = XOriginDest+WidthDest; 655 DestRect.bottom = YOriginDest+HeightDest; 656 657 /* Account for possible negative span values */ 658 if ((WidthDest < 0) && !CaseExcept) 659 { 660 DestRect.left++; 661 DestRect.right++; 662 } 663 if ((HeightDest < 0) && !CaseExcept) 664 { 665 DestRect.top++; 666 DestRect.bottom++; 667 } 668 669 IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2); 670 671 DestRect.left += DCDest->ptlDCOrig.x; 672 DestRect.top += DCDest->ptlDCOrig.y; 673 DestRect.right += DCDest->ptlDCOrig.x; 674 DestRect.bottom += DCDest->ptlDCOrig.y; 675 676 if (DCDest->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 677 { 678 IntUpdateBoundsRect(DCDest, &DestRect); 679 } 680 681 SourceRect.left = XOriginSrc; 682 SourceRect.top = YOriginSrc; 683 SourceRect.right = XOriginSrc+WidthSrc; 684 SourceRect.bottom = YOriginSrc+HeightSrc; 685 686 /* Account for possible negative span values */ 687 if ((WidthSrc < 0) && !CaseExcept) 688 { 689 SourceRect.left++; 690 SourceRect.right++; 691 } 692 if ((HeightSrc < 0) && !CaseExcept) 693 { 694 SourceRect.top++; 695 SourceRect.bottom++; 696 } 697 698 if (UsesSource) 699 { 700 IntLPtoDP(DCSrc, (LPPOINT)&SourceRect, 2); 701 702 SourceRect.left += DCSrc->ptlDCOrig.x; 703 SourceRect.top += DCSrc->ptlDCOrig.y; 704 SourceRect.right += DCSrc->ptlDCOrig.x; 705 SourceRect.bottom += DCSrc->ptlDCOrig.y; 706 } 707 708 BrushOrigin.x = 0; 709 BrushOrigin.y = 0; 710 711 /* Only prepare Source and Dest, hdcMask represents a DIB */ 712 DC_vPrepareDCsForBlit(DCDest, &DestRect, DCSrc, &SourceRect); 713 714 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) 715 DC_vUpdateFillBrush(DCDest); 716 717 /* Determine surfaces to be used in the bitblt */ 718 BitmapDest = DCDest->dclevel.pSurface; 719 if (BitmapDest == NULL) 720 goto failed; 721 if (UsesSource) 722 { 723 BitmapSrc = DCSrc->dclevel.pSurface; 724 if (BitmapSrc == NULL) 725 goto failed; 726 727 /* Create the XLATEOBJ. */ 728 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest); 729 XlateObj = &exlo.xlo; 730 } 731 732 /* Offset the brush */ 733 BrushOrigin.x += DCDest->ptlDCOrig.x; 734 BrushOrigin.y += DCDest->ptlDCOrig.y; 735 736 /* Make mask surface for source surface */ 737 if (BitmapSrc && DCMask) 738 { 739 BitmapMask = DCMask->dclevel.pSurface; 740 if (BitmapMask && 741 (BitmapMask->SurfObj.sizlBitmap.cx < WidthSrc || 742 BitmapMask->SurfObj.sizlBitmap.cy < HeightSrc)) 743 { 744 WARN("%dx%d mask is smaller than %dx%d bitmap\n", 745 BitmapMask->SurfObj.sizlBitmap.cx, BitmapMask->SurfObj.sizlBitmap.cy, 746 WidthSrc, HeightSrc); 747 EXLATEOBJ_vCleanup(&exlo); 748 goto failed; 749 } 750 /* Create mask offset point */ 751 MaskPoint.x = XOriginMask; 752 MaskPoint.y = YOriginMask; 753 IntLPtoDP(DCMask, &MaskPoint, 1); 754 MaskPoint.x += DCMask->ptlDCOrig.x; 755 MaskPoint.y += DCMask->ptlDCOrig.y; 756 } 757 758 DPRINT("Calling IntEngStrethBlt SourceRect: (%d,%d)-(%d,%d) and DestRect: (%d,%d)-(%d,%d).\n", 759 SourceRect.left, SourceRect.top, SourceRect.right, SourceRect.bottom, 760 DestRect.left, DestRect.top, DestRect.right, DestRect.bottom); 761 762 /* Perform the bitblt operation */ 763 Status = IntEngStretchBlt(&BitmapDest->SurfObj, 764 BitmapSrc ? &BitmapSrc->SurfObj : NULL, 765 BitmapMask ? &BitmapMask->SurfObj : NULL, 766 (CLIPOBJ *)&DCDest->co, 767 XlateObj, 768 &DCDest->dclevel.ca, 769 &DestRect, 770 &SourceRect, 771 BitmapMask ? &MaskPoint : NULL, 772 &DCDest->eboFill.BrushObject, 773 &BrushOrigin, 774 rop4); 775 if (UsesSource) 776 { 777 EXLATEOBJ_vCleanup(&exlo); 778 } 779 780 failed: 781 DC_vFinishBlit(DCDest, DCSrc); 782 if (UsesSource) 783 { 784 DC_UnlockDc(DCSrc); 785 } 786 if (DCMask) 787 { 788 DC_UnlockDc(DCMask); 789 } 790 DC_UnlockDc(DCDest); 791 792 return Status; 793 } 794 795 796 BOOL APIENTRY 797 NtGdiStretchBlt( 798 HDC hDCDest, 799 INT XOriginDest, 800 INT YOriginDest, 801 INT WidthDest, 802 INT HeightDest, 803 HDC hDCSrc, 804 INT XOriginSrc, 805 INT YOriginSrc, 806 INT WidthSrc, 807 INT HeightSrc, 808 DWORD dwRop3, 809 IN DWORD dwBackColor) 810 { 811 dwRop3 = dwRop3 & ~(NOMIRRORBITMAP|CAPTUREBLT); 812 813 return GreStretchBltMask( 814 hDCDest, 815 XOriginDest, 816 YOriginDest, 817 WidthDest, 818 HeightDest, 819 hDCSrc, 820 XOriginSrc, 821 YOriginSrc, 822 WidthSrc, 823 HeightSrc, 824 MAKEROP4(dwRop3 & 0xFF0000, dwRop3), 825 dwBackColor, 826 NULL, 827 0, 828 0); 829 } 830 831 832 BOOL FASTCALL 833 IntPatBlt( 834 PDC pdc, 835 INT XLeft, 836 INT YLeft, 837 INT Width, 838 INT Height, 839 DWORD dwRop3, 840 PEBRUSHOBJ pebo) 841 { 842 RECTL DestRect; 843 SURFACE *psurf; 844 POINTL BrushOrigin; 845 BOOL ret; 846 PBRUSH pbrush; 847 848 ASSERT(pebo); 849 pbrush = pebo->pbrush; 850 ASSERT(pbrush); 851 852 if (pbrush->flAttrs & BR_IS_NULL) 853 { 854 return TRUE; 855 } 856 857 if (Width > 0) 858 { 859 DestRect.left = XLeft; 860 DestRect.right = XLeft + Width; 861 } 862 else 863 { 864 DestRect.left = XLeft + Width + 1; 865 DestRect.right = XLeft + 1; 866 } 867 868 if (Height > 0) 869 { 870 DestRect.top = YLeft; 871 DestRect.bottom = YLeft + Height; 872 } 873 else 874 { 875 DestRect.top = YLeft + Height + 1; 876 DestRect.bottom = YLeft + 1; 877 } 878 879 IntLPtoDP(pdc, (LPPOINT)&DestRect, 2); 880 881 DestRect.left += pdc->ptlDCOrig.x; 882 DestRect.top += pdc->ptlDCOrig.y; 883 DestRect.right += pdc->ptlDCOrig.x; 884 DestRect.bottom += pdc->ptlDCOrig.y; 885 886 if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 887 { 888 IntUpdateBoundsRect(pdc, &DestRect); 889 } 890 891 #ifdef _USE_DIBLIB_ 892 BrushOrigin.x = pbrush->ptOrigin.x + pdc->ptlDCOrig.x + XLeft; 893 BrushOrigin.y = pbrush->ptOrigin.y + pdc->ptlDCOrig.y + YLeft; 894 #else 895 BrushOrigin.x = pbrush->ptOrigin.x + pdc->ptlDCOrig.x; 896 BrushOrigin.y = pbrush->ptOrigin.y + pdc->ptlDCOrig.y; 897 #endif 898 899 DC_vPrepareDCsForBlit(pdc, &DestRect, NULL, NULL); 900 901 psurf = pdc->dclevel.pSurface; 902 903 ret = IntEngBitBlt(&psurf->SurfObj, 904 NULL, 905 NULL, 906 (CLIPOBJ *)&pdc->co, 907 NULL, 908 &DestRect, 909 NULL, 910 NULL, 911 &pebo->BrushObject, 912 &BrushOrigin, 913 WIN32_ROP3_TO_ENG_ROP4(dwRop3)); 914 915 DC_vFinishBlit(pdc, NULL); 916 917 return ret; 918 } 919 920 BOOL FASTCALL 921 IntGdiPolyPatBlt( 922 HDC hDC, 923 DWORD dwRop, 924 PPATRECT pRects, 925 INT cRects, 926 ULONG Reserved) 927 { 928 INT i; 929 PBRUSH pbrush; 930 PDC pdc; 931 EBRUSHOBJ eboFill; 932 933 pdc = DC_LockDc(hDC); 934 if (!pdc) 935 { 936 EngSetLastError(ERROR_INVALID_HANDLE); 937 return FALSE; 938 } 939 940 if (pdc->dctype == DC_TYPE_INFO) 941 { 942 DC_UnlockDc(pdc); 943 /* Yes, Windows really returns TRUE in this case */ 944 return TRUE; 945 } 946 947 for (i = 0; i < cRects; i++) 948 { 949 pbrush = BRUSH_ShareLockBrush(pRects->hBrush); 950 951 /* Check if we could lock the brush */ 952 if (pbrush != NULL) 953 { 954 /* Initialize a brush object */ 955 EBRUSHOBJ_vInitFromDC(&eboFill, pbrush, pdc); 956 957 IntPatBlt( 958 pdc, 959 pRects->r.left, 960 pRects->r.top, 961 pRects->r.right, 962 pRects->r.bottom, 963 dwRop, 964 &eboFill); 965 966 /* Cleanup the brush object and unlock the brush */ 967 EBRUSHOBJ_vCleanup(&eboFill); 968 BRUSH_ShareUnlockBrush(pbrush); 969 } 970 pRects++; 971 } 972 973 DC_UnlockDc(pdc); 974 975 return TRUE; 976 } 977 978 BOOL 979 APIENTRY 980 NtGdiPatBlt( 981 _In_ HDC hdcDest, 982 _In_ INT x, 983 _In_ INT y, 984 _In_ INT cx, 985 _In_ INT cy, 986 _In_ DWORD dwRop) 987 { 988 BOOL bResult; 989 PDC pdc; 990 991 /* Convert the ROP3 to a ROP4 */ 992 dwRop = MAKEROP4(dwRop & 0xFF0000, dwRop); 993 994 /* Check if the rop uses a source */ 995 if (WIN32_ROP4_USES_SOURCE(dwRop)) 996 { 997 /* This is not possible */ 998 return FALSE; 999 } 1000 1001 /* Lock the DC */ 1002 pdc = DC_LockDc(hdcDest); 1003 if (pdc == NULL) 1004 { 1005 EngSetLastError(ERROR_INVALID_HANDLE); 1006 return FALSE; 1007 } 1008 1009 /* Check if the DC has no surface (empty mem or info DC) */ 1010 if (pdc->dclevel.pSurface == NULL) 1011 { 1012 /* Nothing to do, Windows returns TRUE! */ 1013 DC_UnlockDc(pdc); 1014 return TRUE; 1015 } 1016 1017 /* Update the fill brush, if necessary */ 1018 if (pdc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) 1019 DC_vUpdateFillBrush(pdc); 1020 1021 /* Call the internal function */ 1022 bResult = IntPatBlt(pdc, x, y, cx, cy, dwRop, &pdc->eboFill); 1023 1024 /* Unlock the DC and return the result */ 1025 DC_UnlockDc(pdc); 1026 return bResult; 1027 } 1028 1029 BOOL 1030 APIENTRY 1031 NtGdiPolyPatBlt( 1032 HDC hDC, 1033 DWORD dwRop, 1034 IN PPOLYPATBLT pRects, 1035 IN DWORD cRects, 1036 IN DWORD Mode) 1037 { 1038 PPATRECT rb = NULL; 1039 NTSTATUS Status = STATUS_SUCCESS; 1040 BOOL Ret; 1041 1042 if (cRects > 0) 1043 { 1044 rb = ExAllocatePoolWithTag(PagedPool, sizeof(PATRECT) * cRects, GDITAG_PLGBLT_DATA); 1045 if (!rb) 1046 { 1047 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 1048 return FALSE; 1049 } 1050 _SEH2_TRY 1051 { 1052 ProbeForRead(pRects, 1053 cRects * sizeof(PATRECT), 1054 1); 1055 RtlCopyMemory(rb, 1056 pRects, 1057 cRects * sizeof(PATRECT)); 1058 } 1059 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1060 { 1061 Status = _SEH2_GetExceptionCode(); 1062 } 1063 _SEH2_END; 1064 1065 if (!NT_SUCCESS(Status)) 1066 { 1067 ExFreePoolWithTag(rb, GDITAG_PLGBLT_DATA); 1068 SetLastNtError(Status); 1069 return FALSE; 1070 } 1071 } 1072 1073 Ret = IntGdiPolyPatBlt(hDC, dwRop, rb, cRects, Mode); 1074 1075 if (cRects > 0) 1076 ExFreePoolWithTag(rb, GDITAG_PLGBLT_DATA); 1077 1078 return Ret; 1079 } 1080 1081 static 1082 BOOL 1083 FASTCALL 1084 REGION_LPTODP( 1085 _In_ PDC pdc, 1086 _Inout_ PREGION prgnDest, 1087 _In_ PREGION prgnSrc) 1088 { 1089 if (IntGdiCombineRgn(prgnDest, prgnSrc, NULL, RGN_COPY) == ERROR) 1090 return FALSE; 1091 1092 return REGION_bXformRgn(prgnDest, DC_pmxWorldToDevice(pdc)); 1093 } 1094 1095 BOOL 1096 APIENTRY 1097 IntGdiBitBltRgn( 1098 _In_ PDC pdc, 1099 _In_ PREGION prgn, 1100 _In_opt_ BRUSHOBJ *pbo, 1101 _In_opt_ POINTL *pptlBrush, 1102 _In_ ROP4 rop4) 1103 { 1104 PREGION prgnClip; 1105 XCLIPOBJ xcoClip; 1106 BOOL bResult; 1107 NT_ASSERT((pdc != NULL) && (prgn != NULL)); 1108 1109 /* Check if we have a surface */ 1110 if (pdc->dclevel.pSurface == NULL) 1111 { 1112 return TRUE; 1113 } 1114 1115 /* Create an empty clip region */ 1116 prgnClip = IntSysCreateRectpRgn(0, 0, 0, 0); 1117 if (prgnClip == NULL) 1118 { 1119 return FALSE; 1120 } 1121 1122 /* Transform given region into device coordinates */ 1123 if (!REGION_LPTODP(pdc, prgnClip, prgn)) 1124 { 1125 REGION_Delete(prgnClip); 1126 return FALSE; 1127 } 1128 1129 /* Intersect with the system or RAO region (these are (atm) without DC-origin) */ 1130 if (pdc->prgnRao) 1131 IntGdiCombineRgn(prgnClip, prgnClip, pdc->prgnRao, RGN_AND); 1132 else 1133 IntGdiCombineRgn(prgnClip, prgnClip, pdc->prgnVis, RGN_AND); 1134 1135 /* Now account for the DC-origin */ 1136 if (!REGION_bOffsetRgn(prgnClip, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y)) 1137 { 1138 REGION_Delete(prgnClip); 1139 return FALSE; 1140 } 1141 1142 if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 1143 { 1144 RECTL rcrgn; 1145 REGION_GetRgnBox(prgnClip, &rcrgn); 1146 IntUpdateBoundsRect(pdc, &rcrgn); 1147 } 1148 1149 /* Prepare the DC */ 1150 DC_vPrepareDCsForBlit(pdc, &prgnClip->rdh.rcBound, NULL, NULL); 1151 1152 /* Initialize a clip object */ 1153 IntEngInitClipObj(&xcoClip); 1154 IntEngUpdateClipRegion(&xcoClip, 1155 prgnClip->rdh.nCount, 1156 prgnClip->Buffer, 1157 &prgnClip->rdh.rcBound); 1158 1159 /* Call the Eng or Drv function */ 1160 bResult = IntEngBitBlt(&pdc->dclevel.pSurface->SurfObj, 1161 NULL, 1162 NULL, 1163 (CLIPOBJ *)&xcoClip, 1164 NULL, 1165 &prgnClip->rdh.rcBound, 1166 NULL, 1167 NULL, 1168 pbo, 1169 pptlBrush, 1170 rop4); 1171 1172 /* Cleanup */ 1173 DC_vFinishBlit(pdc, NULL); 1174 REGION_Delete(prgnClip); 1175 IntEngFreeClipResources(&xcoClip); 1176 1177 /* Return the result */ 1178 return bResult; 1179 } 1180 1181 BOOL 1182 IntGdiFillRgn( 1183 _In_ PDC pdc, 1184 _In_ PREGION prgn, 1185 _In_opt_ PBRUSH pbrFill) 1186 { 1187 PREGION prgnClip; 1188 XCLIPOBJ xcoClip; 1189 EBRUSHOBJ eboFill; 1190 BRUSHOBJ *pbo; 1191 BOOL bRet; 1192 DWORD rop2Fg; 1193 MIX mix; 1194 NT_ASSERT((pdc != NULL) && (prgn != NULL)); 1195 1196 if (pdc->dclevel.pSurface == NULL) 1197 { 1198 return TRUE; 1199 } 1200 1201 prgnClip = IntSysCreateRectpRgn(0, 0, 0, 0); 1202 if (prgnClip == NULL) 1203 { 1204 return FALSE; 1205 } 1206 1207 /* Transform region into device coordinates */ 1208 if (!REGION_LPTODP(pdc, prgnClip, prgn)) 1209 { 1210 REGION_Delete(prgnClip); 1211 return FALSE; 1212 } 1213 1214 /* Intersect with the system or RAO region (these are (atm) without DC-origin) */ 1215 if (pdc->prgnRao) 1216 IntGdiCombineRgn(prgnClip, prgnClip, pdc->prgnRao, RGN_AND); 1217 else 1218 IntGdiCombineRgn(prgnClip, prgnClip, pdc->prgnVis, RGN_AND); 1219 1220 /* Now account for the DC-origin */ 1221 if (!REGION_bOffsetRgn(prgnClip, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y)) 1222 { 1223 REGION_Delete(prgnClip); 1224 return FALSE; 1225 } 1226 1227 if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 1228 { 1229 RECTL rcrgn; 1230 REGION_GetRgnBox(prgnClip, &rcrgn); 1231 IntUpdateBoundsRect(pdc, &rcrgn); 1232 } 1233 1234 IntEngInitClipObj(&xcoClip); 1235 IntEngUpdateClipRegion(&xcoClip, 1236 prgnClip->rdh.nCount, 1237 prgnClip->Buffer, 1238 &prgnClip->rdh.rcBound ); 1239 1240 /* Get the FG rop and create a MIX based on the BK mode */ 1241 rop2Fg = FIXUP_ROP2(pdc->pdcattr->jROP2); 1242 mix = rop2Fg | (pdc->pdcattr->jBkMode == OPAQUE ? rop2Fg : R2_NOP) << 8; 1243 1244 /* Prepare DC for blit */ 1245 DC_vPrepareDCsForBlit(pdc, &prgnClip->rdh.rcBound, NULL, NULL); 1246 1247 /* Check if we have a fill brush */ 1248 if (pbrFill != NULL) 1249 { 1250 /* Initialize the brush object */ 1251 /// \todo Check parameters 1252 EBRUSHOBJ_vInit(&eboFill, pbrFill, pdc->dclevel.pSurface, 0x00FFFFFF, 0, NULL); 1253 pbo = &eboFill.BrushObject; 1254 } 1255 else 1256 { 1257 /* Update the fill brush if needed */ 1258 if (pdc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) 1259 DC_vUpdateFillBrush(pdc); 1260 1261 /* Use the DC brush object */ 1262 pbo = &pdc->eboFill.BrushObject; 1263 } 1264 1265 /* Call the internal function */ 1266 bRet = IntEngPaint(&pdc->dclevel.pSurface->SurfObj, 1267 (CLIPOBJ *)&xcoClip, 1268 pbo, 1269 &pdc->pdcattr->ptlBrushOrigin, 1270 mix); 1271 1272 DC_vFinishBlit(pdc, NULL); 1273 REGION_Delete(prgnClip); 1274 IntEngFreeClipResources(&xcoClip); 1275 1276 // Fill the region 1277 return bRet; 1278 } 1279 1280 BOOL 1281 FASTCALL 1282 IntGdiPaintRgn( 1283 _In_ PDC pdc, 1284 _In_ PREGION prgn) 1285 { 1286 return IntGdiFillRgn(pdc, prgn, NULL); 1287 } 1288 1289 BOOL 1290 APIENTRY 1291 NtGdiFillRgn( 1292 _In_ HDC hdc, 1293 _In_ HRGN hrgn, 1294 _In_ HBRUSH hbrush) 1295 { 1296 PDC pdc; 1297 PREGION prgn; 1298 PBRUSH pbrFill; 1299 BOOL bResult; 1300 1301 /* Lock the DC */ 1302 pdc = DC_LockDc(hdc); 1303 if (pdc == NULL) 1304 { 1305 ERR("Failed to lock hdc %p\n", hdc); 1306 return FALSE; 1307 } 1308 1309 /* Check if the DC has no surface (empty mem or info DC) */ 1310 if (pdc->dclevel.pSurface == NULL) 1311 { 1312 DC_UnlockDc(pdc); 1313 return TRUE; 1314 } 1315 1316 /* Lock the region */ 1317 prgn = REGION_LockRgn(hrgn); 1318 if (prgn == NULL) 1319 { 1320 ERR("Failed to lock hrgn %p\n", hrgn); 1321 DC_UnlockDc(pdc); 1322 return FALSE; 1323 } 1324 1325 /* Lock the brush */ 1326 pbrFill = BRUSH_ShareLockBrush(hbrush); 1327 if (pbrFill == NULL) 1328 { 1329 ERR("Failed to lock hbrush %p\n", hbrush); 1330 REGION_UnlockRgn(prgn); 1331 DC_UnlockDc(pdc); 1332 return FALSE; 1333 } 1334 1335 /* Call the internal function */ 1336 bResult = IntGdiFillRgn(pdc, prgn, pbrFill); 1337 1338 /* Cleanup locks */ 1339 BRUSH_ShareUnlockBrush(pbrFill); 1340 REGION_UnlockRgn(prgn); 1341 DC_UnlockDc(pdc); 1342 1343 return bResult; 1344 } 1345 1346 BOOL 1347 APIENTRY 1348 NtGdiFrameRgn( 1349 _In_ HDC hdc, 1350 _In_ HRGN hrgn, 1351 _In_ HBRUSH hbrush, 1352 _In_ INT xWidth, 1353 _In_ INT yHeight) 1354 { 1355 HRGN hrgnFrame; 1356 BOOL bResult; 1357 1358 hrgnFrame = GreCreateFrameRgn(hrgn, xWidth, yHeight); 1359 if (hrgnFrame == NULL) 1360 { 1361 return FALSE; 1362 } 1363 1364 bResult = NtGdiFillRgn(hdc, hrgnFrame, hbrush); 1365 1366 GreDeleteObject(hrgnFrame); 1367 return bResult; 1368 } 1369 1370 BOOL 1371 APIENTRY 1372 NtGdiInvertRgn( 1373 _In_ HDC hdc, 1374 _In_ HRGN hrgn) 1375 { 1376 BOOL bResult; 1377 PDC pdc; 1378 PREGION prgn; 1379 1380 /* Lock the DC */ 1381 pdc = DC_LockDc(hdc); 1382 if (pdc == NULL) 1383 { 1384 EngSetLastError(ERROR_INVALID_HANDLE); 1385 return FALSE; 1386 } 1387 1388 /* Check if the DC has no surface (empty mem or info DC) */ 1389 if (pdc->dclevel.pSurface == NULL) 1390 { 1391 /* Nothing to do, Windows returns TRUE! */ 1392 DC_UnlockDc(pdc); 1393 return TRUE; 1394 } 1395 1396 /* Lock the region */ 1397 prgn = REGION_LockRgn(hrgn); 1398 if (prgn == NULL) 1399 { 1400 DC_UnlockDc(pdc); 1401 return FALSE; 1402 } 1403 1404 /* Call the internal function */ 1405 bResult = IntGdiBitBltRgn(pdc, 1406 prgn, 1407 NULL, // pbo 1408 NULL, // pptlBrush, 1409 ROP4_DSTINVERT); 1410 1411 /* Unlock the region and DC and return the result */ 1412 REGION_UnlockRgn(prgn); 1413 DC_UnlockDc(pdc); 1414 return bResult; 1415 } 1416 1417 COLORREF 1418 APIENTRY 1419 NtGdiSetPixel( 1420 _In_ HDC hdc, 1421 _In_ INT x, 1422 _In_ INT y, 1423 _In_ COLORREF crColor) 1424 { 1425 PDC pdc; 1426 ULONG iOldColor, iSolidColor; 1427 BOOL bResult; 1428 PEBRUSHOBJ pebo; 1429 ULONG ulDirty; 1430 EXLATEOBJ exlo; 1431 1432 /* Lock the DC */ 1433 pdc = DC_LockDc(hdc); 1434 if (!pdc) 1435 { 1436 EngSetLastError(ERROR_INVALID_HANDLE); 1437 return -1; 1438 } 1439 1440 /* Check if the DC has no surface (empty mem or info DC) */ 1441 if (pdc->dclevel.pSurface == NULL) 1442 { 1443 /* Fail! */ 1444 DC_UnlockDc(pdc); 1445 return -1; 1446 } 1447 1448 if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 1449 { 1450 RECTL rcDst; 1451 1452 RECTL_vSetRect(&rcDst, x, y, x+1, y+1); 1453 1454 IntLPtoDP(pdc, (LPPOINT)&rcDst, 2); 1455 1456 rcDst.left += pdc->ptlDCOrig.x; 1457 rcDst.top += pdc->ptlDCOrig.y; 1458 rcDst.right += pdc->ptlDCOrig.x; 1459 rcDst.bottom += pdc->ptlDCOrig.y; 1460 1461 IntUpdateBoundsRect(pdc, &rcDst); 1462 } 1463 1464 /* Translate the color to the target format */ 1465 iSolidColor = TranslateCOLORREF(pdc, crColor); 1466 1467 /* Use the DC's text brush, which is always a solid brush */ 1468 pebo = &pdc->eboText; 1469 1470 /* Save the old solid color and set the one for the pixel */ 1471 iOldColor = EBRUSHOBJ_iSetSolidColor(pebo, iSolidColor); 1472 1473 /* Save dirty flags and reset dirty text brush flag */ 1474 ulDirty = pdc->pdcattr->ulDirty_; 1475 pdc->pdcattr->ulDirty_ &= ~DIRTY_TEXT; 1476 1477 /* Call the internal function */ 1478 bResult = IntPatBlt(pdc, x, y, 1, 1, PATCOPY, pebo); 1479 1480 /* Restore old text brush color and dirty flags */ 1481 EBRUSHOBJ_iSetSolidColor(pebo, iOldColor); 1482 pdc->pdcattr->ulDirty_ = ulDirty; 1483 1484 /// FIXME: we shouldn't dereference pSurface while the PDEV is not locked! 1485 /* Initialize an XLATEOBJ from the target surface to RGB */ 1486 EXLATEOBJ_vInitialize(&exlo, 1487 pdc->dclevel.pSurface->ppal, 1488 &gpalRGB, 1489 0, 1490 pdc->pdcattr->crBackgroundClr, 1491 pdc->pdcattr->crForegroundClr); 1492 1493 /* Translate the color back to RGB */ 1494 crColor = XLATEOBJ_iXlate(&exlo.xlo, iSolidColor); 1495 1496 /* Cleanup and return the target format color */ 1497 EXLATEOBJ_vCleanup(&exlo); 1498 1499 /* Unlock the DC */ 1500 DC_UnlockDc(pdc); 1501 1502 /* Return the new RGB color or -1 on failure */ 1503 return bResult ? crColor : -1; 1504 } 1505 1506 COLORREF 1507 APIENTRY 1508 NtGdiGetPixel( 1509 _In_ HDC hdc, 1510 _In_ INT x, 1511 _In_ INT y) 1512 { 1513 PDC pdc; 1514 ULONG ulRGBColor = CLR_INVALID; 1515 POINTL ptlSrc; 1516 RECT rcDest; 1517 PSURFACE psurfSrc, psurfDest; 1518 1519 /* Lock the DC */ 1520 pdc = DC_LockDc(hdc); 1521 if (!pdc) 1522 { 1523 EngSetLastError(ERROR_INVALID_HANDLE); 1524 return CLR_INVALID; 1525 } 1526 1527 /* Check if the DC has no surface (empty mem or info DC) */ 1528 if (pdc->dclevel.pSurface == NULL) 1529 { 1530 /* Fail! */ 1531 goto leave; 1532 } 1533 1534 /* Get the logical coordinates */ 1535 ptlSrc.x = x; 1536 ptlSrc.y = y; 1537 1538 /* Translate coordinates to device coordinates */ 1539 IntLPtoDP(pdc, &ptlSrc, 1); 1540 ptlSrc.x += pdc->ptlDCOrig.x; 1541 ptlSrc.y += pdc->ptlDCOrig.y; 1542 1543 rcDest.left = x; 1544 rcDest.top = y; 1545 rcDest.right = x + 1; 1546 rcDest.bottom = y + 1; 1547 1548 /* Prepare DC for blit */ 1549 DC_vPrepareDCsForBlit(pdc, &rcDest, NULL, NULL); 1550 1551 /* Check if the pixel is outside the surface */ 1552 psurfSrc = pdc->dclevel.pSurface; 1553 if ((ptlSrc.x >= psurfSrc->SurfObj.sizlBitmap.cx) || 1554 (ptlSrc.y >= psurfSrc->SurfObj.sizlBitmap.cy) || 1555 (ptlSrc.x < 0) || 1556 (ptlSrc.y < 0)) 1557 { 1558 /* Fail! */ 1559 goto leave; 1560 } 1561 1562 /* Allocate a surface */ 1563 psurfDest = SURFACE_AllocSurface(STYPE_BITMAP, 1564 1, 1565 1, 1566 BMF_32BPP, 1567 0, 1568 0, 1569 0, 1570 &ulRGBColor); 1571 if (psurfDest) 1572 { 1573 RECTL rclDest = {0, 0, 1, 1}; 1574 EXLATEOBJ exlo; 1575 1576 /* Translate from the source palette to RGB color */ 1577 EXLATEOBJ_vInitialize(&exlo, 1578 psurfSrc->ppal, 1579 &gpalRGB, 1580 0, 1581 RGB(0xff,0xff,0xff), 1582 RGB(0,0,0)); 1583 1584 /* Call the copy bits function */ 1585 EngCopyBits(&psurfDest->SurfObj, 1586 &psurfSrc->SurfObj, 1587 NULL, 1588 &exlo.xlo, 1589 &rclDest, 1590 &ptlSrc); 1591 1592 /* Cleanup the XLATEOBJ */ 1593 EXLATEOBJ_vCleanup(&exlo); 1594 1595 /* Delete the surface */ 1596 GDIOBJ_vDeleteObject(&psurfDest->BaseObject); 1597 } 1598 1599 leave: 1600 1601 /* Unlock the DC */ 1602 DC_vFinishBlit(pdc, NULL); 1603 DC_UnlockDc(pdc); 1604 1605 /* Return the new RGB color or -1 on failure */ 1606 return ulRGBColor; 1607 } 1608 1609