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