xref: /reactos/win32ss/gdi/eng/stretchblt.c (revision 003b19dc)
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  * PROGRAMERS:       Jason Filby
7  *                   Doug Lyons
8  */
9 
10 #include <win32k.h>
11 
12 #define NDEBUG
13 #include <debug.h>
14 
15 /***************************************************************************************************************************
16   We want to receive and send the flip state along to existing functions without changing their parameter lists.
17   So a way that we can do this is to use the DestRect to carry this information along with it.
18   Since there are four values, we can use their relative positions (coordinates) to indicate the four flip conditions.
19   if delta-x == 0 then there can be no Left-to-Right flip. If delta-y == 0 there can be no Top-to-Bottom flip.
20   So we can set the four flip conditions based on BOOLEAN flags as follows:
21 
22   We will use internal bits bTopToBottom and bLeftToRight as follows:
23 
24   !bTopToBottom && !bLeftToRight means no flips      therefore left < right and top < bottom (normal well-formed rectangle)
25   bTopToBottom means there is a Top-To-Bottom flip   therefore left < right and top > bottom
26   bLeftToRight means there is a Left-To-Right flip   therefore left > right and top < bottom
27   bLeftToRight && bTopToBottom means both flips      therefore left > right and top > bottom
28 ****************************************************************************************************************************/
29 
30 typedef BOOLEAN (APIENTRY *PSTRETCHRECTFUNC)(SURFOBJ* OutputObj,
31                                             SURFOBJ* InputObj,
32                                             SURFOBJ* Mask,
33                                             XLATEOBJ* ColorTranslation,
34                                             RECTL* OutputRect,
35                                             RECTL* InputRect,
36                                             POINTL* MaskOrigin,
37                                             BRUSHOBJ* pbo,
38                                             POINTL* BrushOrigin,
39                                             ROP4 Rop4);
40 
41 static BOOLEAN APIENTRY
42 CallDibStretchBlt(SURFOBJ* psoDest,
43                   SURFOBJ* psoSource,
44                   SURFOBJ* Mask,
45                   XLATEOBJ* ColorTranslation,
46                   RECTL* OutputRect,
47                   RECTL* InputRect,
48                   POINTL* MaskOrigin,
49                   BRUSHOBJ* pbo,
50                   POINTL* BrushOrigin,
51                   ROP4 Rop4)
52 {
53     POINTL RealBrushOrigin;
54     SURFOBJ* psoPattern;
55     BOOL bResult;
56 
57     DPRINT("Entering CallDibStretchBlt: psoSource cx/cy (%d/%d), psoDest cx/cy (%d/%d) OutputRect: (%d,%d)-(%d,%d)\n",
58            psoSource->sizlBitmap.cx, psoSource->sizlBitmap.cy,
59            psoDest->sizlBitmap.cx, psoDest->sizlBitmap.cy,
60            OutputRect->left, OutputRect->top, OutputRect->right, OutputRect->bottom);
61 
62     if (BrushOrigin == NULL)
63     {
64         RealBrushOrigin.x = RealBrushOrigin.y = 0;
65     }
66     else
67     {
68         RealBrushOrigin = *BrushOrigin;
69     }
70 
71     /* Pattern brush */
72     if (ROP4_USES_PATTERN(Rop4) && pbo && pbo->iSolidColor == 0xFFFFFFFF)
73     {
74         psoPattern = BRUSHOBJ_psoPattern(pbo);
75 
76         if (!psoPattern) return FALSE;
77     }
78     else
79     {
80         psoPattern = NULL;
81     }
82 
83     bResult = DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_StretchBlt(
84                psoDest, psoSource, Mask, psoPattern,
85                OutputRect, InputRect, MaskOrigin, pbo, &RealBrushOrigin,
86                ColorTranslation, Rop4);
87 
88     return bResult;
89 }
90 
91 
92 
93 /*
94  * @implemented
95  */
96 BOOL
97 APIENTRY
98 EngStretchBltROP(
99     IN SURFOBJ  *psoDest,
100     IN SURFOBJ  *psoSource,
101     IN SURFOBJ  *Mask,
102     IN CLIPOBJ  *ClipRegion,
103     IN XLATEOBJ  *ColorTranslation,
104     IN COLORADJUSTMENT  *pca,
105     IN POINTL  *BrushOrigin,
106     IN RECTL  *prclDest,
107     IN RECTL  *prclSrc,
108     IN POINTL  *MaskOrigin,
109     IN ULONG  Mode,
110     IN BRUSHOBJ *pbo,
111     IN ROP4 Rop4)
112 {
113     RECTL              InputRect;
114     RECTL              OutputRect;
115     POINTL             Translate;
116     INTENG_ENTER_LEAVE EnterLeaveSource;
117     INTENG_ENTER_LEAVE EnterLeaveDest;
118     SURFOBJ*           psoInput;
119     SURFOBJ*           psoOutput;
120     PSTRETCHRECTFUNC   BltRectFunc;
121     BOOLEAN            Ret = TRUE;
122     POINTL             AdjustedBrushOrigin;
123     BOOL               UsesSource = ROP4_USES_SOURCE(Rop4);
124 
125     BYTE               clippingType;
126     RECTL              ClipRect;
127     RECT_ENUM          RectEnum;
128     BOOL               EnumMore;
129     ULONG              Direction;
130     RECTL              CombinedRect;
131     RECTL              InputToCombinedRect;
132     unsigned           i;
133 
134     LONG DstHeight;
135     LONG DstWidth;
136     LONG SrcHeight;
137     LONG SrcWidth;
138 
139     LONG cxSrc, cySrc, cxDest, cyDest;
140     BOOLEAN bLeftToRight, bTopToBottom;
141     LONG lTmp;
142 
143     DPRINT("Entering EngStretchBltROP: prclSrc: (%d/%d)-(%d/%d) prclDest: (%d,%d)-(%d,%d)\n",
144            prclSrc->left, prclSrc->top, prclSrc->right, prclSrc->bottom,
145            prclDest->left, prclDest->top, prclDest->right, prclDest->bottom);
146 
147     cxSrc = prclSrc->right - prclSrc->left;
148     cySrc = prclSrc->bottom - prclSrc->top;
149     cxDest = prclDest->right - prclDest->left;
150     cyDest = prclDest->bottom - prclDest->top;
151 
152     /* Here we do the tests and set our conditions */
153     if (((cxSrc < 0) && (cxDest < 0)) || ((cxSrc >= 0) && (cxDest >= 0)))
154         bLeftToRight = FALSE;
155     else
156         bLeftToRight = TRUE;
157 
158     if (((cySrc < 0) && (cyDest < 0)) || ((cySrc >= 0) && (cyDest >= 0)))
159         bTopToBottom = FALSE;
160     else
161         bTopToBottom = TRUE;
162 
163     /* Make Well Ordered to start */
164     OutputRect = *prclDest;
165     RECTL_vMakeWellOrdered(&OutputRect);
166     *prclDest = OutputRect;
167 
168     if (Rop4 == ROP4_NOOP)
169     {
170         /* Copy destination onto itself: nop */
171         return TRUE;
172     }
173 
174 
175     /* Determine clipping type */
176     if (ClipRegion == (CLIPOBJ *) NULL)
177     {
178         clippingType = DC_TRIVIAL;
179     }
180     else
181     {
182         clippingType = ClipRegion->iDComplexity;
183     }
184 
185     OutputRect = *prclDest;
186     if (OutputRect.right < OutputRect.left)
187     {
188         OutputRect.left = prclDest->right;
189         OutputRect.right = prclDest->left;
190     }
191     if (OutputRect.bottom < OutputRect.top)
192     {
193         OutputRect.top = prclDest->bottom;
194         OutputRect.bottom = prclDest->top;
195     }
196 
197     if (UsesSource)
198     {
199         if (NULL == prclSrc)
200         {
201             return FALSE;
202         }
203         InputRect = *prclSrc;
204 
205         if (! IntEngEnter(&EnterLeaveSource, psoSource, &InputRect, TRUE,
206                           &Translate, &psoInput))
207         {
208             return FALSE;
209         }
210 
211         InputRect.left += Translate.x;
212         InputRect.right += Translate.x;
213         InputRect.top += Translate.y;
214         InputRect.bottom += Translate.y;
215     }
216     else
217     {
218         InputRect.left = 0;
219         InputRect.right = OutputRect.right - OutputRect.left;
220         InputRect.top = 0;
221         InputRect.bottom = OutputRect.bottom - OutputRect.top;
222         psoInput = NULL;
223     }
224 
225     if (NULL != ClipRegion)
226     {
227         if (OutputRect.left < ClipRegion->rclBounds.left)
228         {
229             InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
230             OutputRect.left = ClipRegion->rclBounds.left;
231         }
232         if (ClipRegion->rclBounds.right < OutputRect.right)
233         {
234             InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
235             OutputRect.right = ClipRegion->rclBounds.right;
236         }
237         if (OutputRect.top < ClipRegion->rclBounds.top)
238         {
239             InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
240             OutputRect.top = ClipRegion->rclBounds.top;
241         }
242         if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
243         {
244             InputRect.bottom -=  OutputRect.bottom - ClipRegion->rclBounds.bottom;
245             OutputRect.bottom = ClipRegion->rclBounds.bottom;
246         }
247     }
248 
249     /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
250        nothing to do */
251     if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
252     {
253         if (UsesSource)
254         {
255             IntEngLeave(&EnterLeaveSource);
256         }
257         return TRUE;
258     }
259 
260     if (! IntEngEnter(&EnterLeaveDest, psoDest, &OutputRect, FALSE, &Translate, &psoOutput))
261     {
262         if (UsesSource)
263         {
264             IntEngLeave(&EnterLeaveSource);
265         }
266         return FALSE;
267     }
268 
269     OutputRect.left += Translate.x;
270     OutputRect.right += Translate.x;
271     OutputRect.top += Translate.y;
272     OutputRect.bottom += Translate.y;
273 
274     if (BrushOrigin)
275     {
276         AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
277         AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
278     }
279     else
280     {
281         AdjustedBrushOrigin = Translate;
282     }
283 
284     BltRectFunc = CallDibStretchBlt;
285 
286     DstHeight = OutputRect.bottom - OutputRect.top;
287     DstWidth = OutputRect.right - OutputRect.left;
288     SrcHeight = InputRect.bottom - InputRect.top;
289     SrcWidth = InputRect.right - InputRect.left;
290 
291     DPRINT("bLeftToRight is '%d' and bTopToBottom is '%d'.\n", bLeftToRight, bTopToBottom);
292 
293     switch (clippingType)
294     {
295         case DC_TRIVIAL:
296             if (bLeftToRight)
297             {
298                lTmp = OutputRect.left;
299                 OutputRect.left = OutputRect.right;
300                 OutputRect.right = lTmp;
301             }
302 
303             if (bTopToBottom)
304             {
305                 lTmp = OutputRect.top;
306                 OutputRect.top = OutputRect.bottom;
307                 OutputRect.bottom = lTmp;
308             }
309 
310             DPRINT("About to call CallDibStretchBlt: OutputRect: (%d,%d)-(%d,%d)\n",
311                    OutputRect.left, OutputRect.top, OutputRect.right, OutputRect.bottom);
312 
313             Ret = (*BltRectFunc)(psoOutput, psoInput, Mask,
314                          ColorTranslation, &OutputRect, &InputRect, MaskOrigin,
315                          pbo, &AdjustedBrushOrigin, Rop4);
316             break;
317         case DC_RECT:
318             // Clip the blt to the clip rectangle
319             ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
320             ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
321             ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
322             ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
323             if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
324             {
325                 InputToCombinedRect.top = InputRect.top + (CombinedRect.top - OutputRect.top) * SrcHeight / DstHeight;
326                 InputToCombinedRect.bottom = InputRect.top + (CombinedRect.bottom - OutputRect.top) * SrcHeight / DstHeight;
327                 InputToCombinedRect.left = InputRect.left + (CombinedRect.left - OutputRect.left) * SrcWidth / DstWidth;
328                 InputToCombinedRect.right = InputRect.left + (CombinedRect.right - OutputRect.left) * SrcWidth / DstWidth;
329 
330                 if (bLeftToRight)
331                 {
332                    lTmp = CombinedRect.left;
333                     CombinedRect.left = CombinedRect.right;
334                     CombinedRect.right = lTmp;
335                 }
336 
337                 if (bTopToBottom)
338                 {
339                     lTmp = CombinedRect.top;
340                     CombinedRect.top = CombinedRect.bottom;
341                     CombinedRect.bottom = lTmp;
342                 }
343 
344                 DPRINT("About to call CallDibStretchBlt: CombinedRect: (%d,%d)-(%d,%d)\n",
345                        CombinedRect.left, CombinedRect.top, CombinedRect.right, CombinedRect.bottom);
346 
347                 Ret = (*BltRectFunc)(psoOutput, psoInput, Mask,
348                            ColorTranslation,
349                            &CombinedRect,
350                            &InputToCombinedRect,
351                            MaskOrigin,
352                            pbo,
353                            &AdjustedBrushOrigin,
354                            Rop4);
355             }
356             break;
357         case DC_COMPLEX:
358             if (psoOutput == psoInput)
359             {
360                 if (OutputRect.top < InputRect.top)
361                 {
362                     Direction = OutputRect.left < InputRect.left ?
363                                 CD_RIGHTDOWN : CD_LEFTDOWN;
364                 }
365                 else
366                 {
367                     Direction = OutputRect.left < InputRect.left ?
368                                 CD_RIGHTUP : CD_LEFTUP;
369                 }
370             }
371             else
372             {
373                 Direction = CD_ANY;
374             }
375             CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
376             do
377             {
378                 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum),
379                                          (PVOID) &RectEnum);
380                 for (i = 0; i < RectEnum.c; i++)
381                 {
382                     ClipRect.left = RectEnum.arcl[i].left + Translate.x;
383                     ClipRect.right = RectEnum.arcl[i].right + Translate.x;
384                     ClipRect.top = RectEnum.arcl[i].top + Translate.y;
385                     ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
386                     if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
387                     {
388                         InputToCombinedRect.top = InputRect.top + (CombinedRect.top - OutputRect.top) * SrcHeight / DstHeight;
389                         InputToCombinedRect.bottom = InputRect.top + (CombinedRect.bottom - OutputRect.top) * SrcHeight / DstHeight;
390                         InputToCombinedRect.left = InputRect.left + (CombinedRect.left - OutputRect.left) * SrcWidth / DstWidth;
391                         InputToCombinedRect.right = InputRect.left + (CombinedRect.right - OutputRect.left) * SrcWidth / DstWidth;
392 
393                         if (bLeftToRight)
394                         {
395                             lTmp = CombinedRect.left;
396                             CombinedRect.left = CombinedRect.right;
397                             CombinedRect.right = lTmp;
398                         }
399 
400                         if (bTopToBottom)
401                         {
402                             lTmp = CombinedRect.top;
403                             CombinedRect.top = CombinedRect.bottom;
404                             CombinedRect.bottom = lTmp;
405                         }
406 
407                         DPRINT("About to call CallDibStretchBlt: CombinedRect: (%d,%d)-(%d,%d)\n",
408                                CombinedRect.left, CombinedRect.top, CombinedRect.right, CombinedRect.bottom);
409 
410                         Ret = (*BltRectFunc)(psoOutput, psoInput, Mask,
411                            ColorTranslation,
412                            &CombinedRect,
413                            &InputToCombinedRect,
414                            MaskOrigin,
415                            pbo,
416                            &AdjustedBrushOrigin,
417                            Rop4);
418                     }
419                 }
420             }
421             while (EnumMore);
422             break;
423     }
424 
425     IntEngLeave(&EnterLeaveDest);
426     if (UsesSource)
427     {
428         IntEngLeave(&EnterLeaveSource);
429     }
430 
431     return Ret;
432 }
433 
434 /*
435  * @implemented
436  */
437 BOOL
438 APIENTRY
439 EngStretchBlt(
440     IN SURFOBJ  *psoDest,
441     IN SURFOBJ  *psoSource,
442     IN SURFOBJ  *Mask,
443     IN CLIPOBJ  *ClipRegion,
444     IN XLATEOBJ  *ColorTranslation,
445     IN COLORADJUSTMENT  *pca,
446     IN POINTL  *BrushOrigin,
447     IN RECTL  *prclDest,
448     IN RECTL  *prclSrc,
449     IN POINTL  *MaskOrigin,
450     IN ULONG  Mode)
451 {
452     return EngStretchBltROP(
453         psoDest,
454         psoSource,
455         Mask,
456         ClipRegion,
457         ColorTranslation,
458         pca,
459         BrushOrigin,
460         prclDest,
461         prclSrc,
462         MaskOrigin,
463         Mode,
464         NULL,
465         ROP4_FROM_INDEX(R3_OPINDEX_SRCCOPY));
466 }
467 
468 BOOL APIENTRY
469 IntEngStretchBlt(SURFOBJ *psoDest,
470                  SURFOBJ *psoSource,
471                  SURFOBJ *MaskSurf,
472                  CLIPOBJ *ClipRegion,
473                  XLATEOBJ *ColorTranslation,
474                  COLORADJUSTMENT *pca,
475                  RECTL *DestRect,
476                  RECTL *SourceRect,
477                  POINTL *pMaskOrigin,
478                  BRUSHOBJ *pbo,
479                  POINTL *BrushOrigin,
480                  DWORD Rop4)
481 {
482     BOOLEAN ret;
483     POINTL MaskOrigin = {0, 0};
484     SURFACE *psurfDest;
485     //SURFACE *psurfSource = NULL;
486     RECTL InputClippedRect;
487     RECTL InputRect;
488     RECTL OutputRect;
489     BOOL UsesSource = ROP4_USES_SOURCE(Rop4);
490     LONG InputClWidth, InputClHeight, InputWidth, InputHeight;
491     LONG lTmp, cxSrc, cySrc, cxDest, cyDest;
492     BOOLEAN bTopToBottom, bLeftToRight;
493     INT Case0000, Case0001, Case0010, Case0011;
494     INT Case0100, Case0101, Case0110, Case0111;
495     INT Case1000, Case1001, Case1010, Case1011;
496     INT Case1100, Case1101, Case1110;
497 
498     DPRINT("Source cx/cy (%d/%d) and Destination cx/cy (%d/%d).\n",
499             psoSource->sizlBitmap.cx, psoSource->sizlBitmap.cy, psoDest->sizlBitmap.cx, psoDest->sizlBitmap.cy);
500 
501     DPRINT("Source lDelta is '%d' and Destination lDelta is '%d'.\n",
502             psoSource->lDelta, psoDest->lDelta);
503 
504     ASSERT(psoDest);
505     //ASSERT(psoSource); // FIXME!
506     ASSERT(DestRect);
507     ASSERT(SourceRect);
508     //ASSERT(!RECTL_bIsEmptyRect(SourceRect)); // FIXME!
509 
510     /* If no clip object is given, use trivial one */
511     if (!ClipRegion)
512     {
513         DPRINT("Using trivial clip region.\n");
514         ClipRegion = (CLIPOBJ *)&gxcoTrivial;
515     }
516     else
517     {
518         DPRINT("ClipRegion->rclBounds is (%d,%d)-(%d,%d).\n",
519            ClipRegion->rclBounds.left, ClipRegion->rclBounds.top,
520            ClipRegion->rclBounds.right, ClipRegion->rclBounds.bottom);
521     }
522 
523     psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
524 
525     /* Sanity check */
526     ASSERT(IS_VALID_ROP4(Rop4));
527 
528     cxSrc = SourceRect->right - SourceRect->left;
529     cySrc = SourceRect->bottom - SourceRect->top;
530     cxDest = DestRect->right - DestRect->left;
531     cyDest = DestRect->bottom - DestRect->top;
532 
533     Case1110 = ((cxDest > 0) && (cyDest > 0) && (cxSrc > 0) && (cySrc < 0));
534     Case1101 = ((cxDest > 0) && (cyDest > 0) && (cxSrc < 0) && (cySrc > 0));
535     Case1100 = ((cxDest > 0) && (cyDest > 0) && (cxSrc < 0) && (cySrc < 0));
536     Case1011 = ((cxDest > 0) && (cyDest < 0) && (cxSrc > 0) && (cySrc > 0));
537     Case1010 = ((cxDest > 0) && (cyDest < 0) && (cxSrc > 0) && (cySrc < 0));
538     Case1001 = ((cxDest > 0) && (cyDest < 0) && (cxSrc < 0) && (cySrc > 0));
539     Case1000 = ((cxDest > 0) && (cyDest < 0) && (cxSrc < 0) && (cySrc < 0));
540     Case0111 = ((cxDest < 0) && (cyDest > 0) && (cxSrc > 0) && (cySrc > 0));
541     Case0110 = ((cxDest < 0) && (cyDest > 0) && (cxSrc > 0) && (cySrc < 0));
542     Case0101 = ((cxDest < 0) && (cyDest > 0) && (cxSrc < 0) && (cySrc > 0));
543     Case0100 = ((cxDest < 0) && (cyDest > 0) && (cxSrc < 0) && (cySrc < 0));
544     Case0011 = ((cxDest < 0) && (cyDest < 0) && (cxSrc > 0) && (cySrc > 0));
545     Case0010 = ((cxDest < 0) && (cyDest < 0) && (cxSrc > 0) && (cySrc < 0));
546     Case0001 = ((cxDest < 0) && (cyDest < 0) && (cxSrc < 0) && (cySrc > 0));
547     Case0000 = ((cxDest < 0) && (cyDest < 0) && (cxSrc < 0) && (cySrc < 0));
548 
549     /* Make DestRect & OutputRect Well Ordered to start */
550     RECTL_vMakeWellOrdered(DestRect);
551     OutputRect = *DestRect;
552 
553     /* Here we do the tests and set our conditions */
554     if (((cxSrc < 0) && (cxDest < 0)) || ((cxSrc >= 0) && (cxDest >= 0)))
555         bLeftToRight = FALSE;
556     else
557         bLeftToRight = TRUE;
558 
559     if (((cySrc < 0) && (cyDest < 0)) || ((cySrc >= 0) && (cyDest >= 0)))
560         bTopToBottom = FALSE;
561     else
562         bTopToBottom = TRUE;
563 
564     DPRINT("bTopToBottom is '%d' and bLeftToRight is '%d'.\n", bTopToBottom, bLeftToRight);
565 
566     /* Check if source and dest size are equal */
567     if ((abs(DestRect->right - DestRect->left) == abs(SourceRect->right - SourceRect->left)) &&
568         (abs(DestRect->bottom - DestRect->top) == abs(SourceRect->bottom - SourceRect->top)))
569     {
570         DPRINT("source and dest size are equal.\n");
571 
572         DPRINT("IntEngStretchBlt: dstRect: (%d,%d)-(%d,%d)\n",
573                 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
574 
575         if (Case0000 || Case0001 || Case0010 || Case0011) // Destinations X & Y are both negative
576         {
577             lTmp = SourceRect->left;
578             SourceRect->left = SourceRect->right;
579             SourceRect->right = lTmp;
580 
581             lTmp = SourceRect->top;
582             SourceRect->top = SourceRect->bottom;
583             SourceRect->bottom = lTmp;
584         }
585 
586         if (Case0100 || Case0101 || Case0110 || Case0111)  // Destination X is negative and Y is positive
587         {
588             lTmp = SourceRect->left;
589             SourceRect->left = SourceRect->right;
590             SourceRect->right = lTmp;
591         }
592 
593         if (Case1000 || Case1001 || Case1010 || Case1011)  // Destination X is positive and Y is negative
594         {
595             lTmp = SourceRect->top;
596             SourceRect->top = SourceRect->bottom;
597             SourceRect->bottom = lTmp;
598         }
599 
600         if (bLeftToRight)
601         {
602             lTmp = DestRect->left;
603             DestRect->left = DestRect->right;
604             DestRect->right = lTmp;
605         }
606 
607         if (bTopToBottom)
608         {
609             lTmp = DestRect->top;
610             DestRect->top = DestRect->bottom;
611             DestRect->bottom = lTmp;
612         }
613 
614         DPRINT("Calling IntEngBitBlt: SourceRect (%d,%d)-(%d,%d) DestRect: (%d,%d)-(%d,%d)\n",
615            SourceRect->left, SourceRect->top, SourceRect->right, SourceRect->bottom,
616            DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
617 
618         /* Pass the request to IntEngBitBlt */
619         return IntEngBitBlt(psoDest,
620                             psoSource,
621                             MaskSurf,
622                             ClipRegion,
623                             ColorTranslation,
624                             DestRect,
625                             (PPOINTL)SourceRect,
626                             pMaskOrigin,
627                             pbo,
628                             BrushOrigin,
629                             Rop4);
630     }
631 
632     DPRINT("source and dest size are NOT equal.\n");
633 
634     DPRINT("SourceRect: (%d,%d)-(%d,%d) and DestRect: (%d,%d)-(%d,%d)\n",
635            SourceRect->left, SourceRect->top, SourceRect->right, SourceRect->bottom,
636            DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
637 
638     /* if cxSrc < 0 then we change the signs for both cxSrc and cxDest and
639      * we reverse their coordinates, because these outcomes are the same.
640      */
641     if (cxSrc < 0)
642     {
643         lTmp = SourceRect->left;
644         SourceRect->left = SourceRect->right;
645         SourceRect->right = lTmp;
646         lTmp = DestRect->left;
647         DestRect->left = DestRect->right;
648         DestRect->right = lTmp;
649         cxSrc = -cxSrc;
650         cxDest = -cxDest;
651     }
652     /* if cySrc < 0 then we change the signs for both cySrc and cyDest and
653      * we reverse their coordinates, because these outcomes are the same.
654       */
655     if (cySrc < 0)
656     {
657         lTmp = DestRect->top;
658         DestRect->top = DestRect->bottom;
659         DestRect->bottom = lTmp;
660         lTmp = SourceRect->top;
661         SourceRect->top = SourceRect->bottom;
662         SourceRect->bottom = lTmp;
663         cySrc = -cySrc;
664         cyDest = -cyDest;
665     }
666 
667     if (Case0010 || Case0111)  // Horizontal Flips
668     {
669         DestRect->left--;
670     }
671 
672     if (Case0010 || Case0111 || Case1000 || Case1101)  // Horizontal Flips
673     {
674         SourceRect->left--;
675         SourceRect->right--;
676     }
677 
678     if (Case0001 || Case0100 || Case1011 || Case1110)  // Vertical Flips
679     {
680         SourceRect->top--;
681         SourceRect->bottom--;
682     }
683 
684     if (Case0011 || Case0110 || Case1001 || Case1100)  // Horizontal and Vertical Flips
685     {
686         SourceRect->left--;
687         SourceRect->right--;
688 
689         SourceRect->top--;
690         SourceRect->bottom--;
691     }
692 
693     if (Case0000 || Case1010)  // No Flip - Just Copy
694     {
695         SourceRect->top++;
696         SourceRect->bottom++;
697 
698         DestRect->top++;
699         DestRect->bottom++;
700     }
701 
702     if (Case0000 || Case0101)  // No Flip - Just Copy
703     {
704         SourceRect->left++;
705         SourceRect->right++;
706 
707         DestRect->left++;
708         DestRect->right++;
709 
710     }
711 
712     DPRINT("SourceRect: (%d,%d)-(%d,%d) and DestRect: (%d,%d)-(%d,%d)\n",
713                 SourceRect->left, SourceRect->top, SourceRect->right, SourceRect->bottom,
714                 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
715 
716     InputClippedRect = *DestRect;
717     if (InputClippedRect.right < InputClippedRect.left)
718     {
719         InputClippedRect.left = DestRect->right;
720         InputClippedRect.right = DestRect->left;
721     }
722     if (InputClippedRect.bottom < InputClippedRect.top)
723     {
724         InputClippedRect.top = DestRect->bottom;
725         InputClippedRect.bottom = DestRect->top;
726     }
727 
728     if (NULL == psoSource)
729     {
730         DPRINT("Returning FALSE.\n");
731         return FALSE;
732     }
733     InputRect = *SourceRect;
734 
735     if (InputRect.right < InputRect.left ||
736             InputRect.bottom < InputRect.top)
737     {
738         DPRINT("Returning TRUE.\n");
739         /* Everything clipped away, nothing to do */
740         return TRUE;
741     }
742 
743     DPRINT("InputRect: (%d,%d)-(%d,%d) and InputClippedRect: (%d,%d)-(%d,%d)\n",
744         InputRect.left, InputRect.top, InputRect.right, InputRect.bottom,
745         InputClippedRect.left, InputClippedRect.top, InputClippedRect.right, InputClippedRect.bottom);
746 
747     if (ClipRegion->iDComplexity != DC_TRIVIAL)
748     {
749         if (!RECTL_bIntersectRect(&OutputRect, &InputClippedRect,
750                                &ClipRegion->rclBounds))
751         {
752             DPRINT("Returning TRUE.\n");
753             return TRUE;
754         }
755 
756         DPRINT("InputClippedRect: (%d,%d)-(%d,%d) and OutputRect: (%d,%d)-(%d,%d)\n",
757                InputClippedRect.left, InputClippedRect.top, InputClippedRect.right, InputClippedRect.bottom,
758                OutputRect.left, OutputRect.top, OutputRect.right, OutputRect.bottom);
759 
760         /* Update source rect */
761         InputClWidth = InputClippedRect.right - InputClippedRect.left;
762         InputClHeight = InputClippedRect.bottom - InputClippedRect.top;
763         InputWidth = InputRect.right - InputRect.left;
764         InputHeight = InputRect.bottom - InputRect.top;
765 
766         InputRect.left += (InputWidth * (OutputRect.left - InputClippedRect.left)) / InputClWidth;
767         InputRect.right -= (InputWidth * (InputClippedRect.right - OutputRect.right)) / InputClWidth;
768         InputRect.top += (InputHeight * (OutputRect.top - InputClippedRect.top)) / InputClHeight;
769         InputRect.bottom -= (InputHeight * (InputClippedRect.bottom - OutputRect.bottom)) / InputClHeight;
770     }
771     else
772     {
773         DPRINT("Complexity = DC_TRIVIAL.\n");
774         OutputRect = InputClippedRect;
775     }
776 
777 
778     DPRINT("InputRect: (%d,%d)-(%d,%d) and OutputRect: (%d,%d)-(%d,%d)\n",
779            InputRect.left, InputRect.top, InputRect.right, InputRect.bottom,
780            OutputRect.left, OutputRect.top, OutputRect.right, OutputRect.bottom);
781 
782     if (pMaskOrigin != NULL)
783     {
784         MaskOrigin.x = pMaskOrigin->x;
785         MaskOrigin.y = pMaskOrigin->y;
786     }
787 
788     /* No success yet */
789     ret = FALSE;
790 
791     if (UsesSource)
792     {
793         //psurfSource = CONTAINING_RECORD(psoSource, SURFACE, SurfObj);
794     }
795 
796     /* Call the driver's DrvStretchBlt if available */
797     if (psurfDest->flags & HOOK_STRETCHBLTROP)
798     {
799         DPRINT("About to call GDIDEVFUNCS(psoDest).StretchBltROP.\n");
800         /* Drv->StretchBltROP (look at http://www.osronline.com/ddkx/graphics/ddifncs_0z3b.htm ) */
801         ret = GDIDEVFUNCS(psoDest).StretchBltROP(psoDest,
802                                                  psoSource,
803                                                  MaskSurf,
804                                                  ClipRegion,
805                                                  ColorTranslation,
806                                                  pca,
807                                                  BrushOrigin,
808                                                  &OutputRect,
809                                                  &InputRect,
810                                                  &MaskOrigin,
811                                                  COLORONCOLOR,
812                                                  pbo,
813                                                  Rop4);
814     }
815 
816     if (! ret)
817     {
818         /* set OutputRect to follow flip */
819         if (bLeftToRight)
820         {
821             lTmp = OutputRect.left;
822             OutputRect.left = OutputRect.right;
823             OutputRect.right = lTmp;
824         }
825 
826         if (bTopToBottom)
827         {
828             lTmp = OutputRect.top;
829             OutputRect.top = OutputRect.bottom;
830             OutputRect.bottom = lTmp;
831         }
832 
833         DPRINT("Calling EngStretchBltROP: InputRect: (%d,%d)-(%d,%d) and OutputRect: (%d,%d)-(%d,%d)\n",
834                InputRect.left, InputRect.top, InputRect.right, InputRect.bottom,
835                OutputRect.left, OutputRect.top, OutputRect.right, OutputRect.bottom);
836 
837         ret = EngStretchBltROP(psoDest,
838                                psoSource,
839                                MaskSurf,
840                                ClipRegion,
841                                ColorTranslation,
842                                pca,
843                                BrushOrigin,
844                                &OutputRect,
845                                &InputRect,
846                                &MaskOrigin,
847                                COLORONCOLOR,
848                                pbo,
849                                Rop4);
850     }
851 
852     return ret;
853 }
854 
855 BOOL
856 APIENTRY
857 NtGdiEngStretchBlt(
858     IN SURFOBJ  *psoDest,
859     IN SURFOBJ  *psoSource,
860     IN SURFOBJ  *Mask,
861     IN CLIPOBJ  *ClipRegion,
862     IN XLATEOBJ  *ColorTranslation,
863     IN COLORADJUSTMENT  *pca,
864     IN POINTL  *BrushOrigin,
865     IN RECTL  *prclDest,
866     IN RECTL  *prclSrc,
867     IN POINTL  *MaskOrigin,
868     IN ULONG  Mode)
869 {
870     COLORADJUSTMENT  ca;
871     POINTL  lBrushOrigin;
872     RECTL rclDest;
873     RECTL rclSrc;
874     POINTL lMaskOrigin;
875 
876     _SEH2_TRY
877     {
878         if (pca)
879         {
880             ProbeForRead(pca, sizeof(COLORADJUSTMENT), 1);
881             RtlCopyMemory(&ca,pca, sizeof(COLORADJUSTMENT));
882             pca = &ca;
883         }
884 
885         ProbeForRead(BrushOrigin, sizeof(POINTL), 1);
886         RtlCopyMemory(&lBrushOrigin, BrushOrigin, sizeof(POINTL));
887 
888         ProbeForRead(prclDest, sizeof(RECTL), 1);
889         RtlCopyMemory(&rclDest, prclDest, sizeof(RECTL));
890 
891         ProbeForRead(prclSrc, sizeof(RECTL), 1);
892         RtlCopyMemory(&rclSrc, prclSrc, sizeof(RECTL));
893 
894         ProbeForRead(MaskOrigin, sizeof(POINTL), 1);
895         RtlCopyMemory(&lMaskOrigin, MaskOrigin, sizeof(POINTL));
896 
897     }
898     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
899     {
900         _SEH2_YIELD(return FALSE);
901     }
902     _SEH2_END;
903 
904     return EngStretchBlt(psoDest, psoSource, Mask, ClipRegion, ColorTranslation, pca, &lBrushOrigin, &rclDest, &rclSrc, &lMaskOrigin, Mode);
905 }
906 
907 /* EOF */
908