EngMaskBitBlt and IntEngMaskBlt do not have a source surface, so it makes no sense...
[reactos.git] / reactos / subsystems / win32 / 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 <w32k.h>
31
32 #define NDEBUG
33 #include <debug.h>
34
35 typedef BOOLEAN (APIENTRY *PBLTRECTFUNC)(SURFOBJ* OutputObj,
36 SURFOBJ* InputObj,
37 SURFOBJ* Mask,
38 XLATEOBJ* ColorTranslation,
39 RECTL* OutputRect,
40 POINTL* InputPoint,
41 POINTL* MaskOrigin,
42 BRUSHOBJ* pbo,
43 POINTL* BrushOrigin,
44 ROP4 Rop4);
45 typedef BOOLEAN (APIENTRY *PSTRETCHRECTFUNC)(SURFOBJ* OutputObj,
46 SURFOBJ* InputObj,
47 SURFOBJ* Mask,
48 XLATEOBJ* ColorTranslation,
49 RECTL* OutputRect,
50 RECTL* InputRect,
51 POINTL* MaskOrigin,
52 BRUSHOBJ* pbo,
53 POINTL* BrushOrigin,
54 ROP4 Rop4);
55
56 BOOL APIENTRY 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 APIENTRY
80 BltMask(SURFOBJ* psoDest,
81 SURFOBJ* psoSource, // unused
82 SURFOBJ* psoMask,
83 XLATEOBJ* ColorTranslation, // unused
84 RECTL* prclDest,
85 POINTL* pptlSource, // unused
86 POINTL* pptlMask,
87 BRUSHOBJ* pbo,
88 POINTL* pptlBrush,
89 ROP4 Rop4)
90 {
91 LONG x, y;
92 BYTE *pjMskLine, *pjMskCurrent;
93 BYTE fjMaskBit0, fjMaskBit;
94 /* Pattern brushes */
95 PEBRUSHOBJ pebo = NULL;
96 SURFOBJ *psoPattern = NULL;
97 PSURFACE psurfPattern;
98 ULONG PatternWidth = 0, PatternHeight = 0;
99 LONG PatternX0 = 0, PatternX = 0, PatternY = 0;
100 PFN_DIB_PutPixel fnDest_PutPixel = NULL;
101 PFN_DIB_GetPixel fnPattern_GetPixel = NULL;
102 XLATEOBJ *XlateObj;
103 ULONG Pattern = 0;
104
105 if (psoMask == NULL)
106 {
107 return FALSE;
108 }
109
110 if (pbo && pbo->iSolidColor == 0xFFFFFFFF)
111 {
112 pebo = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
113
114 psurfPattern = SURFACE_LockSurface(pebo->pbrush->hbmPattern);
115 if (psurfPattern != NULL)
116 {
117 psoPattern = &psurfPattern->SurfObj;
118 PatternWidth = psoPattern->sizlBitmap.cx;
119 PatternHeight = psoPattern->sizlBitmap.cy;
120 }
121 fnPattern_GetPixel = DibFunctionsForBitmapFormat[psoPattern->iBitmapFormat].DIB_GetPixel;
122 }
123 else
124 psurfPattern = NULL;
125
126 pjMskLine = (PBYTE)psoMask->pvScan0 + pptlMask->y * psoMask->lDelta + (pptlMask->x >> 3);
127 fjMaskBit0 = 0x80 >> (pptlMask->x & 0x07);
128
129 fnDest_PutPixel = DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel;
130 if (psurfPattern)
131 {
132 XlateObj = pebo ? pebo->XlateObject : NULL;
133 PatternY = (prclDest->top - pptlBrush->y) % PatternHeight;
134 if (PatternY < 0)
135 {
136 PatternY += PatternHeight;
137 }
138 PatternX0 = (prclDest->left - pptlBrush->x) % PatternWidth;
139 if (PatternX0 < 0)
140 {
141 PatternX0 += PatternWidth;
142 }
143
144 for (y = prclDest->top; y < prclDest->bottom; y++)
145 {
146 pjMskCurrent = pjMskLine;
147 fjMaskBit = fjMaskBit0;
148 PatternX = PatternX0;
149
150 for (x = prclDest->left; x < prclDest->right; x++)
151 {
152 if (*pjMskCurrent & fjMaskBit)
153 {
154 fnDest_PutPixel(psoDest, x, y,
155 XLATEOBJ_iXlate(XlateObj,
156 fnPattern_GetPixel(psoPattern, PatternX, PatternY)));
157 }
158 fjMaskBit = _rotr8(fjMaskBit, 1);
159 pjMskCurrent += (fjMaskBit >> 7);
160 PatternX++;
161 PatternX %= PatternWidth;
162 }
163 pjMskLine += psoMask->lDelta;
164 PatternY++;
165 PatternY %= PatternHeight;
166 }
167 }
168 else
169 {
170 Pattern = pbo ? pbo->iSolidColor : 0;
171 for (y = prclDest->top; y < prclDest->bottom; y++)
172 {
173 pjMskCurrent = pjMskLine;
174 fjMaskBit = fjMaskBit0;
175
176 for (x = prclDest->left; x < prclDest->right; x++)
177 {
178 if (*pjMskCurrent & fjMaskBit)
179 {
180 fnDest_PutPixel(psoDest, x, y, Pattern);
181 }
182 fjMaskBit = _rotr8(fjMaskBit, 1);
183 pjMskCurrent += (fjMaskBit >> 7);
184 }
185 pjMskLine += psoMask->lDelta;
186 }
187 }
188
189 if (psurfPattern)
190 SURFACE_UnlockSurface(psurfPattern);
191
192 return TRUE;
193 }
194
195 static BOOLEAN APIENTRY
196 BltPatCopy(SURFOBJ* Dest,
197 SURFOBJ* Source,
198 SURFOBJ* Mask,
199 XLATEOBJ* ColorTranslation,
200 RECTL* DestRect,
201 POINTL* SourcePoint,
202 POINTL* MaskPoint,
203 BRUSHOBJ* pbo,
204 POINTL* BrushPoint,
205 ROP4 Rop4)
206 {
207 // These functions are assigned if we're working with a DIB
208 // The assigned functions depend on the bitsPerPixel of the DIB
209
210 DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_ColorFill(Dest, DestRect, pbo ? pbo->iSolidColor : 0);
211
212 return TRUE;
213 }
214
215 static BOOLEAN APIENTRY
216 CallDibBitBlt(SURFOBJ* OutputObj,
217 SURFOBJ* InputObj,
218 SURFOBJ* Mask,
219 XLATEOBJ* ColorTranslation,
220 RECTL* OutputRect,
221 POINTL* InputPoint,
222 POINTL* MaskOrigin,
223 BRUSHOBJ* pbo,
224 POINTL* BrushOrigin,
225 ROP4 Rop4)
226 {
227 BLTINFO BltInfo;
228 PEBRUSHOBJ GdiBrush = NULL;
229 SURFACE *psurfPattern;
230 BOOLEAN Result;
231
232 BltInfo.DestSurface = OutputObj;
233 BltInfo.SourceSurface = InputObj;
234 BltInfo.PatternSurface = NULL;
235 BltInfo.XlateSourceToDest = ColorTranslation;
236 BltInfo.DestRect = *OutputRect;
237 BltInfo.SourcePoint = *InputPoint;
238
239 if (ROP3_TO_ROP4(SRCCOPY) == Rop4)
240 return DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_BitBltSrcCopy(&BltInfo);
241
242 BltInfo.XlatePatternToDest = NULL;
243 BltInfo.Brush = pbo;
244 BltInfo.BrushOrigin = *BrushOrigin;
245 BltInfo.Rop4 = Rop4;
246
247 /* Pattern brush */
248 if (ROP4_USES_PATTERN(Rop4) && pbo && pbo->iSolidColor == 0xFFFFFFFF)
249 {
250 GdiBrush = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
251 if ((psurfPattern = SURFACE_LockSurface(GdiBrush->pbrush->hbmPattern)))
252 {
253 BltInfo.PatternSurface = &psurfPattern->SurfObj;
254 }
255 else
256 {
257 /* FIXME - What to do here? */
258 }
259 BltInfo.XlatePatternToDest = GdiBrush->XlateObject;
260 }
261 else
262 {
263 psurfPattern = NULL;
264 }
265
266 Result = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_BitBlt(&BltInfo);
267
268 /* Pattern brush */
269 if (psurfPattern != NULL)
270 {
271 SURFACE_UnlockSurface(psurfPattern);
272 }
273
274 return Result;
275 }
276
277 INT __cdecl abs(INT nm);
278
279
280 /*
281 * @implemented
282 */
283 BOOL APIENTRY
284 NtGdiEngBitBlt(
285 IN SURFOBJ *psoTrg,
286 IN SURFOBJ *psoSrc,
287 IN SURFOBJ *psoMask,
288 IN CLIPOBJ *pco,
289 IN XLATEOBJ *pxlo,
290 IN RECTL *prclTrg,
291 IN POINTL *pptlSrc,
292 IN POINTL *pptlMask,
293 IN BRUSHOBJ *pbo,
294 IN POINTL *pptlBrush,
295 IN ROP4 rop4 )
296 {
297 RECTL rclTrg;
298 POINTL ptlSrc;
299 POINTL ptlMask;
300 POINTL ptlBrush;
301
302 _SEH2_TRY
303 {
304 ProbeForRead(prclTrg, sizeof(RECTL), 1);
305 RtlCopyMemory(&rclTrg,prclTrg, sizeof(RECTL));
306
307 ProbeForRead(pptlSrc, sizeof(POINTL), 1);
308 RtlCopyMemory(&ptlSrc, pptlSrc, sizeof(POINTL));
309
310 ProbeForRead(pptlMask, sizeof(POINTL), 1);
311 RtlCopyMemory(&ptlMask, pptlMask, sizeof(POINTL));
312
313 ProbeForRead(pptlBrush, sizeof(POINTL), 1);
314 RtlCopyMemory(&ptlBrush, pptlBrush, sizeof(POINTL));
315
316 }
317 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
318 {
319 _SEH2_YIELD(return FALSE);
320 }
321 _SEH2_END;
322
323 return EngBitBlt(psoTrg, psoSrc, psoMask, pco, pxlo, &rclTrg, &ptlSrc, &ptlMask, pbo, &ptlBrush, rop4);
324 }
325
326 /*
327 * @implemented
328 */
329 BOOL APIENTRY
330 EngBitBlt(SURFOBJ *DestObj,
331 SURFOBJ *SourceObj,
332 SURFOBJ *Mask,
333 CLIPOBJ *ClipRegion,
334 XLATEOBJ *ColorTranslation,
335 RECTL *DestRect,
336 POINTL *SourcePoint,
337 POINTL *MaskOrigin,
338 BRUSHOBJ *pbo,
339 POINTL *BrushOrigin,
340 ROP4 Rop4)
341 {
342 BYTE clippingType;
343 RECTL CombinedRect;
344 RECT_ENUM RectEnum;
345 BOOL EnumMore;
346 POINTL InputPoint;
347 RECTL InputRect;
348 RECTL OutputRect;
349 POINTL Translate;
350 INTENG_ENTER_LEAVE EnterLeaveSource;
351 INTENG_ENTER_LEAVE EnterLeaveDest;
352 SURFOBJ* InputObj;
353 SURFOBJ* OutputObj;
354 PBLTRECTFUNC BltRectFunc;
355 BOOLEAN Ret = TRUE;
356 RECTL ClipRect;
357 unsigned i;
358 POINTL Pt;
359 ULONG Direction;
360 BOOL UsesSource;
361 BOOL UsesPattern;
362 POINTL AdjustedBrushOrigin;
363
364 UsesSource = ROP4_USES_SOURCE(Rop4);
365 UsesPattern = ROP4_USES_PATTERN(Rop4);
366 if (R4_NOOP == Rop4)
367 {
368 /* Copy destination onto itself: nop */
369 return TRUE;
370 }
371
372 OutputRect = *DestRect;
373 if (OutputRect.right < OutputRect.left)
374 {
375 OutputRect.left = DestRect->right;
376 OutputRect.right = DestRect->left;
377 }
378 if (OutputRect.bottom < OutputRect.top)
379 {
380 OutputRect.left = DestRect->right;
381 OutputRect.right = DestRect->left;
382 }
383
384 if (UsesSource)
385 {
386 if (NULL == SourcePoint)
387 {
388 return FALSE;
389 }
390
391 /* Make sure we don't try to copy anything outside the valid source
392 region */
393 InputPoint = *SourcePoint;
394 if (InputPoint.x < 0)
395 {
396 OutputRect.left -= InputPoint.x;
397 InputPoint.x = 0;
398 }
399 if (InputPoint.y < 0)
400 {
401 OutputRect.top -= InputPoint.y;
402 InputPoint.y = 0;
403 }
404 if (SourceObj->sizlBitmap.cx < InputPoint.x +
405 OutputRect.right - OutputRect.left)
406 {
407 OutputRect.right = OutputRect.left +
408 SourceObj->sizlBitmap.cx - InputPoint.x;
409 }
410 if (SourceObj->sizlBitmap.cy < InputPoint.y +
411 OutputRect.bottom - OutputRect.top)
412 {
413 OutputRect.bottom = OutputRect.top +
414 SourceObj->sizlBitmap.cy - InputPoint.y;
415 }
416
417 InputRect.left = InputPoint.x;
418 InputRect.right = InputPoint.x + (OutputRect.right - OutputRect.left);
419 InputRect.top = InputPoint.y;
420 InputRect.bottom = InputPoint.y + (OutputRect.bottom - OutputRect.top);
421
422 if (! IntEngEnter(&EnterLeaveSource, SourceObj, &InputRect, TRUE,
423 &Translate, &InputObj))
424 {
425 return FALSE;
426 }
427
428 InputPoint.x += Translate.x;
429 InputPoint.y += Translate.y;
430 }
431 else
432 {
433 InputRect.left = 0;
434 InputRect.right = DestRect->right - DestRect->left;
435 InputRect.top = 0;
436 InputRect.bottom = DestRect->bottom - DestRect->top;
437 }
438
439 if (NULL != ClipRegion)
440 {
441 if (OutputRect.left < ClipRegion->rclBounds.left)
442 {
443 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
444 InputPoint.x += ClipRegion->rclBounds.left - OutputRect.left;
445 OutputRect.left = ClipRegion->rclBounds.left;
446 }
447 if (ClipRegion->rclBounds.right < OutputRect.right)
448 {
449 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
450 OutputRect.right = ClipRegion->rclBounds.right;
451 }
452 if (OutputRect.top < ClipRegion->rclBounds.top)
453 {
454 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
455 InputPoint.y += ClipRegion->rclBounds.top - OutputRect.top;
456 OutputRect.top = ClipRegion->rclBounds.top;
457 }
458 if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
459 {
460 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
461 OutputRect.bottom = ClipRegion->rclBounds.bottom;
462 }
463 }
464
465 /* Check for degenerate case: if height or width of OutputRect is 0 pixels
466 there's nothing to do */
467 if (OutputRect.right <= OutputRect.left ||
468 OutputRect.bottom <= OutputRect.top)
469 {
470 if (UsesSource)
471 {
472 IntEngLeave(&EnterLeaveSource);
473 }
474 return TRUE;
475 }
476
477 if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate,
478 &OutputObj))
479 {
480 if (UsesSource)
481 {
482 IntEngLeave(&EnterLeaveSource);
483 }
484 return FALSE;
485 }
486
487 OutputRect.left += Translate.x;
488 OutputRect.right += Translate.x;
489 OutputRect.top += Translate.y;
490 OutputRect.bottom += Translate.y;
491
492 if (BrushOrigin)
493 {
494 AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
495 AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
496 }
497 else
498 {
499 AdjustedBrushOrigin = Translate;
500 }
501
502 /* Determine clipping type */
503 if (ClipRegion == (CLIPOBJ *) NULL)
504 {
505 clippingType = DC_TRIVIAL;
506 }
507 else
508 {
509 clippingType = ClipRegion->iDComplexity;
510 }
511
512 if (R4_MASK == Rop4)
513 {
514 BltRectFunc = BltMask;
515 }
516 else if (ROP3_TO_ROP4(PATCOPY) == Rop4)
517 {
518 if (pbo && pbo->iSolidColor == 0xFFFFFFFF)
519 BltRectFunc = CallDibBitBlt;
520 else
521 BltRectFunc = BltPatCopy;
522 }
523 else
524 {
525 BltRectFunc = CallDibBitBlt;
526 }
527
528
529 switch (clippingType)
530 {
531 case DC_TRIVIAL:
532 Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ColorTranslation,
533 &OutputRect, &InputPoint, MaskOrigin, pbo,
534 &AdjustedBrushOrigin, Rop4);
535 break;
536 case DC_RECT:
537 /* Clip the blt to the clip rectangle */
538 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
539 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
540 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
541 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
542 if (EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
543 {
544 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
545 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
546 Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ColorTranslation,
547 &CombinedRect, &Pt, MaskOrigin, pbo,
548 &AdjustedBrushOrigin, Rop4);
549 }
550 break;
551 case DC_COMPLEX:
552 Ret = TRUE;
553 if (OutputObj == InputObj)
554 {
555 if (OutputRect.top < InputPoint.y)
556 {
557 Direction = OutputRect.left < InputPoint.x ?
558 CD_RIGHTDOWN : CD_LEFTDOWN;
559 }
560 else
561 {
562 Direction = OutputRect.left < InputPoint.x ?
563 CD_RIGHTUP : CD_LEFTUP;
564 }
565 }
566 else
567 {
568 Direction = CD_ANY;
569 }
570 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
571 do
572 {
573 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum),
574 (PVOID) &RectEnum);
575
576 for (i = 0; i < RectEnum.c; i++)
577 {
578 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
579 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
580 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
581 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
582 if (EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
583 {
584 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
585 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
586 Ret = (*BltRectFunc)(OutputObj, InputObj, Mask,
587 ColorTranslation, &CombinedRect, &Pt,
588 MaskOrigin, pbo, &AdjustedBrushOrigin,
589 Rop4) && Ret;
590 }
591 }
592 }
593 while (EnumMore);
594 break;
595 }
596
597
598 IntEngLeave(&EnterLeaveDest);
599 if (UsesSource)
600 {
601 IntEngLeave(&EnterLeaveSource);
602 }
603
604 return Ret;
605 }
606
607 BOOL APIENTRY
608 IntEngBitBltEx(SURFOBJ *psoDest,
609 SURFOBJ *psoSource,
610 SURFOBJ *MaskSurf,
611 CLIPOBJ *ClipRegion,
612 XLATEOBJ *ColorTranslation,
613 RECTL *DestRect,
614 POINTL *SourcePoint,
615 POINTL *MaskOrigin,
616 BRUSHOBJ *pbo,
617 POINTL *BrushOrigin,
618 ROP4 Rop4,
619 BOOL RemoveMouse)
620 {
621 BOOLEAN ret;
622 RECTL InputClippedRect;
623 RECTL OutputRect;
624 POINTL InputPoint;
625 BOOLEAN UsesSource;
626 SURFACE *psurfDest;
627 SURFACE *psurfSource = NULL;
628
629 if (psoDest == NULL)
630 return FALSE;
631
632 psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
633 ASSERT(psurfDest);
634
635 InputClippedRect = *DestRect;
636 if (InputClippedRect.right < InputClippedRect.left)
637 {
638 InputClippedRect.left = DestRect->right;
639 InputClippedRect.right = DestRect->left;
640 }
641 if (InputClippedRect.bottom < InputClippedRect.top)
642 {
643 InputClippedRect.top = DestRect->bottom;
644 InputClippedRect.bottom = DestRect->top;
645 }
646 UsesSource = ROP4_USES_SOURCE(Rop4);
647 if (UsesSource)
648 {
649 if (NULL == SourcePoint || NULL == psoSource)
650 {
651 return FALSE;
652 }
653 InputPoint = *SourcePoint;
654
655 /* Make sure we don't try to copy anything outside the valid source
656 region */
657 if (InputPoint.x < 0)
658 {
659 InputClippedRect.left -= InputPoint.x;
660 InputPoint.x = 0;
661 }
662 if (InputPoint.y < 0)
663 {
664 InputClippedRect.top -= InputPoint.y;
665 InputPoint.y = 0;
666 }
667 if (psoSource->sizlBitmap.cx < InputPoint.x +
668 InputClippedRect.right -
669 InputClippedRect.left)
670 {
671 InputClippedRect.right = InputClippedRect.left +
672 psoSource->sizlBitmap.cx - InputPoint.x;
673 }
674 if (psoSource->sizlBitmap.cy < InputPoint.y +
675 InputClippedRect.bottom -
676 InputClippedRect.top)
677 {
678 InputClippedRect.bottom = InputClippedRect.top +
679 psoSource->sizlBitmap.cy - InputPoint.y;
680 }
681
682 if (InputClippedRect.right < InputClippedRect.left ||
683 InputClippedRect.bottom < InputClippedRect.top)
684 {
685 /* Everything clipped away, nothing to do */
686 return TRUE;
687 }
688 }
689
690 /* Clip against the bounds of the clipping region so we won't try to write
691 * outside the surface */
692 if (NULL != ClipRegion)
693 {
694 if (! EngIntersectRect(&OutputRect, &InputClippedRect,
695 &ClipRegion->rclBounds))
696 {
697 return TRUE;
698 }
699 InputPoint.x += OutputRect.left - InputClippedRect.left;
700 InputPoint.y += OutputRect.top - InputClippedRect.top;
701 }
702 else
703 {
704 OutputRect = InputClippedRect;
705 }
706
707 if (RemoveMouse)
708 {
709 SURFACE_LockBitmapBits(psurfDest);
710
711 if (UsesSource)
712 {
713 if (psoSource != psoDest)
714 {
715 psurfSource = CONTAINING_RECORD(psoSource, SURFACE, SurfObj);
716 SURFACE_LockBitmapBits(psurfSource);
717 }
718 MouseSafetyOnDrawStart(psoSource, InputPoint.x, InputPoint.y,
719 (InputPoint.x + abs(DestRect->right - DestRect->left)),
720 (InputPoint.y + abs(DestRect->bottom - DestRect->top)));
721 }
722 MouseSafetyOnDrawStart(psoDest, OutputRect.left, OutputRect.top,
723 OutputRect.right, OutputRect.bottom);
724 }
725
726 /* No success yet */
727 ret = FALSE;
728
729 /* Call the driver's DrvBitBlt if available */
730 if (psurfDest->flHooks & HOOK_BITBLT)
731 {
732 ret = GDIDEVFUNCS(psoDest).BitBlt(
733 psoDest, psoSource, MaskSurf, ClipRegion, ColorTranslation,
734 &OutputRect, &InputPoint, MaskOrigin, pbo, BrushOrigin,
735 Rop4);
736 }
737
738 if (! ret)
739 {
740 ret = EngBitBlt(psoDest, psoSource, MaskSurf, ClipRegion, ColorTranslation,
741 &OutputRect, &InputPoint, MaskOrigin, pbo, BrushOrigin,
742 Rop4);
743 }
744
745 if (RemoveMouse)
746 {
747 MouseSafetyOnDrawEnd(psoDest);
748 if (UsesSource)
749 {
750 MouseSafetyOnDrawEnd(psoSource);
751 if (psoSource != psoDest)
752 {
753 SURFACE_UnlockBitmapBits(psurfSource);
754 }
755 }
756
757 SURFACE_UnlockBitmapBits(psurfDest);
758 }
759
760 return ret;
761 }
762
763 static BOOLEAN APIENTRY
764 CallDibStretchBlt(SURFOBJ* psoDest,
765 SURFOBJ* psoSource,
766 SURFOBJ* Mask,
767 XLATEOBJ* ColorTranslation,
768 RECTL* OutputRect,
769 RECTL* InputRect,
770 POINTL* MaskOrigin,
771 BRUSHOBJ* pbo,
772 POINTL* BrushOrigin,
773 ROP4 Rop4)
774 {
775 POINTL RealBrushOrigin;
776 SURFACE* psurfPattern;
777 PEBRUSHOBJ GdiBrush = NULL;
778 SURFOBJ* PatternSurface = NULL;
779 XLATEOBJ* XlatePatternToDest = NULL;
780
781 if (BrushOrigin == NULL)
782 {
783 RealBrushOrigin.x = RealBrushOrigin.y = 0;
784 }
785 else
786 {
787 RealBrushOrigin = *BrushOrigin;
788 }
789
790 /* Pattern brush */
791 if (ROP4_USES_PATTERN(Rop4) && pbo && pbo->iSolidColor == 0xFFFFFFFF)
792 {
793 GdiBrush = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
794 psurfPattern = SURFACE_LockSurface(GdiBrush->pbrush->hbmPattern);
795 if (psurfPattern)
796 {
797 PatternSurface = &psurfPattern->SurfObj;
798 }
799 else
800 {
801 /* FIXME - What to do here? */
802 }
803 XlatePatternToDest = GdiBrush->XlateObject;
804 }
805 else
806 {
807 psurfPattern = NULL;
808 }
809
810 return DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_StretchBlt(
811 psoDest, psoSource, Mask, PatternSurface,
812 OutputRect, InputRect, MaskOrigin, pbo, &RealBrushOrigin,
813 ColorTranslation, XlatePatternToDest, Rop4);
814
815 /* Pattern brush */
816 if (psurfPattern)
817 {
818 SURFACE_UnlockSurface(psurfPattern);
819 }
820 }
821
822
823 BOOL
824 APIENTRY
825 NtGdiEngStretchBlt(
826 IN SURFOBJ *psoDest,
827 IN SURFOBJ *psoSource,
828 IN SURFOBJ *Mask,
829 IN CLIPOBJ *ClipRegion,
830 IN XLATEOBJ *ColorTranslation,
831 IN COLORADJUSTMENT *pca,
832 IN POINTL *BrushOrigin,
833 IN RECTL *prclDest,
834 IN RECTL *prclSrc,
835 IN POINTL *MaskOrigin,
836 IN ULONG Mode)
837 {
838 COLORADJUSTMENT ca;
839 POINTL lBrushOrigin;
840 RECTL rclDest;
841 RECTL rclSrc;
842 POINTL lMaskOrigin;
843
844 _SEH2_TRY
845 {
846 ProbeForRead(pca, sizeof(COLORADJUSTMENT), 1);
847 RtlCopyMemory(&ca,pca, sizeof(COLORADJUSTMENT));
848
849 ProbeForRead(BrushOrigin, sizeof(POINTL), 1);
850 RtlCopyMemory(&lBrushOrigin, BrushOrigin, sizeof(POINTL));
851
852 ProbeForRead(prclDest, sizeof(RECTL), 1);
853 RtlCopyMemory(&rclDest, prclDest, sizeof(RECTL));
854
855 ProbeForRead(prclSrc, sizeof(RECTL), 1);
856 RtlCopyMemory(&rclSrc, prclSrc, sizeof(RECTL));
857
858 ProbeForRead(MaskOrigin, sizeof(POINTL), 1);
859 RtlCopyMemory(&lMaskOrigin, MaskOrigin, sizeof(POINTL));
860
861 }
862 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
863 {
864 _SEH2_YIELD(return FALSE);
865 }
866 _SEH2_END;
867
868 return EngStretchBlt(psoDest, psoSource, Mask, ClipRegion, ColorTranslation, &ca, &lBrushOrigin, &rclDest, &rclSrc, &lMaskOrigin, Mode);
869 }
870
871 /*
872 * @implemented
873 */
874 BOOL
875 APIENTRY
876 EngStretchBltROP(
877 IN SURFOBJ *psoDest,
878 IN SURFOBJ *psoSource,
879 IN SURFOBJ *Mask,
880 IN CLIPOBJ *ClipRegion,
881 IN XLATEOBJ *ColorTranslation,
882 IN COLORADJUSTMENT *pca,
883 IN POINTL *BrushOrigin,
884 IN RECTL *prclDest,
885 IN RECTL *prclSrc,
886 IN POINTL *MaskOrigin,
887 IN ULONG Mode,
888 IN BRUSHOBJ *pbo,
889 IN DWORD ROP4)
890 {
891 RECTL InputRect;
892 RECTL OutputRect;
893 POINTL Translate;
894 INTENG_ENTER_LEAVE EnterLeaveSource;
895 INTENG_ENTER_LEAVE EnterLeaveDest;
896 SURFOBJ* psoInput;
897 SURFOBJ* psoOutput;
898 PSTRETCHRECTFUNC BltRectFunc;
899 BOOLEAN Ret = TRUE;
900 POINTL AdjustedBrushOrigin;
901 BOOL UsesSource = ROP4_USES_SOURCE(ROP4);
902
903 BYTE clippingType;
904 RECTL ClipRect;
905 RECT_ENUM RectEnum;
906 BOOL EnumMore;
907 ULONG Direction;
908 RECTL CombinedRect;
909 RECTL InputToCombinedRect;
910 unsigned i;
911
912 LONG DstHeight;
913 LONG DstWidth;
914 LONG SrcHeight;
915 LONG SrcWidth;
916
917 /* Determine clipping type */
918 if (ClipRegion == (CLIPOBJ *) NULL)
919 {
920 clippingType = DC_TRIVIAL;
921 }
922 else
923 {
924 clippingType = ClipRegion->iDComplexity;
925 }
926
927 if (ROP4 == R4_NOOP)
928 {
929 /* Copy destination onto itself: nop */
930 return TRUE;
931 }
932
933 OutputRect = *prclDest;
934 if (OutputRect.right < OutputRect.left)
935 {
936 OutputRect.left = prclDest->right;
937 OutputRect.right = prclDest->left;
938 }
939 if (OutputRect.bottom < OutputRect.top)
940 {
941 OutputRect.top = prclDest->bottom;
942 OutputRect.bottom = prclDest->top;
943 }
944
945 InputRect = *prclSrc;
946 if (UsesSource)
947 {
948 if (NULL == prclSrc)
949 {
950 return FALSE;
951 }
952
953 if (! IntEngEnter(&EnterLeaveSource, psoSource, &InputRect, TRUE,
954 &Translate, &psoInput))
955 {
956 return FALSE;
957 }
958
959 InputRect.left += Translate.x;
960 InputRect.right += Translate.x;
961 InputRect.top += Translate.y;
962 InputRect.bottom += Translate.y;
963 }
964
965 if (NULL != ClipRegion)
966 {
967 if (OutputRect.left < ClipRegion->rclBounds.left)
968 {
969 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
970 OutputRect.left = ClipRegion->rclBounds.left;
971 }
972 if (ClipRegion->rclBounds.right < OutputRect.right)
973 {
974 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
975 OutputRect.right = ClipRegion->rclBounds.right;
976 }
977 if (OutputRect.top < ClipRegion->rclBounds.top)
978 {
979 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
980 OutputRect.top = ClipRegion->rclBounds.top;
981 }
982 if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
983 {
984 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
985 OutputRect.bottom = ClipRegion->rclBounds.bottom;
986 }
987 }
988
989 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
990 nothing to do */
991 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
992 {
993 if (UsesSource)
994 {
995 IntEngLeave(&EnterLeaveSource);
996 }
997 return TRUE;
998 }
999
1000 if (! IntEngEnter(&EnterLeaveDest, psoDest, &OutputRect, FALSE, &Translate, &psoOutput))
1001 {
1002 if (UsesSource)
1003 {
1004 IntEngLeave(&EnterLeaveSource);
1005 }
1006 return FALSE;
1007 }
1008
1009 OutputRect.left += Translate.x;
1010 OutputRect.right += Translate.x;
1011 OutputRect.top += Translate.y;
1012 OutputRect.bottom += Translate.y;
1013
1014 if (BrushOrigin)
1015 {
1016 AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
1017 AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
1018 }
1019 else
1020 {
1021 AdjustedBrushOrigin = Translate;
1022 }
1023
1024 BltRectFunc = CallDibStretchBlt;
1025
1026 DstHeight = OutputRect.bottom - OutputRect.top;
1027 DstWidth = OutputRect.right - OutputRect.left;
1028 SrcHeight = InputRect.bottom - InputRect.top;
1029 SrcWidth = InputRect.right - InputRect.left;
1030 switch (clippingType)
1031 {
1032 case DC_TRIVIAL:
1033 Ret = (*BltRectFunc)(psoOutput, psoInput, Mask,
1034 ColorTranslation, &OutputRect, &InputRect, MaskOrigin,
1035 pbo, &AdjustedBrushOrigin, ROP4);
1036 break;
1037 case DC_RECT:
1038 // Clip the blt to the clip rectangle
1039 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
1040 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
1041 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
1042 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
1043 if (EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
1044 {
1045 InputToCombinedRect.top = InputRect.top + (CombinedRect.top - OutputRect.top) * SrcHeight / DstHeight;
1046 InputToCombinedRect.bottom = InputRect.top + (CombinedRect.bottom - OutputRect.top) * SrcHeight / DstHeight;
1047 InputToCombinedRect.left = InputRect.left + (CombinedRect.left - OutputRect.left) * SrcWidth / DstWidth;
1048 InputToCombinedRect.right = InputRect.left + (CombinedRect.right - OutputRect.left) * SrcWidth / DstWidth;
1049 Ret = (*BltRectFunc)(psoOutput, psoInput, Mask,
1050 ColorTranslation,
1051 &CombinedRect,
1052 &InputToCombinedRect,
1053 MaskOrigin,
1054 pbo,
1055 &AdjustedBrushOrigin,
1056 ROP4);
1057 }
1058 break;
1059 case DC_COMPLEX:
1060 if (psoOutput == psoInput)
1061 {
1062 if (OutputRect.top < InputRect.top)
1063 {
1064 Direction = OutputRect.left < InputRect.left ?
1065 CD_RIGHTDOWN : CD_LEFTDOWN;
1066 }
1067 else
1068 {
1069 Direction = OutputRect.left < InputRect.left ?
1070 CD_RIGHTUP : CD_LEFTUP;
1071 }
1072 }
1073 else
1074 {
1075 Direction = CD_ANY;
1076 }
1077 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
1078 do
1079 {
1080 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum),
1081 (PVOID) &RectEnum);
1082 for (i = 0; i < RectEnum.c; i++)
1083 {
1084 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
1085 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
1086 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
1087 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
1088 if (EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
1089 {
1090 InputToCombinedRect.top = InputRect.top + (CombinedRect.top - OutputRect.top) * SrcHeight / DstHeight;
1091 InputToCombinedRect.bottom = InputRect.top + (CombinedRect.bottom - OutputRect.top) * SrcHeight / DstHeight;
1092 InputToCombinedRect.left = InputRect.left + (CombinedRect.left - OutputRect.left) * SrcWidth / DstWidth;
1093 InputToCombinedRect.right = InputRect.left + (CombinedRect.right - OutputRect.left) * SrcWidth / DstWidth;
1094 Ret = (*BltRectFunc)(psoOutput, psoInput, Mask,
1095 ColorTranslation,
1096 &CombinedRect,
1097 &InputToCombinedRect,
1098 MaskOrigin,
1099 pbo,
1100 &AdjustedBrushOrigin,
1101 ROP4);
1102 }
1103 }
1104 }
1105 while (EnumMore);
1106 break;
1107 }
1108
1109 IntEngLeave(&EnterLeaveDest);
1110 if (UsesSource)
1111 {
1112 IntEngLeave(&EnterLeaveSource);
1113 }
1114
1115 return Ret;
1116 }
1117
1118 /*
1119 * @implemented
1120 */
1121 BOOL
1122 APIENTRY
1123 EngStretchBlt(
1124 IN SURFOBJ *psoDest,
1125 IN SURFOBJ *psoSource,
1126 IN SURFOBJ *Mask,
1127 IN CLIPOBJ *ClipRegion,
1128 IN XLATEOBJ *ColorTranslation,
1129 IN COLORADJUSTMENT *pca,
1130 IN POINTL *BrushOrigin,
1131 IN RECTL *prclDest,
1132 IN RECTL *prclSrc,
1133 IN POINTL *MaskOrigin,
1134 IN ULONG Mode)
1135 {
1136 return EngStretchBltROP(
1137 psoDest,
1138 psoSource,
1139 Mask,
1140 ClipRegion,
1141 ColorTranslation,
1142 pca,
1143 BrushOrigin,
1144 prclDest,
1145 prclSrc,
1146 MaskOrigin,
1147 Mode,
1148 NULL,
1149 ROP3_TO_ROP4(SRCCOPY));
1150 }
1151
1152 BOOL APIENTRY
1153 IntEngStretchBlt(SURFOBJ *psoDest,
1154 SURFOBJ *psoSource,
1155 SURFOBJ *MaskSurf,
1156 CLIPOBJ *ClipRegion,
1157 XLATEOBJ *ColorTranslation,
1158 RECTL *DestRect,
1159 RECTL *SourceRect,
1160 POINTL *pMaskOrigin,
1161 BRUSHOBJ *pbo,
1162 POINTL *BrushOrigin,
1163 ROP4 ROP)
1164 {
1165 BOOLEAN ret;
1166 COLORADJUSTMENT ca;
1167 POINT MaskOrigin;
1168 SURFACE *psurfDest;
1169 SURFACE *psurfSource = NULL;
1170 RECTL InputClippedRect;
1171 RECTL InputRect;
1172 RECTL OutputRect;
1173 BOOL UsesSource = ROP4_USES_SOURCE(ROP);
1174 LONG InputClWidth, InputClHeight, InputWidth, InputHeight;
1175
1176 ASSERT(psoDest);
1177 psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
1178 ASSERT(psurfDest);
1179 ASSERT(DestRect);
1180
1181 InputClippedRect = *DestRect;
1182 if (InputClippedRect.right < InputClippedRect.left)
1183 {
1184 InputClippedRect.left = DestRect->right;
1185 InputClippedRect.right = DestRect->left;
1186 }
1187 if (InputClippedRect.bottom < InputClippedRect.top)
1188 {
1189 InputClippedRect.top = DestRect->bottom;
1190 InputClippedRect.bottom = DestRect->top;
1191 }
1192
1193 if (UsesSource)
1194 {
1195 if (NULL == SourceRect || NULL == psoSource)
1196 {
1197 return FALSE;
1198 }
1199 InputRect = *SourceRect;
1200
1201 if (InputRect.right < InputRect.left ||
1202 InputRect.bottom < InputRect.top)
1203 {
1204 /* Everything clipped away, nothing to do */
1205 return TRUE;
1206 }
1207 }
1208
1209 if (ClipRegion)
1210 {
1211 if (! EngIntersectRect(&OutputRect, &InputClippedRect,
1212 &ClipRegion->rclBounds))
1213 {
1214 return TRUE;
1215 }
1216 /* Update source rect */
1217 InputClWidth = InputClippedRect.right - InputClippedRect.left;
1218 InputClHeight = InputClippedRect.bottom - InputClippedRect.top;
1219 InputWidth = InputRect.right - InputRect.left;
1220 InputHeight = InputRect.bottom - InputRect.top;
1221
1222 InputRect.left += (InputWidth * (OutputRect.left - InputClippedRect.left)) / InputClWidth;
1223 InputRect.right -= (InputWidth * (InputClippedRect.right - OutputRect.right)) / InputClWidth;
1224 InputRect.top += (InputHeight * (OutputRect.top - InputClippedRect.top)) / InputClHeight;
1225 InputRect.bottom -= (InputHeight * (InputClippedRect.bottom - OutputRect.bottom)) / InputClHeight;
1226 }
1227 else
1228 {
1229 OutputRect = InputClippedRect;
1230 }
1231
1232 if (pMaskOrigin != NULL)
1233 {
1234 MaskOrigin.x = pMaskOrigin->x; MaskOrigin.y = pMaskOrigin->y;
1235 }
1236
1237 /* No success yet */
1238 ret = FALSE;
1239 SURFACE_LockBitmapBits(psurfDest);
1240 MouseSafetyOnDrawStart(psoDest, OutputRect.left, OutputRect.top,
1241 OutputRect.right, OutputRect.bottom);
1242
1243 if (UsesSource)
1244 {
1245 psurfSource = CONTAINING_RECORD(psoSource, SURFACE, SurfObj);
1246 if (psoSource != psoDest)
1247 {
1248 SURFACE_LockBitmapBits(psurfSource);
1249 }
1250 MouseSafetyOnDrawStart(psoSource, InputRect.left, InputRect.top,
1251 InputRect.right, InputRect.bottom);
1252 }
1253
1254 /* Prepare color adjustment */
1255
1256 /* Call the driver's DrvStretchBlt if available */
1257 if (psurfDest->flHooks & HOOK_STRETCHBLTROP)
1258 {
1259 /* Drv->StretchBltROP (look at http://www.osronline.com/ddkx/graphics/ddifncs_0z3b.htm ) */
1260 // FIXME: MaskOrigin is always NULL !
1261 ret = GDIDEVFUNCS(psoDest).StretchBltROP(psoDest, (UsesSource) ? psoSource : NULL, MaskSurf, ClipRegion, ColorTranslation,
1262 &ca, BrushOrigin, &OutputRect, &InputRect, NULL, COLORONCOLOR, pbo, ROP);
1263 }
1264
1265 if (! ret)
1266 {
1267 // FIXME: see previous fixme
1268 ret = EngStretchBltROP(psoDest, (UsesSource) ? psoSource : NULL, MaskSurf, ClipRegion, ColorTranslation,
1269 &ca, BrushOrigin, &OutputRect, &InputRect, NULL, COLORONCOLOR, pbo, ROP);
1270 }
1271
1272 if (UsesSource)
1273 {
1274 MouseSafetyOnDrawEnd(psoSource);
1275 if (psoSource != psoDest)
1276 {
1277 SURFACE_UnlockBitmapBits(psurfSource);
1278 }
1279 }
1280 MouseSafetyOnDrawEnd(psoDest);
1281 SURFACE_UnlockBitmapBits(psurfDest);
1282
1283 return ret;
1284 }
1285
1286
1287 /*
1288 * @implemented
1289 */
1290 BOOL
1291 APIENTRY
1292 NtGdiEngAlphaBlend(IN SURFOBJ *psoDest,
1293 IN SURFOBJ *psoSource,
1294 IN CLIPOBJ *ClipRegion,
1295 IN XLATEOBJ *ColorTranslation,
1296 IN PRECTL upDestRect,
1297 IN PRECTL upSourceRect,
1298 IN BLENDOBJ *BlendObj)
1299 {
1300 RECTL DestRect;
1301 RECTL SourceRect;
1302
1303 _SEH2_TRY
1304 {
1305 ProbeForRead(upDestRect, sizeof(RECTL), 1);
1306 RtlCopyMemory(&DestRect,upDestRect, sizeof(RECTL));
1307
1308 ProbeForRead(upSourceRect, sizeof(RECTL), 1);
1309 RtlCopyMemory(&SourceRect, upSourceRect, sizeof(RECTL));
1310
1311 }
1312 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1313 {
1314 _SEH2_YIELD(return FALSE);
1315 }
1316 _SEH2_END;
1317
1318 return EngAlphaBlend(psoDest, psoSource, ClipRegion, ColorTranslation, &DestRect, &SourceRect, BlendObj);
1319 }
1320
1321 /*
1322 * @implemented
1323 */
1324 BOOL
1325 APIENTRY
1326 EngAlphaBlend(IN SURFOBJ *psoDest,
1327 IN SURFOBJ *psoSource,
1328 IN CLIPOBJ *ClipRegion,
1329 IN XLATEOBJ *ColorTranslation,
1330 IN PRECTL DestRect,
1331 IN PRECTL SourceRect,
1332 IN BLENDOBJ *BlendObj)
1333 {
1334 RECTL SourceStretchedRect;
1335 SIZEL SourceStretchedSize;
1336 HBITMAP SourceStretchedBitmap = 0;
1337 SURFOBJ* SourceStretchedObj = NULL;
1338 RECTL InputRect;
1339 RECTL OutputRect;
1340 RECTL ClipRect;
1341 RECTL CombinedRect;
1342 RECTL Rect;
1343 POINTL Translate;
1344 INTENG_ENTER_LEAVE EnterLeaveSource;
1345 INTENG_ENTER_LEAVE EnterLeaveDest;
1346 SURFOBJ* InputObj;
1347 SURFOBJ* OutputObj;
1348 LONG Width;
1349 LONG ClippingType;
1350 RECT_ENUM RectEnum;
1351 BOOL EnumMore;
1352 INT i;
1353 BOOLEAN Ret;
1354
1355 DPRINT("EngAlphaBlend(psoDest:0x%p, psoSource:0x%p, ClipRegion:0x%p, ColorTranslation:0x%p,\n", psoDest, psoSource, ClipRegion, ColorTranslation);
1356 DPRINT(" DestRect:{0x%x, 0x%x, 0x%x, 0x%x}, SourceRect:{0x%x, 0x%x, 0x%x, 0x%x},\n",
1357 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom,
1358 SourceRect->left, SourceRect->top, SourceRect->right, SourceRect->bottom);
1359 DPRINT(" BlendObj:{0x%x, 0x%x, 0x%x, 0x%x}\n", BlendObj->BlendFunction.BlendOp,
1360 BlendObj->BlendFunction.BlendFlags, BlendObj->BlendFunction.SourceConstantAlpha,
1361 BlendObj->BlendFunction.AlphaFormat);
1362
1363
1364 /* Validate output */
1365 OutputRect = *DestRect;
1366 if (OutputRect.right < OutputRect.left)
1367 {
1368 OutputRect.left = DestRect->right;
1369 OutputRect.right = DestRect->left;
1370 }
1371 if (OutputRect.bottom < OutputRect.top)
1372 {
1373 OutputRect.left = DestRect->right;
1374 OutputRect.right = DestRect->left;
1375 }
1376
1377
1378 /* Validate input */
1379
1380 /* FIXME when WindowOrg.x or .y are negitve this check are not vaild,
1381 * we need convert the inputRect to the windows org and do it right */
1382 InputRect = *SourceRect;
1383 if ( (InputRect.top < 0) || (InputRect.bottom < 0) ||
1384 (InputRect.left < 0) || (InputRect.right < 0) )
1385 {
1386 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1387 return FALSE;
1388 }
1389
1390 if (psoDest == psoSource &&
1391 !(OutputRect.left >= SourceRect->right || InputRect.left >= OutputRect.right ||
1392 OutputRect.top >= SourceRect->bottom || InputRect.top >= OutputRect.bottom))
1393 {
1394 DPRINT1("Source and destination rectangles overlap!\n");
1395 return FALSE;
1396 }
1397
1398 if (BlendObj->BlendFunction.BlendOp != AC_SRC_OVER)
1399 {
1400 DPRINT1("BlendOp != AC_SRC_OVER (0x%x)\n", BlendObj->BlendFunction.BlendOp);
1401 return FALSE;
1402 }
1403 if (BlendObj->BlendFunction.BlendFlags != 0)
1404 {
1405 DPRINT1("BlendFlags != 0 (0x%x)\n", BlendObj->BlendFunction.BlendFlags);
1406 return FALSE;
1407 }
1408 if ((BlendObj->BlendFunction.AlphaFormat & ~AC_SRC_ALPHA) != 0)
1409 {
1410 DPRINT1("Unsupported AlphaFormat (0x%x)\n", BlendObj->BlendFunction.AlphaFormat);
1411 return FALSE;
1412 }
1413
1414 /* Check if there is anything to draw */
1415 if (ClipRegion != NULL &&
1416 (ClipRegion->rclBounds.left >= ClipRegion->rclBounds.right ||
1417 ClipRegion->rclBounds.top >= ClipRegion->rclBounds.bottom))
1418 {
1419 /* Nothing to do */
1420 return TRUE;
1421 }
1422
1423 /* Stretch source if needed */
1424 if (OutputRect.right - OutputRect.left != InputRect.right - InputRect.left ||
1425 OutputRect.bottom - OutputRect.top != InputRect.bottom - InputRect.top)
1426 {
1427 SourceStretchedSize.cx = OutputRect.right - OutputRect.left;
1428 SourceStretchedSize.cy = OutputRect.bottom - OutputRect.top;
1429 Width = DIB_GetDIBWidthBytes(SourceStretchedSize.cx, BitsPerFormat(psoSource->iBitmapFormat));
1430 /* FIXME: Maybe it is a good idea to use EngCreateDeviceBitmap and IntEngStretchBlt
1431 if possible to get a HW accelerated stretch. */
1432 SourceStretchedBitmap = EngCreateBitmap(SourceStretchedSize, Width, psoSource->iBitmapFormat,
1433 BMF_TOPDOWN | BMF_NOZEROINIT, NULL);
1434 if (SourceStretchedBitmap == 0)
1435 {
1436 DPRINT1("EngCreateBitmap failed!\n");
1437 return FALSE;
1438 }
1439 SourceStretchedObj = EngLockSurface((HSURF)SourceStretchedBitmap);
1440 if (SourceStretchedObj == NULL)
1441 {
1442 DPRINT1("EngLockSurface failed!\n");
1443 EngDeleteSurface((HSURF)SourceStretchedBitmap);
1444 return FALSE;
1445 }
1446
1447 SourceStretchedRect.left = 0;
1448 SourceStretchedRect.right = SourceStretchedSize.cx;
1449 SourceStretchedRect.top = 0;
1450 SourceStretchedRect.bottom = SourceStretchedSize.cy;
1451 /* FIXME: IntEngStretchBlt isn't used here atm because it results in a
1452 try to acquire an already acquired mutex (lock the already locked source surface) */
1453 /*if (!IntEngStretchBlt(SourceStretchedObj, psoSource, NULL, NULL,
1454 NULL, &SourceStretchedRect, SourceRect, NULL,
1455 NULL, NULL, COLORONCOLOR))*/
1456 if (!EngStretchBlt(SourceStretchedObj, psoSource, NULL, NULL, NULL,
1457 NULL, NULL, &SourceStretchedRect, &InputRect,
1458 NULL, COLORONCOLOR))
1459 {
1460 DPRINT1("EngStretchBlt failed!\n");
1461 EngFreeMem(SourceStretchedObj->pvBits);
1462 EngUnlockSurface(SourceStretchedObj);
1463 EngDeleteSurface((HSURF)SourceStretchedBitmap);
1464 return FALSE;
1465 }
1466 InputRect.top = SourceStretchedRect.top;
1467 InputRect.bottom = SourceStretchedRect.bottom;
1468 InputRect.left = SourceStretchedRect.left;
1469 InputRect.right = SourceStretchedRect.right;
1470 psoSource = SourceStretchedObj;
1471 }
1472
1473 /* Now call the DIB function */
1474 if (!IntEngEnter(&EnterLeaveSource, psoSource, &InputRect, TRUE, &Translate, &InputObj))
1475 {
1476 if (SourceStretchedObj != NULL)
1477 {
1478 EngFreeMem(SourceStretchedObj->pvBits);
1479 EngUnlockSurface(SourceStretchedObj);
1480 }
1481 if (SourceStretchedBitmap != 0)
1482 {
1483 EngDeleteSurface((HSURF)SourceStretchedBitmap);
1484 }
1485 return FALSE;
1486 }
1487 InputRect.left += Translate.x;
1488 InputRect.right += Translate.x;
1489 InputRect.top += Translate.y;
1490 InputRect.bottom += Translate.y;
1491
1492 if (!IntEngEnter(&EnterLeaveDest, psoDest, &OutputRect, FALSE, &Translate, &OutputObj))
1493 {
1494 IntEngLeave(&EnterLeaveSource);
1495 if (SourceStretchedObj != NULL)
1496 {
1497 EngFreeMem(SourceStretchedObj->pvBits);
1498 EngUnlockSurface(SourceStretchedObj);
1499 }
1500 if (SourceStretchedBitmap != 0)
1501 {
1502 EngDeleteSurface((HSURF)SourceStretchedBitmap);
1503 }
1504 return FALSE;
1505 }
1506 OutputRect.left += Translate.x;
1507 OutputRect.right += Translate.x;
1508 OutputRect.top += Translate.y;
1509 OutputRect.bottom += Translate.y;
1510
1511 Ret = FALSE;
1512 ClippingType = (ClipRegion == NULL) ? DC_TRIVIAL : ClipRegion->iDComplexity;
1513 switch (ClippingType)
1514 {
1515 case DC_TRIVIAL:
1516 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend(
1517 OutputObj, InputObj, &OutputRect, &InputRect, ClipRegion, ColorTranslation, BlendObj);
1518 break;
1519
1520 case DC_RECT:
1521 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
1522 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
1523 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
1524 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
1525 if (EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
1526 {
1527 Rect.left = InputRect.left + CombinedRect.left - OutputRect.left;
1528 Rect.right = InputRect.right + CombinedRect.right - OutputRect.right;
1529 Rect.top = InputRect.top + CombinedRect.top - OutputRect.top;
1530 Rect.bottom = InputRect.bottom + CombinedRect.bottom - OutputRect.bottom;
1531 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend(
1532 OutputObj, InputObj, &CombinedRect, &Rect, ClipRegion, ColorTranslation, BlendObj);
1533 }
1534 break;
1535
1536 case DC_COMPLEX:
1537 Ret = TRUE;
1538 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, CD_ANY, 0);
1539 do
1540 {
1541 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum),
1542 (PVOID) &RectEnum);
1543
1544 for (i = 0; i < RectEnum.c; i++)
1545 {
1546 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
1547 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
1548 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
1549 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
1550 if (EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
1551 {
1552 Rect.left = InputRect.left + CombinedRect.left - OutputRect.left;
1553 Rect.right = InputRect.right + CombinedRect.right - OutputRect.right;
1554 Rect.top = InputRect.top + CombinedRect.top - OutputRect.top;
1555 Rect.bottom = InputRect.bottom + CombinedRect.bottom - OutputRect.bottom;
1556 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend(
1557 OutputObj, InputObj, &CombinedRect, &Rect, ClipRegion, ColorTranslation, BlendObj) && Ret;
1558 }
1559 }
1560 }
1561 while (EnumMore);
1562 break;
1563
1564 default:
1565 UNIMPLEMENTED;
1566 ASSERT(FALSE);
1567 break;
1568 }
1569
1570 IntEngLeave(&EnterLeaveDest);
1571 IntEngLeave(&EnterLeaveSource);
1572
1573 if (SourceStretchedObj != NULL)
1574 {
1575 EngFreeMem(SourceStretchedObj->pvBits);
1576 EngUnlockSurface(SourceStretchedObj);
1577 }
1578 if (SourceStretchedBitmap != 0)
1579 {
1580 EngDeleteSurface((HSURF)SourceStretchedBitmap);
1581 }
1582
1583 return Ret;
1584 }
1585
1586 BOOL APIENTRY
1587 IntEngAlphaBlend(IN SURFOBJ *psoDest,
1588 IN SURFOBJ *psoSource,
1589 IN CLIPOBJ *ClipRegion,
1590 IN XLATEOBJ *ColorTranslation,
1591 IN PRECTL DestRect,
1592 IN PRECTL SourceRect,
1593 IN BLENDOBJ *BlendObj)
1594 {
1595 BOOL ret = FALSE;
1596 SURFACE *psurfDest;
1597 SURFACE *psurfSource;
1598
1599 ASSERT(psoDest);
1600 psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
1601
1602 ASSERT(psoSource);
1603 psurfSource = CONTAINING_RECORD(psoSource, SURFACE, SurfObj);
1604
1605 ASSERT(DestRect);
1606 ASSERT(SourceRect);
1607
1608 /* Check if there is anything to draw */
1609 if (ClipRegion != NULL &&
1610 (ClipRegion->rclBounds.left >= ClipRegion->rclBounds.right ||
1611 ClipRegion->rclBounds.top >= ClipRegion->rclBounds.bottom))
1612 {
1613 /* Nothing to do */
1614 return TRUE;
1615 }
1616
1617 SURFACE_LockBitmapBits(psurfDest);
1618 MouseSafetyOnDrawStart(psoDest, DestRect->left, DestRect->top,
1619 DestRect->right, DestRect->bottom);
1620
1621 if (psoSource != psoDest)
1622 SURFACE_LockBitmapBits(psurfSource);
1623 MouseSafetyOnDrawStart(psoSource, SourceRect->left, SourceRect->top,
1624 SourceRect->right, SourceRect->bottom);
1625
1626 /* Call the driver's DrvAlphaBlend if available */
1627 if (psurfDest->flHooks & HOOK_ALPHABLEND)
1628 {
1629 ret = GDIDEVFUNCS(psoDest).AlphaBlend(
1630 psoDest, psoSource, ClipRegion, ColorTranslation,
1631 DestRect, SourceRect, BlendObj);
1632 }
1633
1634 if (! ret)
1635 {
1636 ret = EngAlphaBlend(psoDest, psoSource, ClipRegion, ColorTranslation,
1637 DestRect, SourceRect, BlendObj);
1638 }
1639
1640 MouseSafetyOnDrawEnd(psoSource);
1641 if (psoSource != psoDest)
1642 SURFACE_UnlockBitmapBits(psurfSource);
1643 MouseSafetyOnDrawEnd(psoDest);
1644 SURFACE_UnlockBitmapBits(psurfDest);
1645
1646 return ret;
1647 }
1648
1649 /**** REACTOS FONT RENDERING CODE *********************************************/
1650
1651 /* renders the alpha mask bitmap */
1652 static BOOLEAN APIENTRY
1653 AlphaBltMask(SURFOBJ* psoDest,
1654 SURFOBJ* psoSource, // unused
1655 SURFOBJ* psoMask,
1656 XLATEOBJ* ColorTranslation,
1657 XLATEOBJ* SrcColorTranslation,
1658 RECTL* prclDest,
1659 POINTL* pptlSource, // unused
1660 POINTL* pptlMask,
1661 BRUSHOBJ* pbo,
1662 POINTL* pptlBrush)
1663 {
1664 LONG i, j, dx, dy;
1665 int r, g, b;
1666 ULONG Background, BrushColor, NewColor;
1667 BYTE *tMask, *lMask;
1668
1669 dx = prclDest->right - prclDest->left;
1670 dy = prclDest->bottom - prclDest->top;
1671
1672 if (psoMask != NULL)
1673 {
1674 BrushColor = XLATEOBJ_iXlate(SrcColorTranslation, pbo ? pbo->iSolidColor : 0);
1675 r = (int)GetRValue(BrushColor);
1676 g = (int)GetGValue(BrushColor);
1677 b = (int)GetBValue(BrushColor);
1678
1679 tMask = (PBYTE)psoMask->pvScan0 + (pptlMask->y * psoMask->lDelta) + pptlMask->x;
1680 for (j = 0; j < dy; j++)
1681 {
1682 lMask = tMask;
1683 for (i = 0; i < dx; i++)
1684 {
1685 if (*lMask > 0)
1686 {
1687 if (*lMask == 0xff)
1688 {
1689 DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel(
1690 psoDest, prclDest->left + i, prclDest->top + j, pbo ? pbo->iSolidColor : 0);
1691 }
1692 else
1693 {
1694 Background = DIB_GetSource(psoDest, prclDest->left + i, prclDest->top + j,
1695 SrcColorTranslation);
1696
1697 NewColor =
1698 RGB((*lMask * (r - GetRValue(Background)) >> 8) + GetRValue(Background),
1699 (*lMask * (g - GetGValue(Background)) >> 8) + GetGValue(Background),
1700 (*lMask * (b - GetBValue(Background)) >> 8) + GetBValue(Background));
1701
1702 Background = XLATEOBJ_iXlate(ColorTranslation, NewColor);
1703 DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel(
1704 psoDest, prclDest->left + i, prclDest->top + j, Background);
1705 }
1706 }
1707 lMask++;
1708 }
1709 tMask += psoMask->lDelta;
1710 }
1711 return TRUE;
1712 }
1713 else
1714 {
1715 return FALSE;
1716 }
1717 }
1718
1719 static
1720 BOOL APIENTRY
1721 EngMaskBitBlt(SURFOBJ *psoDest,
1722 SURFOBJ *psoMask,
1723 CLIPOBJ *ClipRegion,
1724 XLATEOBJ *DestColorTranslation,
1725 XLATEOBJ *SourceColorTranslation,
1726 RECTL *DestRect,
1727 POINTL *pptlMask,
1728 BRUSHOBJ *pbo,
1729 POINTL *BrushOrigin)
1730 {
1731 BYTE clippingType;
1732 RECTL CombinedRect;
1733 RECT_ENUM RectEnum;
1734 BOOL EnumMore;
1735 POINTL InputPoint;
1736 RECTL InputRect;
1737 RECTL OutputRect;
1738 POINTL Translate;
1739 INTENG_ENTER_LEAVE EnterLeaveSource;
1740 INTENG_ENTER_LEAVE EnterLeaveDest;
1741 SURFOBJ* psoInput;
1742 SURFOBJ* psoOutput;
1743 BOOLEAN Ret = TRUE;
1744 RECTL ClipRect;
1745 unsigned i;
1746 POINTL Pt;
1747 ULONG Direction;
1748 POINTL AdjustedBrushOrigin;
1749
1750 ASSERT(psoMask);
1751
1752 if (pptlMask)
1753 {
1754 InputRect.left = pptlMask->x;
1755 InputRect.right = pptlMask->x + (DestRect->right - DestRect->left);
1756 InputRect.top = pptlMask->y;
1757 InputRect.bottom = pptlMask->y + (DestRect->bottom - DestRect->top);
1758 }
1759 else
1760 {
1761 InputRect.left = 0;
1762 InputRect.right = DestRect->right - DestRect->left;
1763 InputRect.top = 0;
1764 InputRect.bottom = DestRect->bottom - DestRect->top;
1765 }
1766
1767 OutputRect = *DestRect;
1768 if (NULL != ClipRegion)
1769 {
1770 if (OutputRect.left < ClipRegion->rclBounds.left)
1771 {
1772 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
1773 OutputRect.left = ClipRegion->rclBounds.left;
1774 }
1775 if (ClipRegion->rclBounds.right < OutputRect.right)
1776 {
1777 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
1778 OutputRect.right = ClipRegion->rclBounds.right;
1779 }
1780 if (OutputRect.top < ClipRegion->rclBounds.top)
1781 {
1782 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
1783 OutputRect.top = ClipRegion->rclBounds.top;
1784 }
1785 if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
1786 {
1787 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
1788 OutputRect.bottom = ClipRegion->rclBounds.bottom;
1789 }
1790 }
1791
1792 if (! IntEngEnter(&EnterLeaveSource, psoMask, &InputRect, TRUE, &Translate, &psoInput))
1793 {
1794 return FALSE;
1795 }
1796
1797 InputPoint.x = InputRect.left + Translate.x;
1798 InputPoint.y = InputRect.top + Translate.y;
1799
1800 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
1801 nothing to do */
1802 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
1803 {
1804 IntEngLeave(&EnterLeaveSource);
1805 return TRUE;
1806 }
1807
1808 if (! IntEngEnter(&EnterLeaveDest, psoDest, &OutputRect, FALSE, &Translate, &psoOutput))
1809 {
1810 IntEngLeave(&EnterLeaveSource);
1811 return FALSE;
1812 }
1813
1814 OutputRect.left = DestRect->left + Translate.x;
1815 OutputRect.right = DestRect->right + Translate.x;
1816 OutputRect.top = DestRect->top + Translate.y;
1817 OutputRect.bottom = DestRect->bottom + Translate.y;
1818
1819 if (BrushOrigin)
1820 {
1821 AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
1822 AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
1823 }
1824 else
1825 AdjustedBrushOrigin = Translate;
1826
1827 // Determine clipping type
1828 if (ClipRegion == (CLIPOBJ *) NULL)
1829 {
1830 clippingType = DC_TRIVIAL;
1831 } else {
1832 clippingType = ClipRegion->iDComplexity;
1833 }
1834
1835 switch (clippingType)
1836 {
1837 case DC_TRIVIAL:
1838 if (psoMask->iBitmapFormat == BMF_8BPP)
1839 Ret = AlphaBltMask(psoOutput, NULL , psoInput, DestColorTranslation, SourceColorTranslation,
1840 &OutputRect, &InputPoint, pptlMask, pbo, &AdjustedBrushOrigin);
1841 else
1842 Ret = BltMask(psoOutput, NULL, psoInput, DestColorTranslation,
1843 &OutputRect, &InputPoint, pptlMask, pbo, &AdjustedBrushOrigin,
1844 R4_MASK);
1845 break;
1846 case DC_RECT:
1847 // Clip the blt to the clip rectangle
1848 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
1849 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
1850 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
1851 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
1852 if (EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
1853 {
1854 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
1855 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
1856 if (psoMask->iBitmapFormat == BMF_8BPP)
1857 {
1858 Ret = AlphaBltMask(psoOutput, psoInput, psoMask, DestColorTranslation, SourceColorTranslation,
1859 &CombinedRect, &Pt, pptlMask, pbo, &AdjustedBrushOrigin);
1860 }
1861 else
1862 {
1863 Ret = BltMask(psoOutput, psoInput, psoMask, DestColorTranslation,
1864 &CombinedRect, &Pt, pptlMask, pbo, &AdjustedBrushOrigin, R4_MASK);
1865 }
1866 }
1867 break;
1868 case DC_COMPLEX:
1869 Ret = TRUE;
1870 if (psoOutput == psoInput)
1871 {
1872 if (OutputRect.top < InputPoint.y)
1873 {
1874 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
1875 }
1876 else
1877 {
1878 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
1879 }
1880 }
1881 else
1882 {
1883 Direction = CD_ANY;
1884 }
1885 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
1886 do
1887 {
1888 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
1889
1890 for (i = 0; i < RectEnum.c; i++)
1891 {
1892 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
1893 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
1894 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
1895 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
1896 if (EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
1897 {
1898 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
1899 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
1900 if (psoMask->iBitmapFormat == BMF_8BPP)
1901 {
1902 Ret = AlphaBltMask(psoOutput, psoInput, psoMask,
1903 DestColorTranslation,
1904 SourceColorTranslation,
1905 &CombinedRect, &Pt, pptlMask, pbo,
1906 &AdjustedBrushOrigin) && Ret;
1907 }
1908 else
1909 {
1910 Ret = BltMask(psoOutput, psoInput, psoMask,
1911 DestColorTranslation, &CombinedRect, &Pt,
1912 pptlMask, pbo, &AdjustedBrushOrigin,
1913 R4_MASK) && Ret;
1914 }
1915 }
1916 }
1917 }
1918 while (EnumMore);
1919 break;
1920 }
1921
1922
1923 IntEngLeave(&EnterLeaveDest);
1924 IntEngLeave(&EnterLeaveSource);
1925
1926 return Ret;
1927 }
1928
1929 BOOL APIENTRY
1930 IntEngMaskBlt(SURFOBJ *psoDest,
1931 SURFOBJ *psoMask,
1932 CLIPOBJ *ClipRegion,
1933 XLATEOBJ *DestColorTranslation,
1934 XLATEOBJ *SourceColorTranslation,
1935 RECTL *DestRect,
1936 POINTL *pptlMask,
1937 BRUSHOBJ *pbo,
1938 POINTL *BrushOrigin)
1939 {
1940 BOOLEAN ret;
1941 RECTL OutputRect;
1942 POINTL InputPoint;
1943 SURFACE *psurfDest;
1944
1945 ASSERT(psoMask);
1946
1947 if (pptlMask)
1948 {
1949 InputPoint = *pptlMask;
1950 }
1951
1952 /* Clip against the bounds of the clipping region so we won't try to write
1953 * outside the surface */
1954 if (NULL != ClipRegion)
1955 {
1956 if (! EngIntersectRect(&OutputRect, DestRect, &ClipRegion->rclBounds))
1957 {
1958 return TRUE;
1959 }
1960 InputPoint.x += OutputRect.left - DestRect->left;
1961 InputPoint.y += OutputRect.top - DestRect->top;
1962 }
1963 else
1964 {
1965 OutputRect = *DestRect;
1966 }
1967
1968 /* No success yet */
1969 ret = FALSE;
1970 ASSERT(psoDest);
1971 psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
1972
1973 SURFACE_LockBitmapBits(psurfDest);
1974 MouseSafetyOnDrawStart(psoDest, OutputRect.left, OutputRect.top,
1975 OutputRect.right, OutputRect.bottom);
1976
1977 /* Dummy BitBlt to let driver know that it should flush its changes.
1978 This should really be done using a call to DrvSynchronizeSurface,
1979 but the VMware driver doesn't hook that call. */
1980 IntEngBitBltEx(psoDest, NULL, psoMask, ClipRegion, DestColorTranslation,
1981 DestRect, pptlMask, pptlMask, pbo, BrushOrigin,
1982 R4_NOOP, FALSE);
1983
1984 ret = EngMaskBitBlt(psoDest, psoMask, ClipRegion, DestColorTranslation, SourceColorTranslation,
1985 &OutputRect, &InputPoint, pbo, BrushOrigin);
1986
1987 /* Dummy BitBlt to let driver know that something has changed. */
1988 IntEngBitBltEx(psoDest, NULL, psoMask, ClipRegion, DestColorTranslation,
1989 DestRect, pptlMask, pptlMask, pbo, BrushOrigin,
1990 R4_NOOP, FALSE);
1991
1992 MouseSafetyOnDrawEnd(psoDest);
1993 SURFACE_UnlockBitmapBits(psurfDest);
1994
1995 return ret;
1996 }
1997 /* EOF */