merge 37282 from amd64-branch:
[reactos.git] / reactos / subsystems / win32 / win32k / eng / stretchblt.c
1 /*
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
7 */
8
9 #include <w32k.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 SURFACE* psurfPattern;
39 PEBRUSHOBJ GdiBrush = NULL;
40 SURFOBJ* PatternSurface = NULL;
41 XLATEOBJ* XlatePatternToDest = NULL;
42
43 if (BrushOrigin == NULL)
44 {
45 RealBrushOrigin.x = RealBrushOrigin.y = 0;
46 }
47 else
48 {
49 RealBrushOrigin = *BrushOrigin;
50 }
51
52 /* Pattern brush */
53 if (ROP4_USES_PATTERN(Rop4) && pbo && pbo->iSolidColor == 0xFFFFFFFF)
54 {
55 GdiBrush = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
56 psurfPattern = SURFACE_LockSurface(GdiBrush->pbrush->hbmPattern);
57 if (psurfPattern)
58 {
59 PatternSurface = &psurfPattern->SurfObj;
60 }
61 else
62 {
63 /* FIXME - What to do here? */
64 }
65 XlatePatternToDest = GdiBrush->XlateObject;
66 }
67 else
68 {
69 psurfPattern = NULL;
70 }
71
72 return DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_StretchBlt(
73 psoDest, psoSource, Mask, PatternSurface,
74 OutputRect, InputRect, MaskOrigin, pbo, &RealBrushOrigin,
75 ColorTranslation, XlatePatternToDest, Rop4);
76
77 /* Pattern brush */
78 if (psurfPattern)
79 {
80 SURFACE_UnlockSurface(psurfPattern);
81 }
82 }
83
84
85
86 /*
87 * @implemented
88 */
89 BOOL
90 APIENTRY
91 EngStretchBltROP(
92 IN SURFOBJ *psoDest,
93 IN SURFOBJ *psoSource,
94 IN SURFOBJ *Mask,
95 IN CLIPOBJ *ClipRegion,
96 IN XLATEOBJ *ColorTranslation,
97 IN COLORADJUSTMENT *pca,
98 IN POINTL *BrushOrigin,
99 IN RECTL *prclDest,
100 IN RECTL *prclSrc,
101 IN POINTL *MaskOrigin,
102 IN ULONG Mode,
103 IN BRUSHOBJ *pbo,
104 IN DWORD ROP4)
105 {
106 RECTL InputRect;
107 RECTL OutputRect;
108 POINTL Translate;
109 INTENG_ENTER_LEAVE EnterLeaveSource;
110 INTENG_ENTER_LEAVE EnterLeaveDest;
111 SURFOBJ* psoInput;
112 SURFOBJ* psoOutput;
113 PSTRETCHRECTFUNC BltRectFunc;
114 BOOLEAN Ret = TRUE;
115 POINTL AdjustedBrushOrigin;
116 BOOL UsesSource = ROP4_USES_SOURCE(ROP4);
117
118 BYTE clippingType;
119 RECTL ClipRect;
120 RECT_ENUM RectEnum;
121 BOOL EnumMore;
122 ULONG Direction;
123 RECTL CombinedRect;
124 RECTL InputToCombinedRect;
125 unsigned i;
126
127 LONG DstHeight;
128 LONG DstWidth;
129 LONG SrcHeight;
130 LONG SrcWidth;
131
132 /* Determine clipping type */
133 if (ClipRegion == (CLIPOBJ *) NULL)
134 {
135 clippingType = DC_TRIVIAL;
136 }
137 else
138 {
139 clippingType = ClipRegion->iDComplexity;
140 }
141
142 if (ROP4 == R4_NOOP)
143 {
144 /* Copy destination onto itself: nop */
145 return TRUE;
146 }
147
148 OutputRect = *prclDest;
149 if (OutputRect.right < OutputRect.left)
150 {
151 OutputRect.left = prclDest->right;
152 OutputRect.right = prclDest->left;
153 }
154 if (OutputRect.bottom < OutputRect.top)
155 {
156 OutputRect.top = prclDest->bottom;
157 OutputRect.bottom = prclDest->top;
158 }
159
160 InputRect = *prclSrc;
161 if (UsesSource)
162 {
163 if (NULL == prclSrc)
164 {
165 return FALSE;
166 }
167
168 if (! IntEngEnter(&EnterLeaveSource, psoSource, &InputRect, TRUE,
169 &Translate, &psoInput))
170 {
171 return FALSE;
172 }
173
174 InputRect.left += Translate.x;
175 InputRect.right += Translate.x;
176 InputRect.top += Translate.y;
177 InputRect.bottom += Translate.y;
178 }
179
180 if (NULL != ClipRegion)
181 {
182 if (OutputRect.left < ClipRegion->rclBounds.left)
183 {
184 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
185 OutputRect.left = ClipRegion->rclBounds.left;
186 }
187 if (ClipRegion->rclBounds.right < OutputRect.right)
188 {
189 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
190 OutputRect.right = ClipRegion->rclBounds.right;
191 }
192 if (OutputRect.top < ClipRegion->rclBounds.top)
193 {
194 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
195 OutputRect.top = ClipRegion->rclBounds.top;
196 }
197 if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
198 {
199 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
200 OutputRect.bottom = ClipRegion->rclBounds.bottom;
201 }
202 }
203
204 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
205 nothing to do */
206 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
207 {
208 if (UsesSource)
209 {
210 IntEngLeave(&EnterLeaveSource);
211 }
212 return TRUE;
213 }
214
215 if (! IntEngEnter(&EnterLeaveDest, psoDest, &OutputRect, FALSE, &Translate, &psoOutput))
216 {
217 if (UsesSource)
218 {
219 IntEngLeave(&EnterLeaveSource);
220 }
221 return FALSE;
222 }
223
224 OutputRect.left += Translate.x;
225 OutputRect.right += Translate.x;
226 OutputRect.top += Translate.y;
227 OutputRect.bottom += Translate.y;
228
229 if (BrushOrigin)
230 {
231 AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
232 AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
233 }
234 else
235 {
236 AdjustedBrushOrigin = Translate;
237 }
238
239 BltRectFunc = CallDibStretchBlt;
240
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)
246 {
247 case DC_TRIVIAL:
248 Ret = (*BltRectFunc)(psoOutput, psoInput, Mask,
249 ColorTranslation, &OutputRect, &InputRect, MaskOrigin,
250 pbo, &AdjustedBrushOrigin, ROP4);
251 break;
252 case DC_RECT:
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))
259 {
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,
265 ColorTranslation,
266 &CombinedRect,
267 &InputToCombinedRect,
268 MaskOrigin,
269 pbo,
270 &AdjustedBrushOrigin,
271 ROP4);
272 }
273 break;
274 case DC_COMPLEX:
275 if (psoOutput == psoInput)
276 {
277 if (OutputRect.top < InputRect.top)
278 {
279 Direction = OutputRect.left < InputRect.left ?
280 CD_RIGHTDOWN : CD_LEFTDOWN;
281 }
282 else
283 {
284 Direction = OutputRect.left < InputRect.left ?
285 CD_RIGHTUP : CD_LEFTUP;
286 }
287 }
288 else
289 {
290 Direction = CD_ANY;
291 }
292 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
293 do
294 {
295 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum),
296 (PVOID) &RectEnum);
297 for (i = 0; i < RectEnum.c; i++)
298 {
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))
304 {
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,
310 ColorTranslation,
311 &CombinedRect,
312 &InputToCombinedRect,
313 MaskOrigin,
314 pbo,
315 &AdjustedBrushOrigin,
316 ROP4);
317 }
318 }
319 }
320 while (EnumMore);
321 break;
322 }
323
324 IntEngLeave(&EnterLeaveDest);
325 if (UsesSource)
326 {
327 IntEngLeave(&EnterLeaveSource);
328 }
329
330 return Ret;
331 }
332
333 /*
334 * @implemented
335 */
336 BOOL
337 APIENTRY
338 EngStretchBlt(
339 IN SURFOBJ *psoDest,
340 IN SURFOBJ *psoSource,
341 IN SURFOBJ *Mask,
342 IN CLIPOBJ *ClipRegion,
343 IN XLATEOBJ *ColorTranslation,
344 IN COLORADJUSTMENT *pca,
345 IN POINTL *BrushOrigin,
346 IN RECTL *prclDest,
347 IN RECTL *prclSrc,
348 IN POINTL *MaskOrigin,
349 IN ULONG Mode)
350 {
351 return EngStretchBltROP(
352 psoDest,
353 psoSource,
354 Mask,
355 ClipRegion,
356 ColorTranslation,
357 pca,
358 BrushOrigin,
359 prclDest,
360 prclSrc,
361 MaskOrigin,
362 Mode,
363 NULL,
364 ROP3_TO_ROP4(SRCCOPY));
365 }
366
367 BOOL APIENTRY
368 IntEngStretchBlt(SURFOBJ *psoDest,
369 SURFOBJ *psoSource,
370 SURFOBJ *MaskSurf,
371 CLIPOBJ *ClipRegion,
372 XLATEOBJ *ColorTranslation,
373 RECTL *DestRect,
374 RECTL *SourceRect,
375 POINTL *pMaskOrigin,
376 BRUSHOBJ *pbo,
377 POINTL *BrushOrigin,
378 ROP4 ROP)
379 {
380 BOOLEAN ret;
381 COLORADJUSTMENT ca;
382 POINT MaskOrigin;
383 SURFACE *psurfDest;
384 SURFACE *psurfSource = NULL;
385 RECTL InputClippedRect;
386 RECTL InputRect;
387 RECTL OutputRect;
388 BOOL UsesSource = ROP4_USES_SOURCE(ROP);
389 LONG InputClWidth, InputClHeight, InputWidth, InputHeight;
390
391 ASSERT(psoDest);
392 psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
393 ASSERT(psurfDest);
394 ASSERT(DestRect);
395
396 InputClippedRect = *DestRect;
397 if (InputClippedRect.right < InputClippedRect.left)
398 {
399 InputClippedRect.left = DestRect->right;
400 InputClippedRect.right = DestRect->left;
401 }
402 if (InputClippedRect.bottom < InputClippedRect.top)
403 {
404 InputClippedRect.top = DestRect->bottom;
405 InputClippedRect.bottom = DestRect->top;
406 }
407
408 if (UsesSource)
409 {
410 if (NULL == SourceRect || NULL == psoSource)
411 {
412 return FALSE;
413 }
414 InputRect = *SourceRect;
415
416 if (InputRect.right < InputRect.left ||
417 InputRect.bottom < InputRect.top)
418 {
419 /* Everything clipped away, nothing to do */
420 return TRUE;
421 }
422 }
423
424 if (ClipRegion)
425 {
426 if (!RECTL_bIntersectRect(&OutputRect, &InputClippedRect,
427 &ClipRegion->rclBounds))
428 {
429 return TRUE;
430 }
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;
436
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;
441 }
442 else
443 {
444 OutputRect = InputClippedRect;
445 }
446
447 if (pMaskOrigin != NULL)
448 {
449 MaskOrigin.x = pMaskOrigin->x; MaskOrigin.y = pMaskOrigin->y;
450 }
451
452 /* No success yet */
453 ret = FALSE;
454 SURFACE_LockBitmapBits(psurfDest);
455 MouseSafetyOnDrawStart(psoDest, OutputRect.left, OutputRect.top,
456 OutputRect.right, OutputRect.bottom);
457
458 if (UsesSource)
459 {
460 psurfSource = CONTAINING_RECORD(psoSource, SURFACE, SurfObj);
461 if (psoSource != psoDest)
462 {
463 SURFACE_LockBitmapBits(psurfSource);
464 }
465 MouseSafetyOnDrawStart(psoSource, InputRect.left, InputRect.top,
466 InputRect.right, InputRect.bottom);
467 }
468
469 /* Prepare color adjustment */
470
471 /* Call the driver's DrvStretchBlt if available */
472 if (psurfDest->flHooks & HOOK_STRETCHBLTROP)
473 {
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);
478 }
479
480 if (! ret)
481 {
482 // FIXME: see previous fixme
483 ret = EngStretchBltROP(psoDest, (UsesSource) ? psoSource : NULL, MaskSurf, ClipRegion, ColorTranslation,
484 &ca, BrushOrigin, &OutputRect, &InputRect, NULL, COLORONCOLOR, pbo, ROP);
485 }
486
487 if (UsesSource)
488 {
489 MouseSafetyOnDrawEnd(psoSource);
490 if (psoSource != psoDest)
491 {
492 SURFACE_UnlockBitmapBits(psurfSource);
493 }
494 }
495 MouseSafetyOnDrawEnd(psoDest);
496 SURFACE_UnlockBitmapBits(psurfDest);
497
498 return ret;
499 }
500
501 BOOL
502 APIENTRY
503 NtGdiEngStretchBlt(
504 IN SURFOBJ *psoDest,
505 IN SURFOBJ *psoSource,
506 IN SURFOBJ *Mask,
507 IN CLIPOBJ *ClipRegion,
508 IN XLATEOBJ *ColorTranslation,
509 IN COLORADJUSTMENT *pca,
510 IN POINTL *BrushOrigin,
511 IN RECTL *prclDest,
512 IN RECTL *prclSrc,
513 IN POINTL *MaskOrigin,
514 IN ULONG Mode)
515 {
516 COLORADJUSTMENT ca;
517 POINTL lBrushOrigin;
518 RECTL rclDest;
519 RECTL rclSrc;
520 POINTL lMaskOrigin;
521
522 _SEH2_TRY
523 {
524 ProbeForRead(pca, sizeof(COLORADJUSTMENT), 1);
525 RtlCopyMemory(&ca,pca, sizeof(COLORADJUSTMENT));
526
527 ProbeForRead(BrushOrigin, sizeof(POINTL), 1);
528 RtlCopyMemory(&lBrushOrigin, BrushOrigin, sizeof(POINTL));
529
530 ProbeForRead(prclDest, sizeof(RECTL), 1);
531 RtlCopyMemory(&rclDest, prclDest, sizeof(RECTL));
532
533 ProbeForRead(prclSrc, sizeof(RECTL), 1);
534 RtlCopyMemory(&rclSrc, prclSrc, sizeof(RECTL));
535
536 ProbeForRead(MaskOrigin, sizeof(POINTL), 1);
537 RtlCopyMemory(&lMaskOrigin, MaskOrigin, sizeof(POINTL));
538
539 }
540 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
541 {
542 _SEH2_YIELD(return FALSE);
543 }
544 _SEH2_END;
545
546 return EngStretchBlt(psoDest, psoSource, Mask, ClipRegion, ColorTranslation, &ca, &lBrushOrigin, &rclDest, &rclSrc, &lMaskOrigin, Mode);
547 }
548