[SHELL-EXPERIMENTS]
[reactos.git] / win32ss / gdi / eng / stretchblt.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: GDI stretch blt functions
5 * FILE: subsystems/win32/win32k/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); // FIXME!
390 //ASSERT(!RECTL_bIsEmptyRect(SourceRect)); // FIXME!
391
392 /* If no clip object is given, use trivial one */
393 if (!ClipRegion) ClipRegion = &gxcoTrivial.ClipObj;
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 == SourceRect || 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 */