Support for VMware video drivers
[reactos.git] / reactos / subsys / win32k / eng / bitblt.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: GDI BitBlt Functions
5 * FILE: subsys/win32k/eng/bitblt.c
6 * PROGRAMER: Jason Filby
7 * REVISION HISTORY:
8 * 2/10/1999: Created
9 */
10
11 #include <ddk/winddi.h>
12 #include <ddk/ntddk.h>
13 #include <ntos/minmax.h>
14 #include "brush.h"
15 #include "clip.h"
16 #include "objects.h"
17 #include "../dib/dib.h"
18 #include <include/mouse.h>
19 #include <include/object.h>
20 #include <include/dib.h>
21 #include <include/surface.h>
22 #include <include/copybits.h>
23
24 #define NDEBUG
25 #include <win32k/debug1.h>
26
27 BOOL EngIntersectRect(PRECTL prcDst, PRECTL prcSrc1, PRECTL prcSrc2)
28 {
29 static const RECTL rclEmpty = { 0, 0, 0, 0 };
30
31 prcDst->left = max(prcSrc1->left, prcSrc2->left);
32 prcDst->right = min(prcSrc1->right, prcSrc2->right);
33
34 if (prcDst->left < prcDst->right)
35 {
36 prcDst->top = max(prcSrc1->top, prcSrc2->top);
37 prcDst->bottom = min(prcSrc1->bottom, prcSrc2->bottom);
38
39 if (prcDst->top < prcDst->bottom) return(TRUE);
40 }
41
42 *prcDst = rclEmpty;
43
44 return(FALSE);
45 }
46
47 static BOOL STDCALL
48 BltMask(SURFOBJ *Dest, PSURFGDI DestGDI, SURFOBJ *Mask,
49 RECTL *DestRect, POINTL *MaskPoint, BRUSHOBJ* Brush,
50 POINTL* BrushPoint)
51 {
52 LONG i, j, dx, dy, c8;
53 BYTE *tMask, *lMask;
54 PFN_DIB_PutPixel DIB_PutPixel;
55 static BYTE maskbit[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
56
57 // Assign DIB functions according to bytes per pixel
58 switch(BitsPerFormat(Dest->iBitmapFormat))
59 {
60 case 1:
61 DIB_PutPixel = (PFN_DIB_PutPixel)DIB_1BPP_PutPixel;
62 break;
63
64 case 4:
65 DIB_PutPixel = (PFN_DIB_PutPixel)DIB_4BPP_PutPixel;
66 break;
67
68 case 16:
69 DIB_PutPixel = (PFN_DIB_PutPixel)DIB_16BPP_PutPixel;
70 break;
71
72 case 24:
73 DIB_PutPixel = (PFN_DIB_PutPixel)DIB_24BPP_PutPixel;
74 break;
75
76 default:
77 DbgPrint("BltMask: unsupported DIB format %u (bitsPerPixel:%u)\n", Dest->iBitmapFormat,
78 BitsPerFormat(Dest->iBitmapFormat));
79 return FALSE;
80 }
81
82 dx = DestRect->right - DestRect->left;
83 dy = DestRect->bottom - DestRect->top;
84
85 if (Mask != NULL)
86 {
87 tMask = Mask->pvBits;
88 for (j = 0; j < dy; j++)
89 {
90 lMask = tMask;
91 c8 = 0;
92 for (i = 0; i < dx; i++)
93 {
94 if (0 != (*lMask & maskbit[c8]))
95 {
96 DIB_PutPixel(Dest, DestRect->left + i, DestRect->top + j, Brush->iSolidColor);
97 }
98 c8++;
99 if (8 == c8)
100 {
101 lMask++;
102 c8=0;
103 }
104 }
105 tMask += Mask->lDelta;
106 }
107 return TRUE;
108 }
109 else
110 {
111 return FALSE;
112 }
113 }
114
115 static BOOL STDCALL
116 BltPatCopy(SURFOBJ *Dest, PSURFGDI DestGDI, SURFOBJ *Mask,
117 RECTL *DestRect, POINTL *MaskPoint, BRUSHOBJ* Brush,
118 POINTL* BrushPoint)
119 {
120 // These functions are assigned if we're working with a DIB
121 // The assigned functions depend on the bitsPerPixel of the DIB
122 PFN_DIB_HLine DIB_HLine;
123 LONG y;
124 ULONG LineWidth;
125
126 MouseSafetyOnDrawStart(Dest, DestGDI, DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
127 // Assign DIB functions according to bytes per pixel
128 DPRINT("BPF: %d\n", BitsPerFormat(Dest->iBitmapFormat));
129 switch(BitsPerFormat(Dest->iBitmapFormat))
130 {
131 case 4:
132 DIB_HLine = (PFN_DIB_HLine)DIB_4BPP_HLine;
133 break;
134
135 case 16:
136 DIB_HLine = (PFN_DIB_HLine)DIB_16BPP_HLine;
137 break;
138
139 case 24:
140 DIB_HLine = (PFN_DIB_HLine)DIB_24BPP_HLine;
141 break;
142
143 default:
144 DbgPrint("BltPatCopy: unsupported DIB format %u (bitsPerPixel:%u)\n", Dest->iBitmapFormat,
145 BitsPerFormat(Dest->iBitmapFormat));
146
147 MouseSafetyOnDrawEnd(Dest, DestGDI);
148 return FALSE;
149 }
150
151 LineWidth = DestRect->right - DestRect->left;
152 for (y = DestRect->top; y < DestRect->bottom; y++)
153 {
154 DIB_HLine(Dest, DestRect->left, DestRect->right, y, Brush->iSolidColor);
155 }
156 MouseSafetyOnDrawEnd(Dest, DestGDI);
157
158 return TRUE;
159 }
160
161 INT abs(INT nm);
162
163 BOOL STDCALL
164 EngBitBlt(SURFOBJ *Dest,
165 SURFOBJ *Source,
166 SURFOBJ *Mask,
167 CLIPOBJ *ClipRegion,
168 XLATEOBJ *ColorTranslation,
169 RECTL *DestRect,
170 POINTL *SourcePoint,
171 POINTL *MaskOrigin,
172 BRUSHOBJ *Brush,
173 POINTL *BrushOrigin,
174 ROP4 rop4)
175 {
176 BOOLEAN ret;
177 BYTE clippingType;
178 RECTL rclTmp;
179 POINTL ptlTmp;
180 RECT_ENUM RectEnum;
181 BOOL EnumMore;
182 PSURFGDI DestGDI, SourceGDI;
183 HSURF hTemp;
184 PSURFOBJ TempSurf = NULL;
185 BOOLEAN canCopyBits;
186 POINTL TempPoint;
187 RECTL TempRect;
188 SIZEL TempSize;
189
190 if(Source != NULL) SourceGDI = (PSURFGDI)AccessInternalObjectFromUserObject(Source);
191 if(Dest != NULL) DestGDI = (PSURFGDI)AccessInternalObjectFromUserObject(Dest);
192
193 if (Source != NULL)
194 {
195 MouseSafetyOnDrawStart(Source, SourceGDI, SourcePoint->x, SourcePoint->y,
196 (SourcePoint->x + abs(DestRect->right - DestRect->left)),
197 (SourcePoint->y + abs(DestRect->bottom - DestRect->top)));
198 }
199 MouseSafetyOnDrawStart(Dest, DestGDI, DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
200
201 // If we don't have to do anything special, we can punt to DrvCopyBits
202 // if it exists
203 if( (Mask == NULL) && (MaskOrigin == NULL) && (Brush == NULL) &&
204 (BrushOrigin == NULL) && (rop4 == 0) )
205 {
206 canCopyBits = TRUE;
207 } else
208 canCopyBits = FALSE;
209
210 // Check for CopyBits or BitBlt hooks if one is not a GDI managed bitmap, IF:
211 // * The destination bitmap is not managed by the GDI OR
212 if(Dest->iType != STYPE_BITMAP)
213 {
214 // Destination surface is device managed
215 if (DestGDI->BitBlt!=NULL)
216 {
217 if (Source!=NULL)
218 {
219 // Get the source into a format compatible surface
220 TempPoint.x = 0;
221 TempPoint.y = 0;
222 TempRect.top = 0;
223 TempRect.left = 0;
224 TempRect.bottom = DestRect->bottom - DestRect->top;
225 TempRect.right = DestRect->right - DestRect->left;
226 TempSize.cx = TempRect.right;
227 TempSize.cy = TempRect.bottom;
228
229 hTemp = EngCreateBitmap(TempSize,
230 DIB_GetDIBWidthBytes(DestRect->right - DestRect->left, BitsPerFormat(Dest->iBitmapFormat)),
231 Dest->iBitmapFormat, 0, NULL);
232 TempSurf = (PSURFOBJ)AccessUserObject((ULONG)hTemp);
233
234 // FIXME: Skip creating a TempSurf if we have the same BPP and palette
235 EngBitBlt(TempSurf, Source, NULL, NULL, ColorTranslation, &TempRect, SourcePoint, NULL, NULL, NULL, 0);
236 }
237
238 ret = DestGDI->BitBlt(Dest, TempSurf, Mask, ClipRegion,
239 NULL, DestRect, &TempPoint,
240 MaskOrigin, Brush, BrushOrigin, rop4);
241
242 MouseSafetyOnDrawEnd(Source, SourceGDI);
243 MouseSafetyOnDrawEnd(Dest, DestGDI);
244
245 return ret;
246 }
247 }
248
249 /* The code currently assumes there will be a source bitmap. This is not true when, for example, using this function to
250 * paint a brush pattern on the destination. */
251 if(!Source && 0xaacc != rop4 && PATCOPY != rop4)
252 {
253 DbgPrint("EngBitBlt: A source is currently required, even though not all operations require one (FIXME)\n");
254 return FALSE;
255 }
256
257 // * The source bitmap is not managed by the GDI and we didn't already obtain it using EngCopyBits from the device
258 if(NULL != Source && STYPE_BITMAP != Source->iType && NULL == SourceGDI->CopyBits)
259 {
260 if (SourceGDI->BitBlt!=NULL)
261 {
262 // Request the device driver to return the bitmap in a format compatible with the device
263 ret = SourceGDI->BitBlt(Dest, Source, Mask, ClipRegion,
264 NULL, DestRect, SourcePoint,
265 MaskOrigin, Brush, BrushOrigin, rop4);
266
267 MouseSafetyOnDrawEnd(Source, SourceGDI);
268 MouseSafetyOnDrawEnd(Dest, DestGDI);
269
270 return ret;
271
272 // Convert the surface from the driver into the required destination surface
273 }
274 }
275
276 // Determine clipping type
277 if (ClipRegion == (CLIPOBJ *) NULL)
278 {
279 clippingType = DC_TRIVIAL;
280 } else {
281 clippingType = ClipRegion->iDComplexity;
282 }
283
284 if (0xaacc == rop4)
285 {
286 return BltMask(Dest, DestGDI, Mask, DestRect, MaskOrigin, Brush, BrushOrigin);
287 } else if (PATCOPY == rop4) {
288 return BltPatCopy(Dest, DestGDI, Mask, DestRect, MaskOrigin, Brush, BrushOrigin);
289 }
290
291
292 // We don't handle color translation just yet [we dont have to.. REMOVE REMOVE REMOVE]
293 switch(clippingType)
294 {
295 case DC_TRIVIAL:
296 CopyBitsCopy(Dest, Source, DestGDI, SourceGDI, DestRect, SourcePoint, Source->lDelta, ColorTranslation);
297
298 MouseSafetyOnDrawEnd(Source, SourceGDI);
299 MouseSafetyOnDrawEnd(Dest, DestGDI);
300
301 return(TRUE);
302
303 case DC_RECT:
304
305 // Clip the blt to the clip rectangle
306 EngIntersectRect(&rclTmp, DestRect, &ClipRegion->rclBounds);
307
308 ptlTmp.x = SourcePoint->x + rclTmp.left - DestRect->left;
309 ptlTmp.y = SourcePoint->y + rclTmp.top - DestRect->top;
310
311 MouseSafetyOnDrawEnd(Source, SourceGDI);
312 MouseSafetyOnDrawEnd(Dest, DestGDI);
313
314 return(TRUE);
315
316 case DC_COMPLEX:
317
318 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, CD_ANY, ENUM_RECT_LIMIT);
319
320 do {
321 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
322
323 if (RectEnum.c > 0)
324 {
325 RECTL* prclEnd = &RectEnum.arcl[RectEnum.c];
326 RECTL* prcl = &RectEnum.arcl[0];
327
328 do {
329 EngIntersectRect(prcl, prcl, DestRect);
330
331 ptlTmp.x = SourcePoint->x + prcl->left - DestRect->left;
332 ptlTmp.y = SourcePoint->y + prcl->top - DestRect->top;
333
334 prcl++;
335
336 } while (prcl < prclEnd);
337 }
338
339 } while(EnumMore);
340
341 MouseSafetyOnDrawEnd(Source, SourceGDI);
342 MouseSafetyOnDrawEnd(Dest, DestGDI);
343
344 return(TRUE);
345 }
346
347 MouseSafetyOnDrawEnd(Source, SourceGDI);
348 MouseSafetyOnDrawEnd(Dest, DestGDI);
349
350 return(FALSE);
351 }