tabs->spaces reformat, no code change.
[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 * @implemented
253 */
254 BOOL STDCALL
255 EngBitBlt(SURFOBJ *DestObj,
256 SURFOBJ *SourceObj,
257 SURFOBJ *Mask,
258 CLIPOBJ *ClipRegion,
259 XLATEOBJ *ColorTranslation,
260 RECTL *DestRect,
261 POINTL *SourcePoint,
262 POINTL *MaskOrigin,
263 BRUSHOBJ *Brush,
264 POINTL *BrushOrigin,
265 ROP4 Rop4)
266 {
267 BYTE clippingType;
268 RECTL CombinedRect;
269 RECT_ENUM RectEnum;
270 BOOL EnumMore;
271 POINTL InputPoint;
272 RECTL InputRect;
273 RECTL OutputRect;
274 POINTL Translate;
275 INTENG_ENTER_LEAVE EnterLeaveSource;
276 INTENG_ENTER_LEAVE EnterLeaveDest;
277 SURFOBJ* InputObj;
278 SURFOBJ* OutputObj;
279 PBLTRECTFUNC BltRectFunc;
280 BOOLEAN Ret = TRUE;
281 RECTL ClipRect;
282 unsigned i;
283 POINTL Pt;
284 ULONG Direction;
285 BOOL UsesSource;
286 BOOL UsesPattern;
287 POINTL AdjustedBrushOrigin;
288
289 UsesSource = ROP4_USES_SOURCE(Rop4);
290 UsesPattern = ROP4_USES_PATTERN(Rop4);
291 if (R4_NOOP == Rop4)
292 {
293 /* Copy destination onto itself: nop */
294 return TRUE;
295 }
296
297 OutputRect = *DestRect;
298 if (OutputRect.right < OutputRect.left)
299 {
300 OutputRect.left = DestRect->right;
301 OutputRect.right = DestRect->left;
302 }
303 if (OutputRect.bottom < OutputRect.top)
304 {
305 OutputRect.left = DestRect->right;
306 OutputRect.right = DestRect->left;
307 }
308
309 if (UsesSource)
310 {
311 if (NULL == SourcePoint)
312 {
313 return FALSE;
314 }
315
316 /* Make sure we don't try to copy anything outside the valid source
317 region */
318 InputPoint = *SourcePoint;
319 if (InputPoint.x < 0)
320 {
321 OutputRect.left -= InputPoint.x;
322 InputPoint.x = 0;
323 }
324 if (InputPoint.y < 0)
325 {
326 OutputRect.top -= InputPoint.y;
327 InputPoint.y = 0;
328 }
329 if (SourceObj->sizlBitmap.cx < InputPoint.x +
330 OutputRect.right - OutputRect.left)
331 {
332 OutputRect.right = OutputRect.left +
333 SourceObj->sizlBitmap.cx - InputPoint.x;
334 }
335 if (SourceObj->sizlBitmap.cy < InputPoint.y +
336 OutputRect.bottom - OutputRect.top)
337 {
338 OutputRect.bottom = OutputRect.top +
339 SourceObj->sizlBitmap.cy - InputPoint.y;
340 }
341
342 InputRect.left = InputPoint.x;
343 InputRect.right = InputPoint.x + (OutputRect.right - OutputRect.left);
344 InputRect.top = InputPoint.y;
345 InputRect.bottom = InputPoint.y + (OutputRect.bottom - OutputRect.top);
346
347 if (! IntEngEnter(&EnterLeaveSource, SourceObj, &InputRect, TRUE,
348 &Translate, &InputObj))
349 {
350 return FALSE;
351 }
352
353 InputPoint.x += Translate.x;
354 InputPoint.y += Translate.y;
355 }
356 else
357 {
358 InputRect.left = 0;
359 InputRect.right = DestRect->right - DestRect->left;
360 InputRect.top = 0;
361 InputRect.bottom = DestRect->bottom - DestRect->top;
362 }
363
364 if (NULL != ClipRegion)
365 {
366 if (OutputRect.left < ClipRegion->rclBounds.left)
367 {
368 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
369 InputPoint.x += ClipRegion->rclBounds.left - OutputRect.left;
370 OutputRect.left = ClipRegion->rclBounds.left;
371 }
372 if (ClipRegion->rclBounds.right < OutputRect.right)
373 {
374 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
375 OutputRect.right = ClipRegion->rclBounds.right;
376 }
377 if (OutputRect.top < ClipRegion->rclBounds.top)
378 {
379 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
380 InputPoint.y += ClipRegion->rclBounds.top - OutputRect.top;
381 OutputRect.top = ClipRegion->rclBounds.top;
382 }
383 if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
384 {
385 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
386 OutputRect.bottom = ClipRegion->rclBounds.bottom;
387 }
388 }
389
390 /* Check for degenerate case: if height or width of OutputRect is 0 pixels
391 there's nothing to do */
392 if (OutputRect.right <= OutputRect.left ||
393 OutputRect.bottom <= OutputRect.top)
394 {
395 if (UsesSource)
396 {
397 IntEngLeave(&EnterLeaveSource);
398 }
399 return TRUE;
400 }
401
402 if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate,
403 &OutputObj))
404 {
405 if (UsesSource)
406 {
407 IntEngLeave(&EnterLeaveSource);
408 }
409 return FALSE;
410 }
411
412 OutputRect.left += Translate.x;
413 OutputRect.right += Translate.x;
414 OutputRect.top += Translate.y;
415 OutputRect.bottom += Translate.y;
416
417 if (BrushOrigin)
418 {
419 AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
420 AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
421 }
422 else
423 {
424 AdjustedBrushOrigin = Translate;
425 }
426
427 /* Determine clipping type */
428 if (ClipRegion == (CLIPOBJ *) NULL)
429 {
430 clippingType = DC_TRIVIAL;
431 }
432 else
433 {
434 clippingType = ClipRegion->iDComplexity;
435 }
436
437 if (R4_MASK == Rop4)
438 {
439 BltRectFunc = BltMask;
440 }
441 else if (ROP3_TO_ROP4(PATCOPY) == Rop4)
442 {
443 if (Brush->iSolidColor == 0xFFFFFFFF)
444 BltRectFunc = CallDibBitBlt;
445 else
446 BltRectFunc = BltPatCopy;
447 }
448 else
449 {
450 BltRectFunc = CallDibBitBlt;
451 }
452
453
454 switch (clippingType)
455 {
456 case DC_TRIVIAL:
457 Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ColorTranslation,
458 &OutputRect, &InputPoint, MaskOrigin, Brush,
459 &AdjustedBrushOrigin, Rop4);
460 break;
461 case DC_RECT:
462 /* Clip the blt to the clip rectangle */
463 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
464 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
465 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
466 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
467 if (EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
468 {
469 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
470 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
471 Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ColorTranslation,
472 &CombinedRect, &Pt, MaskOrigin, Brush,
473 &AdjustedBrushOrigin, Rop4);
474 }
475 break;
476 case DC_COMPLEX:
477 Ret = TRUE;
478 if (OutputObj == InputObj)
479 {
480 if (OutputRect.top < InputPoint.y)
481 {
482 Direction = OutputRect.left < InputPoint.x ?
483 CD_RIGHTDOWN : CD_LEFTDOWN;
484 }
485 else
486 {
487 Direction = OutputRect.left < InputPoint.x ?
488 CD_RIGHTUP : CD_LEFTUP;
489 }
490 }
491 else
492 {
493 Direction = CD_ANY;
494 }
495 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
496 do
497 {
498 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum),
499 (PVOID) &RectEnum);
500
501 for (i = 0; i < RectEnum.c; i++)
502 {
503 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
504 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
505 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
506 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
507 if (EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
508 {
509 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
510 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
511 Ret = (*BltRectFunc)(OutputObj, InputObj, Mask,
512 ColorTranslation, &CombinedRect, &Pt,
513 MaskOrigin, Brush, &AdjustedBrushOrigin,
514 Rop4) && Ret;
515 }
516 }
517 }
518 while (EnumMore);
519 break;
520 }
521
522
523 IntEngLeave(&EnterLeaveDest);
524 if (UsesSource)
525 {
526 IntEngLeave(&EnterLeaveSource);
527 }
528
529 return Ret;
530 }
531
532 BOOL STDCALL
533 IntEngBitBltEx(SURFOBJ *DestSurf,
534 SURFOBJ *SourceSurf,
535 SURFOBJ *MaskSurf,
536 CLIPOBJ *ClipRegion,
537 XLATEOBJ *ColorTranslation,
538 RECTL *DestRect,
539 POINTL *SourcePoint,
540 POINTL *MaskOrigin,
541 BRUSHOBJ *Brush,
542 POINTL *BrushOrigin,
543 ROP4 Rop4,
544 BOOL RemoveMouse)
545 {
546 BOOLEAN ret;
547 RECTL InputClippedRect;
548 RECTL OutputRect;
549 POINTL InputPoint;
550 BOOLEAN UsesSource;
551 BITMAPOBJ *DestObj;
552 BITMAPOBJ *SourceObj = NULL;
553
554 if (DestSurf == NULL)
555 return FALSE;
556
557 ASSERT(DestSurf);
558 DestObj = CONTAINING_RECORD(DestSurf, BITMAPOBJ, SurfObj);
559 ASSERT(DestObj);
560
561 InputClippedRect = *DestRect;
562 if (InputClippedRect.right < InputClippedRect.left)
563 {
564 InputClippedRect.left = DestRect->right;
565 InputClippedRect.right = DestRect->left;
566 }
567 if (InputClippedRect.bottom < InputClippedRect.top)
568 {
569 InputClippedRect.top = DestRect->bottom;
570 InputClippedRect.bottom = DestRect->top;
571 }
572 UsesSource = ROP4_USES_SOURCE(Rop4);
573 if (UsesSource)
574 {
575 if (NULL == SourcePoint || NULL == SourceSurf)
576 {
577 return FALSE;
578 }
579 InputPoint = *SourcePoint;
580
581 /* Make sure we don't try to copy anything outside the valid source
582 region */
583 if (InputPoint.x < 0)
584 {
585 InputClippedRect.left -= InputPoint.x;
586 InputPoint.x = 0;
587 }
588 if (InputPoint.y < 0)
589 {
590 InputClippedRect.top -= InputPoint.y;
591 InputPoint.y = 0;
592 }
593 if (SourceSurf->sizlBitmap.cx < InputPoint.x +
594 InputClippedRect.right -
595 InputClippedRect.left)
596 {
597 InputClippedRect.right = InputClippedRect.left +
598 SourceSurf->sizlBitmap.cx - InputPoint.x;
599 }
600 if (SourceSurf->sizlBitmap.cy < InputPoint.y +
601 InputClippedRect.bottom -
602 InputClippedRect.top)
603 {
604 InputClippedRect.bottom = InputClippedRect.top +
605 SourceSurf->sizlBitmap.cy - InputPoint.y;
606 }
607
608 if (InputClippedRect.right < InputClippedRect.left ||
609 InputClippedRect.bottom < InputClippedRect.top)
610 {
611 /* Everything clipped away, nothing to do */
612 return TRUE;
613 }
614 }
615
616 /* Clip against the bounds of the clipping region so we won't try to write
617 * outside the surface */
618 if (NULL != ClipRegion)
619 {
620 if (! EngIntersectRect(&OutputRect, &InputClippedRect,
621 &ClipRegion->rclBounds))
622 {
623 return TRUE;
624 }
625 InputPoint.x += OutputRect.left - InputClippedRect.left;
626 InputPoint.y += OutputRect.top - InputClippedRect.top;
627 }
628 else
629 {
630 OutputRect = InputClippedRect;
631 }
632
633 if (RemoveMouse)
634 {
635 BITMAPOBJ_LockBitmapBits(DestObj);
636
637 if (UsesSource)
638 {
639 if (SourceSurf != DestSurf)
640 {
641 SourceObj = CONTAINING_RECORD(SourceSurf, BITMAPOBJ, SurfObj);
642 BITMAPOBJ_LockBitmapBits(SourceObj);
643 }
644 MouseSafetyOnDrawStart(SourceSurf, InputPoint.x, InputPoint.y,
645 (InputPoint.x + abs(DestRect->right - DestRect->left)),
646 (InputPoint.y + abs(DestRect->bottom - DestRect->top)));
647 }
648 MouseSafetyOnDrawStart(DestSurf, OutputRect.left, OutputRect.top,
649 OutputRect.right, OutputRect.bottom);
650 }
651
652 /* No success yet */
653 ret = FALSE;
654
655 /* Call the driver's DrvBitBlt if available */
656 if (DestObj->flHooks & HOOK_BITBLT)
657 {
658 ret = GDIDEVFUNCS(DestSurf).BitBlt(
659 DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
660 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin,
661 Rop4);
662 }
663
664 if (! ret)
665 {
666 ret = EngBitBlt(DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
667 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin,
668 Rop4);
669 }
670
671 if (RemoveMouse)
672 {
673 MouseSafetyOnDrawEnd(DestSurf);
674 if (UsesSource)
675 {
676 MouseSafetyOnDrawEnd(SourceSurf);
677 if (SourceSurf != DestSurf)
678 {
679 BITMAPOBJ_UnlockBitmapBits(SourceObj);
680 }
681 }
682
683 BITMAPOBJ_UnlockBitmapBits(DestObj);
684 }
685
686 return ret;
687 }
688
689 static BOOLEAN STDCALL
690 CallDibStretchBlt(SURFOBJ* OutputObj,
691 SURFOBJ* InputObj,
692 SURFOBJ* Mask,
693 CLIPOBJ* ClipRegion,
694 XLATEOBJ* ColorTranslation,
695 RECTL* OutputRect,
696 RECTL* InputRect,
697 POINTL* MaskOrigin,
698 POINTL* BrushOrigin,
699 ULONG Mode)
700 {
701 POINTL RealBrushOrigin;
702 if (BrushOrigin == NULL)
703 {
704 RealBrushOrigin.x = RealBrushOrigin.y = 0;
705 }
706 else
707 {
708 RealBrushOrigin = *BrushOrigin;
709 }
710 return DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_StretchBlt(
711 OutputObj, InputObj, OutputRect, InputRect, MaskOrigin, RealBrushOrigin, ClipRegion, ColorTranslation, Mode);
712 }
713
714
715 BOOL
716 STDCALL
717 EngStretchBlt(
718 IN SURFOBJ *DestObj,
719 IN SURFOBJ *SourceObj,
720 IN SURFOBJ *Mask,
721 IN CLIPOBJ *ClipRegion,
722 IN XLATEOBJ *ColorTranslation,
723 IN COLORADJUSTMENT *pca,
724 IN POINTL *BrushOrigin,
725 IN RECTL *prclDest,
726 IN RECTL *prclSrc,
727 IN POINTL *MaskOrigin,
728 IN ULONG Mode
729 )
730 {
731 // www.osr.com/ddk/graphics/gdifncs_0bs7.htm
732
733 POINTL InputPoint;
734 RECTL InputRect;
735 RECTL OutputRect;
736 POINTL Translate;
737 INTENG_ENTER_LEAVE EnterLeaveSource;
738 INTENG_ENTER_LEAVE EnterLeaveDest;
739 SURFOBJ* InputObj;
740 SURFOBJ* OutputObj;
741 PSTRETCHRECTFUNC BltRectFunc;
742 BOOLEAN Ret;
743 POINTL AdjustedBrushOrigin;
744
745 InputRect.left = prclSrc->left;
746 InputRect.right = prclSrc->right;
747 InputRect.top = prclSrc->top;
748 InputRect.bottom = prclSrc->bottom;
749
750 if (! IntEngEnter(&EnterLeaveSource, SourceObj, &InputRect, TRUE, &Translate, &InputObj))
751 {
752 return FALSE;
753 }
754
755 InputPoint.x = InputRect.left + Translate.x;
756 InputPoint.y = InputRect.top + Translate.y;
757
758 OutputRect = *prclDest;
759
760 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
761 nothing to do */
762 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
763 {
764 IntEngLeave(&EnterLeaveSource);
765 return TRUE;
766 }
767
768 if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate, &OutputObj))
769 {
770 IntEngLeave(&EnterLeaveSource);
771 return FALSE;
772 }
773
774 OutputRect.left = prclDest->left + Translate.x;
775 OutputRect.right = prclDest->right + Translate.x;
776 OutputRect.top = prclDest->top + Translate.y;
777 OutputRect.bottom = prclDest->bottom + Translate.y;
778
779 if (NULL != BrushOrigin)
780 {
781 AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
782 AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
783 }
784 else
785 {
786 AdjustedBrushOrigin = Translate;
787 }
788
789 if (Mask != NULL)
790 {
791 //BltRectFunc = BltMask;
792 DPRINT("EngStretchBlt isn't capable of handling mask yet.\n");
793 IntEngLeave(&EnterLeaveDest);
794 IntEngLeave(&EnterLeaveSource);
795
796 return FALSE;
797 }
798 else
799 {
800 BltRectFunc = CallDibStretchBlt;
801 }
802
803
804 Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ClipRegion,
805 ColorTranslation, &OutputRect, &InputRect, MaskOrigin,
806 &AdjustedBrushOrigin, Mode);
807
808 IntEngLeave(&EnterLeaveDest);
809 IntEngLeave(&EnterLeaveSource);
810
811 return Ret;
812 }
813
814 BOOL STDCALL
815 IntEngStretchBlt(SURFOBJ *DestSurf,
816 SURFOBJ *SourceSurf,
817 SURFOBJ *MaskSurf,
818 CLIPOBJ *ClipRegion,
819 XLATEOBJ *ColorTranslation,
820 RECTL *DestRect,
821 RECTL *SourceRect,
822 POINTL *pMaskOrigin,
823 BRUSHOBJ *Brush,
824 POINTL *BrushOrigin,
825 ULONG Mode)
826 {
827 BOOLEAN ret;
828 COLORADJUSTMENT ca;
829 POINT MaskOrigin;
830 BITMAPOBJ *DestObj;
831 BITMAPOBJ *SourceObj = NULL;
832
833 ASSERT(DestSurf);
834 DestObj = CONTAINING_RECORD(DestSurf, BITMAPOBJ, SurfObj);
835 ASSERT(DestObj);
836
837 if (pMaskOrigin != NULL)
838 {
839 MaskOrigin.x = pMaskOrigin->x; MaskOrigin.y = pMaskOrigin->y;
840 }
841
842 /* No success yet */
843 ret = FALSE;
844 ASSERT(DestRect);
845 BITMAPOBJ_LockBitmapBits(DestObj);
846 MouseSafetyOnDrawStart(DestSurf, DestRect->left, DestRect->top,
847 DestRect->right, DestRect->bottom);
848
849 if (NULL != SourceSurf)
850 {
851 SourceObj = CONTAINING_RECORD(SourceSurf, BITMAPOBJ, SurfObj);
852 ASSERT(SourceRect);
853 if (SourceSurf != DestSurf)
854 {
855 BITMAPOBJ_LockBitmapBits(SourceObj);
856 }
857 MouseSafetyOnDrawStart(SourceSurf, SourceRect->left, SourceRect->top,
858 SourceRect->right, SourceRect->bottom);
859 }
860
861 /* Prepare color adjustment */
862
863 /* Call the driver's DrvStretchBlt if available */
864 if (DestObj->flHooks & HOOK_STRETCHBLT)
865 {
866 /* Drv->StretchBlt (look at http://www.osr.com/ddk/graphics/ddifncs_3ew7.htm )
867 SURFOBJ *psoMask // optional, if it exists, then rop4=0xCCAA, otherwise rop4=0xCCCC */
868 // FIXME: MaskOrigin is always NULL !
869 ret = GDIDEVFUNCS(DestSurf).StretchBlt(
870 DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
871 &ca, BrushOrigin, DestRect, SourceRect, NULL, Mode);
872 }
873
874 if (! ret)
875 {
876 // FIXME: see previous fixme
877 ret = EngStretchBlt(DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
878 &ca, BrushOrigin, DestRect, SourceRect, NULL, Mode);
879 }
880
881 if (NULL != SourceSurf)
882 {
883 MouseSafetyOnDrawEnd(SourceSurf);
884 if (SourceSurf != DestSurf)
885 {
886 BITMAPOBJ_UnlockBitmapBits(SourceObj);
887 }
888 }
889 MouseSafetyOnDrawEnd(DestSurf);
890 BITMAPOBJ_UnlockBitmapBits(DestObj);
891
892 return ret;
893 }
894
895 BOOL
896 STDCALL
897 EngAlphaBlend(IN SURFOBJ *Dest,
898 IN SURFOBJ *Source,
899 IN CLIPOBJ *ClipRegion,
900 IN XLATEOBJ *ColorTranslation,
901 IN PRECTL DestRect,
902 IN PRECTL SourceRect,
903 IN BLENDOBJ *BlendObj)
904 {
905 RECTL SourceStretchedRect;
906 SIZEL SourceStretchedSize;
907 HBITMAP SourceStretchedBitmap = 0;
908 SURFOBJ* SourceStretchedObj = NULL;
909 RECTL InputRect;
910 RECTL OutputRect;
911 RECTL ClipRect;
912 RECTL CombinedRect;
913 RECTL Rect;
914 POINTL Translate;
915 INTENG_ENTER_LEAVE EnterLeaveSource;
916 INTENG_ENTER_LEAVE EnterLeaveDest;
917 SURFOBJ* InputObj;
918 SURFOBJ* OutputObj;
919 LONG Width;
920 LONG ClippingType;
921 RECT_ENUM RectEnum;
922 BOOL EnumMore;
923 INT i;
924 BOOLEAN Ret;
925
926 DPRINT("EngAlphaBlend(Dest:0x%p, Source:0x%p, ClipRegion:0x%p, ColorTranslation:0x%p,\n", Dest, Source, ClipRegion, ColorTranslation);
927 DPRINT(" DestRect:{0x%x, 0x%x, 0x%x, 0x%x}, SourceRect:{0x%x, 0x%x, 0x%x, 0x%x},\n",
928 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom,
929 SourceRect->left, SourceRect->top, SourceRect->right, SourceRect->bottom);
930 DPRINT(" BlendObj:{0x%x, 0x%x, 0x%x, 0x%x}\n", BlendObj->BlendFunction.BlendOp,
931 BlendObj->BlendFunction.BlendFlags, BlendObj->BlendFunction.SourceConstantAlpha,
932 BlendObj->BlendFunction.AlphaFormat);
933
934 /* Validate input */
935 if (DestRect->left >= DestRect->right || DestRect->top >= DestRect->bottom)
936 {
937 DPRINT1("Empty destination rectangle!\n");
938 return FALSE;
939 }
940 if (SourceRect->left >= SourceRect->right || SourceRect->top >= SourceRect->bottom)
941 {
942 DPRINT1("Empty source rectangle!\n");
943 return FALSE;
944 }
945 if (Dest == Source &&
946 !(DestRect->left >= SourceRect->right || SourceRect->left >= DestRect->right ||
947 DestRect->top >= SourceRect->bottom || SourceRect->top >= DestRect->bottom))
948 {
949 DPRINT1("Source and destination rectangles overlap!\n");
950 return FALSE;
951 }
952
953 if (BlendObj->BlendFunction.BlendOp != AC_SRC_OVER)
954 {
955 DPRINT1("BlendOp != AC_SRC_OVER (0x%x)\n", BlendObj->BlendFunction.BlendOp);
956 return FALSE;
957 }
958 if (BlendObj->BlendFunction.BlendFlags != 0)
959 {
960 DPRINT1("BlendFlags != 0 (0x%x)\n", BlendObj->BlendFunction.BlendFlags);
961 return FALSE;
962 }
963 if ((BlendObj->BlendFunction.AlphaFormat & ~AC_SRC_ALPHA) != 0)
964 {
965 DPRINT1("Unsupported AlphaFormat (0x%x)\n", BlendObj->BlendFunction.AlphaFormat);
966 return FALSE;
967 }
968
969 /* Check if there is anything to draw */
970 if (ClipRegion != NULL &&
971 (ClipRegion->rclBounds.left >= ClipRegion->rclBounds.right ||
972 ClipRegion->rclBounds.top >= ClipRegion->rclBounds.bottom))
973 {
974 /* Nothing to do */
975 return TRUE;
976 }
977
978 /* Stretch source if needed */
979 if (DestRect->right - DestRect->left != SourceRect->right - SourceRect->left ||
980 DestRect->bottom - DestRect->top != SourceRect->bottom - SourceRect->top)
981 {
982 SourceStretchedSize.cx = DestRect->right - DestRect->left;
983 SourceStretchedSize.cy = DestRect->bottom - DestRect->top;
984 Width = DIB_GetDIBWidthBytes(SourceStretchedSize.cx, BitsPerFormat(Source->iBitmapFormat));
985 /* FIXME: Maybe it is a good idea to use EngCreateDeviceBitmap and IntEngStretchBlt
986 if possible to get a HW accelerated stretch. */
987 SourceStretchedBitmap = EngCreateBitmap(SourceStretchedSize, Width, Source->iBitmapFormat,
988 BMF_TOPDOWN | BMF_NOZEROINIT, NULL);
989 if (SourceStretchedBitmap == 0)
990 {
991 DPRINT1("EngCreateBitmap failed!\n");
992 return FALSE;
993 }
994 SourceStretchedObj = EngLockSurface((HSURF)SourceStretchedBitmap);
995 if (SourceStretchedObj == NULL)
996 {
997 DPRINT1("EngLockSurface failed!\n");
998 EngDeleteSurface((HSURF)SourceStretchedBitmap);
999 return FALSE;
1000 }
1001
1002 SourceStretchedRect.left = 0;
1003 SourceStretchedRect.right = SourceStretchedSize.cx;
1004 SourceStretchedRect.top = 0;
1005 SourceStretchedRect.bottom = SourceStretchedSize.cy;
1006 /* FIXME: IntEngStretchBlt isn't used here atm because it results in a
1007 try to acquire an already acquired mutex (lock the already locked source surface) */
1008 /*if (!IntEngStretchBlt(SourceStretchedObj, Source, NULL, NULL,
1009 NULL, &SourceStretchedRect, SourceRect, NULL,
1010 NULL, NULL, COLORONCOLOR))*/
1011 if (!EngStretchBlt(SourceStretchedObj, Source, NULL, NULL, NULL,
1012 NULL, NULL, &SourceStretchedRect, SourceRect,
1013 NULL, COLORONCOLOR))
1014 {
1015 DPRINT1("EngStretchBlt failed!\n");
1016 EngFreeMem(SourceStretchedObj->pvBits);
1017 EngUnlockSurface(SourceStretchedObj);
1018 EngDeleteSurface((HSURF)SourceStretchedBitmap);
1019 return FALSE;
1020 }
1021 SourceRect = &SourceStretchedRect;
1022 Source = SourceStretchedObj;
1023 }
1024
1025 /* Now call the DIB function */
1026 InputRect.left = SourceRect->left;
1027 InputRect.right = SourceRect->right;
1028 InputRect.top = SourceRect->top;
1029 InputRect.bottom = SourceRect->bottom;
1030 if (!IntEngEnter(&EnterLeaveSource, Source, &InputRect, TRUE, &Translate, &InputObj))
1031 {
1032 if (SourceStretchedObj != NULL)
1033 {
1034 EngFreeMem(SourceStretchedObj->pvBits);
1035 EngUnlockSurface(SourceStretchedObj);
1036 }
1037 if (SourceStretchedBitmap != 0)
1038 {
1039 EngDeleteSurface((HSURF)SourceStretchedBitmap);
1040 }
1041 return FALSE;
1042 }
1043 InputRect.left = SourceRect->left + Translate.x;
1044 InputRect.right = SourceRect->right + Translate.x;
1045 InputRect.top = SourceRect->top + Translate.y;
1046 InputRect.bottom = SourceRect->bottom + Translate.y;
1047
1048 OutputRect.left = DestRect->left;
1049 OutputRect.right = DestRect->right;
1050 OutputRect.top = DestRect->top;
1051 OutputRect.bottom = DestRect->bottom;
1052 if (!IntEngEnter(&EnterLeaveDest, Dest, &OutputRect, FALSE, &Translate, &OutputObj))
1053 {
1054 IntEngLeave(&EnterLeaveSource);
1055 if (SourceStretchedObj != NULL)
1056 {
1057 EngFreeMem(SourceStretchedObj->pvBits);
1058 EngUnlockSurface(SourceStretchedObj);
1059 }
1060 if (SourceStretchedBitmap != 0)
1061 {
1062 EngDeleteSurface((HSURF)SourceStretchedBitmap);
1063 }
1064 return FALSE;
1065 }
1066 OutputRect.left = DestRect->left + Translate.x;
1067 OutputRect.right = DestRect->right + Translate.x;
1068 OutputRect.top = DestRect->top + Translate.y;
1069 OutputRect.bottom = DestRect->bottom + Translate.y;
1070
1071 Ret = FALSE;
1072 ClippingType = (ClipRegion == NULL) ? DC_TRIVIAL : ClipRegion->iDComplexity;
1073 switch (ClippingType)
1074 {
1075 case DC_TRIVIAL:
1076 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend(
1077 OutputObj, InputObj, &OutputRect, &InputRect, ClipRegion, ColorTranslation, BlendObj);
1078 break;
1079
1080 case DC_RECT:
1081 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
1082 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
1083 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
1084 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
1085 if (EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
1086 {
1087 Rect.left = InputRect.left + CombinedRect.left - OutputRect.left;
1088 Rect.right = InputRect.right + CombinedRect.right - OutputRect.right;
1089 Rect.top = InputRect.top + CombinedRect.top - OutputRect.top;
1090 Rect.bottom = InputRect.bottom + CombinedRect.bottom - OutputRect.bottom;
1091 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend(
1092 OutputObj, InputObj, &CombinedRect, &Rect, ClipRegion, ColorTranslation, BlendObj);
1093 }
1094 break;
1095
1096 case DC_COMPLEX:
1097 Ret = TRUE;
1098 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, CD_ANY, 0);
1099 do
1100 {
1101 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum),
1102 (PVOID) &RectEnum);
1103
1104 for (i = 0; i < RectEnum.c; i++)
1105 {
1106 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
1107 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
1108 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
1109 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
1110 if (EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
1111 {
1112 Rect.left = InputRect.left + CombinedRect.left - OutputRect.left;
1113 Rect.right = InputRect.right + CombinedRect.right - OutputRect.right;
1114 Rect.top = InputRect.top + CombinedRect.top - OutputRect.top;
1115 Rect.bottom = InputRect.bottom + CombinedRect.bottom - OutputRect.bottom;
1116 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend(
1117 OutputObj, InputObj, &CombinedRect, &Rect, ClipRegion, ColorTranslation, BlendObj) && Ret;
1118 }
1119 }
1120 }
1121 while (EnumMore);
1122 break;
1123
1124 default:
1125 UNIMPLEMENTED;
1126 ASSERT(FALSE);
1127 break;
1128 }
1129
1130 IntEngLeave(&EnterLeaveDest);
1131 IntEngLeave(&EnterLeaveSource);
1132
1133 if (SourceStretchedObj != NULL)
1134 {
1135 EngFreeMem(SourceStretchedObj->pvBits);
1136 EngUnlockSurface(SourceStretchedObj);
1137 }
1138 if (SourceStretchedBitmap != 0)
1139 {
1140 EngDeleteSurface((HSURF)SourceStretchedBitmap);
1141 }
1142
1143 return Ret;
1144 }
1145
1146 BOOL STDCALL
1147 IntEngAlphaBlend(IN SURFOBJ *Dest,
1148 IN SURFOBJ *Source,
1149 IN CLIPOBJ *ClipRegion,
1150 IN XLATEOBJ *ColorTranslation,
1151 IN PRECTL DestRect,
1152 IN PRECTL SourceRect,
1153 IN BLENDOBJ *BlendObj)
1154 {
1155 BOOL ret = FALSE;
1156 BITMAPOBJ *DestObj;
1157 BITMAPOBJ *SourceObj;
1158
1159 ASSERT(Dest);
1160 DestObj = CONTAINING_RECORD(Dest, BITMAPOBJ, SurfObj);
1161 ASSERT(DestObj);
1162
1163 ASSERT(Source);
1164 SourceObj = CONTAINING_RECORD(Source, BITMAPOBJ, SurfObj);
1165 ASSERT(SourceObj);
1166
1167 ASSERT(DestRect);
1168 ASSERT(SourceRect);
1169
1170 /* Check if there is anything to draw */
1171 if (ClipRegion != NULL &&
1172 (ClipRegion->rclBounds.left >= ClipRegion->rclBounds.right ||
1173 ClipRegion->rclBounds.top >= ClipRegion->rclBounds.bottom))
1174 {
1175 /* Nothing to do */
1176 return TRUE;
1177 }
1178
1179 BITMAPOBJ_LockBitmapBits(DestObj);
1180 MouseSafetyOnDrawStart(Dest, DestRect->left, DestRect->top,
1181 DestRect->right, DestRect->bottom);
1182
1183 if (Source != Dest)
1184 BITMAPOBJ_LockBitmapBits(SourceObj);
1185 MouseSafetyOnDrawStart(Source, SourceRect->left, SourceRect->top,
1186 SourceRect->right, SourceRect->bottom);
1187
1188 /* Call the driver's DrvAlphaBlend if available */
1189 if (DestObj->flHooks & HOOK_ALPHABLEND)
1190 {
1191 ret = GDIDEVFUNCS(Dest).AlphaBlend(
1192 Dest, Source, ClipRegion, ColorTranslation,
1193 DestRect, SourceRect, BlendObj);
1194 }
1195
1196 if (! ret)
1197 {
1198 ret = EngAlphaBlend(Dest, Source, ClipRegion, ColorTranslation,
1199 DestRect, SourceRect, BlendObj);
1200 }
1201
1202 MouseSafetyOnDrawEnd(Source);
1203 if (Source != Dest)
1204 BITMAPOBJ_UnlockBitmapBits(SourceObj);
1205 MouseSafetyOnDrawEnd(Dest);
1206 BITMAPOBJ_UnlockBitmapBits(DestObj);
1207
1208 return ret;
1209 }
1210
1211 /**** REACTOS FONT RENDERING CODE *********************************************/
1212
1213 /* renders the alpha mask bitmap */
1214 static BOOLEAN STDCALL
1215 AlphaBltMask(SURFOBJ* Dest,
1216 SURFOBJ* Source,
1217 SURFOBJ* Mask,
1218 XLATEOBJ* ColorTranslation,
1219 XLATEOBJ* SrcColorTranslation,
1220 RECTL* DestRect,
1221 POINTL* SourcePoint,
1222 POINTL* MaskPoint,
1223 BRUSHOBJ* Brush,
1224 POINTL* BrushPoint)
1225 {
1226 LONG i, j, dx, dy;
1227 int r, g, b;
1228 ULONG Background, BrushColor, NewColor;
1229 BYTE *tMask, *lMask;
1230
1231 dx = DestRect->right - DestRect->left;
1232 dy = DestRect->bottom - DestRect->top;
1233
1234 if (Mask != NULL)
1235 {
1236 BrushColor = XLATEOBJ_iXlate(SrcColorTranslation, Brush->iSolidColor);
1237 r = (int)GetRValue(BrushColor);
1238 g = (int)GetGValue(BrushColor);
1239 b = (int)GetBValue(BrushColor);
1240
1241 tMask = (PBYTE)Mask->pvScan0 + (SourcePoint->y * Mask->lDelta) + SourcePoint->x;
1242 for (j = 0; j < dy; j++)
1243 {
1244 lMask = tMask;
1245 for (i = 0; i < dx; i++)
1246 {
1247 if (*lMask > 0)
1248 {
1249 if (*lMask == 0xff)
1250 {
1251 DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_PutPixel(
1252 Dest, DestRect->left + i, DestRect->top + j, Brush->iSolidColor);
1253 }
1254 else
1255 {
1256 Background = DIB_GetSource(Dest, DestRect->left + i, DestRect->top + j,
1257 SrcColorTranslation);
1258
1259 NewColor =
1260 RGB((*lMask * (r - GetRValue(Background)) >> 8) + GetRValue(Background),
1261 (*lMask * (g - GetGValue(Background)) >> 8) + GetGValue(Background),
1262 (*lMask * (b - GetBValue(Background)) >> 8) + GetBValue(Background));
1263
1264 Background = XLATEOBJ_iXlate(ColorTranslation, NewColor);
1265 DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_PutPixel(
1266 Dest, DestRect->left + i, DestRect->top + j, Background);
1267 }
1268 }
1269 lMask++;
1270 }
1271 tMask += Mask->lDelta;
1272 }
1273 return TRUE;
1274 }
1275 else
1276 {
1277 return FALSE;
1278 }
1279 }
1280
1281 BOOL STDCALL
1282 EngMaskBitBlt(SURFOBJ *DestObj,
1283 SURFOBJ *Mask,
1284 CLIPOBJ *ClipRegion,
1285 XLATEOBJ *DestColorTranslation,
1286 XLATEOBJ *SourceColorTranslation,
1287 RECTL *DestRect,
1288 POINTL *SourcePoint,
1289 POINTL *MaskOrigin,
1290 BRUSHOBJ *Brush,
1291 POINTL *BrushOrigin)
1292 {
1293 BYTE clippingType;
1294 RECTL CombinedRect;
1295 RECT_ENUM RectEnum;
1296 BOOL EnumMore;
1297 POINTL InputPoint;
1298 RECTL InputRect;
1299 RECTL OutputRect;
1300 POINTL Translate;
1301 INTENG_ENTER_LEAVE EnterLeaveSource;
1302 INTENG_ENTER_LEAVE EnterLeaveDest;
1303 SURFOBJ* InputObj;
1304 SURFOBJ* OutputObj;
1305 BOOLEAN Ret = TRUE;
1306 RECTL ClipRect;
1307 unsigned i;
1308 POINTL Pt;
1309 ULONG Direction;
1310 POINTL AdjustedBrushOrigin;
1311
1312 ASSERT ( Mask );
1313
1314 if (NULL != SourcePoint)
1315 {
1316 InputRect.left = SourcePoint->x;
1317 InputRect.right = SourcePoint->x + (DestRect->right - DestRect->left);
1318 InputRect.top = SourcePoint->y;
1319 InputRect.bottom = SourcePoint->y + (DestRect->bottom - DestRect->top);
1320 }
1321 else
1322 {
1323 InputRect.left = 0;
1324 InputRect.right = DestRect->right - DestRect->left;
1325 InputRect.top = 0;
1326 InputRect.bottom = DestRect->bottom - DestRect->top;
1327 }
1328
1329 if (! IntEngEnter(&EnterLeaveSource, DestObj, &InputRect, TRUE, &Translate, &InputObj))
1330 {
1331 return FALSE;
1332 }
1333
1334 if (NULL != SourcePoint)
1335 {
1336 InputPoint.x = SourcePoint->x + Translate.x;
1337 InputPoint.y = SourcePoint->y + Translate.y;
1338 }
1339 else
1340 {
1341 InputPoint.x = 0;
1342 InputPoint.y = 0;
1343 }
1344
1345 OutputRect = *DestRect;
1346 if (NULL != ClipRegion)
1347 {
1348 if (OutputRect.left < ClipRegion->rclBounds.left)
1349 {
1350 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
1351 InputPoint.x += ClipRegion->rclBounds.left - OutputRect.left;
1352 OutputRect.left = ClipRegion->rclBounds.left;
1353 }
1354 if (ClipRegion->rclBounds.right < OutputRect.right)
1355 {
1356 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
1357 OutputRect.right = ClipRegion->rclBounds.right;
1358 }
1359 if (OutputRect.top < ClipRegion->rclBounds.top)
1360 {
1361 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
1362 InputPoint.y += ClipRegion->rclBounds.top - OutputRect.top;
1363 OutputRect.top = ClipRegion->rclBounds.top;
1364 }
1365 if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
1366 {
1367 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
1368 OutputRect.bottom = ClipRegion->rclBounds.bottom;
1369 }
1370 }
1371
1372 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
1373 nothing to do */
1374 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
1375 {
1376 IntEngLeave(&EnterLeaveSource);
1377 return TRUE;
1378 }
1379
1380 if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate, &OutputObj))
1381 {
1382 IntEngLeave(&EnterLeaveSource);
1383 return FALSE;
1384 }
1385
1386 OutputRect.left = DestRect->left + Translate.x;
1387 OutputRect.right = DestRect->right + Translate.x;
1388 OutputRect.top = DestRect->top + Translate.y;
1389 OutputRect.bottom = DestRect->bottom + Translate.y;
1390
1391 if (BrushOrigin)
1392 {
1393 AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
1394 AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
1395 }
1396 else
1397 AdjustedBrushOrigin = Translate;
1398
1399 // Determine clipping type
1400 if (ClipRegion == (CLIPOBJ *) NULL)
1401 {
1402 clippingType = DC_TRIVIAL;
1403 } else {
1404 clippingType = ClipRegion->iDComplexity;
1405 }
1406
1407 switch (clippingType)
1408 {
1409 case DC_TRIVIAL:
1410 if (Mask->iBitmapFormat == BMF_8BPP)
1411 Ret = AlphaBltMask(OutputObj, InputObj, Mask, DestColorTranslation, SourceColorTranslation,
1412 &OutputRect, &InputPoint, MaskOrigin, Brush, &AdjustedBrushOrigin);
1413 else
1414 Ret = BltMask(OutputObj, InputObj, Mask, DestColorTranslation,
1415 &OutputRect, &InputPoint, MaskOrigin, Brush, &AdjustedBrushOrigin,
1416 R4_MASK);
1417 break;
1418 case DC_RECT:
1419 // Clip the blt to the clip rectangle
1420 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
1421 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
1422 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
1423 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
1424 if (EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
1425 {
1426 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
1427 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
1428 if (Mask->iBitmapFormat == BMF_8BPP)
1429 {
1430 Ret = AlphaBltMask(OutputObj, InputObj, Mask, DestColorTranslation, SourceColorTranslation,
1431 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin);
1432 }
1433 else
1434 {
1435 Ret = BltMask(OutputObj, InputObj, Mask, DestColorTranslation,
1436 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin, R4_MASK);
1437 }
1438 }
1439 break;
1440 case DC_COMPLEX:
1441 Ret = TRUE;
1442 if (OutputObj == InputObj)
1443 {
1444 if (OutputRect.top < InputPoint.y)
1445 {
1446 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
1447 }
1448 else
1449 {
1450 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
1451 }
1452 }
1453 else
1454 {
1455 Direction = CD_ANY;
1456 }
1457 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
1458 do
1459 {
1460 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
1461
1462 for (i = 0; i < RectEnum.c; i++)
1463 {
1464 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
1465 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
1466 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
1467 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
1468 if (EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
1469 {
1470 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
1471 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
1472 if (Mask->iBitmapFormat == BMF_8BPP)
1473 {
1474 Ret = AlphaBltMask(OutputObj, InputObj, Mask,
1475 DestColorTranslation,
1476 SourceColorTranslation,
1477 &CombinedRect, &Pt, MaskOrigin, Brush,
1478 &AdjustedBrushOrigin) && Ret;
1479 }
1480 else
1481 {
1482 Ret = BltMask(OutputObj, InputObj, Mask,
1483 DestColorTranslation, &CombinedRect, &Pt,
1484 MaskOrigin, Brush, &AdjustedBrushOrigin,
1485 R4_MASK) && Ret;
1486 }
1487 }
1488 }
1489 }
1490 while (EnumMore);
1491 break;
1492 }
1493
1494
1495 IntEngLeave(&EnterLeaveDest);
1496 IntEngLeave(&EnterLeaveSource);
1497
1498 return Ret;
1499 }
1500
1501 BOOL STDCALL
1502 IntEngMaskBlt(SURFOBJ *DestSurf,
1503 SURFOBJ *Mask,
1504 CLIPOBJ *ClipRegion,
1505 XLATEOBJ *DestColorTranslation,
1506 XLATEOBJ *SourceColorTranslation,
1507 RECTL *DestRect,
1508 POINTL *SourcePoint,
1509 POINTL *MaskOrigin,
1510 BRUSHOBJ *Brush,
1511 POINTL *BrushOrigin)
1512 {
1513 BOOLEAN ret;
1514 RECTL OutputRect;
1515 POINTL InputPoint;
1516 BITMAPOBJ *DestObj;
1517
1518 ASSERT(Mask);
1519
1520 if (NULL != SourcePoint)
1521 {
1522 InputPoint = *SourcePoint;
1523 }
1524
1525 /* Clip against the bounds of the clipping region so we won't try to write
1526 * outside the surface */
1527 if (NULL != ClipRegion)
1528 {
1529 if (! EngIntersectRect(&OutputRect, DestRect, &ClipRegion->rclBounds))
1530 {
1531 return TRUE;
1532 }
1533 InputPoint.x += OutputRect.left - DestRect->left;
1534 InputPoint.y += OutputRect.top - DestRect->top;
1535 }
1536 else
1537 {
1538 OutputRect = *DestRect;
1539 }
1540
1541 /* No success yet */
1542 ret = FALSE;
1543 ASSERT(DestSurf);
1544 DestObj = CONTAINING_RECORD(DestSurf, BITMAPOBJ, SurfObj);
1545
1546 BITMAPOBJ_LockBitmapBits(DestObj);
1547 MouseSafetyOnDrawStart(DestSurf, OutputRect.left, OutputRect.top,
1548 OutputRect.right, OutputRect.bottom);
1549
1550 /* Dummy BitBlt to let driver know that it should flush its changes.
1551 This should really be done using a call to DrvSynchronizeSurface,
1552 but the VMware driver doesn't hook that call. */
1553 IntEngBitBltEx(DestSurf, NULL, Mask, ClipRegion, DestColorTranslation,
1554 DestRect, SourcePoint, MaskOrigin, Brush, BrushOrigin,
1555 R4_NOOP, FALSE);
1556
1557 ret = EngMaskBitBlt(DestSurf, Mask, ClipRegion, DestColorTranslation, SourceColorTranslation,
1558 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin);
1559
1560 /* Dummy BitBlt to let driver know that something has changed. */
1561 IntEngBitBltEx(DestSurf, NULL, Mask, ClipRegion, DestColorTranslation,
1562 DestRect, SourcePoint, MaskOrigin, Brush, BrushOrigin,
1563 R4_NOOP, FALSE);
1564
1565 MouseSafetyOnDrawEnd(DestSurf);
1566 BITMAPOBJ_UnlockBitmapBits(DestObj);
1567
1568 return ret;
1569 }
1570 /* EOF */