c582ebf678d675afee37e2ce0f2e7ee0fb2223ff
[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 <include/mouse.h>
18 #include <include/object.h>
19 #include <include/dib.h>
20 #include <include/surface.h>
21 #include <include/copybits.h>
22
23 BOOL EngIntersectRect(PRECTL prcDst, PRECTL prcSrc1, PRECTL prcSrc2)
24 {
25   static const RECTL rclEmpty = { 0, 0, 0, 0 };
26
27   prcDst->left  = max(prcSrc1->left, prcSrc2->left);
28   prcDst->right = min(prcSrc1->right, prcSrc2->right);
29
30   if (prcDst->left < prcDst->right)
31   {
32     prcDst->top    = max(prcSrc1->top, prcSrc2->top);
33     prcDst->bottom = min(prcSrc1->bottom, prcSrc2->bottom);
34
35     if (prcDst->top < prcDst->bottom) return(TRUE);
36   }
37
38   *prcDst = rclEmpty;
39
40   return(FALSE);
41 }
42
43 INT abs(INT nm);
44
45 BOOL STDCALL
46 EngBitBlt(SURFOBJ *Dest,
47           SURFOBJ *Source,
48           SURFOBJ *Mask,
49           CLIPOBJ *ClipRegion,
50           XLATEOBJ *ColorTranslation,
51           RECTL *DestRect,
52           POINTL *SourcePoint,
53           POINTL *MaskRect,
54           BRUSHOBJ *Brush,
55           POINTL *BrushOrigin,
56           ROP4 rop4)
57 {
58   BOOLEAN   ret;
59   BYTE      clippingType;
60   RECTL     rclTmp;
61   POINTL    ptlTmp;
62   RECT_ENUM RectEnum;
63   BOOL      EnumMore;
64   PSURFGDI  DestGDI, SourceGDI;
65   HSURF     hTemp;
66   PSURFOBJ  TempSurf = NULL;
67   BOOLEAN   canCopyBits;
68   POINTL    TempPoint;
69   RECTL     TempRect;
70   SIZEL     TempSize;
71
72   if(Source != NULL) SourceGDI = (PSURFGDI)AccessInternalObjectFromUserObject(Source);
73   if(Dest   != NULL) DestGDI   = (PSURFGDI)AccessInternalObjectFromUserObject(Dest);
74
75   if (Source != NULL)
76     {
77       MouseSafetyOnDrawStart(Source, SourceGDI, SourcePoint->x, SourcePoint->y,
78                              (SourcePoint->x + abs(DestRect->right - DestRect->left)),
79                              (SourcePoint->y + abs(DestRect->bottom - DestRect->top)));
80     }
81   MouseSafetyOnDrawStart(Dest, DestGDI, DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
82
83   // If we don't have to do anything special, we can punt to DrvCopyBits
84   // if it exists
85   if( (Mask == NULL)        && (MaskRect == NULL) && (Brush == NULL) &&
86       (BrushOrigin == NULL) && (rop4 == 0) )
87   {
88     canCopyBits = TRUE;
89   } else
90     canCopyBits = FALSE;
91
92   // Check for CopyBits or BitBlt hooks if one is not a GDI managed bitmap, IF:
93   // * The destination bitmap is not managed by the GDI OR
94   if(Dest->iType != STYPE_BITMAP)
95   {
96     // Destination surface is device managed
97     if (DestGDI->BitBlt!=NULL)
98     {
99       if (Source!=NULL)
100       {
101         // Get the source into a format compatible surface
102         TempPoint.x = 0;
103         TempPoint.y = 0;
104         TempRect.top    = 0;
105         TempRect.left   = 0;
106         TempRect.bottom = DestRect->bottom - DestRect->top;
107         TempRect.right  = DestRect->right - DestRect->left;
108         TempSize.cx = TempRect.right;
109         TempSize.cy = TempRect.bottom;
110
111         hTemp = EngCreateBitmap(TempSize,
112                      DIB_GetDIBWidthBytes(DestRect->right - DestRect->left, BitsPerFormat(Dest->iBitmapFormat)),
113                      Dest->iBitmapFormat, 0, NULL);
114         TempSurf = (PSURFOBJ)AccessUserObject((ULONG)hTemp);
115
116         // FIXME: Skip creating a TempSurf if we have the same BPP and palette
117         EngBitBlt(TempSurf, Source, NULL, NULL, ColorTranslation, &TempRect, SourcePoint, NULL, NULL, NULL, 0);
118       }
119
120       ret = DestGDI->BitBlt(Dest, TempSurf, Mask, ClipRegion,
121                             NULL, DestRect, &TempPoint,
122                             MaskRect, Brush, BrushOrigin, rop4);
123
124       MouseSafetyOnDrawEnd(Source, SourceGDI);
125       MouseSafetyOnDrawEnd(Dest, DestGDI);
126
127       return ret;
128     }
129   }
130
131   /* The code currently assumes there will be a source bitmap. This is not true when, for example, using this function to
132    * paint a brush pattern on the destination. */
133   if(!Source)
134   {
135     DbgPrint("EngBitBlt: A source is currently required, even though not all operations require one (FIXME)\n");
136     return FALSE;
137   }
138
139   // * The source bitmap is not managed by the GDI and we didn't already obtain it using EngCopyBits from the device
140   if(Source->iType != STYPE_BITMAP && SourceGDI->CopyBits == NULL)
141   {
142     if (SourceGDI->BitBlt!=NULL)
143     {
144       // Request the device driver to return the bitmap in a format compatible with the device
145       ret = SourceGDI->BitBlt(Dest, Source, Mask, ClipRegion,
146                               NULL, DestRect, SourcePoint,
147                               MaskRect, Brush, BrushOrigin, rop4);
148
149       MouseSafetyOnDrawEnd(Source, SourceGDI);
150       MouseSafetyOnDrawEnd(Dest, DestGDI);
151
152       return ret;
153
154       // Convert the surface from the driver into the required destination surface
155     }
156   }
157
158   // Determine clipping type
159   if (ClipRegion == (CLIPOBJ *) NULL)
160   {
161     clippingType = DC_TRIVIAL;
162   } else {
163     clippingType = ClipRegion->iDComplexity;
164   }
165
166   // We don't handle color translation just yet [we dont have to.. REMOVE REMOVE REMOVE]
167   switch(clippingType)
168   {
169     case DC_TRIVIAL:
170       CopyBitsCopy(Dest, Source, DestGDI, SourceGDI, DestRect, SourcePoint, Source->lDelta, ColorTranslation);
171
172       MouseSafetyOnDrawEnd(Source, SourceGDI);
173       MouseSafetyOnDrawEnd(Dest, DestGDI);
174
175       return(TRUE);
176
177     case DC_RECT:
178
179       // Clip the blt to the clip rectangle
180       EngIntersectRect(&rclTmp, DestRect, &ClipRegion->rclBounds);
181
182       ptlTmp.x = SourcePoint->x + rclTmp.left - DestRect->left;
183       ptlTmp.y = SourcePoint->y + rclTmp.top  - DestRect->top;
184
185       MouseSafetyOnDrawEnd(Source, SourceGDI);
186       MouseSafetyOnDrawEnd(Dest, DestGDI);
187
188       return(TRUE);
189
190     case DC_COMPLEX:
191
192       CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, CD_ANY, ENUM_RECT_LIMIT);
193
194       do {
195         EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
196
197         if (RectEnum.c > 0)
198         {
199           RECTL* prclEnd = &RectEnum.arcl[RectEnum.c];
200           RECTL* prcl    = &RectEnum.arcl[0];
201
202           do {
203             EngIntersectRect(prcl, prcl, DestRect);
204
205             ptlTmp.x = SourcePoint->x + prcl->left - DestRect->left;
206             ptlTmp.y = SourcePoint->y + prcl->top - DestRect->top;
207
208             prcl++;
209
210           } while (prcl < prclEnd);
211         }
212
213       } while(EnumMore);
214
215     MouseSafetyOnDrawEnd(Source, SourceGDI);
216     MouseSafetyOnDrawEnd(Dest, DestGDI);
217
218     return(TRUE);
219   }
220
221   MouseSafetyOnDrawEnd(Source, SourceGDI);
222   MouseSafetyOnDrawEnd(Dest, DestGDI);
223
224   return(FALSE);
225 }