cleanup
[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.42 2004/02/24 13:27:02 weiden 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/eng.h>
44 #include <include/inteng.h>
45
46 #define NDEBUG
47 #include <win32k/debug1.h>
48
49 #define ROP_NOOP 0x00AA0029
50
51 typedef BOOLEAN STDCALL (*PBLTRECTFUNC)(SURFOBJ* OutputObj,
52 SURFGDI* OutputGDI,
53 SURFOBJ* InputObj,
54 SURFGDI* InputGDI,
55 SURFOBJ* Mask,
56 XLATEOBJ* ColorTranslation,
57 RECTL* OutputRect,
58 POINTL* InputPoint,
59 POINTL* MaskOrigin,
60 BRUSHOBJ* Brush,
61 POINTL* BrushOrigin,
62 ROP4 Rop4);
63 typedef BOOLEAN STDCALL (*PSTRETCHRECTFUNC)(SURFOBJ* OutputObj,
64 SURFGDI* OutputGDI,
65 SURFOBJ* InputObj,
66 SURFGDI* InputGDI,
67 SURFOBJ* Mask,
68 XLATEOBJ* ColorTranslation,
69 RECTL* OutputRect,
70 RECTL* InputRect,
71 POINTL* MaskOrigin,
72 POINTL* BrushOrigin,
73 ULONG Mode);
74
75 BOOL STDCALL EngIntersectRect(RECTL* prcDst, RECTL* prcSrc1, RECTL* prcSrc2)
76 {
77 static const RECTL rclEmpty = { 0, 0, 0, 0 };
78
79 prcDst->left = max(prcSrc1->left, prcSrc2->left);
80 prcDst->right = min(prcSrc1->right, prcSrc2->right);
81
82 if (prcDst->left < prcDst->right)
83 {
84 prcDst->top = max(prcSrc1->top, prcSrc2->top);
85 prcDst->bottom = min(prcSrc1->bottom, prcSrc2->bottom);
86
87 if (prcDst->top < prcDst->bottom)
88 {
89 return TRUE;
90 }
91 }
92
93 *prcDst = rclEmpty;
94
95 return FALSE;
96 }
97
98 static BOOLEAN STDCALL
99 BltMask(SURFOBJ* Dest,
100 SURFGDI* DestGDI,
101 SURFOBJ* Source,
102 SURFGDI* SourceGDI,
103 SURFOBJ* Mask,
104 XLATEOBJ* ColorTranslation,
105 RECTL* DestRect,
106 POINTL* SourcePoint,
107 POINTL* MaskPoint,
108 BRUSHOBJ* Brush,
109 POINTL* BrushPoint,
110 ROP4 Rop4)
111 {
112 LONG i, j, dx, dy, c8;
113 BYTE *tMask, *lMask;
114 static BYTE maskbit[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
115
116 dx = DestRect->right - DestRect->left;
117 dy = DestRect->bottom - DestRect->top;
118
119 if (Mask != NULL)
120 {
121 tMask = Mask->pvBits + SourcePoint->y * Mask->lDelta + (SourcePoint->x >> 3);
122 for (j = 0; j < dy; j++)
123 {
124 lMask = tMask;
125 c8 = SourcePoint->x & 0x07;
126 for (i = 0; i < dx; i++)
127 {
128 if (0 != (*lMask & maskbit[c8]))
129 {
130 DestGDI->DIB_PutPixel(Dest, DestRect->left + i, DestRect->top + j, Brush->iSolidColor);
131 }
132 c8++;
133 if (8 == c8)
134 {
135 lMask++;
136 c8=0;
137 }
138 }
139 tMask += Mask->lDelta;
140 }
141 return TRUE;
142 }
143 else
144 {
145 return FALSE;
146 }
147 }
148
149 static BOOLEAN STDCALL
150 BltPatCopy(SURFOBJ* Dest,
151 SURFGDI* DestGDI,
152 SURFOBJ* Source,
153 SURFGDI* SourceGDI,
154 SURFOBJ* Mask,
155 XLATEOBJ* ColorTranslation,
156 RECTL* DestRect,
157 POINTL* SourcePoint,
158 POINTL* MaskPoint,
159 BRUSHOBJ* Brush,
160 POINTL* BrushPoint,
161 ROP4 Rop4)
162 {
163 // These functions are assigned if we're working with a DIB
164 // The assigned functions depend on the bitsPerPixel of the DIB
165 LONG y;
166 ULONG LineWidth;
167
168 LineWidth = DestRect->right - DestRect->left;
169 for (y = DestRect->top; y < DestRect->bottom; y++)
170 {
171 DestGDI->DIB_HLine(Dest, DestRect->left, DestRect->right, y, Brush->iSolidColor);
172 }
173
174 return TRUE;
175 }
176
177 static BOOLEAN STDCALL
178 CallDibBitBlt(SURFOBJ* OutputObj,
179 SURFGDI* OutputGDI,
180 SURFOBJ* InputObj,
181 SURFGDI* InputGDI,
182 SURFOBJ* Mask,
183 XLATEOBJ* ColorTranslation,
184 RECTL* OutputRect,
185 POINTL* InputPoint,
186 POINTL* MaskOrigin,
187 BRUSHOBJ* Brush,
188 POINTL* BrushOrigin,
189 ROP4 Rop4)
190 {
191 return OutputGDI->DIB_BitBlt(OutputObj, InputObj, OutputGDI, InputGDI, OutputRect, InputPoint, Brush, BrushOrigin, ColorTranslation, Rop4);
192 }
193
194 INT abs(INT nm);
195
196 /*
197 * @implemented
198 */
199 BOOL STDCALL
200 EngBitBlt(SURFOBJ *DestObj,
201 SURFOBJ *SourceObj,
202 SURFOBJ *Mask,
203 CLIPOBJ *ClipRegion,
204 XLATEOBJ *ColorTranslation,
205 RECTL *DestRect,
206 POINTL *SourcePoint,
207 POINTL *MaskOrigin,
208 BRUSHOBJ *Brush,
209 POINTL *BrushOrigin,
210 ROP4 Rop4)
211 {
212 BYTE clippingType;
213 RECTL CombinedRect;
214 RECT_ENUM RectEnum;
215 BOOL EnumMore;
216 SURFGDI* OutputGDI;
217 SURFGDI* InputGDI;
218 POINTL InputPoint;
219 RECTL InputRect;
220 RECTL OutputRect;
221 POINTL Translate;
222 INTENG_ENTER_LEAVE EnterLeaveSource;
223 INTENG_ENTER_LEAVE EnterLeaveDest;
224 SURFOBJ* InputObj;
225 SURFOBJ* OutputObj;
226 PBLTRECTFUNC BltRectFunc;
227 BOOLEAN Ret;
228 RECTL ClipRect;
229 unsigned i;
230 POINTL Pt;
231 ULONG Direction;
232 BOOL UsesSource;
233 BOOL UsesPattern;
234
235 UsesSource = ((Rop4 & 0xCC0000) >> 2) != (Rop4 & 0x330000);
236 UsesPattern = ((Rop4 & 0xF00000) >> 4) != (Rop4 & 0x0F0000);
237 if (ROP_NOOP == Rop4)
238 {
239 /* Copy destination onto itself: nop */
240 return TRUE;
241 }
242
243 if (NULL != SourcePoint)
244 {
245 InputRect.left = SourcePoint->x;
246 InputRect.right = SourcePoint->x + (DestRect->right - DestRect->left);
247 InputRect.top = SourcePoint->y;
248 InputRect.bottom = SourcePoint->y + (DestRect->bottom - DestRect->top);
249 }
250 else
251 {
252 InputRect.left = 0;
253 InputRect.right = DestRect->right - DestRect->left;
254 InputRect.top = 0;
255 InputRect.bottom = DestRect->bottom - DestRect->top;
256 }
257
258 if (! IntEngEnter(&EnterLeaveSource, SourceObj, &InputRect, TRUE, &Translate, &InputObj))
259 {
260 return FALSE;
261 }
262
263 if (NULL != SourcePoint)
264 {
265 InputPoint.x = SourcePoint->x + Translate.x;
266 InputPoint.y = SourcePoint->y + Translate.y;
267 }
268 else
269 {
270 InputPoint.x = 0;
271 InputPoint.y = 0;
272 }
273
274 if (NULL != InputObj)
275 {
276 InputGDI = (SURFGDI*) AccessInternalObjectFromUserObject(InputObj);
277 }
278 else
279 {
280 InputGDI = NULL;
281 }
282
283 OutputRect = *DestRect;
284 if (NULL != ClipRegion)
285 {
286 if (OutputRect.left < ClipRegion->rclBounds.left)
287 {
288 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
289 InputPoint.x += ClipRegion->rclBounds.left - OutputRect.left;
290 OutputRect.left = ClipRegion->rclBounds.left;
291 }
292 if (ClipRegion->rclBounds.right < OutputRect.right)
293 {
294 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
295 OutputRect.right = ClipRegion->rclBounds.right;
296 }
297 if (OutputRect.top < ClipRegion->rclBounds.top)
298 {
299 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
300 InputPoint.y += ClipRegion->rclBounds.top - OutputRect.top;
301 OutputRect.top = ClipRegion->rclBounds.top;
302 }
303 if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
304 {
305 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
306 OutputRect.bottom = ClipRegion->rclBounds.bottom;
307 }
308 }
309
310 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
311 nothing to do */
312 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
313 {
314 IntEngLeave(&EnterLeaveSource);
315 return TRUE;
316 }
317
318 if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate, &OutputObj))
319 {
320 IntEngLeave(&EnterLeaveSource);
321 return FALSE;
322 }
323
324 OutputRect.left = DestRect->left + Translate.x;
325 OutputRect.right = DestRect->right + Translate.x;
326 OutputRect.top = DestRect->top + Translate.y;
327 OutputRect.bottom = DestRect->bottom + Translate.y;
328
329 if (NULL != OutputObj)
330 {
331 OutputGDI = (SURFGDI*)AccessInternalObjectFromUserObject(OutputObj);
332 }
333
334 // Determine clipping type
335 if (ClipRegion == (CLIPOBJ *) NULL)
336 {
337 clippingType = DC_TRIVIAL;
338 } else {
339 clippingType = ClipRegion->iDComplexity;
340 }
341
342 if (0xaacc == Rop4)
343 {
344 BltRectFunc = BltMask;
345 }
346 else if (PATCOPY == Rop4)
347 {
348 BltRectFunc = BltPatCopy;
349 }
350 else
351 {
352 BltRectFunc = CallDibBitBlt;
353 }
354
355
356 switch(clippingType)
357 {
358 case DC_TRIVIAL:
359 Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
360 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin, Rop4);
361 break;
362 case DC_RECT:
363 // Clip the blt to the clip rectangle
364 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
365 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
366 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
367 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
368 EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
369 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
370 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
371 Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
372 &CombinedRect, &Pt, MaskOrigin, Brush, BrushOrigin, Rop4);
373 break;
374 case DC_COMPLEX:
375 Ret = TRUE;
376 if (OutputObj == InputObj)
377 {
378 if (OutputRect.top < InputPoint.y)
379 {
380 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
381 }
382 else
383 {
384 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
385 }
386 }
387 else
388 {
389 Direction = CD_ANY;
390 }
391 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
392 do
393 {
394 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
395
396 for (i = 0; i < RectEnum.c; i++)
397 {
398 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
399 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
400 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
401 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
402 EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
403 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
404 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
405 Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
406 &CombinedRect, &Pt, MaskOrigin, Brush, BrushOrigin, Rop4) &&
407 Ret;
408 }
409 }
410 while(EnumMore);
411 break;
412 }
413
414
415 IntEngLeave(&EnterLeaveDest);
416 IntEngLeave(&EnterLeaveSource);
417
418 return Ret;
419 }
420
421 BOOL STDCALL
422 IntEngBitBlt(SURFOBJ *DestObj,
423 SURFOBJ *SourceObj,
424 SURFOBJ *Mask,
425 CLIPOBJ *ClipRegion,
426 XLATEOBJ *ColorTranslation,
427 RECTL *DestRect,
428 POINTL *SourcePoint,
429 POINTL *MaskOrigin,
430 BRUSHOBJ *Brush,
431 POINTL *BrushOrigin,
432 ROP4 Rop4)
433 {
434 BOOLEAN ret;
435 SURFGDI *DestGDI;
436 SURFGDI *SourceGDI;
437 RECTL InputClippedRect;
438 RECTL OutputRect;
439 POINTL InputPoint;
440 BOOLEAN UsesSource;
441
442 InputClippedRect = *DestRect;
443 if (InputClippedRect.right < InputClippedRect.left)
444 {
445 InputClippedRect.left = DestRect->right;
446 InputClippedRect.right = DestRect->left;
447 }
448 if (InputClippedRect.bottom < InputClippedRect.top)
449 {
450 InputClippedRect.top = DestRect->bottom;
451 InputClippedRect.bottom = DestRect->top;
452 }
453 UsesSource = ((Rop4 & 0xCC0000) >> 2) != (Rop4 & 0x330000);
454 if (UsesSource)
455 {
456 if (NULL == SourcePoint || NULL == SourceObj)
457 {
458 return FALSE;
459 }
460 InputPoint = *SourcePoint;
461 SourceGDI = (SURFGDI*) AccessInternalObjectFromUserObject(SourceObj);
462
463 /* Make sure we don't try to copy anything outside the valid source region */
464 if (InputPoint.x < 0)
465 {
466 InputClippedRect.left -= InputPoint.x;
467 InputPoint.x = 0;
468 }
469 if (InputPoint.y < 0)
470 {
471 InputClippedRect.top -= InputPoint.y;
472 InputPoint.y = 0;
473 }
474 if (SourceObj->sizlBitmap.cx < InputPoint.x + InputClippedRect.right - InputClippedRect.left)
475 {
476 InputClippedRect.right = InputClippedRect.left + SourceObj->sizlBitmap.cx - InputPoint.x;
477 }
478 if (SourceObj->sizlBitmap.cy < InputPoint.y + InputClippedRect.bottom - InputClippedRect.top)
479 {
480 InputClippedRect.bottom = InputClippedRect.top + SourceObj->sizlBitmap.cy - InputPoint.y;
481 }
482
483 if (InputClippedRect.right < InputClippedRect.left ||
484 InputClippedRect.bottom < InputClippedRect.top)
485 {
486 /* Everything clipped away, nothing to do */
487 return TRUE;
488 }
489 }
490
491 /* Clip against the bounds of the clipping region so we won't try to write
492 * outside the surface */
493 if (NULL != ClipRegion)
494 {
495 if (! EngIntersectRect(&OutputRect, &InputClippedRect, &ClipRegion->rclBounds))
496 {
497 return TRUE;
498 }
499 InputPoint.x += OutputRect.left - DestRect->left;
500 InputPoint.y += OutputRect.top - DestRect->top;
501 }
502 else
503 {
504 OutputRect = InputClippedRect;
505 }
506
507 if (UsesSource)
508 {
509 MouseSafetyOnDrawStart(SourceObj, SourceGDI, InputPoint.x, InputPoint.y,
510 (InputPoint.x + abs(DestRect->right - DestRect->left)),
511 (InputPoint.y + abs(DestRect->bottom - DestRect->top)));
512 }
513
514 /* No success yet */
515 ret = FALSE;
516 DestGDI = (SURFGDI*)AccessInternalObjectFromUserObject(DestObj);
517 MouseSafetyOnDrawStart(DestObj, DestGDI, OutputRect.left, OutputRect.top,
518 OutputRect.right, OutputRect.bottom);
519
520 /* Call the driver's DrvBitBlt if available */
521 if (NULL != DestGDI->BitBlt)
522 {
523 IntLockGDIDriver(DestGDI);
524 ret = DestGDI->BitBlt(DestObj, SourceObj, Mask, ClipRegion, ColorTranslation,
525 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin,
526 Rop4);
527 IntUnLockGDIDriver(DestGDI);
528 }
529
530 if (! ret)
531 {
532 ret = EngBitBlt(DestObj, SourceObj, Mask, ClipRegion, ColorTranslation,
533 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin,
534 Rop4);
535 }
536
537 MouseSafetyOnDrawEnd(DestObj, DestGDI);
538 if (UsesSource)
539 {
540 MouseSafetyOnDrawEnd(SourceObj, SourceGDI);
541 }
542
543 return ret;
544 }
545
546 static BOOLEAN STDCALL
547 CallDibStretchBlt(SURFOBJ* OutputObj,
548 SURFGDI* OutputGDI,
549 SURFOBJ* InputObj,
550 SURFGDI* InputGDI,
551 SURFOBJ* Mask,
552 XLATEOBJ* ColorTranslation,
553 RECTL* OutputRect,
554 RECTL* InputRect,
555 POINTL* MaskOrigin,
556 POINTL* BrushOrigin,
557 ULONG Mode)
558 {
559 return OutputGDI->DIB_StretchBlt(OutputObj, InputObj, OutputGDI, InputGDI, OutputRect, InputRect, MaskOrigin, BrushOrigin, ColorTranslation, Mode);
560 }
561
562
563 BOOL
564 STDCALL
565 EngStretchBlt(
566 IN SURFOBJ *DestObj,
567 IN SURFOBJ *SourceObj,
568 IN SURFOBJ *Mask,
569 IN CLIPOBJ *ClipRegion,
570 IN XLATEOBJ *ColorTranslation,
571 IN COLORADJUSTMENT *pca,
572 IN POINTL *BrushOrigin,
573 IN RECTL *prclDest,
574 IN RECTL *prclSrc,
575 IN POINTL *MaskOrigin,
576 IN ULONG Mode
577 )
578 {
579 // www.osr.com/ddk/graphics/gdifncs_0bs7.htm
580
581 BYTE clippingType;
582 RECTL CombinedRect;
583 // RECT_ENUM RectEnum;
584 // BOOL EnumMore;
585 SURFGDI* OutputGDI;
586 SURFGDI* InputGDI;
587 POINTL InputPoint;
588 RECTL InputRect;
589 RECTL OutputRect;
590 POINTL Translate;
591 INTENG_ENTER_LEAVE EnterLeaveSource;
592 INTENG_ENTER_LEAVE EnterLeaveDest;
593 SURFOBJ* InputObj;
594 SURFOBJ* OutputObj;
595 PSTRETCHRECTFUNC BltRectFunc;
596 BOOLEAN Ret;
597 RECTL ClipRect;
598 // unsigned i;
599 POINTL Pt;
600 // ULONG Direction;
601
602 InputRect.left = prclSrc->left;
603 InputRect.right = prclSrc->right;
604 InputRect.top = prclSrc->top;
605 InputRect.bottom = prclSrc->bottom;
606
607 if (! IntEngEnter(&EnterLeaveSource, SourceObj, &InputRect, TRUE, &Translate, &InputObj))
608 {
609 return FALSE;
610 }
611
612 InputPoint.x = InputRect.left + Translate.x;
613 InputPoint.y = InputRect.top + Translate.y;
614
615 if (NULL != InputObj)
616 {
617 InputGDI = (SURFGDI*) AccessInternalObjectFromUserObject(InputObj);
618 }
619 else
620 {
621 InputGDI = NULL;
622 }
623
624 OutputRect = *prclDest;
625 if (NULL != ClipRegion)
626 {
627 if (OutputRect.left < ClipRegion->rclBounds.left)
628 {
629 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
630 InputPoint.x += ClipRegion->rclBounds.left - OutputRect.left;
631 OutputRect.left = ClipRegion->rclBounds.left;
632 }
633 if (ClipRegion->rclBounds.right < OutputRect.right)
634 {
635 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
636 OutputRect.right = ClipRegion->rclBounds.right;
637 }
638 if (OutputRect.top < ClipRegion->rclBounds.top)
639 {
640 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
641 InputPoint.y += ClipRegion->rclBounds.top - OutputRect.top;
642 OutputRect.top = ClipRegion->rclBounds.top;
643 }
644 if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
645 {
646 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
647 OutputRect.bottom = ClipRegion->rclBounds.bottom;
648 }
649 }
650
651 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
652 nothing to do */
653 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
654 {
655 IntEngLeave(&EnterLeaveSource);
656 return TRUE;
657 }
658
659 if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate, &OutputObj))
660 {
661 IntEngLeave(&EnterLeaveSource);
662 return FALSE;
663 }
664
665 OutputRect.left = prclDest->left + Translate.x;
666 OutputRect.right = prclDest->right + Translate.x;
667 OutputRect.top = prclDest->top + Translate.y;
668 OutputRect.bottom = prclDest->bottom + Translate.y;
669
670 if (NULL != OutputObj)
671 {
672 OutputGDI = (SURFGDI*)AccessInternalObjectFromUserObject(OutputObj);
673 }
674
675 // Determine clipping type
676 if (ClipRegion == (CLIPOBJ *) NULL)
677 {
678 clippingType = DC_TRIVIAL;
679 } else {
680 clippingType = ClipRegion->iDComplexity;
681 }
682
683 if (Mask != NULL)//(0xaacc == Rop4)
684 {
685 //BltRectFunc = BltMask;
686 DPRINT("EngStretchBlt isn't capable of handling mask yet.\n");
687 IntEngLeave(&EnterLeaveDest);
688 IntEngLeave(&EnterLeaveSource);
689
690 return FALSE;
691 }
692 else
693 {
694 BltRectFunc = CallDibStretchBlt;
695 }
696
697
698 switch(clippingType)
699 {
700 case DC_TRIVIAL:
701 Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
702 &OutputRect, &InputRect, MaskOrigin, BrushOrigin, Mode);
703 break;
704 case DC_RECT:
705 // Clip the blt to the clip rectangle
706 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
707 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
708 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
709 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
710 EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
711 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
712 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
713 Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
714 &OutputRect, &InputRect, MaskOrigin, BrushOrigin, Mode);
715 //Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
716 // &CombinedRect, &Pt, MaskOrigin, Brush, BrushOrigin, Rop4);
717 DPRINT("EngStretchBlt() doesn't support DC_RECT clipping yet, so blitting w/o clip.\n");
718 break;
719 // TODO: Complex clipping
720 /*
721 case DC_COMPLEX:
722 Ret = TRUE;
723 if (OutputObj == InputObj)
724 {
725 if (OutputRect.top < InputPoint.y)
726 {
727 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
728 }
729 else
730 {
731 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
732 }
733 }
734 else
735 {
736 Direction = CD_ANY;
737 }
738 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
739 do
740 {
741 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
742
743 for (i = 0; i < RectEnum.c; i++)
744 {
745 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
746 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
747 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
748 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
749 EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
750 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
751 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
752 Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
753 &CombinedRect, &Pt, MaskOrigin, Brush, BrushOrigin, Rop4) &&
754 Ret;
755 }
756 }
757 while(EnumMore);
758 break;
759 */
760 }
761
762
763 IntEngLeave(&EnterLeaveDest);
764 IntEngLeave(&EnterLeaveSource);
765
766 return Ret;
767 }
768
769 BOOL STDCALL
770 IntEngStretchBlt(SURFOBJ *DestObj,
771 SURFOBJ *SourceObj,
772 SURFOBJ *Mask,
773 CLIPOBJ *ClipRegion,
774 XLATEOBJ *ColorTranslation,
775 RECTL *DestRect,
776 RECTL *SourceRect,
777 POINTL *pMaskOrigin,
778 BRUSHOBJ *Brush,
779 POINTL *BrushOrigin,
780 ULONG Mode)
781 {
782 BOOLEAN ret;
783 SURFGDI *DestGDI;
784 SURFGDI *SourceGDI;
785 RECTL OutputRect;
786 RECTL InputRect;
787 COLORADJUSTMENT ca;
788 POINT MaskOrigin;
789
790 if (pMaskOrigin != NULL)
791 {
792 MaskOrigin.x = pMaskOrigin->x; MaskOrigin.y = pMaskOrigin->y;
793 }
794
795 if (NULL != SourceRect)
796 {
797 InputRect = *SourceRect;
798 }
799
800 // FIXME: Clipping is taken from IntEngBitBlt w/o modifications!
801
802 /* Clip against the bounds of the clipping region so we won't try to write
803 * outside the surface */
804 if (NULL != ClipRegion)
805 {
806 if (! EngIntersectRect(&OutputRect, DestRect, &ClipRegion->rclBounds))
807 {
808 return TRUE;
809 }
810 DPRINT("Clipping isn't handled in IntEngStretchBlt() correctly yet\n");
811 //InputPoint.x += OutputRect.left - DestRect->left;
812 //InputPoint.y += OutputRect.top - DestRect->top;
813 }
814 else
815 {
816 OutputRect = *DestRect;
817 }
818
819 if (NULL != SourceObj)
820 {
821 SourceGDI = (SURFGDI*) AccessInternalObjectFromUserObject(SourceObj);
822 MouseSafetyOnDrawStart(SourceObj, SourceGDI, InputRect.left, InputRect.top,
823 (InputRect.left + abs(InputRect.right - InputRect.left)),
824 (InputRect.top + abs(InputRect.bottom - InputRect.top)));
825 }
826
827 /* No success yet */
828 ret = FALSE;
829 DestGDI = (SURFGDI*)AccessInternalObjectFromUserObject(DestObj);
830 MouseSafetyOnDrawStart(DestObj, DestGDI, OutputRect.left, OutputRect.top,
831 OutputRect.right, OutputRect.bottom);
832
833 /* Prepare color adjustment */
834
835 /* Call the driver's DrvStretchBlt if available */
836 if (NULL != DestGDI->StretchBlt)
837 {
838 /* Drv->StretchBlt (look at http://www.osr.com/ddk/graphics/ddifncs_3ew7.htm )
839 SURFOBJ *psoMask // optional, if it exists, then rop4=0xCCAA, otherwise rop4=0xCCCC */
840 // FIXME: MaskOrigin is always NULL !
841 IntLockGDIDriver(DestGDI);
842 ret = DestGDI->StretchBlt(DestObj, SourceObj, Mask, ClipRegion, ColorTranslation,
843 &ca, BrushOrigin, &OutputRect, &InputRect, NULL, Mode);
844 IntUnLockGDIDriver(DestGDI);
845 }
846
847 if (! ret)
848 {
849 // FIXME: see previous fixme
850 ret = EngStretchBlt(DestObj, SourceObj, Mask, ClipRegion, ColorTranslation,
851 &ca, BrushOrigin, &OutputRect, &InputRect, NULL, Mode);
852 }
853
854 MouseSafetyOnDrawEnd(DestObj, DestGDI);
855 if (NULL != SourceObj)
856 {
857 MouseSafetyOnDrawEnd(SourceObj, SourceGDI);
858 }
859
860 return ret;
861 }
862
863 /**** REACTOS FONT RENDERING CODE *********************************************/
864
865 /* renders the alpha mask bitmap */
866 static BOOLEAN STDCALL
867 AlphaBltMask(SURFOBJ* Dest,
868 SURFGDI* DestGDI,
869 SURFOBJ* Source,
870 SURFGDI* SourceGDI,
871 SURFOBJ* Mask,
872 XLATEOBJ* ColorTranslation,
873 XLATEOBJ* SrcColorTranslation,
874 RECTL* DestRect,
875 POINTL* SourcePoint,
876 POINTL* MaskPoint,
877 BRUSHOBJ* Brush,
878 POINTL* BrushPoint)
879 {
880 LONG i, j, dx, dy;
881 int r, g, b;
882 ULONG Background, BrushColor, NewColor;
883 BYTE *tMask, *lMask;
884
885 dx = DestRect->right - DestRect->left;
886 dy = DestRect->bottom - DestRect->top;
887
888 if (Mask != NULL)
889 {
890 BrushColor = XLATEOBJ_iXlate(SrcColorTranslation, Brush->iSolidColor);
891 r = (int)GetRValue(BrushColor);
892 g = (int)GetGValue(BrushColor);
893 b = (int)GetBValue(BrushColor);
894
895 tMask = Mask->pvBits + MaskPoint->y * Mask->lDelta + MaskPoint->x;
896 for (j = 0; j < dy; j++)
897 {
898 lMask = tMask;
899 for (i = 0; i < dx; i++)
900 {
901 if (*lMask > 0)
902 {
903 if(*lMask == 0xff)
904 {
905 DestGDI->DIB_PutPixel(Dest, DestRect->left + i, DestRect->top + j, Brush->iSolidColor);
906 }
907 else
908 {
909 Background = DIB_GetSource(Dest, DestGDI, DestRect->left + i, DestRect->top + j, SrcColorTranslation);
910
911 NewColor =
912 RGB((*lMask * (r - GetRValue(Background)) >> 8) + GetRValue(Background),
913 (*lMask * (g - GetGValue(Background)) >> 8) + GetGValue(Background),
914 (*lMask * (b - GetBValue(Background)) >> 8) + GetBValue(Background));
915
916 Background = XLATEOBJ_iXlate(ColorTranslation, NewColor);
917 DestGDI->DIB_PutPixel(Dest, DestRect->left + i, DestRect->top + j, Background);
918 }
919 }
920 lMask++;
921 }
922 tMask += Mask->lDelta;
923 }
924 return TRUE;
925 }
926 else
927 {
928 return FALSE;
929 }
930 }
931
932 BOOL STDCALL
933 EngMaskBitBlt(SURFOBJ *DestObj,
934 SURFOBJ *Mask,
935 CLIPOBJ *ClipRegion,
936 XLATEOBJ *DestColorTranslation,
937 XLATEOBJ *SourceColorTranslation,
938 RECTL *DestRect,
939 POINTL *SourcePoint,
940 POINTL *MaskOrigin,
941 BRUSHOBJ *Brush,
942 POINTL *BrushOrigin)
943 {
944 BYTE clippingType;
945 RECTL CombinedRect;
946 RECT_ENUM RectEnum;
947 BOOL EnumMore;
948 SURFGDI* OutputGDI;
949 SURFGDI* InputGDI;
950 POINTL InputPoint;
951 RECTL InputRect;
952 RECTL OutputRect;
953 POINTL Translate;
954 INTENG_ENTER_LEAVE EnterLeaveSource;
955 INTENG_ENTER_LEAVE EnterLeaveDest;
956 SURFOBJ* InputObj;
957 SURFOBJ* OutputObj;
958 BOOLEAN Ret;
959 RECTL ClipRect;
960 unsigned i;
961 POINTL Pt;
962 ULONG Direction;
963 SURFGDI* DestGDI;
964
965 if (NULL != SourcePoint)
966 {
967 InputRect.left = SourcePoint->x;
968 InputRect.right = SourcePoint->x + (DestRect->right - DestRect->left);
969 InputRect.top = SourcePoint->y;
970 InputRect.bottom = SourcePoint->y + (DestRect->bottom - DestRect->top);
971 }
972 else
973 {
974 InputRect.left = 0;
975 InputRect.right = DestRect->right - DestRect->left;
976 InputRect.top = 0;
977 InputRect.bottom = DestRect->bottom - DestRect->top;
978 }
979
980 DestGDI = (SURFGDI*)AccessInternalObjectFromUserObject(DestObj);
981 IntLockGDIDriver(DestGDI);
982 if (! IntEngEnter(&EnterLeaveSource, NULL, &InputRect, TRUE, &Translate, &InputObj))
983 {
984 IntUnLockGDIDriver(DestGDI);
985 return FALSE;
986 }
987
988 if (NULL != SourcePoint)
989 {
990 InputPoint.x = SourcePoint->x + Translate.x;
991 InputPoint.y = SourcePoint->y + Translate.y;
992 }
993 else
994 {
995 InputPoint.x = 0;
996 InputPoint.y = 0;
997 }
998
999 if (NULL != InputObj)
1000 {
1001 InputGDI = (SURFGDI*) AccessInternalObjectFromUserObject(InputObj);
1002 }
1003 else
1004 {
1005 InputGDI = NULL;
1006 }
1007
1008 OutputRect = *DestRect;
1009 if (NULL != ClipRegion)
1010 {
1011 if (OutputRect.left < ClipRegion->rclBounds.left)
1012 {
1013 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
1014 InputPoint.x += ClipRegion->rclBounds.left - OutputRect.left;
1015 OutputRect.left = ClipRegion->rclBounds.left;
1016 }
1017 if (ClipRegion->rclBounds.right < OutputRect.right)
1018 {
1019 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
1020 OutputRect.right = ClipRegion->rclBounds.right;
1021 }
1022 if (OutputRect.top < ClipRegion->rclBounds.top)
1023 {
1024 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
1025 InputPoint.y += ClipRegion->rclBounds.top - OutputRect.top;
1026 OutputRect.top = ClipRegion->rclBounds.top;
1027 }
1028 if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
1029 {
1030 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
1031 OutputRect.bottom = ClipRegion->rclBounds.bottom;
1032 }
1033 }
1034
1035 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
1036 nothing to do */
1037 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
1038 {
1039 IntEngLeave(&EnterLeaveSource);
1040 IntUnLockGDIDriver(DestGDI);
1041 return TRUE;
1042 }
1043
1044 if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate, &OutputObj))
1045 {
1046 IntEngLeave(&EnterLeaveSource);
1047 IntUnLockGDIDriver(DestGDI);
1048 return FALSE;
1049 }
1050
1051 OutputRect.left = DestRect->left + Translate.x;
1052 OutputRect.right = DestRect->right + Translate.x;
1053 OutputRect.top = DestRect->top + Translate.y;
1054 OutputRect.bottom = DestRect->bottom + Translate.y;
1055
1056 if (NULL != OutputObj)
1057 {
1058 OutputGDI = (SURFGDI*)AccessInternalObjectFromUserObject(OutputObj);
1059 }
1060
1061 // Determine clipping type
1062 if (ClipRegion == (CLIPOBJ *) NULL)
1063 {
1064 clippingType = DC_TRIVIAL;
1065 } else {
1066 clippingType = ClipRegion->iDComplexity;
1067 }
1068
1069 switch(clippingType)
1070 {
1071 case DC_TRIVIAL:
1072 if(Mask->iBitmapFormat == BMF_8BPP)
1073 Ret = AlphaBltMask(OutputObj, OutputGDI, InputObj, InputGDI, Mask, DestColorTranslation, SourceColorTranslation,
1074 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin);
1075 else
1076 Ret = BltMask(OutputObj, OutputGDI, InputObj, InputGDI, Mask, DestColorTranslation,
1077 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin, 0xAACC);
1078 break;
1079 case DC_RECT:
1080 // Clip the blt to the clip rectangle
1081 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
1082 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
1083 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
1084 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
1085 EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
1086 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
1087 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
1088 if(Mask->iBitmapFormat == BMF_8BPP)
1089 Ret = AlphaBltMask(OutputObj, OutputGDI, InputObj, InputGDI, Mask, DestColorTranslation, SourceColorTranslation,
1090 &CombinedRect, &Pt, MaskOrigin, Brush, BrushOrigin);
1091 else
1092 Ret = BltMask(OutputObj, OutputGDI, InputObj, InputGDI, Mask, DestColorTranslation,
1093 &CombinedRect, &Pt, MaskOrigin, Brush, BrushOrigin, 0xAACC);
1094 break;
1095 case DC_COMPLEX:
1096 Ret = TRUE;
1097 if (OutputObj == InputObj)
1098 {
1099 if (OutputRect.top < InputPoint.y)
1100 {
1101 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
1102 }
1103 else
1104 {
1105 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
1106 }
1107 }
1108 else
1109 {
1110 Direction = CD_ANY;
1111 }
1112 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
1113 do
1114 {
1115 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
1116
1117 for (i = 0; i < RectEnum.c; i++)
1118 {
1119 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
1120 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
1121 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
1122 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
1123 EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
1124 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
1125 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
1126 if(Mask->iBitmapFormat == BMF_8BPP)
1127 Ret = AlphaBltMask(OutputObj, OutputGDI, InputObj, InputGDI, Mask, DestColorTranslation, SourceColorTranslation,
1128 &CombinedRect, &Pt, MaskOrigin, Brush, BrushOrigin) && Ret;
1129 else
1130 Ret = BltMask(OutputObj, OutputGDI, InputObj, InputGDI, Mask, DestColorTranslation,
1131 &CombinedRect, &Pt, MaskOrigin, Brush, BrushOrigin, 0xAACC) && Ret;
1132 }
1133 }
1134 while(EnumMore);
1135 break;
1136 }
1137
1138
1139 IntEngLeave(&EnterLeaveDest);
1140 IntEngLeave(&EnterLeaveSource);
1141
1142 IntUnLockGDIDriver(DestGDI);
1143
1144 /* Dummy BitBlt to let driver know that something has changed.
1145 0x00AA0029 is the Rop for D (no-op) */
1146 IntEngBitBlt(DestObj, NULL, Mask, ClipRegion, DestColorTranslation,
1147 DestRect, SourcePoint, MaskOrigin, Brush, BrushOrigin, ROP_NOOP);
1148
1149 return Ret;
1150 }
1151
1152 BOOL STDCALL
1153 IntEngMaskBlt(SURFOBJ *DestObj,
1154 SURFOBJ *Mask,
1155 CLIPOBJ *ClipRegion,
1156 XLATEOBJ *DestColorTranslation,
1157 XLATEOBJ *SourceColorTranslation,
1158 RECTL *DestRect,
1159 POINTL *SourcePoint,
1160 POINTL *MaskOrigin,
1161 BRUSHOBJ *Brush,
1162 POINTL *BrushOrigin)
1163 {
1164 BOOLEAN ret;
1165 SURFGDI *DestGDI;
1166 RECTL OutputRect;
1167 POINTL InputPoint;
1168
1169 if (NULL != SourcePoint)
1170 {
1171 InputPoint = *SourcePoint;
1172 }
1173
1174 /* Clip against the bounds of the clipping region so we won't try to write
1175 * outside the surface */
1176 if (NULL != ClipRegion)
1177 {
1178 if (! EngIntersectRect(&OutputRect, DestRect, &ClipRegion->rclBounds))
1179 {
1180 return TRUE;
1181 }
1182 InputPoint.x += OutputRect.left - DestRect->left;
1183 InputPoint.y += OutputRect.top - DestRect->top;
1184 }
1185 else
1186 {
1187 OutputRect = *DestRect;
1188 }
1189
1190 /* No success yet */
1191 ret = FALSE;
1192 DestGDI = (SURFGDI*)AccessInternalObjectFromUserObject(DestObj);
1193 MouseSafetyOnDrawStart(DestObj, DestGDI, OutputRect.left, OutputRect.top,
1194 OutputRect.right, OutputRect.bottom);
1195
1196 ret = EngMaskBitBlt(DestObj, Mask, ClipRegion, DestColorTranslation, SourceColorTranslation,
1197 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin);
1198
1199 MouseSafetyOnDrawEnd(DestObj, DestGDI);
1200
1201 return ret;
1202 }
1203 /* EOF */