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