2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
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
;
41 XLATEOBJ
* XlatePatternToDest
= NULL
;
43 if (BrushOrigin
== NULL
)
45 RealBrushOrigin
.x
= RealBrushOrigin
.y
= 0;
49 RealBrushOrigin
= *BrushOrigin
;
53 if (ROP4_USES_PATTERN(Rop4
) && pbo
&& pbo
->iSolidColor
== 0xFFFFFFFF)
55 GdiBrush
= CONTAINING_RECORD(pbo
, EBRUSHOBJ
, BrushObject
);
56 psurfPattern
= SURFACE_LockSurface(GdiBrush
->pbrush
->hbmPattern
);
59 PatternSurface
= &psurfPattern
->SurfObj
;
63 /* FIXME - What to do here? */
65 XlatePatternToDest
= GdiBrush
->XlateObject
;
72 return DibFunctionsForBitmapFormat
[psoDest
->iBitmapFormat
].DIB_StretchBlt(
73 psoDest
, psoSource
, Mask
, PatternSurface
,
74 OutputRect
, InputRect
, MaskOrigin
, pbo
, &RealBrushOrigin
,
75 ColorTranslation
, XlatePatternToDest
, Rop4
);
80 SURFACE_UnlockSurface(psurfPattern
);
93 IN SURFOBJ
*psoSource
,
95 IN CLIPOBJ
*ClipRegion
,
96 IN XLATEOBJ
*ColorTranslation
,
97 IN COLORADJUSTMENT
*pca
,
98 IN POINTL
*BrushOrigin
,
101 IN POINTL
*MaskOrigin
,
109 INTENG_ENTER_LEAVE EnterLeaveSource
;
110 INTENG_ENTER_LEAVE EnterLeaveDest
;
113 PSTRETCHRECTFUNC BltRectFunc
;
115 POINTL AdjustedBrushOrigin
;
116 BOOL UsesSource
= ROP4_USES_SOURCE(ROP4
);
124 RECTL InputToCombinedRect
;
132 /* Determine clipping type */
133 if (ClipRegion
== (CLIPOBJ
*) NULL
)
135 clippingType
= DC_TRIVIAL
;
139 clippingType
= ClipRegion
->iDComplexity
;
144 /* Copy destination onto itself: nop */
148 OutputRect
= *prclDest
;
149 if (OutputRect
.right
< OutputRect
.left
)
151 OutputRect
.left
= prclDest
->right
;
152 OutputRect
.right
= prclDest
->left
;
154 if (OutputRect
.bottom
< OutputRect
.top
)
156 OutputRect
.top
= prclDest
->bottom
;
157 OutputRect
.bottom
= prclDest
->top
;
160 InputRect
= *prclSrc
;
168 if (! IntEngEnter(&EnterLeaveSource
, psoSource
, &InputRect
, TRUE
,
169 &Translate
, &psoInput
))
174 InputRect
.left
+= Translate
.x
;
175 InputRect
.right
+= Translate
.x
;
176 InputRect
.top
+= Translate
.y
;
177 InputRect
.bottom
+= Translate
.y
;
180 if (NULL
!= ClipRegion
)
182 if (OutputRect
.left
< ClipRegion
->rclBounds
.left
)
184 InputRect
.left
+= ClipRegion
->rclBounds
.left
- OutputRect
.left
;
185 OutputRect
.left
= ClipRegion
->rclBounds
.left
;
187 if (ClipRegion
->rclBounds
.right
< OutputRect
.right
)
189 InputRect
.right
-= OutputRect
.right
- ClipRegion
->rclBounds
.right
;
190 OutputRect
.right
= ClipRegion
->rclBounds
.right
;
192 if (OutputRect
.top
< ClipRegion
->rclBounds
.top
)
194 InputRect
.top
+= ClipRegion
->rclBounds
.top
- OutputRect
.top
;
195 OutputRect
.top
= ClipRegion
->rclBounds
.top
;
197 if (ClipRegion
->rclBounds
.bottom
< OutputRect
.bottom
)
199 InputRect
.bottom
-= OutputRect
.bottom
- ClipRegion
->rclBounds
.bottom
;
200 OutputRect
.bottom
= ClipRegion
->rclBounds
.bottom
;
204 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
206 if (OutputRect
.right
<= OutputRect
.left
|| OutputRect
.bottom
<= OutputRect
.top
)
210 IntEngLeave(&EnterLeaveSource
);
215 if (! IntEngEnter(&EnterLeaveDest
, psoDest
, &OutputRect
, FALSE
, &Translate
, &psoOutput
))
219 IntEngLeave(&EnterLeaveSource
);
224 OutputRect
.left
+= Translate
.x
;
225 OutputRect
.right
+= Translate
.x
;
226 OutputRect
.top
+= Translate
.y
;
227 OutputRect
.bottom
+= Translate
.y
;
231 AdjustedBrushOrigin
.x
= BrushOrigin
->x
+ Translate
.x
;
232 AdjustedBrushOrigin
.y
= BrushOrigin
->y
+ Translate
.y
;
236 AdjustedBrushOrigin
= Translate
;
239 BltRectFunc
= CallDibStretchBlt
;
241 DstHeight
= OutputRect
.bottom
- OutputRect
.top
;
242 DstWidth
= OutputRect
.right
- OutputRect
.left
;
243 SrcHeight
= InputRect
.bottom
- InputRect
.top
;
244 SrcWidth
= InputRect
.right
- InputRect
.left
;
245 switch (clippingType
)
248 Ret
= (*BltRectFunc
)(psoOutput
, psoInput
, Mask
,
249 ColorTranslation
, &OutputRect
, &InputRect
, MaskOrigin
,
250 pbo
, &AdjustedBrushOrigin
, ROP4
);
253 // Clip the blt to the clip rectangle
254 ClipRect
.left
= ClipRegion
->rclBounds
.left
+ Translate
.x
;
255 ClipRect
.right
= ClipRegion
->rclBounds
.right
+ Translate
.x
;
256 ClipRect
.top
= ClipRegion
->rclBounds
.top
+ Translate
.y
;
257 ClipRect
.bottom
= ClipRegion
->rclBounds
.bottom
+ Translate
.y
;
258 if (RECTL_bIntersectRect(&CombinedRect
, &OutputRect
, &ClipRect
))
260 InputToCombinedRect
.top
= InputRect
.top
+ (CombinedRect
.top
- OutputRect
.top
) * SrcHeight
/ DstHeight
;
261 InputToCombinedRect
.bottom
= InputRect
.top
+ (CombinedRect
.bottom
- OutputRect
.top
) * SrcHeight
/ DstHeight
;
262 InputToCombinedRect
.left
= InputRect
.left
+ (CombinedRect
.left
- OutputRect
.left
) * SrcWidth
/ DstWidth
;
263 InputToCombinedRect
.right
= InputRect
.left
+ (CombinedRect
.right
- OutputRect
.left
) * SrcWidth
/ DstWidth
;
264 Ret
= (*BltRectFunc
)(psoOutput
, psoInput
, Mask
,
267 &InputToCombinedRect
,
270 &AdjustedBrushOrigin
,
275 if (psoOutput
== psoInput
)
277 if (OutputRect
.top
< InputRect
.top
)
279 Direction
= OutputRect
.left
< InputRect
.left
?
280 CD_RIGHTDOWN
: CD_LEFTDOWN
;
284 Direction
= OutputRect
.left
< InputRect
.left
?
285 CD_RIGHTUP
: CD_LEFTUP
;
292 CLIPOBJ_cEnumStart(ClipRegion
, FALSE
, CT_RECTANGLES
, Direction
, 0);
295 EnumMore
= CLIPOBJ_bEnum(ClipRegion
,(ULONG
) sizeof(RectEnum
),
297 for (i
= 0; i
< RectEnum
.c
; i
++)
299 ClipRect
.left
= RectEnum
.arcl
[i
].left
+ Translate
.x
;
300 ClipRect
.right
= RectEnum
.arcl
[i
].right
+ Translate
.x
;
301 ClipRect
.top
= RectEnum
.arcl
[i
].top
+ Translate
.y
;
302 ClipRect
.bottom
= RectEnum
.arcl
[i
].bottom
+ Translate
.y
;
303 if (RECTL_bIntersectRect(&CombinedRect
, &OutputRect
, &ClipRect
))
305 InputToCombinedRect
.top
= InputRect
.top
+ (CombinedRect
.top
- OutputRect
.top
) * SrcHeight
/ DstHeight
;
306 InputToCombinedRect
.bottom
= InputRect
.top
+ (CombinedRect
.bottom
- OutputRect
.top
) * SrcHeight
/ DstHeight
;
307 InputToCombinedRect
.left
= InputRect
.left
+ (CombinedRect
.left
- OutputRect
.left
) * SrcWidth
/ DstWidth
;
308 InputToCombinedRect
.right
= InputRect
.left
+ (CombinedRect
.right
- OutputRect
.left
) * SrcWidth
/ DstWidth
;
309 Ret
= (*BltRectFunc
)(psoOutput
, psoInput
, Mask
,
312 &InputToCombinedRect
,
315 &AdjustedBrushOrigin
,
324 IntEngLeave(&EnterLeaveDest
);
327 IntEngLeave(&EnterLeaveSource
);
340 IN SURFOBJ
*psoSource
,
342 IN CLIPOBJ
*ClipRegion
,
343 IN XLATEOBJ
*ColorTranslation
,
344 IN COLORADJUSTMENT
*pca
,
345 IN POINTL
*BrushOrigin
,
348 IN POINTL
*MaskOrigin
,
351 return EngStretchBltROP(
364 ROP3_TO_ROP4(SRCCOPY
));
368 IntEngStretchBlt(SURFOBJ
*psoDest
,
372 XLATEOBJ
*ColorTranslation
,
384 SURFACE
*psurfSource
= NULL
;
385 RECTL InputClippedRect
;
388 BOOL UsesSource
= ROP4_USES_SOURCE(ROP
);
389 LONG InputClWidth
, InputClHeight
, InputWidth
, InputHeight
;
392 psurfDest
= CONTAINING_RECORD(psoDest
, SURFACE
, SurfObj
);
396 InputClippedRect
= *DestRect
;
397 if (InputClippedRect
.right
< InputClippedRect
.left
)
399 InputClippedRect
.left
= DestRect
->right
;
400 InputClippedRect
.right
= DestRect
->left
;
402 if (InputClippedRect
.bottom
< InputClippedRect
.top
)
404 InputClippedRect
.top
= DestRect
->bottom
;
405 InputClippedRect
.bottom
= DestRect
->top
;
410 if (NULL
== SourceRect
|| NULL
== psoSource
)
414 InputRect
= *SourceRect
;
416 if (InputRect
.right
< InputRect
.left
||
417 InputRect
.bottom
< InputRect
.top
)
419 /* Everything clipped away, nothing to do */
426 if (!RECTL_bIntersectRect(&OutputRect
, &InputClippedRect
,
427 &ClipRegion
->rclBounds
))
431 /* Update source rect */
432 InputClWidth
= InputClippedRect
.right
- InputClippedRect
.left
;
433 InputClHeight
= InputClippedRect
.bottom
- InputClippedRect
.top
;
434 InputWidth
= InputRect
.right
- InputRect
.left
;
435 InputHeight
= InputRect
.bottom
- InputRect
.top
;
437 InputRect
.left
+= (InputWidth
* (OutputRect
.left
- InputClippedRect
.left
)) / InputClWidth
;
438 InputRect
.right
-= (InputWidth
* (InputClippedRect
.right
- OutputRect
.right
)) / InputClWidth
;
439 InputRect
.top
+= (InputHeight
* (OutputRect
.top
- InputClippedRect
.top
)) / InputClHeight
;
440 InputRect
.bottom
-= (InputHeight
* (InputClippedRect
.bottom
- OutputRect
.bottom
)) / InputClHeight
;
444 OutputRect
= InputClippedRect
;
447 if (pMaskOrigin
!= NULL
)
449 MaskOrigin
.x
= pMaskOrigin
->x
; MaskOrigin
.y
= pMaskOrigin
->y
;
454 SURFACE_LockBitmapBits(psurfDest
);
455 MouseSafetyOnDrawStart(psoDest
, OutputRect
.left
, OutputRect
.top
,
456 OutputRect
.right
, OutputRect
.bottom
);
460 psurfSource
= CONTAINING_RECORD(psoSource
, SURFACE
, SurfObj
);
461 if (psoSource
!= psoDest
)
463 SURFACE_LockBitmapBits(psurfSource
);
465 MouseSafetyOnDrawStart(psoSource
, InputRect
.left
, InputRect
.top
,
466 InputRect
.right
, InputRect
.bottom
);
469 /* Prepare color adjustment */
471 /* Call the driver's DrvStretchBlt if available */
472 if (psurfDest
->flHooks
& HOOK_STRETCHBLTROP
)
474 /* Drv->StretchBltROP (look at http://www.osronline.com/ddkx/graphics/ddifncs_0z3b.htm ) */
475 // FIXME: MaskOrigin is always NULL !
476 ret
= GDIDEVFUNCS(psoDest
).StretchBltROP(psoDest
, (UsesSource
) ? psoSource
: NULL
, MaskSurf
, ClipRegion
, ColorTranslation
,
477 &ca
, BrushOrigin
, &OutputRect
, &InputRect
, NULL
, COLORONCOLOR
, pbo
, ROP
);
482 // FIXME: see previous fixme
483 ret
= EngStretchBltROP(psoDest
, (UsesSource
) ? psoSource
: NULL
, MaskSurf
, ClipRegion
, ColorTranslation
,
484 &ca
, BrushOrigin
, &OutputRect
, &InputRect
, NULL
, COLORONCOLOR
, pbo
, ROP
);
489 MouseSafetyOnDrawEnd(psoSource
);
490 if (psoSource
!= psoDest
)
492 SURFACE_UnlockBitmapBits(psurfSource
);
495 MouseSafetyOnDrawEnd(psoDest
);
496 SURFACE_UnlockBitmapBits(psurfDest
);
505 IN SURFOBJ
*psoSource
,
507 IN CLIPOBJ
*ClipRegion
,
508 IN XLATEOBJ
*ColorTranslation
,
509 IN COLORADJUSTMENT
*pca
,
510 IN POINTL
*BrushOrigin
,
513 IN POINTL
*MaskOrigin
,
524 ProbeForRead(pca
, sizeof(COLORADJUSTMENT
), 1);
525 RtlCopyMemory(&ca
,pca
, sizeof(COLORADJUSTMENT
));
527 ProbeForRead(BrushOrigin
, sizeof(POINTL
), 1);
528 RtlCopyMemory(&lBrushOrigin
, BrushOrigin
, sizeof(POINTL
));
530 ProbeForRead(prclDest
, sizeof(RECTL
), 1);
531 RtlCopyMemory(&rclDest
, prclDest
, sizeof(RECTL
));
533 ProbeForRead(prclSrc
, sizeof(RECTL
), 1);
534 RtlCopyMemory(&rclSrc
, prclSrc
, sizeof(RECTL
));
536 ProbeForRead(MaskOrigin
, sizeof(POINTL
), 1);
537 RtlCopyMemory(&lMaskOrigin
, MaskOrigin
, sizeof(POINTL
));
540 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
542 _SEH2_YIELD(return FALSE
);
546 return EngStretchBlt(psoDest
, psoSource
, Mask
, ClipRegion
, ColorTranslation
, &ca
, &lBrushOrigin
, &rclDest
, &rclSrc
, &lMaskOrigin
, Mode
);