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
14 typedef BOOLEAN (APIENTRY
*PSTRETCHRECTFUNC
)(SURFOBJ
* OutputObj
,
17 XLATEOBJ
* ColorTranslation
,
25 static BOOLEAN APIENTRY
26 CallDibStretchBlt(SURFOBJ
* psoDest
,
29 XLATEOBJ
* ColorTranslation
,
37 POINTL RealBrushOrigin
;
41 if (BrushOrigin
== NULL
)
43 RealBrushOrigin
.x
= RealBrushOrigin
.y
= 0;
47 RealBrushOrigin
= *BrushOrigin
;
51 if (ROP4_USES_PATTERN(Rop4
) && pbo
&& pbo
->iSolidColor
== 0xFFFFFFFF)
53 psoPattern
= BRUSHOBJ_psoPattern(pbo
);
55 if (!psoPattern
) return FALSE
;
62 bResult
= DibFunctionsForBitmapFormat
[psoDest
->iBitmapFormat
].DIB_StretchBlt(
63 psoDest
, psoSource
, Mask
, psoPattern
,
64 OutputRect
, InputRect
, MaskOrigin
, pbo
, &RealBrushOrigin
,
65 ColorTranslation
, Rop4
);
79 IN SURFOBJ
*psoSource
,
81 IN CLIPOBJ
*ClipRegion
,
82 IN XLATEOBJ
*ColorTranslation
,
83 IN COLORADJUSTMENT
*pca
,
84 IN POINTL
*BrushOrigin
,
87 IN POINTL
*MaskOrigin
,
95 INTENG_ENTER_LEAVE EnterLeaveSource
;
96 INTENG_ENTER_LEAVE EnterLeaveDest
;
99 PSTRETCHRECTFUNC BltRectFunc
;
101 POINTL AdjustedBrushOrigin
;
102 BOOL UsesSource
= ROP4_USES_SOURCE(Rop4
);
110 RECTL InputToCombinedRect
;
118 if (Rop4
== ROP4_NOOP
)
120 /* Copy destination onto itself: nop */
125 /* Determine clipping type */
126 if (ClipRegion
== (CLIPOBJ
*) NULL
)
128 clippingType
= DC_TRIVIAL
;
132 clippingType
= ClipRegion
->iDComplexity
;
135 OutputRect
= *prclDest
;
136 if (OutputRect
.right
< OutputRect
.left
)
138 OutputRect
.left
= prclDest
->right
;
139 OutputRect
.right
= prclDest
->left
;
141 if (OutputRect
.bottom
< OutputRect
.top
)
143 OutputRect
.top
= prclDest
->bottom
;
144 OutputRect
.bottom
= prclDest
->top
;
153 InputRect
= *prclSrc
;
155 if (! IntEngEnter(&EnterLeaveSource
, psoSource
, &InputRect
, TRUE
,
156 &Translate
, &psoInput
))
161 InputRect
.left
+= Translate
.x
;
162 InputRect
.right
+= Translate
.x
;
163 InputRect
.top
+= Translate
.y
;
164 InputRect
.bottom
+= Translate
.y
;
169 InputRect
.right
= OutputRect
.right
- OutputRect
.left
;
171 InputRect
.bottom
= OutputRect
.bottom
- OutputRect
.top
;
175 if (NULL
!= ClipRegion
)
177 if (OutputRect
.left
< ClipRegion
->rclBounds
.left
)
179 InputRect
.left
+= ClipRegion
->rclBounds
.left
- OutputRect
.left
;
180 OutputRect
.left
= ClipRegion
->rclBounds
.left
;
182 if (ClipRegion
->rclBounds
.right
< OutputRect
.right
)
184 InputRect
.right
-= OutputRect
.right
- ClipRegion
->rclBounds
.right
;
185 OutputRect
.right
= ClipRegion
->rclBounds
.right
;
187 if (OutputRect
.top
< ClipRegion
->rclBounds
.top
)
189 InputRect
.top
+= ClipRegion
->rclBounds
.top
- OutputRect
.top
;
190 OutputRect
.top
= ClipRegion
->rclBounds
.top
;
192 if (ClipRegion
->rclBounds
.bottom
< OutputRect
.bottom
)
194 InputRect
.bottom
-= OutputRect
.bottom
- ClipRegion
->rclBounds
.bottom
;
195 OutputRect
.bottom
= ClipRegion
->rclBounds
.bottom
;
199 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
201 if (OutputRect
.right
<= OutputRect
.left
|| OutputRect
.bottom
<= OutputRect
.top
)
205 IntEngLeave(&EnterLeaveSource
);
210 if (! IntEngEnter(&EnterLeaveDest
, psoDest
, &OutputRect
, FALSE
, &Translate
, &psoOutput
))
214 IntEngLeave(&EnterLeaveSource
);
219 OutputRect
.left
+= Translate
.x
;
220 OutputRect
.right
+= Translate
.x
;
221 OutputRect
.top
+= Translate
.y
;
222 OutputRect
.bottom
+= Translate
.y
;
226 AdjustedBrushOrigin
.x
= BrushOrigin
->x
+ Translate
.x
;
227 AdjustedBrushOrigin
.y
= BrushOrigin
->y
+ Translate
.y
;
231 AdjustedBrushOrigin
= Translate
;
234 BltRectFunc
= CallDibStretchBlt
;
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
)
243 Ret
= (*BltRectFunc
)(psoOutput
, psoInput
, Mask
,
244 ColorTranslation
, &OutputRect
, &InputRect
, MaskOrigin
,
245 pbo
, &AdjustedBrushOrigin
, Rop4
);
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
))
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
,
262 &InputToCombinedRect
,
265 &AdjustedBrushOrigin
,
270 if (psoOutput
== psoInput
)
272 if (OutputRect
.top
< InputRect
.top
)
274 Direction
= OutputRect
.left
< InputRect
.left
?
275 CD_RIGHTDOWN
: CD_LEFTDOWN
;
279 Direction
= OutputRect
.left
< InputRect
.left
?
280 CD_RIGHTUP
: CD_LEFTUP
;
287 CLIPOBJ_cEnumStart(ClipRegion
, FALSE
, CT_RECTANGLES
, Direction
, 0);
290 EnumMore
= CLIPOBJ_bEnum(ClipRegion
,(ULONG
) sizeof(RectEnum
),
292 for (i
= 0; i
< RectEnum
.c
; i
++)
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
))
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
,
307 &InputToCombinedRect
,
310 &AdjustedBrushOrigin
,
319 IntEngLeave(&EnterLeaveDest
);
322 IntEngLeave(&EnterLeaveSource
);
335 IN SURFOBJ
*psoSource
,
337 IN CLIPOBJ
*ClipRegion
,
338 IN XLATEOBJ
*ColorTranslation
,
339 IN COLORADJUSTMENT
*pca
,
340 IN POINTL
*BrushOrigin
,
343 IN POINTL
*MaskOrigin
,
346 return EngStretchBltROP(
359 ROP4_FROM_INDEX(R3_OPINDEX_SRCCOPY
));
363 IntEngStretchBlt(SURFOBJ
*psoDest
,
367 XLATEOBJ
*ColorTranslation
,
368 COLORADJUSTMENT
*pca
,
377 POINTL MaskOrigin
= {0, 0};
379 //SURFACE *psurfSource = NULL;
380 RECTL InputClippedRect
;
383 BOOL UsesSource
= ROP4_USES_SOURCE(Rop4
);
384 LONG InputClWidth
, InputClHeight
, InputWidth
, InputHeight
;
387 //ASSERT(psoSource); // FIXME!
390 //ASSERT(!RECTL_bIsEmptyRect(SourceRect)); // FIXME!
392 /* If no clip object is given, use trivial one */
393 if (!ClipRegion
) ClipRegion
= (CLIPOBJ
*)&gxcoTrivial
;
395 psurfDest
= CONTAINING_RECORD(psoDest
, SURFACE
, SurfObj
);
398 ASSERT(IS_VALID_ROP4(Rop4
));
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
)))
404 /* Pass the request to IntEngBitBlt */
405 return IntEngBitBlt(psoDest
,
418 InputClippedRect
= *DestRect
;
419 if (InputClippedRect
.right
< InputClippedRect
.left
)
421 InputClippedRect
.left
= DestRect
->right
;
422 InputClippedRect
.right
= DestRect
->left
;
424 if (InputClippedRect
.bottom
< InputClippedRect
.top
)
426 InputClippedRect
.top
= DestRect
->bottom
;
427 InputClippedRect
.bottom
= DestRect
->top
;
430 if (NULL
== psoSource
)
434 InputRect
= *SourceRect
;
436 if (InputRect
.right
< InputRect
.left
||
437 InputRect
.bottom
< InputRect
.top
)
439 /* Everything clipped away, nothing to do */
443 if (ClipRegion
->iDComplexity
!= DC_TRIVIAL
)
445 if (!RECTL_bIntersectRect(&OutputRect
, &InputClippedRect
,
446 &ClipRegion
->rclBounds
))
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
;
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
;
463 OutputRect
= InputClippedRect
;
466 if (pMaskOrigin
!= NULL
)
468 MaskOrigin
.x
= pMaskOrigin
->x
;
469 MaskOrigin
.y
= pMaskOrigin
->y
;
477 //psurfSource = CONTAINING_RECORD(psoSource, SURFACE, SurfObj);
480 /* Call the driver's DrvStretchBlt if available */
481 if (psurfDest
->flags
& HOOK_STRETCHBLTROP
)
483 /* Drv->StretchBltROP (look at http://www.osronline.com/ddkx/graphics/ddifncs_0z3b.htm ) */
484 ret
= GDIDEVFUNCS(psoDest
).StretchBltROP(psoDest
,
501 ret
= EngStretchBltROP(psoDest
,
523 IN SURFOBJ
*psoSource
,
525 IN CLIPOBJ
*ClipRegion
,
526 IN XLATEOBJ
*ColorTranslation
,
527 IN COLORADJUSTMENT
*pca
,
528 IN POINTL
*BrushOrigin
,
531 IN POINTL
*MaskOrigin
,
544 ProbeForRead(pca
, sizeof(COLORADJUSTMENT
), 1);
545 RtlCopyMemory(&ca
,pca
, sizeof(COLORADJUSTMENT
));
549 ProbeForRead(BrushOrigin
, sizeof(POINTL
), 1);
550 RtlCopyMemory(&lBrushOrigin
, BrushOrigin
, sizeof(POINTL
));
552 ProbeForRead(prclDest
, sizeof(RECTL
), 1);
553 RtlCopyMemory(&rclDest
, prclDest
, sizeof(RECTL
));
555 ProbeForRead(prclSrc
, sizeof(RECTL
), 1);
556 RtlCopyMemory(&rclSrc
, prclSrc
, sizeof(RECTL
));
558 ProbeForRead(MaskOrigin
, sizeof(POINTL
), 1);
559 RtlCopyMemory(&lMaskOrigin
, MaskOrigin
, sizeof(POINTL
));
562 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
564 _SEH2_YIELD(return FALSE
);
568 return EngStretchBlt(psoDest
, psoSource
, Mask
, ClipRegion
, ColorTranslation
, pca
, &lBrushOrigin
, &rclDest
, &rclSrc
, &lMaskOrigin
, Mode
);