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