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