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