1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Win32k subsystem 4 * PURPOSE: GDI stretch blt functions 5 * FILE: win32ss/gdi/eng/stretchblt.c 6 * PROGRAMER: Jason Filby 7 */ 8 9 #include <win32k.h> 10 11 #define NDEBUG 12 #include <debug.h> 13 14 typedef BOOLEAN (APIENTRY *PSTRETCHRECTFUNC)(SURFOBJ* OutputObj, 15 SURFOBJ* InputObj, 16 SURFOBJ* Mask, 17 XLATEOBJ* ColorTranslation, 18 RECTL* OutputRect, 19 RECTL* InputRect, 20 POINTL* MaskOrigin, 21 BRUSHOBJ* pbo, 22 POINTL* BrushOrigin, 23 ROP4 Rop4); 24 25 static BOOLEAN APIENTRY 26 CallDibStretchBlt(SURFOBJ* psoDest, 27 SURFOBJ* psoSource, 28 SURFOBJ* Mask, 29 XLATEOBJ* ColorTranslation, 30 RECTL* OutputRect, 31 RECTL* InputRect, 32 POINTL* MaskOrigin, 33 BRUSHOBJ* pbo, 34 POINTL* BrushOrigin, 35 ROP4 Rop4) 36 { 37 POINTL RealBrushOrigin; 38 SURFOBJ* psoPattern; 39 BOOL bResult; 40 41 if (BrushOrigin == NULL) 42 { 43 RealBrushOrigin.x = RealBrushOrigin.y = 0; 44 } 45 else 46 { 47 RealBrushOrigin = *BrushOrigin; 48 } 49 50 /* Pattern brush */ 51 if (ROP4_USES_PATTERN(Rop4) && pbo && pbo->iSolidColor == 0xFFFFFFFF) 52 { 53 psoPattern = BRUSHOBJ_psoPattern(pbo); 54 55 if (!psoPattern) return FALSE; 56 } 57 else 58 { 59 psoPattern = NULL; 60 } 61 62 bResult = DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_StretchBlt( 63 psoDest, psoSource, Mask, psoPattern, 64 OutputRect, InputRect, MaskOrigin, pbo, &RealBrushOrigin, 65 ColorTranslation, Rop4); 66 67 return bResult; 68 } 69 70 71 72 /* 73 * @implemented 74 */ 75 BOOL 76 APIENTRY 77 EngStretchBltROP( 78 IN SURFOBJ *psoDest, 79 IN SURFOBJ *psoSource, 80 IN SURFOBJ *Mask, 81 IN CLIPOBJ *ClipRegion, 82 IN XLATEOBJ *ColorTranslation, 83 IN COLORADJUSTMENT *pca, 84 IN POINTL *BrushOrigin, 85 IN RECTL *prclDest, 86 IN RECTL *prclSrc, 87 IN POINTL *MaskOrigin, 88 IN ULONG Mode, 89 IN BRUSHOBJ *pbo, 90 IN ROP4 Rop4) 91 { 92 RECTL InputRect; 93 RECTL OutputRect; 94 POINTL Translate; 95 INTENG_ENTER_LEAVE EnterLeaveSource; 96 INTENG_ENTER_LEAVE EnterLeaveDest; 97 SURFOBJ* psoInput; 98 SURFOBJ* psoOutput; 99 PSTRETCHRECTFUNC BltRectFunc; 100 BOOLEAN Ret = TRUE; 101 POINTL AdjustedBrushOrigin; 102 BOOL UsesSource = ROP4_USES_SOURCE(Rop4); 103 104 BYTE clippingType; 105 RECTL ClipRect; 106 RECT_ENUM RectEnum; 107 BOOL EnumMore; 108 ULONG Direction; 109 RECTL CombinedRect; 110 RECTL InputToCombinedRect; 111 unsigned i; 112 113 LONG DstHeight; 114 LONG DstWidth; 115 LONG SrcHeight; 116 LONG SrcWidth; 117 118 if (Rop4 == ROP4_NOOP) 119 { 120 /* Copy destination onto itself: nop */ 121 return TRUE; 122 } 123 124 125 /* Determine clipping type */ 126 if (ClipRegion == (CLIPOBJ *) NULL) 127 { 128 clippingType = DC_TRIVIAL; 129 } 130 else 131 { 132 clippingType = ClipRegion->iDComplexity; 133 } 134 135 OutputRect = *prclDest; 136 if (OutputRect.right < OutputRect.left) 137 { 138 OutputRect.left = prclDest->right; 139 OutputRect.right = prclDest->left; 140 } 141 if (OutputRect.bottom < OutputRect.top) 142 { 143 OutputRect.top = prclDest->bottom; 144 OutputRect.bottom = prclDest->top; 145 } 146 147 if (UsesSource) 148 { 149 if (NULL == prclSrc) 150 { 151 return FALSE; 152 } 153 InputRect = *prclSrc; 154 155 if (! IntEngEnter(&EnterLeaveSource, psoSource, &InputRect, TRUE, 156 &Translate, &psoInput)) 157 { 158 return FALSE; 159 } 160 161 InputRect.left += Translate.x; 162 InputRect.right += Translate.x; 163 InputRect.top += Translate.y; 164 InputRect.bottom += Translate.y; 165 } 166 else 167 { 168 InputRect.left = 0; 169 InputRect.right = OutputRect.right - OutputRect.left; 170 InputRect.top = 0; 171 InputRect.bottom = OutputRect.bottom - OutputRect.top; 172 psoInput = NULL; 173 } 174 175 if (NULL != ClipRegion) 176 { 177 if (OutputRect.left < ClipRegion->rclBounds.left) 178 { 179 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left; 180 OutputRect.left = ClipRegion->rclBounds.left; 181 } 182 if (ClipRegion->rclBounds.right < OutputRect.right) 183 { 184 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right; 185 OutputRect.right = ClipRegion->rclBounds.right; 186 } 187 if (OutputRect.top < ClipRegion->rclBounds.top) 188 { 189 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top; 190 OutputRect.top = ClipRegion->rclBounds.top; 191 } 192 if (ClipRegion->rclBounds.bottom < OutputRect.bottom) 193 { 194 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom; 195 OutputRect.bottom = ClipRegion->rclBounds.bottom; 196 } 197 } 198 199 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's 200 nothing to do */ 201 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top) 202 { 203 if (UsesSource) 204 { 205 IntEngLeave(&EnterLeaveSource); 206 } 207 return TRUE; 208 } 209 210 if (! IntEngEnter(&EnterLeaveDest, psoDest, &OutputRect, FALSE, &Translate, &psoOutput)) 211 { 212 if (UsesSource) 213 { 214 IntEngLeave(&EnterLeaveSource); 215 } 216 return FALSE; 217 } 218 219 OutputRect.left += Translate.x; 220 OutputRect.right += Translate.x; 221 OutputRect.top += Translate.y; 222 OutputRect.bottom += Translate.y; 223 224 if (BrushOrigin) 225 { 226 AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x; 227 AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y; 228 } 229 else 230 { 231 AdjustedBrushOrigin = Translate; 232 } 233 234 BltRectFunc = CallDibStretchBlt; 235 236 DstHeight = OutputRect.bottom - OutputRect.top; 237 DstWidth = OutputRect.right - OutputRect.left; 238 SrcHeight = InputRect.bottom - InputRect.top; 239 SrcWidth = InputRect.right - InputRect.left; 240 switch (clippingType) 241 { 242 case DC_TRIVIAL: 243 Ret = (*BltRectFunc)(psoOutput, psoInput, Mask, 244 ColorTranslation, &OutputRect, &InputRect, MaskOrigin, 245 pbo, &AdjustedBrushOrigin, Rop4); 246 break; 247 case DC_RECT: 248 // Clip the blt to the clip rectangle 249 ClipRect.left = ClipRegion->rclBounds.left + Translate.x; 250 ClipRect.right = ClipRegion->rclBounds.right + Translate.x; 251 ClipRect.top = ClipRegion->rclBounds.top + Translate.y; 252 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y; 253 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect)) 254 { 255 InputToCombinedRect.top = InputRect.top + (CombinedRect.top - OutputRect.top) * SrcHeight / DstHeight; 256 InputToCombinedRect.bottom = InputRect.top + (CombinedRect.bottom - OutputRect.top) * SrcHeight / DstHeight; 257 InputToCombinedRect.left = InputRect.left + (CombinedRect.left - OutputRect.left) * SrcWidth / DstWidth; 258 InputToCombinedRect.right = InputRect.left + (CombinedRect.right - OutputRect.left) * SrcWidth / DstWidth; 259 Ret = (*BltRectFunc)(psoOutput, psoInput, Mask, 260 ColorTranslation, 261 &CombinedRect, 262 &InputToCombinedRect, 263 MaskOrigin, 264 pbo, 265 &AdjustedBrushOrigin, 266 Rop4); 267 } 268 break; 269 case DC_COMPLEX: 270 if (psoOutput == psoInput) 271 { 272 if (OutputRect.top < InputRect.top) 273 { 274 Direction = OutputRect.left < InputRect.left ? 275 CD_RIGHTDOWN : CD_LEFTDOWN; 276 } 277 else 278 { 279 Direction = OutputRect.left < InputRect.left ? 280 CD_RIGHTUP : CD_LEFTUP; 281 } 282 } 283 else 284 { 285 Direction = CD_ANY; 286 } 287 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0); 288 do 289 { 290 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), 291 (PVOID) &RectEnum); 292 for (i = 0; i < RectEnum.c; i++) 293 { 294 ClipRect.left = RectEnum.arcl[i].left + Translate.x; 295 ClipRect.right = RectEnum.arcl[i].right + Translate.x; 296 ClipRect.top = RectEnum.arcl[i].top + Translate.y; 297 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y; 298 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect)) 299 { 300 InputToCombinedRect.top = InputRect.top + (CombinedRect.top - OutputRect.top) * SrcHeight / DstHeight; 301 InputToCombinedRect.bottom = InputRect.top + (CombinedRect.bottom - OutputRect.top) * SrcHeight / DstHeight; 302 InputToCombinedRect.left = InputRect.left + (CombinedRect.left - OutputRect.left) * SrcWidth / DstWidth; 303 InputToCombinedRect.right = InputRect.left + (CombinedRect.right - OutputRect.left) * SrcWidth / DstWidth; 304 Ret = (*BltRectFunc)(psoOutput, psoInput, Mask, 305 ColorTranslation, 306 &CombinedRect, 307 &InputToCombinedRect, 308 MaskOrigin, 309 pbo, 310 &AdjustedBrushOrigin, 311 Rop4); 312 } 313 } 314 } 315 while (EnumMore); 316 break; 317 } 318 319 IntEngLeave(&EnterLeaveDest); 320 if (UsesSource) 321 { 322 IntEngLeave(&EnterLeaveSource); 323 } 324 325 return Ret; 326 } 327 328 /* 329 * @implemented 330 */ 331 BOOL 332 APIENTRY 333 EngStretchBlt( 334 IN SURFOBJ *psoDest, 335 IN SURFOBJ *psoSource, 336 IN SURFOBJ *Mask, 337 IN CLIPOBJ *ClipRegion, 338 IN XLATEOBJ *ColorTranslation, 339 IN COLORADJUSTMENT *pca, 340 IN POINTL *BrushOrigin, 341 IN RECTL *prclDest, 342 IN RECTL *prclSrc, 343 IN POINTL *MaskOrigin, 344 IN ULONG Mode) 345 { 346 return EngStretchBltROP( 347 psoDest, 348 psoSource, 349 Mask, 350 ClipRegion, 351 ColorTranslation, 352 pca, 353 BrushOrigin, 354 prclDest, 355 prclSrc, 356 MaskOrigin, 357 Mode, 358 NULL, 359 ROP4_FROM_INDEX(R3_OPINDEX_SRCCOPY)); 360 } 361 362 BOOL APIENTRY 363 IntEngStretchBlt(SURFOBJ *psoDest, 364 SURFOBJ *psoSource, 365 SURFOBJ *MaskSurf, 366 CLIPOBJ *ClipRegion, 367 XLATEOBJ *ColorTranslation, 368 COLORADJUSTMENT *pca, 369 RECTL *DestRect, 370 RECTL *SourceRect, 371 POINTL *pMaskOrigin, 372 BRUSHOBJ *pbo, 373 POINTL *BrushOrigin, 374 DWORD Rop4) 375 { 376 BOOLEAN ret; 377 POINTL MaskOrigin = {0, 0}; 378 SURFACE *psurfDest; 379 //SURFACE *psurfSource = NULL; 380 RECTL InputClippedRect; 381 RECTL InputRect; 382 RECTL OutputRect; 383 BOOL UsesSource = ROP4_USES_SOURCE(Rop4); 384 LONG InputClWidth, InputClHeight, InputWidth, InputHeight; 385 386 ASSERT(psoDest); 387 //ASSERT(psoSource); // FIXME! 388 ASSERT(DestRect); 389 ASSERT(SourceRect); 390 //ASSERT(!RECTL_bIsEmptyRect(SourceRect)); // FIXME! 391 392 /* If no clip object is given, use trivial one */ 393 if (!ClipRegion) ClipRegion = (CLIPOBJ *)&gxcoTrivial; 394 395 psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj); 396 397 /* Sanity check */ 398 ASSERT(IS_VALID_ROP4(Rop4)); 399 400 /* Check if source and dest size are equal */ 401 if (((DestRect->right - DestRect->left) == (SourceRect->right - SourceRect->left)) && 402 ((DestRect->bottom - DestRect->top) == (SourceRect->bottom - SourceRect->top))) 403 { 404 /* Pass the request to IntEngBitBlt */ 405 return IntEngBitBlt(psoDest, 406 psoSource, 407 MaskSurf, 408 ClipRegion, 409 ColorTranslation, 410 DestRect, 411 (PPOINTL)SourceRect, 412 pMaskOrigin, 413 pbo, 414 BrushOrigin, 415 Rop4); 416 } 417 418 InputClippedRect = *DestRect; 419 if (InputClippedRect.right < InputClippedRect.left) 420 { 421 InputClippedRect.left = DestRect->right; 422 InputClippedRect.right = DestRect->left; 423 } 424 if (InputClippedRect.bottom < InputClippedRect.top) 425 { 426 InputClippedRect.top = DestRect->bottom; 427 InputClippedRect.bottom = DestRect->top; 428 } 429 430 if (NULL == psoSource) 431 { 432 return FALSE; 433 } 434 InputRect = *SourceRect; 435 436 if (InputRect.right < InputRect.left || 437 InputRect.bottom < InputRect.top) 438 { 439 /* Everything clipped away, nothing to do */ 440 return TRUE; 441 } 442 443 if (ClipRegion->iDComplexity != DC_TRIVIAL) 444 { 445 if (!RECTL_bIntersectRect(&OutputRect, &InputClippedRect, 446 &ClipRegion->rclBounds)) 447 { 448 return TRUE; 449 } 450 /* Update source rect */ 451 InputClWidth = InputClippedRect.right - InputClippedRect.left; 452 InputClHeight = InputClippedRect.bottom - InputClippedRect.top; 453 InputWidth = InputRect.right - InputRect.left; 454 InputHeight = InputRect.bottom - InputRect.top; 455 456 InputRect.left += (InputWidth * (OutputRect.left - InputClippedRect.left)) / InputClWidth; 457 InputRect.right -= (InputWidth * (InputClippedRect.right - OutputRect.right)) / InputClWidth; 458 InputRect.top += (InputHeight * (OutputRect.top - InputClippedRect.top)) / InputClHeight; 459 InputRect.bottom -= (InputHeight * (InputClippedRect.bottom - OutputRect.bottom)) / InputClHeight; 460 } 461 else 462 { 463 OutputRect = InputClippedRect; 464 } 465 466 if (pMaskOrigin != NULL) 467 { 468 MaskOrigin.x = pMaskOrigin->x; 469 MaskOrigin.y = pMaskOrigin->y; 470 } 471 472 /* No success yet */ 473 ret = FALSE; 474 475 if (UsesSource) 476 { 477 //psurfSource = CONTAINING_RECORD(psoSource, SURFACE, SurfObj); 478 } 479 480 /* Call the driver's DrvStretchBlt if available */ 481 if (psurfDest->flags & HOOK_STRETCHBLTROP) 482 { 483 /* Drv->StretchBltROP (look at http://www.osronline.com/ddkx/graphics/ddifncs_0z3b.htm ) */ 484 ret = GDIDEVFUNCS(psoDest).StretchBltROP(psoDest, 485 psoSource, 486 MaskSurf, 487 ClipRegion, 488 ColorTranslation, 489 pca, 490 BrushOrigin, 491 &OutputRect, 492 &InputRect, 493 &MaskOrigin, 494 COLORONCOLOR, 495 pbo, 496 Rop4); 497 } 498 499 if (! ret) 500 { 501 ret = EngStretchBltROP(psoDest, 502 psoSource, 503 MaskSurf, 504 ClipRegion, 505 ColorTranslation, 506 pca, 507 BrushOrigin, 508 &OutputRect, 509 &InputRect, 510 &MaskOrigin, 511 COLORONCOLOR, 512 pbo, 513 Rop4); 514 } 515 516 return ret; 517 } 518 519 BOOL 520 APIENTRY 521 NtGdiEngStretchBlt( 522 IN SURFOBJ *psoDest, 523 IN SURFOBJ *psoSource, 524 IN SURFOBJ *Mask, 525 IN CLIPOBJ *ClipRegion, 526 IN XLATEOBJ *ColorTranslation, 527 IN COLORADJUSTMENT *pca, 528 IN POINTL *BrushOrigin, 529 IN RECTL *prclDest, 530 IN RECTL *prclSrc, 531 IN POINTL *MaskOrigin, 532 IN ULONG Mode) 533 { 534 COLORADJUSTMENT ca; 535 POINTL lBrushOrigin; 536 RECTL rclDest; 537 RECTL rclSrc; 538 POINTL lMaskOrigin; 539 540 _SEH2_TRY 541 { 542 if (pca) 543 { 544 ProbeForRead(pca, sizeof(COLORADJUSTMENT), 1); 545 RtlCopyMemory(&ca,pca, sizeof(COLORADJUSTMENT)); 546 pca = &ca; 547 } 548 549 ProbeForRead(BrushOrigin, sizeof(POINTL), 1); 550 RtlCopyMemory(&lBrushOrigin, BrushOrigin, sizeof(POINTL)); 551 552 ProbeForRead(prclDest, sizeof(RECTL), 1); 553 RtlCopyMemory(&rclDest, prclDest, sizeof(RECTL)); 554 555 ProbeForRead(prclSrc, sizeof(RECTL), 1); 556 RtlCopyMemory(&rclSrc, prclSrc, sizeof(RECTL)); 557 558 ProbeForRead(MaskOrigin, sizeof(POINTL), 1); 559 RtlCopyMemory(&lMaskOrigin, MaskOrigin, sizeof(POINTL)); 560 561 } 562 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 563 { 564 _SEH2_YIELD(return FALSE); 565 } 566 _SEH2_END; 567 568 return EngStretchBlt(psoDest, psoSource, Mask, ClipRegion, ColorTranslation, pca, &lBrushOrigin, &rclDest, &rclSrc, &lMaskOrigin, Mode); 569 } 570 571 /* EOF */ 572