update for HEAD-2003091401
[reactos.git] / subsys / win32k / eng / bitblt.c
1 /*
2  *  ReactOS W32 Subsystem
3  *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /* $Id$
20  *
21  * COPYRIGHT:        See COPYING in the top level directory
22  * PROJECT:          ReactOS kernel
23  * PURPOSE:          GDI BitBlt Functions
24  * FILE:             subsys/win32k/eng/bitblt.c
25  * PROGRAMER:        Jason Filby
26  * REVISION HISTORY:
27  *        2/10/1999: Created
28  */
29
30 #include <ddk/winddi.h>
31 #include <ddk/ntddk.h>
32 #include <ddk/ntddmou.h>
33 #include <ntos/minmax.h>
34 #include "brush.h"
35 #include "clip.h"
36 #include "objects.h"
37 #include "../dib/dib.h"
38 #include "misc.h"
39 #include <include/mouse.h>
40 #include <include/object.h>
41 #include <include/dib.h>
42 #include <include/surface.h>
43 #include <include/copybits.h>
44 #include <include/inteng.h>
45
46 //#define NDEBUG
47 #include <win32k/debug1.h>
48
49 typedef BOOLEAN STDCALL (*PBLTRECTFUNC)(PSURFOBJ OutputObj,
50                                         PSURFGDI OutputGDI,
51                                         PSURFOBJ InputObj,
52                                         PSURFGDI InputGDI,
53                                         PSURFOBJ Mask,
54                                         PXLATEOBJ ColorTranslation,
55                                         PRECTL OutputRect,
56                                         PPOINTL InputPoint,
57                                         PPOINTL MaskOrigin,
58                                         PBRUSHOBJ Brush,
59                                         PPOINTL BrushOrigin,
60                                         ROP4 Rop4);
61
62 BOOL STDCALL EngIntersectRect(PRECTL prcDst, PRECTL prcSrc1, PRECTL prcSrc2)
63 {
64   static const RECTL rclEmpty = { 0, 0, 0, 0 };
65
66   prcDst->left  = max(prcSrc1->left, prcSrc2->left);
67   prcDst->right = min(prcSrc1->right, prcSrc2->right);
68
69   if (prcDst->left < prcDst->right)
70     {
71       prcDst->top    = max(prcSrc1->top, prcSrc2->top);
72       prcDst->bottom = min(prcSrc1->bottom, prcSrc2->bottom);
73
74       if (prcDst->top < prcDst->bottom)
75         {
76           return TRUE;
77         }
78     }
79
80   *prcDst = rclEmpty;
81
82   return FALSE;
83 }
84
85 static BOOLEAN STDCALL
86 BltMask(PSURFOBJ Dest,
87         PSURFGDI DestGDI,
88         PSURFOBJ Source,
89         PSURFGDI SourceGDI,
90         PSURFOBJ Mask, 
91         PXLATEOBJ ColorTranslation,
92         PRECTL DestRect,
93         PPOINTL SourcePoint,
94         PPOINTL MaskPoint,
95         PBRUSHOBJ Brush,
96         PPOINTL BrushPoint,
97         ROP4 Rop4)
98 {
99   LONG i, j, dx, dy, c8;
100   BYTE *tMask, *lMask;
101   static BYTE maskbit[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
102
103   dx = DestRect->right  - DestRect->left;
104   dy = DestRect->bottom - DestRect->top;
105
106   if (Mask != NULL)
107     {
108       tMask = Mask->pvBits + SourcePoint->y * Mask->lDelta + (SourcePoint->x >> 3);
109       for (j = 0; j < dy; j++)
110         {
111           lMask = tMask;
112           c8 = SourcePoint->x & 0x07;
113           for (i = 0; i < dx; i++)
114             {
115               if (0 != (*lMask & maskbit[c8]))
116                 {
117                   DestGDI->DIB_PutPixel(Dest, DestRect->left + i, DestRect->top + j, Brush->iSolidColor);
118                 }
119               c8++;
120               if (8 == c8)
121                 {
122                   lMask++;
123                   c8=0;
124                 }
125             }
126           tMask += Mask->lDelta;
127         }
128       return TRUE;
129     }
130   else
131     {
132     return FALSE;
133     }
134 }
135
136 static BOOLEAN STDCALL
137 BltPatCopy(PSURFOBJ Dest,
138            PSURFGDI DestGDI,
139            PSURFOBJ Source,
140            PSURFGDI SourceGDI,
141            PSURFOBJ Mask, 
142            PXLATEOBJ ColorTranslation,
143            PRECTL DestRect,
144            PPOINTL SourcePoint,
145            PPOINTL MaskPoint,
146            PBRUSHOBJ Brush,
147            PPOINTL BrushPoint,
148            ROP4 Rop4)
149 {
150   // These functions are assigned if we're working with a DIB
151   // The assigned functions depend on the bitsPerPixel of the DIB
152   LONG y;
153   ULONG LineWidth;
154
155   LineWidth  = DestRect->right - DestRect->left;
156   for (y = DestRect->top; y < DestRect->bottom; y++)
157   {
158     DestGDI->DIB_HLine(Dest, DestRect->left, DestRect->right, y,  Brush->iSolidColor);
159   }
160
161   return TRUE;
162 }
163
164 static BOOLEAN STDCALL
165 CallDibBitBlt(PSURFOBJ OutputObj,
166               PSURFGDI OutputGDI,
167               PSURFOBJ InputObj,
168               PSURFGDI InputGDI,
169               PSURFOBJ Mask,
170               PXLATEOBJ ColorTranslation,
171               PRECTL OutputRect,
172               PPOINTL InputPoint,
173               PPOINTL MaskOrigin,
174               PBRUSHOBJ Brush,
175               PPOINTL BrushOrigin,
176               ROP4 Rop4)
177 {
178   return OutputGDI->DIB_BitBlt(OutputObj, InputObj, OutputGDI, InputGDI, OutputRect, InputPoint, Brush, BrushOrigin, ColorTranslation, Rop4);
179 }
180
181 INT abs(INT nm);
182
183 /*
184  * @implemented
185  */
186 BOOL STDCALL
187 EngBitBlt(SURFOBJ *DestObj,
188           SURFOBJ *SourceObj,
189           SURFOBJ *Mask,
190           CLIPOBJ *ClipRegion,
191           XLATEOBJ *ColorTranslation,
192           RECTL *DestRect,
193           POINTL *SourcePoint,
194           POINTL *MaskOrigin,
195           BRUSHOBJ *Brush,
196           POINTL *BrushOrigin,
197           ROP4 Rop4)
198 {
199   BYTE               clippingType;
200   RECTL              CombinedRect;
201   RECT_ENUM          RectEnum;
202   BOOL               EnumMore;
203   PSURFGDI           OutputGDI, InputGDI;
204   POINTL             InputPoint;
205   RECTL              InputRect;
206   RECTL              OutputRect;
207   POINTL             Translate;
208   INTENG_ENTER_LEAVE EnterLeaveSource;
209   INTENG_ENTER_LEAVE EnterLeaveDest;
210   PSURFOBJ           InputObj;
211   PSURFOBJ           OutputObj;
212   PBLTRECTFUNC       BltRectFunc;
213   BOOLEAN            Ret;
214   RECTL              ClipRect;
215   unsigned           i;
216   POINTL             Pt;
217   ULONG              Direction;
218
219   if (NULL != SourcePoint)
220     {
221     InputRect.left = SourcePoint->x;
222     InputRect.right = SourcePoint->x + (DestRect->right - DestRect->left);
223     InputRect.top = SourcePoint->y;
224     InputRect.bottom = SourcePoint->y + (DestRect->bottom - DestRect->top);
225     }
226   else
227     {
228     InputRect.left = 0;
229     InputRect.right = DestRect->right - DestRect->left;
230     InputRect.top = 0;
231     InputRect.bottom = DestRect->bottom - DestRect->top;
232     }
233
234   if (! IntEngEnter(&EnterLeaveSource, SourceObj, &InputRect, TRUE, &Translate, &InputObj))
235     {
236     return FALSE;
237     }
238
239   if (NULL != SourcePoint)
240     {
241     InputPoint.x = SourcePoint->x + Translate.x;
242     InputPoint.y = SourcePoint->y + Translate.y;
243     }
244   else
245     {
246     InputPoint.x = 0;
247     InputPoint.y = 0;
248     }
249
250   if (NULL != InputObj)
251     {
252     InputGDI = (PSURFGDI) AccessInternalObjectFromUserObject(InputObj);
253     }
254   else
255     {
256       InputGDI = NULL;
257     }
258
259   OutputRect = *DestRect;
260   if (NULL != ClipRegion)
261     {
262       if (OutputRect.left < ClipRegion->rclBounds.left)
263         {
264           InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
265           InputPoint.x += ClipRegion->rclBounds.left - OutputRect.left;
266           OutputRect.left = ClipRegion->rclBounds.left;
267         }
268       if (ClipRegion->rclBounds.right < OutputRect.right)
269         {
270           InputRect.right -=  OutputRect.right - ClipRegion->rclBounds.right;
271           OutputRect.right = ClipRegion->rclBounds.right;
272         }
273       if (OutputRect.top < ClipRegion->rclBounds.top)
274         {
275           InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
276           InputPoint.y += ClipRegion->rclBounds.top - OutputRect.top;
277           OutputRect.top = ClipRegion->rclBounds.top;
278         }
279       if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
280         {
281           InputRect.bottom -=  OutputRect.bottom - ClipRegion->rclBounds.bottom;
282           OutputRect.bottom = ClipRegion->rclBounds.bottom;
283         }
284     }
285
286   /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
287      nothing to do */
288   if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
289     {
290     IntEngLeave(&EnterLeaveSource);
291     return TRUE;
292     }
293
294   if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate, &OutputObj))
295     {
296     IntEngLeave(&EnterLeaveSource);
297     return FALSE;
298     }
299
300   OutputRect.left = DestRect->left + Translate.x;
301   OutputRect.right = DestRect->right + Translate.x;
302   OutputRect.top = DestRect->top + Translate.y;
303   OutputRect.bottom = DestRect->bottom + Translate.y;
304
305   if (NULL != OutputObj)
306     {
307     OutputGDI = (PSURFGDI)AccessInternalObjectFromUserObject(OutputObj);
308     }
309
310   // Determine clipping type
311   if (ClipRegion == (CLIPOBJ *) NULL)
312   {
313     clippingType = DC_TRIVIAL;
314   } else {
315     clippingType = ClipRegion->iDComplexity;
316   }
317
318   if (0xaacc == Rop4)
319     {
320       BltRectFunc = BltMask;
321     }
322   else if (PATCOPY == Rop4)
323     {
324       BltRectFunc = BltPatCopy;
325     }
326   else
327     {
328       BltRectFunc = CallDibBitBlt;
329     }
330
331
332   switch(clippingType)
333   {
334     case DC_TRIVIAL:
335       Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
336                            &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin, Rop4);
337       break;
338     case DC_RECT:
339       // Clip the blt to the clip rectangle
340       ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
341       ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
342       ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
343       ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
344       EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
345       Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
346       Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
347       Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
348                            &CombinedRect, &Pt, MaskOrigin, Brush, BrushOrigin, Rop4);
349       break;
350     case DC_COMPLEX:
351       Ret = TRUE;
352       if (OutputObj == InputObj)
353         {
354           if (OutputRect.top < InputPoint.y)
355             {
356               Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
357             }
358           else
359             {
360               Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
361             }
362         }
363       else
364         {
365           Direction = CD_ANY;
366         }
367       CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, ENUM_RECT_LIMIT);
368       do
369         {
370           EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
371
372           for (i = 0; i < RectEnum.c; i++)
373             {
374               ClipRect.left = RectEnum.arcl[i].left + Translate.x;
375               ClipRect.right = RectEnum.arcl[i].right + Translate.x;
376               ClipRect.top = RectEnum.arcl[i].top + Translate.y;
377               ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
378               EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
379               Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
380               Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
381               Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
382                                    &CombinedRect, &Pt, MaskOrigin, Brush, BrushOrigin, Rop4) &&
383                     Ret;
384             }
385         }
386       while(EnumMore);
387       break;
388   }
389
390
391   IntEngLeave(&EnterLeaveDest);
392   IntEngLeave(&EnterLeaveSource);
393
394   return Ret;
395 }
396
397 BOOL STDCALL
398 IntEngBitBlt(SURFOBJ *DestObj,
399              SURFOBJ *SourceObj,
400              SURFOBJ *Mask,
401              CLIPOBJ *ClipRegion,
402              XLATEOBJ *ColorTranslation,
403              RECTL *DestRect,
404              POINTL *SourcePoint,
405              POINTL *MaskOrigin,
406              BRUSHOBJ *Brush,
407              POINTL *BrushOrigin,
408              ROP4 Rop4)
409 {
410   BOOLEAN ret;
411   SURFGDI *DestGDI;
412   SURFGDI *SourceGDI;
413   RECTL OutputRect;
414   POINTL InputPoint;
415
416   if (NULL != SourcePoint)
417     {
418       InputPoint = *SourcePoint;
419     }
420
421   /* Clip against the bounds of the clipping region so we won't try to write
422    * outside the surface */
423   if (NULL != ClipRegion)
424     {
425       if (! EngIntersectRect(&OutputRect, DestRect, &ClipRegion->rclBounds))
426         {
427           return TRUE;
428         }
429       InputPoint.x += OutputRect.left - DestRect->left;
430       InputPoint.y += OutputRect.top - DestRect->top;
431     }
432   else
433     {
434       OutputRect = *DestRect;
435     }
436
437   if (NULL != SourceObj)
438     {
439     SourceGDI = (PSURFGDI) AccessInternalObjectFromUserObject(SourceObj);
440     MouseSafetyOnDrawStart(SourceObj, SourceGDI, InputPoint.x, InputPoint.y,
441                            (InputPoint.x + abs(DestRect->right - DestRect->left)),
442                            (InputPoint.y + abs(DestRect->bottom - DestRect->top)));
443     }
444
445   /* No success yet */
446   ret = FALSE;
447   DestGDI = (SURFGDI*)AccessInternalObjectFromUserObject(DestObj);
448   MouseSafetyOnDrawStart(DestObj, DestGDI, OutputRect.left, OutputRect.top,
449                          OutputRect.right, OutputRect.bottom);
450
451   /* Call the driver's DrvBitBlt if available */
452   if (NULL != DestGDI->BitBlt)
453     {
454       ret = DestGDI->BitBlt(DestObj, SourceObj, Mask, ClipRegion, ColorTranslation,
455                             &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin,
456                             Rop4);
457     }
458
459   if (! ret)
460     {
461       ret = EngBitBlt(DestObj, SourceObj, Mask, ClipRegion, ColorTranslation,
462                       &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin,
463                       Rop4);
464     }
465
466   MouseSafetyOnDrawEnd(DestObj, DestGDI);
467   if (NULL != SourceObj)
468     {
469     MouseSafetyOnDrawEnd(SourceObj, SourceGDI);
470     }
471
472   return ret;
473 }
474 /* EOF */