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