marked implemented functions as such
[reactos.git] / reactos / 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: bitblt.c,v 1.25 2003/08/04 19:57:05 royce Exp $
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;
109 for (j = 0; j < dy; j++)
110 {
111 lMask = tMask;
112 c8 = 0;
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
217 if (NULL != SourcePoint)
218 {
219 InputRect.left = SourcePoint->x;
220 InputRect.right = SourcePoint->x + (DestRect->right - DestRect->left);
221 InputRect.top = SourcePoint->y;
222 InputRect.bottom = SourcePoint->y + (DestRect->bottom - DestRect->top);
223 }
224 else
225 {
226 InputRect.left = 0;
227 InputRect.right = DestRect->right - DestRect->left;
228 InputRect.top = 0;
229 InputRect.bottom = DestRect->bottom - DestRect->top;
230 }
231
232 if (! IntEngEnter(&EnterLeaveSource, SourceObj, &InputRect, TRUE, &Translate, &InputObj))
233 {
234 return FALSE;
235 }
236
237 if (NULL != SourcePoint)
238 {
239 InputPoint.x = SourcePoint->x + Translate.x;
240 InputPoint.y = SourcePoint->y + Translate.y;
241 }
242 else
243 {
244 InputPoint.x = 0;
245 InputPoint.y = 0;
246 }
247
248 if (NULL != InputObj)
249 {
250 InputGDI = (PSURFGDI) AccessInternalObjectFromUserObject(InputObj);
251 }
252 else
253 {
254 InputGDI = NULL;
255 }
256
257 OutputRect = *DestRect;
258 if (NULL != ClipRegion)
259 {
260 if (OutputRect.left < ClipRegion->rclBounds.left)
261 {
262 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
263 InputPoint.x += ClipRegion->rclBounds.left - OutputRect.left;
264 OutputRect.left = ClipRegion->rclBounds.left;
265 }
266 if (ClipRegion->rclBounds.right < OutputRect.right)
267 {
268 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
269 OutputRect.right = ClipRegion->rclBounds.right;
270 }
271 if (OutputRect.top < ClipRegion->rclBounds.top)
272 {
273 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
274 InputPoint.y += ClipRegion->rclBounds.top - OutputRect.top;
275 OutputRect.top = ClipRegion->rclBounds.top;
276 }
277 if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
278 {
279 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
280 OutputRect.bottom = ClipRegion->rclBounds.bottom;
281 }
282 }
283
284 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
285 nothing to do */
286 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
287 {
288 IntEngLeave(&EnterLeaveSource);
289 return TRUE;
290 }
291
292 if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate, &OutputObj))
293 {
294 IntEngLeave(&EnterLeaveSource);
295 return FALSE;
296 }
297
298 OutputRect.left = DestRect->left + Translate.x;
299 OutputRect.right = DestRect->right + Translate.x;
300 OutputRect.top = DestRect->top + Translate.y;
301 OutputRect.bottom = DestRect->bottom + Translate.y;
302
303 if (NULL != OutputObj)
304 {
305 OutputGDI = (PSURFGDI)AccessInternalObjectFromUserObject(OutputObj);
306 }
307
308 // Determine clipping type
309 if (ClipRegion == (CLIPOBJ *) NULL)
310 {
311 clippingType = DC_TRIVIAL;
312 } else {
313 clippingType = ClipRegion->iDComplexity;
314 }
315
316 if (0xaacc == Rop4)
317 {
318 BltRectFunc = BltMask;
319 }
320 else if (PATCOPY == Rop4)
321 {
322 BltRectFunc = BltPatCopy;
323 }
324 else
325 {
326 BltRectFunc = CallDibBitBlt;
327 }
328
329
330 switch(clippingType)
331 {
332 case DC_TRIVIAL:
333 Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
334 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin, Rop4);
335 break;
336 case DC_RECT:
337 // Clip the blt to the clip rectangle
338 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
339 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
340 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
341 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
342 EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
343 Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
344 &CombinedRect, &InputPoint, MaskOrigin, Brush, BrushOrigin, Rop4);
345 break;
346 case DC_COMPLEX:
347 Ret = TRUE;
348 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, CD_ANY, ENUM_RECT_LIMIT);
349 do
350 {
351 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
352
353 for (i = 0; i < RectEnum.c; i++)
354 {
355 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
356 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
357 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
358 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
359 EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
360 Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
361 &CombinedRect, &InputPoint, MaskOrigin, Brush, BrushOrigin, Rop4) &&
362 Ret;
363 }
364 }
365 while(EnumMore);
366 break;
367 }
368
369
370 IntEngLeave(&EnterLeaveDest);
371 IntEngLeave(&EnterLeaveSource);
372
373 return Ret;
374 }
375
376 BOOL STDCALL
377 IntEngBitBlt(SURFOBJ *DestObj,
378 SURFOBJ *SourceObj,
379 SURFOBJ *Mask,
380 CLIPOBJ *ClipRegion,
381 XLATEOBJ *ColorTranslation,
382 RECTL *DestRect,
383 POINTL *SourcePoint,
384 POINTL *MaskOrigin,
385 BRUSHOBJ *Brush,
386 POINTL *BrushOrigin,
387 ROP4 Rop4)
388 {
389 BOOLEAN ret;
390 SURFGDI *DestGDI;
391 SURFGDI *SourceGDI;
392 RECTL OutputRect;
393 POINTL InputPoint;
394
395 if (NULL != SourcePoint)
396 {
397 InputPoint = *SourcePoint;
398 }
399
400 /* Clip against the bounds of the clipping region so we won't try to write
401 * outside the surface */
402 if (NULL != ClipRegion)
403 {
404 if (! EngIntersectRect(&OutputRect, DestRect, &ClipRegion->rclBounds))
405 {
406 return TRUE;
407 }
408 InputPoint.x += OutputRect.left - DestRect->left;
409 InputPoint.y += OutputRect.top - DestRect->top;
410 }
411 else
412 {
413 OutputRect = *DestRect;
414 }
415
416 if (NULL != SourceObj)
417 {
418 SourceGDI = (PSURFGDI) AccessInternalObjectFromUserObject(SourceObj);
419 MouseSafetyOnDrawStart(SourceObj, SourceGDI, InputPoint.x, InputPoint.y,
420 (InputPoint.x + abs(DestRect->right - DestRect->left)),
421 (InputPoint.y + abs(DestRect->bottom - DestRect->top)));
422 }
423
424 /* No success yet */
425 ret = FALSE;
426 DestGDI = (SURFGDI*)AccessInternalObjectFromUserObject(DestObj);
427 MouseSafetyOnDrawStart(DestObj, DestGDI, OutputRect.left, OutputRect.top,
428 OutputRect.right, OutputRect.bottom);
429
430 /* Call the driver's DrvBitBlt if available */
431 if (NULL != DestGDI->BitBlt)
432 {
433 ret = DestGDI->BitBlt(DestObj, SourceObj, Mask, ClipRegion, ColorTranslation,
434 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin,
435 Rop4);
436 }
437
438 if (! ret)
439 {
440 ret = EngBitBlt(DestObj, SourceObj, Mask, ClipRegion, ColorTranslation,
441 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin,
442 Rop4);
443 }
444
445 MouseSafetyOnDrawEnd(DestObj, DestGDI);
446 if (NULL != SourceObj)
447 {
448 MouseSafetyOnDrawEnd(SourceObj, SourceGDI);
449 }
450
451 return ret;
452 }
453 /* EOF */