2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32 kernelmode subsystem
4 * PURPOSE: GDI stretch blt functions
5 * FILE: subsystems/win32/win32k/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
;
38 SURFACE
* psurfPattern
;
39 PEBRUSHOBJ GdiBrush
= NULL
;
40 SURFOBJ
* PatternSurface
= NULL
;
44 if (BrushOrigin
== NULL
)
46 RealBrushOrigin
.x
= RealBrushOrigin
.y
= 0;
50 RealBrushOrigin
= *BrushOrigin
;
54 if (ROP4_USES_PATTERN(Rop4
) && pbo
&& pbo
->iSolidColor
== 0xFFFFFFFF)
56 GdiBrush
= CONTAINING_RECORD(pbo
, EBRUSHOBJ
, BrushObject
);
57 hbmPattern
= EBRUSHOBJ_pvGetEngBrush(GdiBrush
);
58 psurfPattern
= SURFACE_LockSurface(hbmPattern
);
61 PatternSurface
= &psurfPattern
->SurfObj
;
65 /* FIXME - What to do here? */
73 bResult
= DibFunctionsForBitmapFormat
[psoDest
->iBitmapFormat
].DIB_StretchBlt(
74 psoDest
, psoSource
, Mask
, PatternSurface
,
75 OutputRect
, InputRect
, MaskOrigin
, pbo
, &RealBrushOrigin
,
76 ColorTranslation
, Rop4
);
81 SURFACE_UnlockSurface(psurfPattern
);
96 IN SURFOBJ
*psoSource
,
98 IN CLIPOBJ
*ClipRegion
,
99 IN XLATEOBJ
*ColorTranslation
,
100 IN COLORADJUSTMENT
*pca
,
101 IN POINTL
*BrushOrigin
,
104 IN POINTL
*MaskOrigin
,
112 INTENG_ENTER_LEAVE EnterLeaveSource
;
113 INTENG_ENTER_LEAVE EnterLeaveDest
;
116 PSTRETCHRECTFUNC BltRectFunc
;
118 POINTL AdjustedBrushOrigin
;
119 BOOL UsesSource
= ROP4_USES_SOURCE(ROP4
);
127 RECTL InputToCombinedRect
;
135 /* Determine clipping type */
136 if (ClipRegion
== (CLIPOBJ
*) NULL
)
138 clippingType
= DC_TRIVIAL
;
142 clippingType
= ClipRegion
->iDComplexity
;
147 /* Copy destination onto itself: nop */
151 OutputRect
= *prclDest
;
152 if (OutputRect
.right
< OutputRect
.left
)
154 OutputRect
.left
= prclDest
->right
;
155 OutputRect
.right
= prclDest
->left
;
157 if (OutputRect
.bottom
< OutputRect
.top
)
159 OutputRect
.top
= prclDest
->bottom
;
160 OutputRect
.bottom
= prclDest
->top
;
169 InputRect
= *prclSrc
;
171 if (! IntEngEnter(&EnterLeaveSource
, psoSource
, &InputRect
, TRUE
,
172 &Translate
, &psoInput
))
177 InputRect
.left
+= Translate
.x
;
178 InputRect
.right
+= Translate
.x
;
179 InputRect
.top
+= Translate
.y
;
180 InputRect
.bottom
+= Translate
.y
;
185 InputRect
.right
= OutputRect
.right
- OutputRect
.left
;
187 InputRect
.bottom
= OutputRect
.bottom
- OutputRect
.top
;
190 if (NULL
!= ClipRegion
)
192 if (OutputRect
.left
< ClipRegion
->rclBounds
.left
)
194 InputRect
.left
+= ClipRegion
->rclBounds
.left
- OutputRect
.left
;
195 OutputRect
.left
= ClipRegion
->rclBounds
.left
;
197 if (ClipRegion
->rclBounds
.right
< OutputRect
.right
)
199 InputRect
.right
-= OutputRect
.right
- ClipRegion
->rclBounds
.right
;
200 OutputRect
.right
= ClipRegion
->rclBounds
.right
;
202 if (OutputRect
.top
< ClipRegion
->rclBounds
.top
)
204 InputRect
.top
+= ClipRegion
->rclBounds
.top
- OutputRect
.top
;
205 OutputRect
.top
= ClipRegion
->rclBounds
.top
;
207 if (ClipRegion
->rclBounds
.bottom
< OutputRect
.bottom
)
209 InputRect
.bottom
-= OutputRect
.bottom
- ClipRegion
->rclBounds
.bottom
;
210 OutputRect
.bottom
= ClipRegion
->rclBounds
.bottom
;
214 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
216 if (OutputRect
.right
<= OutputRect
.left
|| OutputRect
.bottom
<= OutputRect
.top
)
220 IntEngLeave(&EnterLeaveSource
);
225 if (! IntEngEnter(&EnterLeaveDest
, psoDest
, &OutputRect
, FALSE
, &Translate
, &psoOutput
))
229 IntEngLeave(&EnterLeaveSource
);
234 OutputRect
.left
+= Translate
.x
;
235 OutputRect
.right
+= Translate
.x
;
236 OutputRect
.top
+= Translate
.y
;
237 OutputRect
.bottom
+= Translate
.y
;
241 AdjustedBrushOrigin
.x
= BrushOrigin
->x
+ Translate
.x
;
242 AdjustedBrushOrigin
.y
= BrushOrigin
->y
+ Translate
.y
;
246 AdjustedBrushOrigin
= Translate
;
249 BltRectFunc
= CallDibStretchBlt
;
251 DstHeight
= OutputRect
.bottom
- OutputRect
.top
;
252 DstWidth
= OutputRect
.right
- OutputRect
.left
;
253 SrcHeight
= InputRect
.bottom
- InputRect
.top
;
254 SrcWidth
= InputRect
.right
- InputRect
.left
;
255 switch (clippingType
)
258 Ret
= (*BltRectFunc
)(psoOutput
, psoInput
, Mask
,
259 ColorTranslation
, &OutputRect
, &InputRect
, MaskOrigin
,
260 pbo
, &AdjustedBrushOrigin
, ROP4
);
263 // Clip the blt to the clip rectangle
264 ClipRect
.left
= ClipRegion
->rclBounds
.left
+ Translate
.x
;
265 ClipRect
.right
= ClipRegion
->rclBounds
.right
+ Translate
.x
;
266 ClipRect
.top
= ClipRegion
->rclBounds
.top
+ Translate
.y
;
267 ClipRect
.bottom
= ClipRegion
->rclBounds
.bottom
+ Translate
.y
;
268 if (RECTL_bIntersectRect(&CombinedRect
, &OutputRect
, &ClipRect
))
270 InputToCombinedRect
.top
= InputRect
.top
+ (CombinedRect
.top
- OutputRect
.top
) * SrcHeight
/ DstHeight
;
271 InputToCombinedRect
.bottom
= InputRect
.top
+ (CombinedRect
.bottom
- OutputRect
.top
) * SrcHeight
/ DstHeight
;
272 InputToCombinedRect
.left
= InputRect
.left
+ (CombinedRect
.left
- OutputRect
.left
) * SrcWidth
/ DstWidth
;
273 InputToCombinedRect
.right
= InputRect
.left
+ (CombinedRect
.right
- OutputRect
.left
) * SrcWidth
/ DstWidth
;
274 Ret
= (*BltRectFunc
)(psoOutput
, psoInput
, Mask
,
277 &InputToCombinedRect
,
280 &AdjustedBrushOrigin
,
285 if (psoOutput
== psoInput
)
287 if (OutputRect
.top
< InputRect
.top
)
289 Direction
= OutputRect
.left
< InputRect
.left
?
290 CD_RIGHTDOWN
: CD_LEFTDOWN
;
294 Direction
= OutputRect
.left
< InputRect
.left
?
295 CD_RIGHTUP
: CD_LEFTUP
;
302 CLIPOBJ_cEnumStart(ClipRegion
, FALSE
, CT_RECTANGLES
, Direction
, 0);
305 EnumMore
= CLIPOBJ_bEnum(ClipRegion
,(ULONG
) sizeof(RectEnum
),
307 for (i
= 0; i
< RectEnum
.c
; i
++)
309 ClipRect
.left
= RectEnum
.arcl
[i
].left
+ Translate
.x
;
310 ClipRect
.right
= RectEnum
.arcl
[i
].right
+ Translate
.x
;
311 ClipRect
.top
= RectEnum
.arcl
[i
].top
+ Translate
.y
;
312 ClipRect
.bottom
= RectEnum
.arcl
[i
].bottom
+ Translate
.y
;
313 if (RECTL_bIntersectRect(&CombinedRect
, &OutputRect
, &ClipRect
))
315 InputToCombinedRect
.top
= InputRect
.top
+ (CombinedRect
.top
- OutputRect
.top
) * SrcHeight
/ DstHeight
;
316 InputToCombinedRect
.bottom
= InputRect
.top
+ (CombinedRect
.bottom
- OutputRect
.top
) * SrcHeight
/ DstHeight
;
317 InputToCombinedRect
.left
= InputRect
.left
+ (CombinedRect
.left
- OutputRect
.left
) * SrcWidth
/ DstWidth
;
318 InputToCombinedRect
.right
= InputRect
.left
+ (CombinedRect
.right
- OutputRect
.left
) * SrcWidth
/ DstWidth
;
319 Ret
= (*BltRectFunc
)(psoOutput
, psoInput
, Mask
,
322 &InputToCombinedRect
,
325 &AdjustedBrushOrigin
,
334 IntEngLeave(&EnterLeaveDest
);
337 IntEngLeave(&EnterLeaveSource
);
350 IN SURFOBJ
*psoSource
,
352 IN CLIPOBJ
*ClipRegion
,
353 IN XLATEOBJ
*ColorTranslation
,
354 IN COLORADJUSTMENT
*pca
,
355 IN POINTL
*BrushOrigin
,
358 IN POINTL
*MaskOrigin
,
361 return EngStretchBltROP(
374 ROP3_TO_ROP4(SRCCOPY
));
378 IntEngStretchBlt(SURFOBJ
*psoDest
,
382 XLATEOBJ
*ColorTranslation
,
392 POINTL MaskOrigin
= {0, 0};
394 SURFACE
*psurfSource
= NULL
;
395 RECTL InputClippedRect
;
398 BOOL UsesSource
= ROP4_USES_SOURCE(ROP
);
399 LONG InputClWidth
, InputClHeight
, InputWidth
, InputHeight
;
402 psurfDest
= CONTAINING_RECORD(psoDest
, SURFACE
, SurfObj
);
406 InputClippedRect
= *DestRect
;
407 if (InputClippedRect
.right
< InputClippedRect
.left
)
409 InputClippedRect
.left
= DestRect
->right
;
410 InputClippedRect
.right
= DestRect
->left
;
412 if (InputClippedRect
.bottom
< InputClippedRect
.top
)
414 InputClippedRect
.top
= DestRect
->bottom
;
415 InputClippedRect
.bottom
= DestRect
->top
;
420 if (NULL
== SourceRect
|| NULL
== psoSource
)
424 InputRect
= *SourceRect
;
426 if (InputRect
.right
< InputRect
.left
||
427 InputRect
.bottom
< InputRect
.top
)
429 /* Everything clipped away, nothing to do */
436 if (!RECTL_bIntersectRect(&OutputRect
, &InputClippedRect
,
437 &ClipRegion
->rclBounds
))
441 /* Update source rect */
442 InputClWidth
= InputClippedRect
.right
- InputClippedRect
.left
;
443 InputClHeight
= InputClippedRect
.bottom
- InputClippedRect
.top
;
444 InputWidth
= InputRect
.right
- InputRect
.left
;
445 InputHeight
= InputRect
.bottom
- InputRect
.top
;
447 InputRect
.left
+= (InputWidth
* (OutputRect
.left
- InputClippedRect
.left
)) / InputClWidth
;
448 InputRect
.right
-= (InputWidth
* (InputClippedRect
.right
- OutputRect
.right
)) / InputClWidth
;
449 InputRect
.top
+= (InputHeight
* (OutputRect
.top
- InputClippedRect
.top
)) / InputClHeight
;
450 InputRect
.bottom
-= (InputHeight
* (InputClippedRect
.bottom
- OutputRect
.bottom
)) / InputClHeight
;
454 OutputRect
= InputClippedRect
;
457 if (pMaskOrigin
!= NULL
)
459 MaskOrigin
.x
= pMaskOrigin
->x
;
460 MaskOrigin
.y
= pMaskOrigin
->y
;
465 SURFACE_LockBitmapBits(psurfDest
);
466 MouseSafetyOnDrawStart(psoDest
, OutputRect
.left
, OutputRect
.top
,
467 OutputRect
.right
, OutputRect
.bottom
);
471 psurfSource
= CONTAINING_RECORD(psoSource
, SURFACE
, SurfObj
);
472 if (psoSource
!= psoDest
)
474 SURFACE_LockBitmapBits(psurfSource
);
476 MouseSafetyOnDrawStart(psoSource
, InputRect
.left
, InputRect
.top
,
477 InputRect
.right
, InputRect
.bottom
);
480 /* Prepare color adjustment */
482 /* Call the driver's DrvStretchBlt if available */
483 if (psurfDest
->flHooks
& HOOK_STRETCHBLTROP
)
485 /* Drv->StretchBltROP (look at http://www.osronline.com/ddkx/graphics/ddifncs_0z3b.htm ) */
486 ret
= GDIDEVFUNCS(psoDest
).StretchBltROP(psoDest
,
487 (UsesSource
) ? psoSource
: NULL
,
502 ret
= EngStretchBltROP(psoDest
,
503 (UsesSource
) ? psoSource
: NULL
,
519 MouseSafetyOnDrawEnd(psoSource
);
520 if (psoSource
!= psoDest
)
522 SURFACE_UnlockBitmapBits(psurfSource
);
525 MouseSafetyOnDrawEnd(psoDest
);
526 SURFACE_UnlockBitmapBits(psurfDest
);
535 IN SURFOBJ
*psoSource
,
537 IN CLIPOBJ
*ClipRegion
,
538 IN XLATEOBJ
*ColorTranslation
,
539 IN COLORADJUSTMENT
*pca
,
540 IN POINTL
*BrushOrigin
,
543 IN POINTL
*MaskOrigin
,
554 ProbeForRead(pca
, sizeof(COLORADJUSTMENT
), 1);
555 RtlCopyMemory(&ca
,pca
, sizeof(COLORADJUSTMENT
));
557 ProbeForRead(BrushOrigin
, sizeof(POINTL
), 1);
558 RtlCopyMemory(&lBrushOrigin
, BrushOrigin
, sizeof(POINTL
));
560 ProbeForRead(prclDest
, sizeof(RECTL
), 1);
561 RtlCopyMemory(&rclDest
, prclDest
, sizeof(RECTL
));
563 ProbeForRead(prclSrc
, sizeof(RECTL
), 1);
564 RtlCopyMemory(&rclSrc
, prclSrc
, sizeof(RECTL
));
566 ProbeForRead(MaskOrigin
, sizeof(POINTL
), 1);
567 RtlCopyMemory(&lMaskOrigin
, MaskOrigin
, sizeof(POINTL
));
570 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
572 _SEH2_YIELD(return FALSE
);
576 return EngStretchBlt(psoDest
, psoSource
, Mask
, ClipRegion
, ColorTranslation
, &ca
, &lBrushOrigin
, &rclDest
, &rclSrc
, &lMaskOrigin
, Mode
);