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