xref: /reactos/win32ss/gdi/dib/stretchblt.c (revision cdf90707)
1 /*
2  * PROJECT:         ReactOS Win32k subsystem
3  * LICENSE:         See COPYING in the top level directory
4  * FILE:            win32ss/gdi/dib/stretchblt.c
5  * PURPOSE:         StretchBlt implementation suitable for all bit depths
6  * PROGRAMMERS:     Magnus Olsen
7  *                  Evgeniy Boltik
8  *                  Gregor Schneider
9  *                  Doug Lyons
10  */
11 
12 #include <win32k.h>
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 BOOLEAN DIB_XXBPP_StretchBlt(SURFOBJ *DestSurf, SURFOBJ *SourceSurf, SURFOBJ *MaskSurf,
18                             SURFOBJ *PatternSurface,
19                             RECTL *DestRect, RECTL *SourceRect,
20                             POINTL *MaskOrigin, BRUSHOBJ *Brush,
21                             POINTL *BrushOrigin, XLATEOBJ *ColorTranslation,
22                             ROP4 ROP)
23 {
24   LONG sx = 0;
25   LONG sy = 0;
26   LONG DesX;
27   LONG DesY;
28 
29   LONG DstHeight;
30   LONG DstWidth;
31   LONG SrcHeight;
32   LONG SrcWidth;
33   LONG MaskCy;
34   LONG SourceCy;
35 
36   ULONG Color;
37   ULONG Dest, Source = 0, Pattern = 0;
38   ULONG xxBPPMask;
39   BOOLEAN CanDraw;
40 
41   PFN_DIB_GetPixel fnSource_GetPixel = NULL;
42   PFN_DIB_GetPixel fnDest_GetPixel = NULL;
43   PFN_DIB_PutPixel fnDest_PutPixel = NULL;
44   PFN_DIB_GetPixel fnPattern_GetPixel = NULL;
45   PFN_DIB_GetPixel fnMask_GetPixel = NULL;
46 
47   LONG PatternX = 0, PatternY = 0;
48 
49   BOOL UsesSource = ROP4_USES_SOURCE(ROP);
50   BOOL UsesPattern = ROP4_USES_PATTERN(ROP);
51   BOOLEAN bTopToBottom, bLeftToRight;
52 
53   ASSERT(IS_VALID_ROP4(ROP));
54 
55   fnDest_GetPixel = DibFunctionsForBitmapFormat[DestSurf->iBitmapFormat].DIB_GetPixel;
56   fnDest_PutPixel = DibFunctionsForBitmapFormat[DestSurf->iBitmapFormat].DIB_PutPixel;
57 
58   DPRINT("Dest BPP: %u, DestRect: (%d,%d)-(%d,%d)\n",
59     BitsPerFormat(DestSurf->iBitmapFormat), DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
60 
61   DstHeight = DestRect->bottom - DestRect->top;
62   DstWidth = DestRect->right - DestRect->left;
63   SrcHeight = SourceRect->bottom - SourceRect->top;
64   SrcWidth = SourceRect->right - SourceRect->left;
65 
66   /* Here we do the tests and set our conditions */
67   if (((SrcWidth < 0) && (DstWidth < 0)) || ((SrcWidth >= 0) && (DstWidth >= 0)))
68     bLeftToRight = FALSE;
69   else
70     bLeftToRight = TRUE;
71 
72   if (((SrcHeight < 0) && (DstHeight < 0)) || ((SrcHeight >= 0) && (DstHeight >= 0)))
73     bTopToBottom = FALSE;
74   else
75     bTopToBottom = TRUE;
76 
77   /* Make Well Ordered to start */
78   RECTL_vMakeWellOrdered(DestRect);
79 
80   if (UsesSource)
81   {
82     SourceCy = SourceSurf->sizlBitmap.cy;
83     fnSource_GetPixel = DibFunctionsForBitmapFormat[SourceSurf->iBitmapFormat].DIB_GetPixel;
84     DPRINT("Source BPP: %u, SourceRect: (%d,%d)-(%d,%d)\n",
85       BitsPerFormat(SourceSurf->iBitmapFormat), SourceRect->left, SourceRect->top, SourceRect->right, SourceRect->bottom);
86   }
87 
88   if (MaskSurf)
89   {
90     DPRINT("MaskSurf is not NULL.\n");
91     fnMask_GetPixel = DibFunctionsForBitmapFormat[MaskSurf->iBitmapFormat].DIB_GetPixel;
92     MaskCy = MaskSurf->sizlBitmap.cy;
93   }
94 
95   DstHeight = DestRect->bottom - DestRect->top;
96   DstWidth = DestRect->right - DestRect->left;
97   SrcHeight = SourceRect->bottom - SourceRect->top;
98   SrcWidth = SourceRect->right - SourceRect->left;
99 
100   /* FIXME: MaskOrigin? */
101 
102   switch(DestSurf->iBitmapFormat)
103   {
104   case BMF_1BPP: xxBPPMask = 0x1; break;
105   case BMF_4BPP: xxBPPMask = 0xF; break;
106   case BMF_8BPP: xxBPPMask = 0xFF; break;
107   case BMF_16BPP: xxBPPMask = 0xFFFF; break;
108   case BMF_24BPP: xxBPPMask = 0xFFFFFF; break;
109   default:
110     xxBPPMask = 0xFFFFFFFF;
111   }
112   DPRINT("xxBPPMask is 0x%x.\n", xxBPPMask);
113 
114   if (UsesPattern)
115   {
116     DPRINT("UsesPattern is not NULL.\n");
117     if (PatternSurface)
118     {
119       PatternY = (DestRect->top - BrushOrigin->y) % PatternSurface->sizlBitmap.cy;
120       if (PatternY < 0)
121       {
122         PatternY += PatternSurface->sizlBitmap.cy;
123       }
124       fnPattern_GetPixel = DibFunctionsForBitmapFormat[PatternSurface->iBitmapFormat].DIB_GetPixel;
125     }
126     else
127     {
128       if (Brush)
129         Pattern = Brush->iSolidColor;
130     }
131   }
132 
133   if (PatternSurface)
134   {
135     DPRINT("PatternSurface is not NULL.\n");
136   }
137 
138   DPRINT("bLeftToRight is '%d' and bTopToBottom is '%d'.\n", bLeftToRight, bTopToBottom);
139 
140   for (DesY = DestRect->top; DesY < DestRect->bottom; DesY++)
141   {
142     if (PatternSurface)
143     {
144       PatternX = (DestRect->left - BrushOrigin->x) % PatternSurface->sizlBitmap.cx;
145       if (PatternX < 0)
146       {
147         PatternX += PatternSurface->sizlBitmap.cx;
148       }
149     }
150     if (UsesSource)
151     {
152       if (bTopToBottom)
153       {
154         sy = SourceRect->bottom-(DesY - DestRect->top) * SrcHeight / DstHeight;  // flips about the x-axis
155       }
156       else
157       {
158         sy = SourceRect->top+(DesY - DestRect->top) * SrcHeight / DstHeight;
159       }
160     }
161 
162     for (DesX = DestRect->left; DesX < DestRect->right; DesX++)
163     {
164       CanDraw = TRUE;
165 
166       if (fnMask_GetPixel)
167       {
168         if (bLeftToRight)
169         {
170           sx = SourceRect->right - (DesX - DestRect->left) * SrcWidth / DstWidth;  // flips about the y-axis
171         }
172         else
173         {
174           sx = SourceRect->left+(DesX - DestRect->left) * SrcWidth / DstWidth;
175         }
176         if (sx < 0 || sy < 0 ||
177           MaskSurf->sizlBitmap.cx < sx || MaskCy < sy ||
178           fnMask_GetPixel(MaskSurf, sx, sy) != 0)
179         {
180           CanDraw = FALSE;
181         }
182       }
183 
184       if (UsesSource && CanDraw)
185       {
186         if (bLeftToRight)
187         {
188           sx = SourceRect->right-(DesX - DestRect->left) * SrcWidth / DstWidth;  // flips about the y-axis
189         }
190         else
191         {
192           sx = SourceRect->left + (DesX - DestRect->left) * SrcWidth / DstWidth;
193         }
194         if (sx >= 0 && sy >= 0 &&
195           SourceSurf->sizlBitmap.cx > sx && SourceCy > sy)
196         {
197           Source = XLATEOBJ_iXlate(ColorTranslation, fnSource_GetPixel(SourceSurf, sx, sy));
198         }
199         else
200         {
201           Source = 0;
202           CanDraw = ((ROP & 0xFF) != R3_OPINDEX_SRCCOPY);
203         }
204       }
205 
206       if (CanDraw)
207       {
208         if (UsesPattern && PatternSurface)
209         {
210           Pattern = fnPattern_GetPixel(PatternSurface, PatternX, PatternY);
211           PatternX++;
212           PatternX %= PatternSurface->sizlBitmap.cx;
213         }
214 
215         Dest = fnDest_GetPixel(DestSurf, DesX, DesY);
216         Color = DIB_DoRop(ROP, Dest, Source, Pattern) & xxBPPMask;
217 
218         fnDest_PutPixel(DestSurf, DesX, DesY, Color);
219       }
220     }
221 
222     if (PatternSurface)
223     {
224       PatternY++;
225       PatternY %= PatternSurface->sizlBitmap.cy;
226     }
227   }
228 
229   return TRUE;
230 }
231 
232 /* EOF */
233