1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Win32k subsystem 4 * PURPOSE: GDI BitBlt Functions 5 * FILE: win32ss/gdi/eng/bitblt.c 6 * PROGRAMERS: Jason Filby 7 * Timo Kreuzer 8 * Doug Lyons 9 * 10 * WARNING: Modify this file with extreme caution. It is very sensitive to timing changes. 11 * Adding code can cause the system to show a Fatal Exception Error and fail to boot!. 12 * This is especially true in CallDibBitBlt, IntEngBitBlt and EngBitBlt (even DPRINT's). 13 */ 14 15 #include <win32k.h> 16 17 #define NDEBUG 18 #include <debug.h> 19 20 XCLIPOBJ gxcoTrivial = 21 { 22 /* CLIPOBJ */ 23 { 24 0, /* iUniq */ 25 {LONG_MIN, LONG_MIN, LONG_MAX, LONG_MAX}, /* rclBounds */ 26 DC_TRIVIAL, /* idCOmplexity */ 27 FC_RECT, /* iFComplexity */ 28 TC_RECTANGLES, /* iMode */ 29 0 /* fjOptions */ 30 }, 31 { 0, {0,0,0,0}, 0}, 32 0, {0,0,0,0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 33 }; 34 35 typedef BOOLEAN (APIENTRY *PBLTRECTFUNC)(SURFOBJ* OutputObj, 36 SURFOBJ* InputObj, 37 SURFOBJ* Mask, 38 XLATEOBJ* ColorTranslation, 39 RECTL* OutputRect, 40 POINTL* InputPoint, 41 POINTL* MaskOrigin, 42 BRUSHOBJ* pbo, 43 POINTL* BrushOrigin, 44 ROP4 Rop4); 45 46 static BOOLEAN APIENTRY 47 BltMask(SURFOBJ* psoDest, 48 SURFOBJ* psoSource, 49 SURFOBJ* psoMask, 50 XLATEOBJ* ColorTranslation, 51 RECTL* prclDest, 52 POINTL* pptlSource, 53 POINTL* pptlMask, 54 BRUSHOBJ* pbo, 55 POINTL* pptlBrush, 56 ROP4 Rop4) 57 { 58 LONG x, y, cx, cy; 59 BYTE *pjMskLine, *pjMskCurrent; 60 BYTE fjMaskBit0, fjMaskBit; 61 /* Pattern brushes */ 62 SURFOBJ *psoPattern; 63 ULONG PatternWidth = 0, PatternHeight = 0; 64 LONG PatternX0 = 0, PatternX = 0, PatternY = 0; 65 LONG SrcX = 0, SrcY = 0; 66 PFN_DIB_PutPixel fnDest_PutPixel = NULL; 67 PFN_DIB_GetPixel fnPattern_GetPixel = NULL, fnSrc_GetPixel = NULL, fnDest_GetPixel; 68 ULONG Pattern = 0, Source = 0, Dest = 0; 69 DWORD fgndRop, bkgndRop; 70 71 ASSERT(IS_VALID_ROP4(Rop4)); 72 ASSERT(psoMask->iBitmapFormat == BMF_1BPP); 73 74 fgndRop = ROP4_FGND(Rop4); 75 bkgndRop = ROP4_BKGND(Rop4); 76 77 //DPRINT1("Rop4 : 0x%08x\n", Rop4); 78 79 /* Determine pattern */ 80 if (pbo && pbo->iSolidColor == 0xFFFFFFFF) 81 { 82 psoPattern = BRUSHOBJ_psoPattern(pbo); 83 if (psoPattern) 84 { 85 PatternWidth = psoPattern->sizlBitmap.cx; 86 PatternHeight = psoPattern->sizlBitmap.cy; 87 fnPattern_GetPixel = DibFunctionsForBitmapFormat[psoPattern->iBitmapFormat].DIB_GetPixel; 88 } 89 } 90 else 91 psoPattern = NULL; 92 93 cx = prclDest->right - prclDest->left; 94 cy = prclDest->bottom - prclDest->top; 95 if ((pptlMask->x + cx > psoMask->sizlBitmap.cx) || 96 (pptlMask->y + cy > psoMask->sizlBitmap.cy)) 97 { 98 return FALSE; 99 } 100 101 pjMskLine = (PBYTE)psoMask->pvScan0 + pptlMask->y * psoMask->lDelta + (pptlMask->x >> 3); 102 fjMaskBit0 = 0x80 >> (pptlMask->x & 0x07); 103 104 fnDest_PutPixel = DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel; 105 fnDest_GetPixel = DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_GetPixel; 106 107 /* Do we have a source */ 108 if(psoSource) 109 { 110 /* Sanity check */ 111 ASSERT(ROP4_USES_SOURCE(Rop4)); 112 fnSrc_GetPixel = DibFunctionsForBitmapFormat[psoSource->iBitmapFormat].DIB_GetPixel; 113 SrcY = pptlSource->y; 114 SrcX = pptlSource->x; 115 } 116 117 if (psoPattern) 118 { 119 PatternY = (prclDest->top - pptlBrush->y) % PatternHeight; 120 if (PatternY < 0) 121 { 122 PatternY += PatternHeight; 123 } 124 PatternX0 = (prclDest->left - pptlBrush->x) % PatternWidth; 125 if (PatternX0 < 0) 126 { 127 PatternX0 += PatternWidth; 128 } 129 PatternX = PatternX0; 130 } 131 else 132 { 133 Pattern = pbo ? pbo->iSolidColor : 0; 134 } 135 136 for (y = prclDest->top; y < prclDest->bottom; y++) 137 { 138 pjMskCurrent = pjMskLine; 139 fjMaskBit = fjMaskBit0; 140 141 for (x = prclDest->left; x < prclDest->right; x++) 142 { 143 Rop4 = (*pjMskCurrent & fjMaskBit) ? fgndRop : bkgndRop; 144 145 if(psoPattern) 146 { 147 if(ROP4_USES_PATTERN(Rop4)) 148 Pattern = fnPattern_GetPixel(psoPattern, PatternX, PatternY); 149 PatternX++; 150 PatternX %= PatternWidth; 151 } 152 153 if(psoSource) 154 { 155 if(ROP4_USES_SOURCE(Rop4)) 156 { 157 Source = XLATEOBJ_iXlate(ColorTranslation, 158 fnSrc_GetPixel(psoSource, SrcX, SrcY)); 159 } 160 SrcX++; 161 } 162 163 if(ROP4_USES_DEST(Rop4)) 164 Dest = fnDest_GetPixel(psoDest, x, y); 165 166 fnDest_PutPixel(psoDest, 167 x, 168 y, 169 DIB_DoRop(Rop4, 170 Dest, 171 Source, 172 Pattern)); 173 fjMaskBit = _rotr8(fjMaskBit, 1); 174 pjMskCurrent += (fjMaskBit >> 7); 175 } 176 pjMskLine += psoMask->lDelta; 177 if(psoPattern) 178 { 179 PatternY++; 180 PatternY %= PatternHeight; 181 PatternX = PatternX0; 182 } 183 if(psoSource) 184 { 185 SrcY++; 186 SrcX = pptlSource->x; 187 } 188 } 189 190 return TRUE; 191 } 192 193 #ifndef _USE_DIBLIB_ 194 195 static BOOLEAN APIENTRY 196 BltPatCopy(SURFOBJ* Dest, 197 SURFOBJ* Source, 198 SURFOBJ* Mask, 199 XLATEOBJ* ColorTranslation, 200 RECTL* DestRect, 201 POINTL* SourcePoint, 202 POINTL* MaskPoint, 203 BRUSHOBJ* pbo, 204 POINTL* BrushPoint, 205 DWORD Rop4) 206 { 207 // These functions are assigned if we're working with a DIB 208 // The assigned functions depend on the bitsPerPixel of the DIB 209 210 DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_ColorFill(Dest, DestRect, pbo ? pbo->iSolidColor : 0); 211 212 return TRUE; 213 } 214 215 static BOOLEAN APIENTRY 216 CallDibBitBlt(SURFOBJ* OutputObj, 217 SURFOBJ* InputObj, 218 SURFOBJ* Mask, 219 XLATEOBJ* ColorTranslation, 220 RECTL* OutputRect, 221 POINTL* InputPoint, 222 POINTL* MaskOrigin, 223 BRUSHOBJ* pbo, 224 POINTL* BrushOrigin, 225 ROP4 Rop4) 226 { 227 BLTINFO BltInfo; 228 SURFOBJ *psoPattern; 229 BOOLEAN Result; 230 231 BltInfo.DestSurface = OutputObj; 232 BltInfo.SourceSurface = InputObj; 233 BltInfo.PatternSurface = NULL; 234 BltInfo.XlateSourceToDest = ColorTranslation; 235 BltInfo.DestRect = *OutputRect; 236 BltInfo.SourcePoint = *InputPoint; 237 238 if ((Rop4 & 0xFF) == R3_OPINDEX_SRCCOPY) 239 return DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_BitBltSrcCopy(&BltInfo); 240 241 BltInfo.Brush = pbo; 242 BltInfo.BrushOrigin = *BrushOrigin; 243 BltInfo.Rop4 = Rop4; 244 245 /* Pattern brush */ 246 if (ROP4_USES_PATTERN(Rop4) && pbo && pbo->iSolidColor == 0xFFFFFFFF) 247 { 248 psoPattern = BRUSHOBJ_psoPattern(pbo); 249 if (psoPattern) 250 { 251 BltInfo.PatternSurface = psoPattern; 252 } 253 else 254 { 255 /* FIXME: What to do here? */ 256 } 257 } 258 else 259 { 260 psoPattern = NULL; 261 } 262 263 /* Make WellOrdered with top < bottom and left < right */ 264 RECTL_vMakeWellOrdered(&BltInfo.DestRect); 265 266 DPRINT("CallDibBitBlt: BltInfo.DestRect: (%d,%d)-(%d,%d)\n", 267 BltInfo.DestRect.left, BltInfo.DestRect.top, BltInfo.DestRect.right, BltInfo.DestRect.bottom); 268 269 Result = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_BitBlt(&BltInfo); 270 271 return Result; 272 } 273 274 INT __cdecl abs(INT nm); 275 276 277 /* 278 * @implemented 279 */ 280 BOOL APIENTRY 281 NtGdiEngBitBlt( 282 IN SURFOBJ *psoTrg, 283 IN SURFOBJ *psoSrc, 284 IN SURFOBJ *psoMask, 285 IN CLIPOBJ *pco, 286 IN XLATEOBJ *pxlo, 287 IN RECTL *prclTrg, 288 IN POINTL *pptlSrc, 289 IN POINTL *pptlMask, 290 IN BRUSHOBJ *pbo, 291 IN POINTL *pptlBrush, 292 IN ROP4 Rop4) 293 { 294 RECTL rclTrg; 295 POINTL ptlSrc; 296 POINTL ptlMask; 297 POINTL ptlBrush; 298 299 _SEH2_TRY 300 { 301 ProbeForRead(prclTrg, sizeof(RECTL), 1); 302 RtlCopyMemory(&rclTrg,prclTrg, sizeof(RECTL)); 303 304 ProbeForRead(pptlSrc, sizeof(POINTL), 1); 305 RtlCopyMemory(&ptlSrc, pptlSrc, sizeof(POINTL)); 306 307 ProbeForRead(pptlMask, sizeof(POINTL), 1); 308 RtlCopyMemory(&ptlMask, pptlMask, sizeof(POINTL)); 309 310 ProbeForRead(pptlBrush, sizeof(POINTL), 1); 311 RtlCopyMemory(&ptlBrush, pptlBrush, sizeof(POINTL)); 312 313 } 314 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 315 { 316 _SEH2_YIELD(return FALSE); 317 } 318 _SEH2_END; 319 320 return EngBitBlt(psoTrg, psoSrc, psoMask, pco, pxlo, &rclTrg, &ptlSrc, &ptlMask, pbo, &ptlBrush, Rop4); 321 } 322 323 /* 324 * @implemented 325 */ 326 BOOL 327 APIENTRY 328 EngBitBlt( 329 _Inout_ SURFOBJ *psoTrg, 330 _In_opt_ SURFOBJ *psoSrc, 331 _In_opt_ SURFOBJ *psoMask, 332 _In_opt_ CLIPOBJ *pco, 333 _In_opt_ XLATEOBJ *pxlo, 334 _In_ RECTL *prclTrg, 335 _In_opt_ POINTL *pptlSrc, 336 _In_opt_ POINTL *pptlMask, 337 _In_opt_ BRUSHOBJ *pbo, 338 _In_opt_ POINTL *pptlBrush, 339 _In_ ROP4 rop4) 340 { 341 BYTE clippingType; 342 RECTL CombinedRect; 343 RECT_ENUM RectEnum; 344 BOOL EnumMore; 345 POINTL InputPoint; 346 RECTL InputRect; 347 RECTL OutputRect; 348 SURFOBJ* InputObj = 0; 349 SURFOBJ* OutputObj; 350 PBLTRECTFUNC BltRectFunc; 351 BOOLEAN Ret = TRUE; 352 RECTL ClipRect; 353 ULONG i; 354 POINTL Pt; 355 ULONG Direction; 356 BOOL UsesSource, UsesMask; 357 POINTL AdjustedBrushOrigin; 358 LONG lTmp; 359 BOOLEAN bTopToBottom, bLeftToRight; 360 361 UsesSource = ROP4_USES_SOURCE(rop4); 362 UsesMask = ROP4_USES_MASK(rop4); 363 364 if (prclTrg->left > prclTrg->right) 365 { 366 bLeftToRight = TRUE; 367 } 368 else 369 { 370 bLeftToRight = FALSE; 371 } 372 373 if (prclTrg->top > prclTrg->bottom) 374 { 375 bTopToBottom = TRUE; 376 } 377 else 378 { 379 bTopToBottom = FALSE; 380 } 381 382 if (rop4 == ROP4_NOOP) 383 { 384 /* Copy destination onto itself: nop */ 385 return TRUE; 386 } 387 388 //DPRINT1("rop4 : 0x%08x\n", rop4); 389 390 OutputRect = *prclTrg; 391 RECTL_vMakeWellOrdered(&OutputRect); 392 393 DPRINT("EngBitBlt: prclTrg: (%d,%d)-(%d,%d)\n", 394 prclTrg->left, prclTrg->top, prclTrg->right, prclTrg->bottom); 395 396 DPRINT("EngBitBlt: OutputRect: (%d,%d)-(%d,%d)\n", 397 OutputRect.left, OutputRect.top, OutputRect.right, OutputRect.bottom); 398 399 if (UsesSource) 400 { 401 if (!psoSrc || !pptlSrc) 402 { 403 return FALSE; 404 } 405 406 /* Make sure we don't try to copy anything outside the valid source 407 region */ 408 InputPoint = *pptlSrc; 409 if (InputPoint.x < 0) 410 { 411 OutputRect.left -= InputPoint.x; 412 InputPoint.x = 0; 413 } 414 if (InputPoint.y < 0) 415 { 416 OutputRect.top -= InputPoint.y; 417 InputPoint.y = 0; 418 } 419 if (psoSrc->sizlBitmap.cx < InputPoint.x + 420 OutputRect.right - OutputRect.left) 421 { 422 OutputRect.right = OutputRect.left + 423 psoSrc->sizlBitmap.cx - InputPoint.x; 424 } 425 if (psoSrc->sizlBitmap.cy < InputPoint.y + 426 OutputRect.bottom - OutputRect.top) 427 { 428 OutputRect.bottom = OutputRect.top + 429 psoSrc->sizlBitmap.cy - InputPoint.y; 430 } 431 432 InputRect.left = InputPoint.x; 433 InputRect.right = InputPoint.x + (OutputRect.right - OutputRect.left); 434 InputRect.top = InputPoint.y; 435 InputRect.bottom = InputPoint.y + (OutputRect.bottom - OutputRect.top); 436 437 InputObj = psoSrc; 438 } 439 else 440 { 441 InputPoint.x = InputPoint.y = 0; 442 InputRect.left = 0; 443 InputRect.right = prclTrg->right - prclTrg->left; 444 InputRect.top = 0; 445 InputRect.bottom = prclTrg->bottom - prclTrg->top; 446 } 447 448 if (NULL != pco) 449 { 450 if (OutputRect.left < pco->rclBounds.left) 451 { 452 InputRect.left += pco->rclBounds.left - OutputRect.left; 453 InputPoint.x += pco->rclBounds.left - OutputRect.left; 454 OutputRect.left = pco->rclBounds.left; 455 } 456 if (pco->rclBounds.right < OutputRect.right) 457 { 458 InputRect.right -= OutputRect.right - pco->rclBounds.right; 459 OutputRect.right = pco->rclBounds.right; 460 } 461 if (OutputRect.top < pco->rclBounds.top) 462 { 463 InputRect.top += pco->rclBounds.top - OutputRect.top; 464 InputPoint.y += pco->rclBounds.top - OutputRect.top; 465 OutputRect.top = pco->rclBounds.top; 466 } 467 if (pco->rclBounds.bottom < OutputRect.bottom) 468 { 469 InputRect.bottom -= OutputRect.bottom - pco->rclBounds.bottom; 470 OutputRect.bottom = pco->rclBounds.bottom; 471 } 472 } 473 474 /* Check for degenerate case: if height or width of OutputRect is 0 pixels 475 there's nothing to do */ 476 if (OutputRect.right <= OutputRect.left || 477 OutputRect.bottom <= OutputRect.top) 478 { 479 return TRUE; 480 } 481 482 OutputObj = psoTrg; 483 484 if (pptlBrush) 485 { 486 AdjustedBrushOrigin.x = pptlBrush->x; 487 AdjustedBrushOrigin.y = pptlBrush->y; 488 } 489 else 490 { 491 AdjustedBrushOrigin.x = 0; 492 AdjustedBrushOrigin.y = 0; 493 } 494 495 /* Determine clipping type */ 496 if (pco == (CLIPOBJ *) NULL) 497 { 498 clippingType = DC_TRIVIAL; 499 } 500 else 501 { 502 clippingType = pco->iDComplexity; 503 } 504 505 /* Check if we need a mask but have no mask surface */ 506 if (UsesMask && (psoMask == NULL)) 507 { 508 /* Check if the BRUSHOBJ can provide the mask */ 509 psoMask = BRUSHOBJ_psoMask(pbo); 510 if (psoMask == NULL) 511 { 512 /* We have no mask, assume the mask is all foreground */ 513 rop4 = (rop4 & 0xFF) | ((rop4 & 0xFF) << 8); 514 UsesMask = FALSE; 515 } 516 } 517 518 if (UsesMask) 519 { 520 BltRectFunc = BltMask; 521 } 522 else if ((rop4 & 0xFF) == R3_OPINDEX_PATCOPY) 523 { 524 if (pbo && pbo->iSolidColor == 0xFFFFFFFF) 525 BltRectFunc = CallDibBitBlt; 526 else 527 BltRectFunc = BltPatCopy; 528 } 529 else 530 { 531 BltRectFunc = CallDibBitBlt; 532 } 533 534 535 switch (clippingType) 536 { 537 case DC_TRIVIAL: 538 /* Fix up OutputRect here */ 539 if (bLeftToRight) 540 { 541 lTmp = OutputRect.left; 542 OutputRect.left = OutputRect.right; 543 OutputRect.right = lTmp; 544 } 545 546 if (bTopToBottom) 547 { 548 lTmp = OutputRect.top; 549 OutputRect.top = OutputRect.bottom; 550 OutputRect.bottom = lTmp; 551 } 552 553 Ret = (*BltRectFunc)(OutputObj, 554 InputObj, 555 psoMask, 556 pxlo, 557 &OutputRect, 558 &InputPoint, 559 pptlMask, 560 pbo, 561 &AdjustedBrushOrigin, 562 rop4); 563 break; 564 case DC_RECT: 565 /* Clip the blt to the clip rectangle */ 566 ClipRect.left = pco->rclBounds.left; 567 ClipRect.right = pco->rclBounds.right; 568 ClipRect.top = pco->rclBounds.top; 569 ClipRect.bottom = pco->rclBounds.bottom; 570 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect)) 571 { 572 #ifdef _USE_DIBLIB_ 573 if (BrushOrigin) 574 { 575 AdjustedBrushOrigin.x = BrushOrigin->x + CombinedRect.left - OutputRect.left; 576 AdjustedBrushOrigin.y = BrushOrigin->y + CombinedRect.top - OutputRect.top; 577 } 578 #endif 579 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left; 580 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top; 581 Ret = (*BltRectFunc)(OutputObj, 582 InputObj, 583 psoMask, 584 pxlo, 585 &CombinedRect, 586 &Pt, 587 pptlMask, 588 pbo, 589 &AdjustedBrushOrigin, 590 rop4); 591 } 592 break; 593 case DC_COMPLEX: 594 Ret = TRUE; 595 if (OutputObj == InputObj) 596 { 597 if (OutputRect.top < InputPoint.y) 598 { 599 Direction = OutputRect.left < InputPoint.x ? 600 CD_RIGHTDOWN : CD_LEFTDOWN; 601 } 602 else 603 { 604 Direction = OutputRect.left < InputPoint.x ? 605 CD_RIGHTUP : CD_LEFTUP; 606 } 607 } 608 else 609 { 610 Direction = CD_ANY; 611 } 612 CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, Direction, 0); 613 do 614 { 615 EnumMore = CLIPOBJ_bEnum(pco, sizeof(RectEnum), 616 (PVOID) &RectEnum); 617 618 for (i = 0; i < RectEnum.c; i++) 619 { 620 ClipRect.left = RectEnum.arcl[i].left; 621 ClipRect.right = RectEnum.arcl[i].right; 622 ClipRect.top = RectEnum.arcl[i].top; 623 ClipRect.bottom = RectEnum.arcl[i].bottom; 624 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect)) 625 { 626 #ifdef _USE_DIBLIB_ 627 if (BrushOrigin) 628 { 629 AdjustedBrushOrigin.x = BrushOrigin->x + CombinedRect.left - OutputRect.left; 630 AdjustedBrushOrigin.y = BrushOrigin->y + CombinedRect.top - OutputRect.top; 631 } 632 #endif 633 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left; 634 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top; 635 Ret = (*BltRectFunc)(OutputObj, 636 InputObj, 637 psoMask, 638 pxlo, 639 &CombinedRect, 640 &Pt, 641 pptlMask, 642 pbo, 643 &AdjustedBrushOrigin, 644 rop4) && Ret; 645 } 646 } 647 } 648 while (EnumMore); 649 break; 650 } 651 652 return Ret; 653 } 654 655 BOOL APIENTRY 656 IntEngBitBlt( 657 SURFOBJ *psoTrg, 658 SURFOBJ *psoSrc, 659 SURFOBJ *psoMask, 660 CLIPOBJ *pco, 661 XLATEOBJ *pxlo, 662 RECTL *prclTrg, 663 POINTL *pptlSrc, 664 POINTL *pptlMask, 665 BRUSHOBJ *pbo, 666 POINTL *pptlBrush, 667 ROP4 Rop4) 668 { 669 SURFACE *psurfTrg; 670 SURFACE *psurfSrc = NULL; 671 BOOL bResult; 672 RECTL rclClipped; 673 RECTL rclSrc; 674 RECTL rclSrcClipped; 675 POINTL ptlBrush; 676 PFN_DrvBitBlt pfnBitBlt; 677 LONG lTmp; 678 BOOLEAN bTopToBottom, bLeftToRight; 679 680 /* Sanity checks */ 681 ASSERT(IS_VALID_ROP4(Rop4)); 682 ASSERT(psoTrg); 683 684 psurfTrg = CONTAINING_RECORD(psoTrg, SURFACE, SurfObj); 685 686 bLeftToRight = prclTrg->left > prclTrg->right; 687 bTopToBottom = prclTrg->top > prclTrg->bottom; 688 689 /* Get the target rect and make it well ordered */ 690 rclClipped = *prclTrg; 691 RECTL_vMakeWellOrdered(&rclClipped); 692 693 /* Clip the target rect against the bounds of the target surface */ 694 if (!RECTL_bClipRectBySize(&rclClipped, &rclClipped, &psoTrg->sizlBitmap)) 695 { 696 /* Nothing left */ 697 return TRUE; 698 } 699 700 if (pco) 701 { 702 /* Clip target rect against the bounds of the clipping region */ 703 if (!RECTL_bIntersectRect(&rclClipped, &rclClipped, &pco->rclBounds)) 704 { 705 /* Nothing left */ 706 return TRUE; 707 } 708 709 /* Don't pass a clipobj with only a single rect */ 710 if (pco->iDComplexity == DC_RECT) 711 pco = NULL; 712 } 713 else 714 pco = (CLIPOBJ *)&gxcoTrivial; 715 716 if (ROP4_USES_SOURCE(Rop4)) 717 { 718 ASSERT(psoSrc); 719 psurfSrc = CONTAINING_RECORD(psoSrc, SURFACE, SurfObj); 720 721 /* Calculate source rect */ 722 rclSrc.left = pptlSrc->x + rclClipped.left - prclTrg->left; 723 rclSrc.top = pptlSrc->y + rclClipped.top - prclTrg->top; 724 rclSrc.right = rclSrc.left + rclClipped.right - rclClipped.left; 725 rclSrc.bottom = rclSrc.top + rclClipped.bottom - rclClipped.top; 726 727 /* Clip the source rect against the size of the source surface */ 728 if (!RECTL_bClipRectBySize(&rclSrcClipped, &rclSrc, &psoSrc->sizlBitmap)) 729 { 730 /* Nothing left */ 731 return TRUE; 732 } 733 734 /* Fix up target rect */ 735 rclClipped.left += (rclSrcClipped.left - rclSrc.left); 736 rclClipped.top += (rclSrcClipped.top - rclSrc.top); 737 rclClipped.right -= (rclSrc.right - rclSrcClipped.right); 738 rclClipped.bottom -= (rclSrc.bottom - rclSrcClipped.bottom); 739 740 pptlSrc = (PPOINTL)&rclSrcClipped; 741 } 742 else 743 { 744 psoSrc = NULL; 745 psurfSrc = NULL; 746 } 747 748 if (pptlBrush) 749 { 750 #ifdef _USE_DIBLIB_ 751 ptlBrush.x = pptlBrush->x + rclClipped.left - prclTrg->left; 752 ptlBrush.y = pptlBrush->y + rclClipped.top - prclTrg->top; 753 #else 754 ptlBrush = *pptlBrush; 755 #endif 756 } 757 758 /* Is the target surface device managed? */ 759 if (psurfTrg->flags & HOOK_BITBLT) 760 { 761 /* Is the source a different device managed surface? */ 762 if (psoSrc && psoSrc->hdev != psoTrg->hdev && psurfSrc->flags & HOOK_BITBLT) 763 { 764 DPRINT1("Need to copy to standard bitmap format!\n"); 765 ASSERT(FALSE); 766 } 767 768 pfnBitBlt = GDIDEVFUNCS(psoTrg).BitBlt; 769 } 770 771 /* Is the source surface device managed? */ 772 else if (psoSrc && psurfSrc->flags & HOOK_BITBLT) 773 { 774 pfnBitBlt = GDIDEVFUNCS(psoSrc).BitBlt; 775 } 776 else 777 { 778 pfnBitBlt = EngBitBlt; 779 } 780 781 /* rclClipped needs to be modified in accordance with flips here */ 782 if (bLeftToRight) 783 { 784 lTmp = rclClipped.left; 785 rclClipped.left = rclClipped.right; 786 rclClipped.right = lTmp; 787 } 788 789 if (bTopToBottom) 790 { 791 lTmp = rclClipped.top; 792 rclClipped.top = rclClipped.bottom; 793 rclClipped.bottom = lTmp; 794 } 795 796 DPRINT("About to call EngBitBlt: rclClipped: (%d,%d)-(%d,%d)\n", 797 rclClipped.left, rclClipped.top, rclClipped.right, rclClipped.bottom); 798 799 bResult = pfnBitBlt(psoTrg, 800 psoSrc, 801 psoMask, 802 pco, 803 pxlo, 804 &rclClipped, 805 pptlSrc, 806 pptlMask, 807 pbo, 808 pptlBrush ? &ptlBrush : NULL, 809 Rop4); 810 811 // FIXME: cleanup temp surface! 812 813 return bResult; 814 } 815 816 #endif // !_USE_DIBLIB_ 817 818 /**** REACTOS FONT RENDERING CODE *********************************************/ 819 820 /* renders the alpha mask bitmap */ 821 static BOOLEAN APIENTRY 822 AlphaBltMask(SURFOBJ* psoDest, 823 SURFOBJ* psoSource, // unused 824 SURFOBJ* psoMask, 825 XLATEOBJ* pxloRGB2Dest, 826 XLATEOBJ* pxloBrush, 827 RECTL* prclDest, 828 POINTL* pptlSource, // unused 829 POINTL* pptlMask, 830 BRUSHOBJ* pbo, 831 POINTL* pptlBrush) 832 { 833 LONG i, j, dx, dy; 834 int r, g, b; 835 ULONG Background, BrushColor, NewColor; 836 BYTE *tMask, *lMask; 837 838 ASSERT(psoSource == NULL); 839 ASSERT(pptlSource == NULL); 840 841 dx = prclDest->right - prclDest->left; 842 dy = prclDest->bottom - prclDest->top; 843 844 if (psoMask != NULL) 845 { 846 BrushColor = XLATEOBJ_iXlate(pxloBrush, pbo ? pbo->iSolidColor : 0); 847 r = (int)GetRValue(BrushColor); 848 g = (int)GetGValue(BrushColor); 849 b = (int)GetBValue(BrushColor); 850 851 tMask = (PBYTE)psoMask->pvScan0 + (pptlMask->y * psoMask->lDelta) + pptlMask->x; 852 for (j = 0; j < dy; j++) 853 { 854 lMask = tMask; 855 for (i = 0; i < dx; i++) 856 { 857 if (*lMask > 0) 858 { 859 if (*lMask == 0xff) 860 { 861 DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel( 862 psoDest, prclDest->left + i, prclDest->top + j, pbo ? pbo->iSolidColor : 0); 863 } 864 else 865 { 866 Background = DIB_GetSource(psoDest, prclDest->left + i, prclDest->top + j, 867 pxloBrush); 868 869 NewColor = 870 RGB((*lMask * (r - GetRValue(Background)) >> 8) + GetRValue(Background), 871 (*lMask * (g - GetGValue(Background)) >> 8) + GetGValue(Background), 872 (*lMask * (b - GetBValue(Background)) >> 8) + GetBValue(Background)); 873 874 Background = XLATEOBJ_iXlate(pxloRGB2Dest, NewColor); 875 DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel( 876 psoDest, prclDest->left + i, prclDest->top + j, Background); 877 } 878 } 879 lMask++; 880 } 881 tMask += psoMask->lDelta; 882 } 883 return TRUE; 884 } 885 else 886 { 887 return FALSE; 888 } 889 } 890 891 static 892 BOOL APIENTRY 893 EngMaskBitBlt(SURFOBJ *psoDest, 894 SURFOBJ *psoMask, 895 CLIPOBJ *ClipRegion, 896 XLATEOBJ *DestColorTranslation, 897 XLATEOBJ *SourceColorTranslation, 898 RECTL *DestRect, 899 POINTL *pptlMask, 900 BRUSHOBJ *pbo, 901 POINTL *BrushOrigin) 902 { 903 BYTE clippingType; 904 RECTL CombinedRect; 905 RECT_ENUM RectEnum; 906 BOOL EnumMore; 907 POINTL InputPoint; 908 RECTL InputRect; 909 RECTL OutputRect; 910 POINTL Translate; 911 INTENG_ENTER_LEAVE EnterLeaveSource; 912 INTENG_ENTER_LEAVE EnterLeaveDest; 913 SURFOBJ* psoInput; 914 SURFOBJ* psoOutput; 915 BOOLEAN Ret = TRUE; 916 RECTL ClipRect; 917 unsigned i; 918 POINTL Pt; 919 ULONG Direction; 920 POINTL AdjustedBrushOrigin; 921 922 ASSERT(psoMask); 923 924 if (pptlMask) 925 { 926 InputRect.left = pptlMask->x; 927 InputRect.right = pptlMask->x + (DestRect->right - DestRect->left); 928 InputRect.top = pptlMask->y; 929 InputRect.bottom = pptlMask->y + (DestRect->bottom - DestRect->top); 930 } 931 else 932 { 933 InputRect.left = 0; 934 InputRect.right = DestRect->right - DestRect->left; 935 InputRect.top = 0; 936 InputRect.bottom = DestRect->bottom - DestRect->top; 937 } 938 939 OutputRect = *DestRect; 940 if (NULL != ClipRegion) 941 { 942 if (OutputRect.left < ClipRegion->rclBounds.left) 943 { 944 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left; 945 OutputRect.left = ClipRegion->rclBounds.left; 946 } 947 if (ClipRegion->rclBounds.right < OutputRect.right) 948 { 949 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right; 950 OutputRect.right = ClipRegion->rclBounds.right; 951 } 952 if (OutputRect.top < ClipRegion->rclBounds.top) 953 { 954 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top; 955 OutputRect.top = ClipRegion->rclBounds.top; 956 } 957 if (ClipRegion->rclBounds.bottom < OutputRect.bottom) 958 { 959 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom; 960 OutputRect.bottom = ClipRegion->rclBounds.bottom; 961 } 962 } 963 964 if (! IntEngEnter(&EnterLeaveSource, psoMask, &InputRect, TRUE, &Translate, &psoInput)) 965 { 966 return FALSE; 967 } 968 969 InputPoint.x = InputRect.left + Translate.x; 970 InputPoint.y = InputRect.top + Translate.y; 971 972 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's 973 nothing to do */ 974 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top) 975 { 976 IntEngLeave(&EnterLeaveSource); 977 return TRUE; 978 } 979 980 if (! IntEngEnter(&EnterLeaveDest, psoDest, &OutputRect, FALSE, &Translate, &psoOutput)) 981 { 982 IntEngLeave(&EnterLeaveSource); 983 return FALSE; 984 } 985 986 OutputRect.left = DestRect->left + Translate.x; 987 OutputRect.right = DestRect->right + Translate.x; 988 OutputRect.top = DestRect->top + Translate.y; 989 OutputRect.bottom = DestRect->bottom + Translate.y; 990 991 if (BrushOrigin) 992 { 993 AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x; 994 AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y; 995 } 996 else 997 AdjustedBrushOrigin = Translate; 998 999 // Determine clipping type 1000 if (ClipRegion == (CLIPOBJ *) NULL) 1001 { 1002 clippingType = DC_TRIVIAL; 1003 } else { 1004 clippingType = ClipRegion->iDComplexity; 1005 } 1006 1007 switch (clippingType) 1008 { 1009 case DC_TRIVIAL: 1010 if (psoMask->iBitmapFormat == BMF_8BPP) 1011 Ret = AlphaBltMask(psoOutput, NULL , psoInput, DestColorTranslation, SourceColorTranslation, 1012 &OutputRect, NULL, &InputPoint, pbo, &AdjustedBrushOrigin); 1013 else 1014 Ret = BltMask(psoOutput, NULL, psoInput, DestColorTranslation, 1015 &OutputRect, NULL, &InputPoint, pbo, &AdjustedBrushOrigin, 1016 ROP4_MASK); 1017 break; 1018 case DC_RECT: 1019 // Clip the blt to the clip rectangle 1020 ClipRect.left = ClipRegion->rclBounds.left + Translate.x; 1021 ClipRect.right = ClipRegion->rclBounds.right + Translate.x; 1022 ClipRect.top = ClipRegion->rclBounds.top + Translate.y; 1023 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y; 1024 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect)) 1025 { 1026 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left; 1027 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top; 1028 if (psoMask->iBitmapFormat == BMF_8BPP) 1029 { 1030 Ret = AlphaBltMask(psoOutput, NULL, psoInput, DestColorTranslation, SourceColorTranslation, 1031 &CombinedRect, NULL, &Pt, pbo, &AdjustedBrushOrigin); 1032 } 1033 else 1034 { 1035 Ret = BltMask(psoOutput, NULL, psoInput, DestColorTranslation, 1036 &CombinedRect, NULL, &Pt, pbo, &AdjustedBrushOrigin, ROP4_MASK); 1037 } 1038 } 1039 break; 1040 case DC_COMPLEX: 1041 Ret = TRUE; 1042 if (psoOutput == psoInput) 1043 { 1044 if (OutputRect.top < InputPoint.y) 1045 { 1046 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN; 1047 } 1048 else 1049 { 1050 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP; 1051 } 1052 } 1053 else 1054 { 1055 Direction = CD_ANY; 1056 } 1057 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0); 1058 do 1059 { 1060 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum); 1061 1062 for (i = 0; i < RectEnum.c; i++) 1063 { 1064 ClipRect.left = RectEnum.arcl[i].left + Translate.x; 1065 ClipRect.right = RectEnum.arcl[i].right + Translate.x; 1066 ClipRect.top = RectEnum.arcl[i].top + Translate.y; 1067 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y; 1068 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect)) 1069 { 1070 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left; 1071 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top; 1072 if (psoMask->iBitmapFormat == BMF_8BPP) 1073 { 1074 Ret = AlphaBltMask(psoOutput, NULL, psoInput, 1075 DestColorTranslation, 1076 SourceColorTranslation, 1077 &CombinedRect, NULL, &Pt, pbo, 1078 &AdjustedBrushOrigin) && Ret; 1079 } 1080 else 1081 { 1082 Ret = BltMask(psoOutput, NULL, psoInput, 1083 DestColorTranslation, &CombinedRect, NULL, 1084 &Pt, pbo, &AdjustedBrushOrigin, 1085 ROP4_MASK) && Ret; 1086 } 1087 } 1088 } 1089 } 1090 while (EnumMore); 1091 break; 1092 } 1093 1094 1095 IntEngLeave(&EnterLeaveDest); 1096 IntEngLeave(&EnterLeaveSource); 1097 1098 return Ret; 1099 } 1100 1101 BOOL 1102 APIENTRY 1103 IntEngMaskBlt( 1104 _Inout_ SURFOBJ *psoDest, 1105 _In_ SURFOBJ *psoMask, 1106 _In_ CLIPOBJ *pco, 1107 _In_ XLATEOBJ *pxloDest, 1108 _In_ XLATEOBJ *pxloSource, 1109 _In_ RECTL *prclDest, 1110 _In_ POINTL *pptlMask, 1111 _In_ BRUSHOBJ *pbo, 1112 _In_ POINTL *pptlBrushOrg) 1113 { 1114 BOOLEAN ret; 1115 RECTL rcDest; 1116 POINTL ptMask = {0,0}; 1117 PSURFACE psurfTemp; 1118 RECTL rcTemp; 1119 1120 ASSERT(psoDest); 1121 ASSERT(psoMask); 1122 1123 /* Is this a 1 BPP mask? */ 1124 if (psoMask->iBitmapFormat == BMF_1BPP) 1125 { 1126 /* Use IntEngBitBlt with an appropriate ROP4 */ 1127 return IntEngBitBlt(psoDest, 1128 NULL, 1129 psoMask, 1130 pco, 1131 pxloDest, 1132 prclDest, 1133 NULL, 1134 pptlMask, 1135 pbo, 1136 pptlBrushOrg, 1137 ROP4_MASKPAINT); 1138 } 1139 1140 ASSERT(psoMask->iBitmapFormat == BMF_8BPP); 1141 1142 if (pptlMask) 1143 { 1144 ptMask = *pptlMask; 1145 } 1146 1147 /* Clip against the bounds of the clipping region so we won't try to write 1148 * outside the surface */ 1149 if (pco != NULL) 1150 { 1151 /* Intersect with the clip bounds and check if everything was clipped */ 1152 if (!RECTL_bIntersectRect(&rcDest, prclDest, &pco->rclBounds)) 1153 { 1154 return TRUE; 1155 } 1156 1157 /* Adjust the mask point */ 1158 ptMask.x += rcDest.left - prclDest->left; 1159 ptMask.y += rcDest.top - prclDest->top; 1160 } 1161 else 1162 { 1163 rcDest = *prclDest; 1164 } 1165 1166 /* Check if the target surface is device managed */ 1167 if (psoDest->iType != STYPE_BITMAP) 1168 { 1169 rcTemp.left = 0; 1170 rcTemp.top = 0; 1171 rcTemp.right = rcDest.right - rcDest.left; 1172 rcTemp.bottom = rcDest.bottom - rcDest.top; 1173 1174 /* Allocate a temporary surface */ 1175 psurfTemp = SURFACE_AllocSurface(STYPE_BITMAP, 1176 rcTemp.right, 1177 rcTemp.bottom, 1178 psoDest->iBitmapFormat, 1179 0, 1180 0, 1181 0, 1182 NULL); 1183 if (psurfTemp == NULL) 1184 { 1185 return FALSE; 1186 } 1187 1188 /* Copy the current target surface bits to the temp surface */ 1189 ret = EngCopyBits(&psurfTemp->SurfObj, 1190 psoDest, 1191 NULL, // pco 1192 NULL, // pxlo 1193 &rcTemp, 1194 (PPOINTL)&rcDest); 1195 1196 if (ret) 1197 { 1198 /* Do the operation on the temp surface */ 1199 ret = EngMaskBitBlt(&psurfTemp->SurfObj, 1200 psoMask, 1201 NULL, 1202 pxloDest, 1203 pxloSource, 1204 &rcTemp, 1205 &ptMask, 1206 pbo, 1207 pptlBrushOrg); 1208 } 1209 1210 if (ret) 1211 { 1212 /* Copy the result back to the dest surface */ 1213 ret = EngCopyBits(psoDest, 1214 &psurfTemp->SurfObj, 1215 pco, 1216 NULL, 1217 &rcDest, 1218 (PPOINTL)&rcTemp); 1219 } 1220 1221 /* Delete the temp surface */ 1222 GDIOBJ_vDeleteObject(&psurfTemp->BaseObject); 1223 } 1224 else 1225 { 1226 /* Do the operation on the target surface */ 1227 ret = EngMaskBitBlt(psoDest, 1228 psoMask, 1229 pco, 1230 pxloDest, 1231 pxloSource, 1232 &rcDest, 1233 &ptMask, 1234 pbo, 1235 pptlBrushOrg); 1236 } 1237 1238 return ret; 1239 } 1240 1241 /* EOF */ 1242