update for HEAD-2003050101
[reactos.git] / 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 "misc.h"
19 #include <include/mouse.h>
20 #include <include/object.h>
21 #include <include/dib.h>
22 #include <include/surface.h>
23 #include <include/copybits.h>
24 #include <include/inteng.h>
25
26 #define NDEBUG
27 #include <win32k/debug1.h>
28
29 BOOL EngIntersectRect(PRECTL prcDst, PRECTL prcSrc1, PRECTL prcSrc2)
30 {
31   static const RECTL rclEmpty = { 0, 0, 0, 0 };
32
33   prcDst->left  = max(prcSrc1->left, prcSrc2->left);
34   prcDst->right = min(prcSrc1->right, prcSrc2->right);
35
36   if (prcDst->left < prcDst->right)
37   {
38     prcDst->top    = max(prcSrc1->top, prcSrc2->top);
39     prcDst->bottom = min(prcSrc1->bottom, prcSrc2->bottom);
40
41     if (prcDst->top < prcDst->bottom) return(TRUE);
42   }
43
44   *prcDst = rclEmpty;
45
46   return(FALSE);
47 }
48
49 static BOOL STDCALL
50 BltMask(SURFOBJ *Dest, PSURFGDI DestGDI, SURFOBJ *Mask, 
51         RECTL *DestRect, POINTL *MaskPoint, BRUSHOBJ* Brush,
52         POINTL* BrushPoint)
53 {
54   LONG i, j, dx, dy, c8;
55   BYTE *tMask, *lMask;
56   static BYTE maskbit[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
57
58   dx = DestRect->right  - DestRect->left;
59   dy = DestRect->bottom - DestRect->top;
60
61   if (Mask != NULL)
62     {
63       tMask = Mask->pvBits;
64       for (j = 0; j < dy; j++)
65         {
66           lMask = tMask;
67           c8 = 0;
68           for (i = 0; i < dx; i++)
69             {
70               if (0 != (*lMask & maskbit[c8]))
71                 {
72                   DestGDI->DIB_PutPixel(Dest, DestRect->left + i, DestRect->top + j, Brush->iSolidColor);
73                 }
74               c8++;
75               if (8 == c8)
76                 {
77                   lMask++;
78                   c8=0;
79                 }
80             }
81           tMask += Mask->lDelta;
82         }
83       return TRUE;
84     }
85   else
86     {
87     return FALSE;
88     }
89 }
90
91 static BOOL STDCALL
92 BltPatCopy(SURFOBJ *Dest, PSURFGDI DestGDI, SURFOBJ *Mask, 
93            RECTL *DestRect, POINTL *MaskPoint, BRUSHOBJ* Brush,
94            POINTL* BrushPoint)
95 {
96   // These functions are assigned if we're working with a DIB
97   // The assigned functions depend on the bitsPerPixel of the DIB
98   LONG y;
99   ULONG LineWidth;
100
101   LineWidth  = DestRect->right - DestRect->left;
102   for (y = DestRect->top; y < DestRect->bottom; y++)
103   {
104     DestGDI->DIB_HLine(Dest, DestRect->left, DestRect->right, y,  Brush->iSolidColor);
105   }
106
107   return TRUE;
108 }
109
110 INT abs(INT nm);
111
112 BOOL STDCALL
113 EngBitBlt(SURFOBJ *DestObj,
114           SURFOBJ *SourceObj,
115           SURFOBJ *Mask,
116           CLIPOBJ *ClipRegion,
117           XLATEOBJ *ColorTranslation,
118           RECTL *DestRect,
119           POINTL *SourcePoint,
120           POINTL *MaskOrigin,
121           BRUSHOBJ *Brush,
122           POINTL *BrushOrigin,
123           ROP4 rop4)
124 {
125   BOOLEAN            ret;
126   BYTE               clippingType;
127   RECTL              rclTmp;
128   POINTL             ptlTmp;
129   RECT_ENUM          RectEnum;
130   BOOL               EnumMore;
131   PSURFGDI           OutputGDI, InputGDI;
132   POINTL             InputPoint;
133   RECTL              InputRect;
134   RECTL              OutputRect;
135   POINTL             Translate;
136   INTENG_ENTER_LEAVE EnterLeaveSource;
137   INTENG_ENTER_LEAVE EnterLeaveDest;
138   PSURFOBJ           InputObj;
139   PSURFOBJ           OutputObj;
140
141   /* Check for degenerate case: if height or width of DestRect is 0 pixels there's
142      nothing to do */
143   if (DestRect->right == DestRect->left || DestRect->bottom == DestRect->top)
144     {
145     return TRUE;
146     }
147
148   if (NULL != SourcePoint)
149     {
150     InputRect.left = SourcePoint->x;
151     InputRect.right = SourcePoint->x + (DestRect->right - DestRect->left);
152     InputRect.top = SourcePoint->y;
153     InputRect.bottom = SourcePoint->y + (DestRect->bottom - DestRect->top);
154     }
155   else
156     {
157     InputRect.left = 0;
158     InputRect.right = DestRect->right - DestRect->left;
159     InputRect.top = 0;
160     InputRect.bottom = DestRect->bottom - DestRect->top;
161     }
162
163   if (! IntEngEnter(&EnterLeaveSource, SourceObj, &InputRect, TRUE, &Translate, &InputObj))
164     {
165     return FALSE;
166     }
167
168   if (NULL != SourcePoint)
169     {
170     InputPoint.x = SourcePoint->x + Translate.x;
171     InputPoint.y = SourcePoint->y + Translate.y;
172     }
173   else
174     {
175     InputPoint.x = 0;
176     InputPoint.y = 0;
177     }
178
179   if (NULL != InputObj)
180     {
181     InputGDI = (PSURFGDI) AccessInternalObjectFromUserObject(InputObj);
182     }
183
184   OutputRect = *DestRect;
185
186   if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate, &OutputObj))
187     {
188     IntEngLeave(&EnterLeaveSource);
189     return FALSE;
190     }
191
192   OutputRect.left = DestRect->left + Translate.x;
193   OutputRect.right = DestRect->right + Translate.x;
194   OutputRect.top = DestRect->top + Translate.y;
195   OutputRect.bottom = DestRect->bottom + Translate.y;
196
197
198   if (NULL != OutputObj)
199     {
200     OutputGDI = (PSURFGDI)AccessInternalObjectFromUserObject(OutputObj);
201     }
202
203   /* The code currently assumes there will be a source bitmap. This is not true when, for example, using this function to
204    * paint a brush pattern on the destination. */
205   if (NULL == InputObj && 0xaacc != rop4 && PATCOPY != rop4)
206   {
207     DbgPrint("EngBitBlt: A source is currently required, even though not all operations require one (FIXME)\n");
208     return FALSE;
209   }
210
211   // Determine clipping type
212   if (ClipRegion == (CLIPOBJ *) NULL)
213   {
214     clippingType = DC_TRIVIAL;
215   } else {
216     clippingType = ClipRegion->iDComplexity;
217   }
218
219   if (0xaacc == rop4)
220   {
221     ret = BltMask(OutputObj, OutputGDI, Mask, &OutputRect, MaskOrigin, Brush, BrushOrigin);
222     IntEngLeave(&EnterLeaveDest);
223     IntEngLeave(&EnterLeaveSource);
224     return ret;
225   } else if (PATCOPY == rop4) {
226     ret = BltPatCopy(OutputObj, OutputGDI, Mask, &OutputRect, MaskOrigin, Brush, BrushOrigin);
227     IntEngLeave(&EnterLeaveDest);
228     IntEngLeave(&EnterLeaveSource);
229     return ret;
230   }
231
232
233   // We don't handle color translation just yet [we dont have to.. REMOVE REMOVE REMOVE]
234   switch(clippingType)
235   {
236     case DC_TRIVIAL:
237       OutputGDI->DIB_BitBlt(OutputObj, InputObj, OutputGDI, InputGDI, &OutputRect, &InputPoint, ColorTranslation);
238
239       IntEngLeave(&EnterLeaveDest);
240       IntEngLeave(&EnterLeaveSource);
241
242       return(TRUE);
243
244     case DC_RECT:
245
246       // Clip the blt to the clip rectangle
247       EngIntersectRect(&rclTmp, &OutputRect, &ClipRegion->rclBounds);
248
249       ptlTmp.x = InputPoint.x + rclTmp.left - OutputRect.left;
250       ptlTmp.y = InputPoint.y + rclTmp.top  - OutputRect.top;
251
252       IntEngLeave(&EnterLeaveDest);
253       IntEngLeave(&EnterLeaveSource);
254
255       return(TRUE);
256
257     case DC_COMPLEX:
258
259       CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, CD_ANY, ENUM_RECT_LIMIT);
260
261       do {
262         EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
263
264         if (RectEnum.c > 0)
265         {
266           RECTL* prclEnd = &RectEnum.arcl[RectEnum.c];
267           RECTL* prcl    = &RectEnum.arcl[0];
268
269           do {
270             EngIntersectRect(prcl, prcl, &OutputRect);
271
272             ptlTmp.x = InputPoint.x + prcl->left - OutputRect.left;
273             ptlTmp.y = InputPoint.y + prcl->top - OutputRect.top;
274
275             prcl++;
276
277           } while (prcl < prclEnd);
278         }
279
280       } while(EnumMore);
281
282     IntEngLeave(&EnterLeaveDest);
283     IntEngLeave(&EnterLeaveSource);
284
285     return(TRUE);
286   }
287
288   IntEngLeave(&EnterLeaveDest);
289   IntEngLeave(&EnterLeaveSource);
290
291   return(FALSE);
292 }
293
294 BOOL STDCALL
295 IntEngBitBlt(SURFOBJ *DestObj,
296              SURFOBJ *SourceObj,
297              SURFOBJ *Mask,
298              CLIPOBJ *ClipRegion,
299              XLATEOBJ *ColorTranslation,
300              RECTL *DestRect,
301              POINTL *SourcePoint,
302              POINTL *MaskOrigin,
303              BRUSHOBJ *Brush,
304              POINTL *BrushOrigin,
305              ROP4 rop4)
306 {
307   BOOLEAN ret;
308   SURFGDI *DestGDI;
309   SURFGDI *SourceGDI;
310
311   if (NULL != SourceObj)
312     {
313     SourceGDI = (PSURFGDI) AccessInternalObjectFromUserObject(SourceObj);
314     MouseSafetyOnDrawStart(SourceObj, SourceGDI, SourcePoint->x, SourcePoint->y,
315                            (SourcePoint->x + abs(DestRect->right - DestRect->left)),
316                            (SourcePoint->y + abs(DestRect->bottom - DestRect->top)));
317     }
318
319   /* No success yet */
320   ret = FALSE;
321   DestGDI = (SURFGDI*)AccessInternalObjectFromUserObject(DestObj);
322   MouseSafetyOnDrawStart(DestObj, DestGDI, DestRect->left, DestRect->top,
323                          DestRect->right, DestRect->bottom);
324
325   /* Call the driver's DrvBitBlt if available */
326   if (NULL != DestGDI->BitBlt) {
327     ret = DestGDI->BitBlt(DestObj, SourceObj, Mask, ClipRegion, ColorTranslation,
328                           DestRect, SourcePoint, MaskOrigin, Brush, BrushOrigin, rop4);
329   }
330
331   if (! ret) {
332     ret = EngBitBlt(DestObj, SourceObj, Mask, ClipRegion, ColorTranslation,
333                     DestRect, SourcePoint, MaskOrigin, Brush, BrushOrigin, rop4);
334   }
335
336   MouseSafetyOnDrawEnd(DestObj, DestGDI);
337   if (NULL != SourceObj)
338     {
339     MouseSafetyOnDrawEnd(SourceObj, SourceGDI);
340     }
341
342   return ret;
343 }