8195fe1c0a77dd5fd06d6259ff17eebdffc30942
[reactos.git] / reactos / subsys / win32k / eng / bitblt.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
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 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 ASSERT(DestSurf);
555 DestObj = CONTAINING_RECORD(DestSurf, BITMAPOBJ, SurfObj);
556 ASSERT(DestObj);
557
558 InputClippedRect = *DestRect;
559 if (InputClippedRect.right < InputClippedRect.left)
560 {
561 InputClippedRect.left = DestRect->right;
562 InputClippedRect.right = DestRect->left;
563 }
564 if (InputClippedRect.bottom < InputClippedRect.top)
565 {
566 InputClippedRect.top = DestRect->bottom;
567 InputClippedRect.bottom = DestRect->top;
568 }
569 UsesSource = ROP4_USES_SOURCE(Rop4);
570 if (UsesSource)
571 {
572 if (NULL == SourcePoint || NULL == SourceSurf)
573 {
574 return FALSE;
575 }
576 InputPoint = *SourcePoint;
577
578 /* Make sure we don't try to copy anything outside the valid source
579 region */
580 if (InputPoint.x < 0)
581 {
582 InputClippedRect.left -= InputPoint.x;
583 InputPoint.x = 0;
584 }
585 if (InputPoint.y < 0)
586 {
587 InputClippedRect.top -= InputPoint.y;
588 InputPoint.y = 0;
589 }
590 if (SourceSurf->sizlBitmap.cx < InputPoint.x +
591 InputClippedRect.right -
592 InputClippedRect.left)
593 {
594 InputClippedRect.right = InputClippedRect.left +
595 SourceSurf->sizlBitmap.cx - InputPoint.x;
596 }
597 if (SourceSurf->sizlBitmap.cy < InputPoint.y +
598 InputClippedRect.bottom -
599 InputClippedRect.top)
600 {
601 InputClippedRect.bottom = InputClippedRect.top +
602 SourceSurf->sizlBitmap.cy - InputPoint.y;
603 }
604
605 if (InputClippedRect.right < InputClippedRect.left ||
606 InputClippedRect.bottom < InputClippedRect.top)
607 {
608 /* Everything clipped away, nothing to do */
609 return TRUE;
610 }
611 }
612
613 /* Clip against the bounds of the clipping region so we won't try to write
614 * outside the surface */
615 if (NULL != ClipRegion)
616 {
617 if (! EngIntersectRect(&OutputRect, &InputClippedRect,
618 &ClipRegion->rclBounds))
619 {
620 return TRUE;
621 }
622 InputPoint.x += OutputRect.left - InputClippedRect.left;
623 InputPoint.y += OutputRect.top - InputClippedRect.top;
624 }
625 else
626 {
627 OutputRect = InputClippedRect;
628 }
629
630 if (RemoveMouse)
631 {
632 BITMAPOBJ_LockBitmapBits(DestObj);
633
634 if (UsesSource)
635 {
636 if (SourceSurf != DestSurf)
637 {
638 SourceObj = CONTAINING_RECORD(SourceSurf, BITMAPOBJ, SurfObj);
639 BITMAPOBJ_LockBitmapBits(SourceObj);
640 }
641 MouseSafetyOnDrawStart(SourceSurf, InputPoint.x, InputPoint.y,
642 (InputPoint.x + abs(DestRect->right - DestRect->left)),
643 (InputPoint.y + abs(DestRect->bottom - DestRect->top)));
644 }
645 MouseSafetyOnDrawStart(DestSurf, OutputRect.left, OutputRect.top,
646 OutputRect.right, OutputRect.bottom);
647 }
648
649 /* No success yet */
650 ret = FALSE;
651
652 /* Call the driver's DrvBitBlt if available */
653 if (DestObj->flHooks & HOOK_BITBLT)
654 {
655 ret = GDIDEVFUNCS(DestSurf).BitBlt(
656 DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
657 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin,
658 Rop4);
659 }
660
661 if (! ret)
662 {
663 ret = EngBitBlt(DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
664 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin,
665 Rop4);
666 }
667
668 if (RemoveMouse)
669 {
670 MouseSafetyOnDrawEnd(DestSurf);
671 if (UsesSource)
672 {
673 MouseSafetyOnDrawEnd(SourceSurf);
674 if (SourceSurf != DestSurf)
675 {
676 BITMAPOBJ_UnlockBitmapBits(SourceObj);
677 }
678 }
679
680 BITMAPOBJ_UnlockBitmapBits(DestObj);
681 }
682
683 return ret;
684 }
685
686 static BOOLEAN STDCALL
687 CallDibStretchBlt(SURFOBJ* OutputObj,
688 SURFOBJ* InputObj,
689 SURFOBJ* Mask,
690 CLIPOBJ* ClipRegion,
691 XLATEOBJ* ColorTranslation,
692 RECTL* OutputRect,
693 RECTL* InputRect,
694 POINTL* MaskOrigin,
695 POINTL* BrushOrigin,
696 ULONG Mode)
697 {
698 POINTL RealBrushOrigin;
699 if (BrushOrigin == NULL)
700 {
701 RealBrushOrigin.x = RealBrushOrigin.y = 0;
702 }
703 else
704 {
705 RealBrushOrigin = *BrushOrigin;
706 }
707 return DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_StretchBlt(
708 OutputObj, InputObj, OutputRect, InputRect, MaskOrigin, RealBrushOrigin, ClipRegion, ColorTranslation, Mode);
709 }
710
711
712 BOOL
713 STDCALL
714 EngStretchBlt(
715 IN SURFOBJ *DestObj,
716 IN SURFOBJ *SourceObj,
717 IN SURFOBJ *Mask,
718 IN CLIPOBJ *ClipRegion,
719 IN XLATEOBJ *ColorTranslation,
720 IN COLORADJUSTMENT *pca,
721 IN POINTL *BrushOrigin,
722 IN RECTL *prclDest,
723 IN RECTL *prclSrc,
724 IN POINTL *MaskOrigin,
725 IN ULONG Mode
726 )
727 {
728 // www.osr.com/ddk/graphics/gdifncs_0bs7.htm
729
730 POINTL InputPoint;
731 RECTL InputRect;
732 RECTL OutputRect;
733 POINTL Translate;
734 INTENG_ENTER_LEAVE EnterLeaveSource;
735 INTENG_ENTER_LEAVE EnterLeaveDest;
736 SURFOBJ* InputObj;
737 SURFOBJ* OutputObj;
738 PSTRETCHRECTFUNC BltRectFunc;
739 BOOLEAN Ret;
740 POINTL AdjustedBrushOrigin;
741
742 InputRect.left = prclSrc->left;
743 InputRect.right = prclSrc->right;
744 InputRect.top = prclSrc->top;
745 InputRect.bottom = prclSrc->bottom;
746
747 if (! IntEngEnter(&EnterLeaveSource, SourceObj, &InputRect, TRUE, &Translate, &InputObj))
748 {
749 return FALSE;
750 }
751
752 InputPoint.x = InputRect.left + Translate.x;
753 InputPoint.y = InputRect.top + Translate.y;
754
755 OutputRect = *prclDest;
756
757 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
758 nothing to do */
759 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
760 {
761 IntEngLeave(&EnterLeaveSource);
762 return TRUE;
763 }
764
765 if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate, &OutputObj))
766 {
767 IntEngLeave(&EnterLeaveSource);
768 return FALSE;
769 }
770
771 OutputRect.left = prclDest->left + Translate.x;
772 OutputRect.right = prclDest->right + Translate.x;
773 OutputRect.top = prclDest->top + Translate.y;
774 OutputRect.bottom = prclDest->bottom + Translate.y;
775
776 if (NULL != BrushOrigin)
777 {
778 AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
779 AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
780 }
781 else
782 {
783 AdjustedBrushOrigin = Translate;
784 }
785
786 if (Mask != NULL)
787 {
788 //BltRectFunc = BltMask;
789 DPRINT("EngStretchBlt isn't capable of handling mask yet.\n");
790 IntEngLeave(&EnterLeaveDest);
791 IntEngLeave(&EnterLeaveSource);
792
793 return FALSE;
794 }
795 else
796 {
797 BltRectFunc = CallDibStretchBlt;
798 }
799
800
801 Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ClipRegion,
802 ColorTranslation, &OutputRect, &InputRect, MaskOrigin,
803 &AdjustedBrushOrigin, Mode);
804
805 IntEngLeave(&EnterLeaveDest);
806 IntEngLeave(&EnterLeaveSource);
807
808 return Ret;
809 }
810
811 BOOL STDCALL
812 IntEngStretchBlt(SURFOBJ *DestSurf,
813 SURFOBJ *SourceSurf,
814 SURFOBJ *MaskSurf,
815 CLIPOBJ *ClipRegion,
816 XLATEOBJ *ColorTranslation,
817 RECTL *DestRect,
818 RECTL *SourceRect,
819 POINTL *pMaskOrigin,
820 BRUSHOBJ *Brush,
821 POINTL *BrushOrigin,
822 ULONG Mode)
823 {
824 BOOLEAN ret;
825 COLORADJUSTMENT ca;
826 POINT MaskOrigin;
827 BITMAPOBJ *DestObj;
828 BITMAPOBJ *SourceObj = NULL;
829
830 ASSERT(DestSurf);
831 DestObj = CONTAINING_RECORD(DestSurf, BITMAPOBJ, SurfObj);
832 ASSERT(DestObj);
833
834 if (pMaskOrigin != NULL)
835 {
836 MaskOrigin.x = pMaskOrigin->x; MaskOrigin.y = pMaskOrigin->y;
837 }
838
839 /* No success yet */
840 ret = FALSE;
841 ASSERT(DestRect);
842 BITMAPOBJ_LockBitmapBits(DestObj);
843 MouseSafetyOnDrawStart(DestSurf, DestRect->left, DestRect->top,
844 DestRect->right, DestRect->bottom);
845
846 if (NULL != SourceSurf)
847 {
848 SourceObj = CONTAINING_RECORD(SourceSurf, BITMAPOBJ, SurfObj);
849 ASSERT(SourceRect);
850 if (SourceSurf != DestSurf)
851 {
852 BITMAPOBJ_LockBitmapBits(SourceObj);
853 }
854 MouseSafetyOnDrawStart(SourceSurf, SourceRect->left, SourceRect->top,
855 SourceRect->right, SourceRect->bottom);
856 }
857
858 /* Prepare color adjustment */
859
860 /* Call the driver's DrvStretchBlt if available */
861 if (DestObj->flHooks & HOOK_STRETCHBLT)
862 {
863 /* Drv->StretchBlt (look at http://www.osr.com/ddk/graphics/ddifncs_3ew7.htm )
864 SURFOBJ *psoMask // optional, if it exists, then rop4=0xCCAA, otherwise rop4=0xCCCC */
865 // FIXME: MaskOrigin is always NULL !
866 ret = GDIDEVFUNCS(DestSurf).StretchBlt(
867 DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
868 &ca, BrushOrigin, DestRect, SourceRect, NULL, Mode);
869 }
870
871 if (! ret)
872 {
873 // FIXME: see previous fixme
874 ret = EngStretchBlt(DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
875 &ca, BrushOrigin, DestRect, SourceRect, NULL, Mode);
876 }
877
878 if (NULL != SourceSurf)
879 {
880 MouseSafetyOnDrawEnd(SourceSurf);
881 if (SourceSurf != DestSurf)
882 {
883 BITMAPOBJ_UnlockBitmapBits(SourceObj);
884 }
885 }
886 MouseSafetyOnDrawEnd(DestSurf);
887 BITMAPOBJ_UnlockBitmapBits(DestObj);
888
889 return ret;
890 }
891
892 BOOL
893 STDCALL
894 EngAlphaBlend(IN SURFOBJ *Dest,
895 IN SURFOBJ *Source,
896 IN CLIPOBJ *ClipRegion,
897 IN XLATEOBJ *ColorTranslation,
898 IN PRECTL DestRect,
899 IN PRECTL SourceRect,
900 IN BLENDOBJ *BlendObj)
901 {
902 RECTL SourceStretchedRect;
903 SIZEL SourceStretchedSize;
904 HBITMAP SourceStretchedBitmap = 0;
905 SURFOBJ* SourceStretchedObj = NULL;
906 RECTL InputRect;
907 RECTL OutputRect;
908 RECTL ClipRect;
909 RECTL CombinedRect;
910 RECTL Rect;
911 POINTL Translate;
912 INTENG_ENTER_LEAVE EnterLeaveSource;
913 INTENG_ENTER_LEAVE EnterLeaveDest;
914 SURFOBJ* InputObj;
915 SURFOBJ* OutputObj;
916 LONG Width;
917 LONG ClippingType;
918 RECT_ENUM RectEnum;
919 BOOL EnumMore;
920 INT i;
921 BOOLEAN Ret;
922
923 DPRINT("EngAlphaBlend(Dest:0x%p, Source:0x%p, ClipRegion:0x%p, ColorTranslation:0x%p,\n", Dest, Source, ClipRegion, ColorTranslation);
924 DPRINT(" DestRect:{0x%x, 0x%x, 0x%x, 0x%x}, SourceRect:{0x%x, 0x%x, 0x%x, 0x%x},\n",
925 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom,
926 SourceRect->left, SourceRect->top, SourceRect->right, SourceRect->bottom);
927 DPRINT(" BlendObj:{0x%x, 0x%x, 0x%x, 0x%x}\n", BlendObj->BlendFunction.BlendOp,
928 BlendObj->BlendFunction.BlendFlags, BlendObj->BlendFunction.SourceConstantAlpha,
929 BlendObj->BlendFunction.AlphaFormat);
930
931 /* Validate input */
932 if (DestRect->left >= DestRect->right || DestRect->top >= DestRect->bottom)
933 {
934 DPRINT1("Empty destination rectangle!\n");
935 return FALSE;
936 }
937 if (SourceRect->left >= SourceRect->right || SourceRect->top >= SourceRect->bottom)
938 {
939 DPRINT1("Empty source rectangle!\n");
940 return FALSE;
941 }
942 if (Dest == Source &&
943 !(DestRect->left >= SourceRect->right || SourceRect->left >= DestRect->right ||
944 DestRect->top >= SourceRect->bottom || SourceRect->top >= DestRect->bottom))
945 {
946 DPRINT1("Source and destination rectangles overlap!\n");
947 return FALSE;
948 }
949
950 if (BlendObj->BlendFunction.BlendOp != AC_SRC_OVER)
951 {
952 DPRINT1("BlendOp != AC_SRC_OVER (0x%x)\n", BlendObj->BlendFunction.BlendOp);
953 return FALSE;
954 }
955 if (BlendObj->BlendFunction.BlendFlags != 0)
956 {
957 DPRINT1("BlendFlags != 0 (0x%x)\n", BlendObj->BlendFunction.BlendFlags);
958 return FALSE;
959 }
960 if ((BlendObj->BlendFunction.AlphaFormat & ~AC_SRC_ALPHA) != 0)
961 {
962 DPRINT1("Unsupported AlphaFormat (0x%x)\n", BlendObj->BlendFunction.AlphaFormat);
963 return FALSE;
964 }
965
966 /* Check if there is anything to draw */
967 if (ClipRegion != NULL &&
968 (ClipRegion->rclBounds.left >= ClipRegion->rclBounds.right ||
969 ClipRegion->rclBounds.top >= ClipRegion->rclBounds.bottom))
970 {
971 /* Nothing to do */
972 return TRUE;
973 }
974
975 /* Stretch source if needed */
976 if (DestRect->right - DestRect->left != SourceRect->right - SourceRect->left ||
977 DestRect->bottom - DestRect->top != SourceRect->bottom - SourceRect->top)
978 {
979 SourceStretchedSize.cx = DestRect->right - DestRect->left;
980 SourceStretchedSize.cy = DestRect->bottom - DestRect->top;
981 Width = DIB_GetDIBWidthBytes(SourceStretchedSize.cx, BitsPerFormat(Source->iBitmapFormat));
982 /* FIXME: Maybe it is a good idea to use EngCreateDeviceBitmap and IntEngStretchBlt
983 if possible to get a HW accelerated stretch. */
984 SourceStretchedBitmap = EngCreateBitmap(SourceStretchedSize, Width, Source->iBitmapFormat,
985 BMF_TOPDOWN | BMF_NOZEROINIT, NULL);
986 if (SourceStretchedBitmap == 0)
987 {
988 DPRINT1("EngCreateBitmap failed!\n");
989 return FALSE;
990 }
991 SourceStretchedObj = EngLockSurface((HSURF)SourceStretchedBitmap);
992 if (SourceStretchedObj == NULL)
993 {
994 DPRINT1("EngLockSurface failed!\n");
995 EngDeleteSurface((HSURF)SourceStretchedBitmap);
996 return FALSE;
997 }
998
999 SourceStretchedRect.left = 0;
1000 SourceStretchedRect.right = SourceStretchedSize.cx;
1001 SourceStretchedRect.top = 0;
1002 SourceStretchedRect.bottom = SourceStretchedSize.cy;
1003 /* FIXME: IntEngStretchBlt isn't used here atm because it results in a
1004 try to acquire an already acquired mutex (lock the already locked source surface) */
1005 /*if (!IntEngStretchBlt(SourceStretchedObj, Source, NULL, NULL,
1006 NULL, &SourceStretchedRect, SourceRect, NULL,
1007 NULL, NULL, COLORONCOLOR))*/
1008 if (!EngStretchBlt(SourceStretchedObj, Source, NULL, NULL, NULL,
1009 NULL, NULL, &SourceStretchedRect, SourceRect,
1010 NULL, COLORONCOLOR))
1011 {
1012 DPRINT1("EngStretchBlt failed!\n");
1013 EngFreeMem(SourceStretchedObj->pvBits);
1014 EngUnlockSurface(SourceStretchedObj);
1015 EngDeleteSurface((HSURF)SourceStretchedBitmap);
1016 return FALSE;
1017 }
1018 SourceRect = &SourceStretchedRect;
1019 Source = SourceStretchedObj;
1020 }
1021
1022 /* Now call the DIB function */
1023 InputRect.left = SourceRect->left;
1024 InputRect.right = SourceRect->right;
1025 InputRect.top = SourceRect->top;
1026 InputRect.bottom = SourceRect->bottom;
1027 if (!IntEngEnter(&EnterLeaveSource, Source, &InputRect, TRUE, &Translate, &InputObj))
1028 {
1029 if (SourceStretchedObj != NULL)
1030 {
1031 EngFreeMem(SourceStretchedObj->pvBits);
1032 EngUnlockSurface(SourceStretchedObj);
1033 }
1034 if (SourceStretchedBitmap != 0)
1035 {
1036 EngDeleteSurface((HSURF)SourceStretchedBitmap);
1037 }
1038 return FALSE;
1039 }
1040 InputRect.left = SourceRect->left + Translate.x;
1041 InputRect.right = SourceRect->right + Translate.x;
1042 InputRect.top = SourceRect->top + Translate.y;
1043 InputRect.bottom = SourceRect->bottom + Translate.y;
1044
1045 OutputRect.left = DestRect->left;
1046 OutputRect.right = DestRect->right;
1047 OutputRect.top = DestRect->top;
1048 OutputRect.bottom = DestRect->bottom;
1049 if (!IntEngEnter(&EnterLeaveDest, Dest, &OutputRect, FALSE, &Translate, &OutputObj))
1050 {
1051 IntEngLeave(&EnterLeaveSource);
1052 if (SourceStretchedObj != NULL)
1053 {
1054 EngFreeMem(SourceStretchedObj->pvBits);
1055 EngUnlockSurface(SourceStretchedObj);
1056 }
1057 if (SourceStretchedBitmap != 0)
1058 {
1059 EngDeleteSurface((HSURF)SourceStretchedBitmap);
1060 }
1061 return FALSE;
1062 }
1063 OutputRect.left = DestRect->left + Translate.x;
1064 OutputRect.right = DestRect->right + Translate.x;
1065 OutputRect.top = DestRect->top + Translate.y;
1066 OutputRect.bottom = DestRect->bottom + Translate.y;
1067
1068 Ret = FALSE;
1069 ClippingType = (ClipRegion == NULL) ? DC_TRIVIAL : ClipRegion->iDComplexity;
1070 switch(ClippingType)
1071 {
1072 case DC_TRIVIAL:
1073 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend(
1074 OutputObj, InputObj, &OutputRect, &InputRect, ClipRegion, ColorTranslation, BlendObj);
1075 break;
1076
1077 case DC_RECT:
1078 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
1079 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
1080 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
1081 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
1082 if (EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
1083 {
1084 Rect.left = InputRect.left + CombinedRect.left - OutputRect.left;
1085 Rect.right = InputRect.right + CombinedRect.right - OutputRect.right;
1086 Rect.top = InputRect.top + CombinedRect.top - OutputRect.top;
1087 Rect.bottom = InputRect.bottom + CombinedRect.bottom - OutputRect.bottom;
1088 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend(
1089 OutputObj, InputObj, &CombinedRect, &Rect, ClipRegion, ColorTranslation, BlendObj);
1090 }
1091 break;
1092
1093 case DC_COMPLEX:
1094 Ret = TRUE;
1095 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, CD_ANY, 0);
1096 do
1097 {
1098 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum),
1099 (PVOID) &RectEnum);
1100
1101 for (i = 0; i < RectEnum.c; i++)
1102 {
1103 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
1104 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
1105 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
1106 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
1107 if (EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
1108 {
1109 Rect.left = InputRect.left + CombinedRect.left - OutputRect.left;
1110 Rect.right = InputRect.right + CombinedRect.right - OutputRect.right;
1111 Rect.top = InputRect.top + CombinedRect.top - OutputRect.top;
1112 Rect.bottom = InputRect.bottom + CombinedRect.bottom - OutputRect.bottom;
1113 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend(
1114 OutputObj, InputObj, &CombinedRect, &Rect, ClipRegion, ColorTranslation, BlendObj) && Ret;
1115 }
1116 }
1117 }
1118 while(EnumMore);
1119 break;
1120
1121 default:
1122 UNIMPLEMENTED;
1123 ASSERT(FALSE);
1124 break;
1125 }
1126
1127 IntEngLeave(&EnterLeaveDest);
1128 IntEngLeave(&EnterLeaveSource);
1129
1130 if (SourceStretchedObj != NULL)
1131 {
1132 EngFreeMem(SourceStretchedObj->pvBits);
1133 EngUnlockSurface(SourceStretchedObj);
1134 }
1135 if (SourceStretchedBitmap != 0)
1136 {
1137 EngDeleteSurface((HSURF)SourceStretchedBitmap);
1138 }
1139
1140 return Ret;
1141 }
1142
1143 BOOL STDCALL
1144 IntEngAlphaBlend(IN SURFOBJ *Dest,
1145 IN SURFOBJ *Source,
1146 IN CLIPOBJ *ClipRegion,
1147 IN XLATEOBJ *ColorTranslation,
1148 IN PRECTL DestRect,
1149 IN PRECTL SourceRect,
1150 IN BLENDOBJ *BlendObj)
1151 {
1152 BOOL ret = FALSE;
1153 BITMAPOBJ *DestObj;
1154 BITMAPOBJ *SourceObj;
1155
1156 ASSERT(Dest);
1157 DestObj = CONTAINING_RECORD(Dest, BITMAPOBJ, SurfObj);
1158 ASSERT(DestObj);
1159
1160 ASSERT(Source);
1161 SourceObj = CONTAINING_RECORD(Source, BITMAPOBJ, SurfObj);
1162 ASSERT(SourceObj);
1163
1164 ASSERT(DestRect);
1165 ASSERT(SourceRect);
1166
1167 /* Check if there is anything to draw */
1168 if (ClipRegion != NULL &&
1169 (ClipRegion->rclBounds.left >= ClipRegion->rclBounds.right ||
1170 ClipRegion->rclBounds.top >= ClipRegion->rclBounds.bottom))
1171 {
1172 /* Nothing to do */
1173 return TRUE;
1174 }
1175
1176 BITMAPOBJ_LockBitmapBits(DestObj);
1177 MouseSafetyOnDrawStart(Dest, DestRect->left, DestRect->top,
1178 DestRect->right, DestRect->bottom);
1179
1180 if (Source != Dest)
1181 BITMAPOBJ_LockBitmapBits(SourceObj);
1182 MouseSafetyOnDrawStart(Source, SourceRect->left, SourceRect->top,
1183 SourceRect->right, SourceRect->bottom);
1184
1185 /* Call the driver's DrvAlphaBlend if available */
1186 if (DestObj->flHooks & HOOK_ALPHABLEND)
1187 {
1188 ret = GDIDEVFUNCS(Dest).AlphaBlend(
1189 Dest, Source, ClipRegion, ColorTranslation,
1190 DestRect, SourceRect, BlendObj);
1191 }
1192
1193 if (! ret)
1194 {
1195 ret = EngAlphaBlend(Dest, Source, ClipRegion, ColorTranslation,
1196 DestRect, SourceRect, BlendObj);
1197 }
1198
1199 MouseSafetyOnDrawEnd(Source);
1200 if (Source != Dest)
1201 BITMAPOBJ_UnlockBitmapBits(SourceObj);
1202 MouseSafetyOnDrawEnd(Dest);
1203 BITMAPOBJ_UnlockBitmapBits(DestObj);
1204
1205 return ret;
1206 }
1207
1208 /**** REACTOS FONT RENDERING CODE *********************************************/
1209
1210 /* renders the alpha mask bitmap */
1211 static BOOLEAN STDCALL
1212 AlphaBltMask(SURFOBJ* Dest,
1213 SURFOBJ* Source,
1214 SURFOBJ* Mask,
1215 XLATEOBJ* ColorTranslation,
1216 XLATEOBJ* SrcColorTranslation,
1217 RECTL* DestRect,
1218 POINTL* SourcePoint,
1219 POINTL* MaskPoint,
1220 BRUSHOBJ* Brush,
1221 POINTL* BrushPoint)
1222 {
1223 LONG i, j, dx, dy;
1224 int r, g, b;
1225 ULONG Background, BrushColor, NewColor;
1226 BYTE *tMask, *lMask;
1227
1228 dx = DestRect->right - DestRect->left;
1229 dy = DestRect->bottom - DestRect->top;
1230
1231 if (Mask != NULL)
1232 {
1233 BrushColor = XLATEOBJ_iXlate(SrcColorTranslation, Brush->iSolidColor);
1234 r = (int)GetRValue(BrushColor);
1235 g = (int)GetGValue(BrushColor);
1236 b = (int)GetBValue(BrushColor);
1237
1238 tMask = (PBYTE)Mask->pvScan0 + (SourcePoint->y * Mask->lDelta) + SourcePoint->x;
1239 for (j = 0; j < dy; j++)
1240 {
1241 lMask = tMask;
1242 for (i = 0; i < dx; i++)
1243 {
1244 if (*lMask > 0)
1245 {
1246 if (*lMask == 0xff)
1247 {
1248 DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_PutPixel(
1249 Dest, DestRect->left + i, DestRect->top + j, Brush->iSolidColor);
1250 }
1251 else
1252 {
1253 Background = DIB_GetSource(Dest, DestRect->left + i, DestRect->top + j,
1254 SrcColorTranslation);
1255
1256 NewColor =
1257 RGB((*lMask * (r - GetRValue(Background)) >> 8) + GetRValue(Background),
1258 (*lMask * (g - GetGValue(Background)) >> 8) + GetGValue(Background),
1259 (*lMask * (b - GetBValue(Background)) >> 8) + GetBValue(Background));
1260
1261 Background = XLATEOBJ_iXlate(ColorTranslation, NewColor);
1262 DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_PutPixel(
1263 Dest, DestRect->left + i, DestRect->top + j, Background);
1264 }
1265 }
1266 lMask++;
1267 }
1268 tMask += Mask->lDelta;
1269 }
1270 return TRUE;
1271 }
1272 else
1273 {
1274 return FALSE;
1275 }
1276 }
1277
1278 BOOL STDCALL
1279 EngMaskBitBlt(SURFOBJ *DestObj,
1280 SURFOBJ *Mask,
1281 CLIPOBJ *ClipRegion,
1282 XLATEOBJ *DestColorTranslation,
1283 XLATEOBJ *SourceColorTranslation,
1284 RECTL *DestRect,
1285 POINTL *SourcePoint,
1286 POINTL *MaskOrigin,
1287 BRUSHOBJ *Brush,
1288 POINTL *BrushOrigin)
1289 {
1290 BYTE clippingType;
1291 RECTL CombinedRect;
1292 RECT_ENUM RectEnum;
1293 BOOL EnumMore;
1294 POINTL InputPoint;
1295 RECTL InputRect;
1296 RECTL OutputRect;
1297 POINTL Translate;
1298 INTENG_ENTER_LEAVE EnterLeaveSource;
1299 INTENG_ENTER_LEAVE EnterLeaveDest;
1300 SURFOBJ* InputObj;
1301 SURFOBJ* OutputObj;
1302 BOOLEAN Ret = TRUE;
1303 RECTL ClipRect;
1304 unsigned i;
1305 POINTL Pt;
1306 ULONG Direction;
1307 POINTL AdjustedBrushOrigin;
1308
1309 ASSERT ( Mask );
1310
1311 if (NULL != SourcePoint)
1312 {
1313 InputRect.left = SourcePoint->x;
1314 InputRect.right = SourcePoint->x + (DestRect->right - DestRect->left);
1315 InputRect.top = SourcePoint->y;
1316 InputRect.bottom = SourcePoint->y + (DestRect->bottom - DestRect->top);
1317 }
1318 else
1319 {
1320 InputRect.left = 0;
1321 InputRect.right = DestRect->right - DestRect->left;
1322 InputRect.top = 0;
1323 InputRect.bottom = DestRect->bottom - DestRect->top;
1324 }
1325
1326 if (! IntEngEnter(&EnterLeaveSource, DestObj, &InputRect, TRUE, &Translate, &InputObj))
1327 {
1328 return FALSE;
1329 }
1330
1331 if (NULL != SourcePoint)
1332 {
1333 InputPoint.x = SourcePoint->x + Translate.x;
1334 InputPoint.y = SourcePoint->y + Translate.y;
1335 }
1336 else
1337 {
1338 InputPoint.x = 0;
1339 InputPoint.y = 0;
1340 }
1341
1342 OutputRect = *DestRect;
1343 if (NULL != ClipRegion)
1344 {
1345 if (OutputRect.left < ClipRegion->rclBounds.left)
1346 {
1347 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
1348 InputPoint.x += ClipRegion->rclBounds.left - OutputRect.left;
1349 OutputRect.left = ClipRegion->rclBounds.left;
1350 }
1351 if (ClipRegion->rclBounds.right < OutputRect.right)
1352 {
1353 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
1354 OutputRect.right = ClipRegion->rclBounds.right;
1355 }
1356 if (OutputRect.top < ClipRegion->rclBounds.top)
1357 {
1358 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
1359 InputPoint.y += ClipRegion->rclBounds.top - OutputRect.top;
1360 OutputRect.top = ClipRegion->rclBounds.top;
1361 }
1362 if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
1363 {
1364 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
1365 OutputRect.bottom = ClipRegion->rclBounds.bottom;
1366 }
1367 }
1368
1369 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
1370 nothing to do */
1371 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
1372 {
1373 IntEngLeave(&EnterLeaveSource);
1374 return TRUE;
1375 }
1376
1377 if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate, &OutputObj))
1378 {
1379 IntEngLeave(&EnterLeaveSource);
1380 return FALSE;
1381 }
1382
1383 OutputRect.left = DestRect->left + Translate.x;
1384 OutputRect.right = DestRect->right + Translate.x;
1385 OutputRect.top = DestRect->top + Translate.y;
1386 OutputRect.bottom = DestRect->bottom + Translate.y;
1387
1388 if(BrushOrigin)
1389 {
1390 AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
1391 AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
1392 }
1393 else
1394 AdjustedBrushOrigin = Translate;
1395
1396 // Determine clipping type
1397 if (ClipRegion == (CLIPOBJ *) NULL)
1398 {
1399 clippingType = DC_TRIVIAL;
1400 } else {
1401 clippingType = ClipRegion->iDComplexity;
1402 }
1403
1404 switch(clippingType)
1405 {
1406 case DC_TRIVIAL:
1407 if(Mask->iBitmapFormat == BMF_8BPP)
1408 Ret = AlphaBltMask(OutputObj, InputObj, Mask, DestColorTranslation, SourceColorTranslation,
1409 &OutputRect, &InputPoint, MaskOrigin, Brush, &AdjustedBrushOrigin);
1410 else
1411 Ret = BltMask(OutputObj, InputObj, Mask, DestColorTranslation,
1412 &OutputRect, &InputPoint, MaskOrigin, Brush, &AdjustedBrushOrigin,
1413 R4_MASK);
1414 break;
1415 case DC_RECT:
1416 // Clip the blt to the clip rectangle
1417 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
1418 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
1419 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
1420 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
1421 if (EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
1422 {
1423 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
1424 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
1425 if(Mask->iBitmapFormat == BMF_8BPP)
1426 {
1427 Ret = AlphaBltMask(OutputObj, InputObj, Mask, DestColorTranslation, SourceColorTranslation,
1428 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin);
1429 }
1430 else
1431 {
1432 Ret = BltMask(OutputObj, InputObj, Mask, DestColorTranslation,
1433 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin, R4_MASK);
1434 }
1435 }
1436 break;
1437 case DC_COMPLEX:
1438 Ret = TRUE;
1439 if (OutputObj == InputObj)
1440 {
1441 if (OutputRect.top < InputPoint.y)
1442 {
1443 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
1444 }
1445 else
1446 {
1447 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
1448 }
1449 }
1450 else
1451 {
1452 Direction = CD_ANY;
1453 }
1454 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
1455 do
1456 {
1457 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
1458
1459 for (i = 0; i < RectEnum.c; i++)
1460 {
1461 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
1462 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
1463 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
1464 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
1465 if (EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
1466 {
1467 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
1468 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
1469 if(Mask->iBitmapFormat == BMF_8BPP)
1470 {
1471 Ret = AlphaBltMask(OutputObj, InputObj, Mask,
1472 DestColorTranslation,
1473 SourceColorTranslation,
1474 &CombinedRect, &Pt, MaskOrigin, Brush,
1475 &AdjustedBrushOrigin) && Ret;
1476 }
1477 else
1478 {
1479 Ret = BltMask(OutputObj, InputObj, Mask,
1480 DestColorTranslation, &CombinedRect, &Pt,
1481 MaskOrigin, Brush, &AdjustedBrushOrigin,
1482 R4_MASK) && Ret;
1483 }
1484 }
1485 }
1486 }
1487 while(EnumMore);
1488 break;
1489 }
1490
1491
1492 IntEngLeave(&EnterLeaveDest);
1493 IntEngLeave(&EnterLeaveSource);
1494
1495 return Ret;
1496 }
1497
1498 BOOL STDCALL
1499 IntEngMaskBlt(SURFOBJ *DestSurf,
1500 SURFOBJ *Mask,
1501 CLIPOBJ *ClipRegion,
1502 XLATEOBJ *DestColorTranslation,
1503 XLATEOBJ *SourceColorTranslation,
1504 RECTL *DestRect,
1505 POINTL *SourcePoint,
1506 POINTL *MaskOrigin,
1507 BRUSHOBJ *Brush,
1508 POINTL *BrushOrigin)
1509 {
1510 BOOLEAN ret;
1511 RECTL OutputRect;
1512 POINTL InputPoint;
1513 BITMAPOBJ *DestObj;
1514
1515 ASSERT(Mask);
1516
1517 if (NULL != SourcePoint)
1518 {
1519 InputPoint = *SourcePoint;
1520 }
1521
1522 /* Clip against the bounds of the clipping region so we won't try to write
1523 * outside the surface */
1524 if (NULL != ClipRegion)
1525 {
1526 if (! EngIntersectRect(&OutputRect, DestRect, &ClipRegion->rclBounds))
1527 {
1528 return TRUE;
1529 }
1530 InputPoint.x += OutputRect.left - DestRect->left;
1531 InputPoint.y += OutputRect.top - DestRect->top;
1532 }
1533 else
1534 {
1535 OutputRect = *DestRect;
1536 }
1537
1538 /* No success yet */
1539 ret = FALSE;
1540 ASSERT(DestSurf);
1541 DestObj = CONTAINING_RECORD(DestSurf, BITMAPOBJ, SurfObj);
1542
1543 BITMAPOBJ_LockBitmapBits(DestObj);
1544 MouseSafetyOnDrawStart(DestSurf, OutputRect.left, OutputRect.top,
1545 OutputRect.right, OutputRect.bottom);
1546
1547 /* Dummy BitBlt to let driver know that it should flush its changes.
1548 This should really be done using a call to DrvSynchronizeSurface,
1549 but the VMware driver doesn't hook that call. */
1550 IntEngBitBltEx(DestSurf, NULL, Mask, ClipRegion, DestColorTranslation,
1551 DestRect, SourcePoint, MaskOrigin, Brush, BrushOrigin,
1552 R4_NOOP, FALSE);
1553
1554 ret = EngMaskBitBlt(DestSurf, Mask, ClipRegion, DestColorTranslation, SourceColorTranslation,
1555 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin);
1556
1557 /* Dummy BitBlt to let driver know that something has changed. */
1558 IntEngBitBltEx(DestSurf, NULL, Mask, ClipRegion, DestColorTranslation,
1559 DestRect, SourcePoint, MaskOrigin, Brush, BrushOrigin,
1560 R4_NOOP, FALSE);
1561
1562 MouseSafetyOnDrawEnd(DestSurf);
1563 BITMAPOBJ_UnlockBitmapBits(DestObj);
1564
1565 return ret;
1566 }
1567 /* EOF */