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 POINTL ptlBrush; 623 PFN_DrvBitBlt pfnBitBlt; 624 625 ASSERT(psoTrg); 626 psurfTrg = CONTAINING_RECORD(psoTrg, SURFACE, SurfObj); 627 628 /* FIXME: Should we really allow to pass non-well-ordered rects? */ 629 rclClipped = *prclTrg; 630 RECTL_vMakeWellOrdered(&rclClipped); 631 632 //DPRINT1("Rop4 : 0x%08x\n", Rop4); 633 634 /* Sanity check */ 635 ASSERT(IS_VALID_ROP4(Rop4)); 636 637 if (pco) 638 { 639 /* Clip target rect against the bounds of the clipping region */ 640 if (!RECTL_bIntersectRect(&rclClipped, &rclClipped, &pco->rclBounds)) 641 { 642 /* Nothing left */ 643 return TRUE; 644 } 645 646 /* Don't pass a clipobj with only a single rect */ 647 if (pco->iDComplexity == DC_RECT) 648 pco = NULL; 649 } 650 else 651 pco = (CLIPOBJ *)&gxcoTrivial; 652 653 if (ROP4_USES_SOURCE(Rop4)) 654 { 655 ASSERT(psoSrc); 656 psurfSrc = CONTAINING_RECORD(psoSrc, SURFACE, SurfObj); 657 658 /* Calculate source rect */ 659 rclSrc.left = pptlSrc->x + rclClipped.left - prclTrg->left; 660 rclSrc.top = pptlSrc->y + rclClipped.top - prclTrg->top; 661 rclSrc.right = rclSrc.left + rclClipped.right - rclClipped.left; 662 rclSrc.bottom = rclSrc.top + rclClipped.bottom - rclClipped.top; 663 pptlSrc = (PPOINTL)&rclSrc; 664 } 665 else 666 { 667 psoSrc = NULL; 668 psurfSrc = NULL; 669 } 670 671 if (pptlBrush) 672 { 673 #ifdef _USE_DIBLIB_ 674 ptlBrush.x = pptlBrush->x + rclClipped.left - prclTrg->left; 675 ptlBrush.y = pptlBrush->y + rclClipped.top - prclTrg->top; 676 #else 677 ptlBrush = *pptlBrush; 678 #endif 679 } 680 681 /* Is the target surface device managed? */ 682 if (psurfTrg->flags & HOOK_BITBLT) 683 { 684 /* Is the source a different device managed surface? */ 685 if (psoSrc && psoSrc->hdev != psoTrg->hdev && psurfSrc->flags & HOOK_BITBLT) 686 { 687 DPRINT1("Need to copy to standard bitmap format!\n"); 688 ASSERT(FALSE); 689 } 690 691 pfnBitBlt = GDIDEVFUNCS(psoTrg).BitBlt; 692 } 693 694 /* Is the source surface device managed? */ 695 else if (psoSrc && psurfSrc->flags & HOOK_BITBLT) 696 { 697 pfnBitBlt = GDIDEVFUNCS(psoSrc).BitBlt; 698 } 699 else 700 { 701 pfnBitBlt = EngBitBlt; 702 } 703 704 bResult = pfnBitBlt(psoTrg, 705 psoSrc, 706 psoMask, 707 pco, 708 pxlo, 709 &rclClipped, 710 pptlSrc, 711 pptlMask, 712 pbo, 713 pptlBrush ? &ptlBrush : NULL, 714 Rop4); 715 716 // FIXME: cleanup temp surface! 717 718 return bResult; 719 } 720 721 #endif // !_USE_DIBLIB_ 722 723 /**** REACTOS FONT RENDERING CODE *********************************************/ 724 725 /* renders the alpha mask bitmap */ 726 static BOOLEAN APIENTRY 727 AlphaBltMask(SURFOBJ* psoDest, 728 SURFOBJ* psoSource, // unused 729 SURFOBJ* psoMask, 730 XLATEOBJ* pxloRGB2Dest, 731 XLATEOBJ* pxloBrush, 732 RECTL* prclDest, 733 POINTL* pptlSource, // unused 734 POINTL* pptlMask, 735 BRUSHOBJ* pbo, 736 POINTL* pptlBrush) 737 { 738 LONG i, j, dx, dy; 739 int r, g, b; 740 ULONG Background, BrushColor, NewColor; 741 BYTE *tMask, *lMask; 742 743 ASSERT(psoSource == NULL); 744 ASSERT(pptlSource == NULL); 745 746 dx = prclDest->right - prclDest->left; 747 dy = prclDest->bottom - prclDest->top; 748 749 if (psoMask != NULL) 750 { 751 BrushColor = XLATEOBJ_iXlate(pxloBrush, pbo ? pbo->iSolidColor : 0); 752 r = (int)GetRValue(BrushColor); 753 g = (int)GetGValue(BrushColor); 754 b = (int)GetBValue(BrushColor); 755 756 tMask = (PBYTE)psoMask->pvScan0 + (pptlMask->y * psoMask->lDelta) + pptlMask->x; 757 for (j = 0; j < dy; j++) 758 { 759 lMask = tMask; 760 for (i = 0; i < dx; i++) 761 { 762 if (*lMask > 0) 763 { 764 if (*lMask == 0xff) 765 { 766 DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel( 767 psoDest, prclDest->left + i, prclDest->top + j, pbo ? pbo->iSolidColor : 0); 768 } 769 else 770 { 771 Background = DIB_GetSource(psoDest, prclDest->left + i, prclDest->top + j, 772 pxloBrush); 773 774 NewColor = 775 RGB((*lMask * (r - GetRValue(Background)) >> 8) + GetRValue(Background), 776 (*lMask * (g - GetGValue(Background)) >> 8) + GetGValue(Background), 777 (*lMask * (b - GetBValue(Background)) >> 8) + GetBValue(Background)); 778 779 Background = XLATEOBJ_iXlate(pxloRGB2Dest, NewColor); 780 DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel( 781 psoDest, prclDest->left + i, prclDest->top + j, Background); 782 } 783 } 784 lMask++; 785 } 786 tMask += psoMask->lDelta; 787 } 788 return TRUE; 789 } 790 else 791 { 792 return FALSE; 793 } 794 } 795 796 static 797 BOOL APIENTRY 798 EngMaskBitBlt(SURFOBJ *psoDest, 799 SURFOBJ *psoMask, 800 CLIPOBJ *ClipRegion, 801 XLATEOBJ *DestColorTranslation, 802 XLATEOBJ *SourceColorTranslation, 803 RECTL *DestRect, 804 POINTL *pptlMask, 805 BRUSHOBJ *pbo, 806 POINTL *BrushOrigin) 807 { 808 BYTE clippingType; 809 RECTL CombinedRect; 810 RECT_ENUM RectEnum; 811 BOOL EnumMore; 812 POINTL InputPoint; 813 RECTL InputRect; 814 RECTL OutputRect; 815 POINTL Translate; 816 INTENG_ENTER_LEAVE EnterLeaveSource; 817 INTENG_ENTER_LEAVE EnterLeaveDest; 818 SURFOBJ* psoInput; 819 SURFOBJ* psoOutput; 820 BOOLEAN Ret = TRUE; 821 RECTL ClipRect; 822 unsigned i; 823 POINTL Pt; 824 ULONG Direction; 825 POINTL AdjustedBrushOrigin; 826 827 ASSERT(psoMask); 828 829 if (pptlMask) 830 { 831 InputRect.left = pptlMask->x; 832 InputRect.right = pptlMask->x + (DestRect->right - DestRect->left); 833 InputRect.top = pptlMask->y; 834 InputRect.bottom = pptlMask->y + (DestRect->bottom - DestRect->top); 835 } 836 else 837 { 838 InputRect.left = 0; 839 InputRect.right = DestRect->right - DestRect->left; 840 InputRect.top = 0; 841 InputRect.bottom = DestRect->bottom - DestRect->top; 842 } 843 844 OutputRect = *DestRect; 845 if (NULL != ClipRegion) 846 { 847 if (OutputRect.left < ClipRegion->rclBounds.left) 848 { 849 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left; 850 OutputRect.left = ClipRegion->rclBounds.left; 851 } 852 if (ClipRegion->rclBounds.right < OutputRect.right) 853 { 854 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right; 855 OutputRect.right = ClipRegion->rclBounds.right; 856 } 857 if (OutputRect.top < ClipRegion->rclBounds.top) 858 { 859 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top; 860 OutputRect.top = ClipRegion->rclBounds.top; 861 } 862 if (ClipRegion->rclBounds.bottom < OutputRect.bottom) 863 { 864 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom; 865 OutputRect.bottom = ClipRegion->rclBounds.bottom; 866 } 867 } 868 869 if (! IntEngEnter(&EnterLeaveSource, psoMask, &InputRect, TRUE, &Translate, &psoInput)) 870 { 871 return FALSE; 872 } 873 874 InputPoint.x = InputRect.left + Translate.x; 875 InputPoint.y = InputRect.top + Translate.y; 876 877 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's 878 nothing to do */ 879 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top) 880 { 881 IntEngLeave(&EnterLeaveSource); 882 return TRUE; 883 } 884 885 if (! IntEngEnter(&EnterLeaveDest, psoDest, &OutputRect, FALSE, &Translate, &psoOutput)) 886 { 887 IntEngLeave(&EnterLeaveSource); 888 return FALSE; 889 } 890 891 OutputRect.left = DestRect->left + Translate.x; 892 OutputRect.right = DestRect->right + Translate.x; 893 OutputRect.top = DestRect->top + Translate.y; 894 OutputRect.bottom = DestRect->bottom + Translate.y; 895 896 if (BrushOrigin) 897 { 898 AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x; 899 AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y; 900 } 901 else 902 AdjustedBrushOrigin = Translate; 903 904 // Determine clipping type 905 if (ClipRegion == (CLIPOBJ *) NULL) 906 { 907 clippingType = DC_TRIVIAL; 908 } else { 909 clippingType = ClipRegion->iDComplexity; 910 } 911 912 switch (clippingType) 913 { 914 case DC_TRIVIAL: 915 if (psoMask->iBitmapFormat == BMF_8BPP) 916 Ret = AlphaBltMask(psoOutput, NULL , psoInput, DestColorTranslation, SourceColorTranslation, 917 &OutputRect, NULL, &InputPoint, pbo, &AdjustedBrushOrigin); 918 else 919 Ret = BltMask(psoOutput, NULL, psoInput, DestColorTranslation, 920 &OutputRect, NULL, &InputPoint, pbo, &AdjustedBrushOrigin, 921 ROP4_MASK); 922 break; 923 case DC_RECT: 924 // Clip the blt to the clip rectangle 925 ClipRect.left = ClipRegion->rclBounds.left + Translate.x; 926 ClipRect.right = ClipRegion->rclBounds.right + Translate.x; 927 ClipRect.top = ClipRegion->rclBounds.top + Translate.y; 928 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y; 929 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect)) 930 { 931 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left; 932 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top; 933 if (psoMask->iBitmapFormat == BMF_8BPP) 934 { 935 Ret = AlphaBltMask(psoOutput, NULL, psoInput, DestColorTranslation, SourceColorTranslation, 936 &CombinedRect, NULL, &Pt, pbo, &AdjustedBrushOrigin); 937 } 938 else 939 { 940 Ret = BltMask(psoOutput, NULL, psoInput, DestColorTranslation, 941 &CombinedRect, NULL, &Pt, pbo, &AdjustedBrushOrigin, ROP4_MASK); 942 } 943 } 944 break; 945 case DC_COMPLEX: 946 Ret = TRUE; 947 if (psoOutput == psoInput) 948 { 949 if (OutputRect.top < InputPoint.y) 950 { 951 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN; 952 } 953 else 954 { 955 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP; 956 } 957 } 958 else 959 { 960 Direction = CD_ANY; 961 } 962 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0); 963 do 964 { 965 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum); 966 967 for (i = 0; i < RectEnum.c; i++) 968 { 969 ClipRect.left = RectEnum.arcl[i].left + Translate.x; 970 ClipRect.right = RectEnum.arcl[i].right + Translate.x; 971 ClipRect.top = RectEnum.arcl[i].top + Translate.y; 972 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y; 973 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect)) 974 { 975 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left; 976 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top; 977 if (psoMask->iBitmapFormat == BMF_8BPP) 978 { 979 Ret = AlphaBltMask(psoOutput, NULL, psoInput, 980 DestColorTranslation, 981 SourceColorTranslation, 982 &CombinedRect, NULL, &Pt, pbo, 983 &AdjustedBrushOrigin) && Ret; 984 } 985 else 986 { 987 Ret = BltMask(psoOutput, NULL, psoInput, 988 DestColorTranslation, &CombinedRect, NULL, 989 &Pt, pbo, &AdjustedBrushOrigin, 990 ROP4_MASK) && Ret; 991 } 992 } 993 } 994 } 995 while (EnumMore); 996 break; 997 } 998 999 1000 IntEngLeave(&EnterLeaveDest); 1001 IntEngLeave(&EnterLeaveSource); 1002 1003 return Ret; 1004 } 1005 1006 BOOL 1007 APIENTRY 1008 IntEngMaskBlt( 1009 _Inout_ SURFOBJ *psoDest, 1010 _In_ SURFOBJ *psoMask, 1011 _In_ CLIPOBJ *pco, 1012 _In_ XLATEOBJ *pxloDest, 1013 _In_ XLATEOBJ *pxloSource, 1014 _In_ RECTL *prclDest, 1015 _In_ POINTL *pptlMask, 1016 _In_ BRUSHOBJ *pbo, 1017 _In_ POINTL *pptlBrushOrg) 1018 { 1019 BOOLEAN ret; 1020 RECTL rcDest; 1021 POINTL ptMask = {0,0}; 1022 PSURFACE psurfTemp; 1023 RECTL rcTemp; 1024 1025 ASSERT(psoDest); 1026 ASSERT(psoMask); 1027 1028 /* Is this a 1 BPP mask? */ 1029 if (psoMask->iBitmapFormat == BMF_1BPP) 1030 { 1031 /* Use IntEngBitBlt with an appropriate ROP4 */ 1032 return IntEngBitBlt(psoDest, 1033 NULL, 1034 psoMask, 1035 pco, 1036 pxloDest, 1037 prclDest, 1038 NULL, 1039 pptlMask, 1040 pbo, 1041 pptlBrushOrg, 1042 ROP4_MASKPAINT); 1043 } 1044 1045 ASSERT(psoMask->iBitmapFormat == BMF_8BPP); 1046 1047 if (pptlMask) 1048 { 1049 ptMask = *pptlMask; 1050 } 1051 1052 /* Clip against the bounds of the clipping region so we won't try to write 1053 * outside the surface */ 1054 if (pco != NULL) 1055 { 1056 /* Intersect with the clip bounds and check if everything was clipped */ 1057 if (!RECTL_bIntersectRect(&rcDest, prclDest, &pco->rclBounds)) 1058 { 1059 return TRUE; 1060 } 1061 1062 /* Adjust the mask point */ 1063 ptMask.x += rcDest.left - prclDest->left; 1064 ptMask.y += rcDest.top - prclDest->top; 1065 } 1066 else 1067 { 1068 rcDest = *prclDest; 1069 } 1070 1071 /* Check if the target surface is device managed */ 1072 if (psoDest->iType != STYPE_BITMAP) 1073 { 1074 rcTemp.left = 0; 1075 rcTemp.top = 0; 1076 rcTemp.right = rcDest.right - rcDest.left; 1077 rcTemp.bottom = rcDest.bottom - rcDest.top; 1078 1079 /* Allocate a temporary surface */ 1080 psurfTemp = SURFACE_AllocSurface(STYPE_BITMAP, 1081 rcTemp.right, 1082 rcTemp.bottom, 1083 psoDest->iBitmapFormat, 1084 0, 1085 0, 1086 0, 1087 NULL); 1088 if (psurfTemp == NULL) 1089 { 1090 return FALSE; 1091 } 1092 1093 /* Copy the current target surface bits to the temp surface */ 1094 ret = EngCopyBits(&psurfTemp->SurfObj, 1095 psoDest, 1096 NULL, // pco 1097 NULL, // pxlo 1098 &rcTemp, 1099 (PPOINTL)&rcDest); 1100 1101 if (ret) 1102 { 1103 /* Do the operation on the temp surface */ 1104 ret = EngMaskBitBlt(&psurfTemp->SurfObj, 1105 psoMask, 1106 NULL, 1107 pxloDest, 1108 pxloSource, 1109 &rcTemp, 1110 &ptMask, 1111 pbo, 1112 pptlBrushOrg); 1113 } 1114 1115 if (ret) 1116 { 1117 /* Copy the result back to the dest surface */ 1118 ret = EngCopyBits(psoDest, 1119 &psurfTemp->SurfObj, 1120 pco, 1121 NULL, 1122 &rcDest, 1123 (PPOINTL)&rcTemp); 1124 } 1125 1126 /* Delete the temp surface */ 1127 GDIOBJ_vDeleteObject(&psurfTemp->BaseObject); 1128 } 1129 else 1130 { 1131 /* Do the operation on the target surface */ 1132 ret = EngMaskBitBlt(psoDest, 1133 psoMask, 1134 pco, 1135 pxloDest, 1136 pxloSource, 1137 &rcDest, 1138 &ptMask, 1139 pbo, 1140 pptlBrushOrg); 1141 } 1142 1143 return ret; 1144 } 1145 1146 /* EOF */ 1147