[WIN32K]
[reactos.git] / subsystems / win32 / win32k / eng / bitblt.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: GDI BitBlt Functions
5 * FILE: subsys/win32k/eng/bitblt.c
6 * PROGRAMER: Jason Filby
7 * Timo Kreuzer
8 * REVISION HISTORY:
9 * 2/10/1999: Created
10 */
11
12 #include <win32k.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 typedef BOOLEAN (APIENTRY *PBLTRECTFUNC)(SURFOBJ* OutputObj,
18 SURFOBJ* InputObj,
19 SURFOBJ* Mask,
20 XLATEOBJ* ColorTranslation,
21 RECTL* OutputRect,
22 POINTL* InputPoint,
23 POINTL* MaskOrigin,
24 BRUSHOBJ* pbo,
25 POINTL* BrushOrigin,
26 ROP4 Rop4);
27
28 static BOOLEAN APIENTRY
29 BltMask(SURFOBJ* psoDest,
30 SURFOBJ* psoSource, // unused
31 SURFOBJ* psoMask,
32 XLATEOBJ* ColorTranslation, // unused
33 RECTL* prclDest,
34 POINTL* pptlSource, // unused
35 POINTL* pptlMask,
36 BRUSHOBJ* pbo,
37 POINTL* pptlBrush,
38 ROP4 Rop4)
39 {
40 LONG x, y;
41 BYTE *pjMskLine, *pjMskCurrent;
42 BYTE fjMaskBit0, fjMaskBit;
43 /* Pattern brushes */
44 PEBRUSHOBJ pebo = NULL;
45 SURFOBJ *psoPattern = NULL;
46 PSURFACE psurfPattern;
47 ULONG PatternWidth = 0, PatternHeight = 0;
48 LONG PatternX0 = 0, PatternX = 0, PatternY = 0;
49 PFN_DIB_PutPixel fnDest_PutPixel = NULL;
50 PFN_DIB_GetPixel fnPattern_GetPixel = NULL;
51 ULONG Pattern = 0;
52 HBITMAP hbmPattern;
53
54 ASSERT(psoSource == NULL);
55 ASSERT(pptlSource == NULL);
56
57 if (psoMask == NULL)
58 {
59 return FALSE;
60 }
61
62 if (pbo && pbo->iSolidColor == 0xFFFFFFFF)
63 {
64 pebo = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
65
66 hbmPattern = EBRUSHOBJ_pvGetEngBrush(pebo);
67 psurfPattern = SURFACE_LockSurface(hbmPattern);
68 if (psurfPattern != NULL)
69 {
70 psoPattern = &psurfPattern->SurfObj;
71 PatternWidth = psoPattern->sizlBitmap.cx;
72 PatternHeight = psoPattern->sizlBitmap.cy;
73 fnPattern_GetPixel = DibFunctionsForBitmapFormat[psoPattern->iBitmapFormat].DIB_GetPixel;
74 }
75 }
76 else
77 psurfPattern = NULL;
78
79 pjMskLine = (PBYTE)psoMask->pvScan0 + pptlMask->y * psoMask->lDelta + (pptlMask->x >> 3);
80 fjMaskBit0 = 0x80 >> (pptlMask->x & 0x07);
81
82 fnDest_PutPixel = DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel;
83 if (psurfPattern)
84 {
85 PatternY = (prclDest->top - pptlBrush->y) % PatternHeight;
86 if (PatternY < 0)
87 {
88 PatternY += PatternHeight;
89 }
90 PatternX0 = (prclDest->left - pptlBrush->x) % PatternWidth;
91 if (PatternX0 < 0)
92 {
93 PatternX0 += PatternWidth;
94 }
95
96 for (y = prclDest->top; y < prclDest->bottom; y++)
97 {
98 pjMskCurrent = pjMskLine;
99 fjMaskBit = fjMaskBit0;
100 PatternX = PatternX0;
101
102 for (x = prclDest->left; x < prclDest->right; x++)
103 {
104 if (*pjMskCurrent & fjMaskBit)
105 {
106 fnDest_PutPixel(psoDest, x, y,
107 fnPattern_GetPixel(psoPattern, PatternX, PatternY));
108 }
109 fjMaskBit = _rotr8(fjMaskBit, 1);
110 pjMskCurrent += (fjMaskBit >> 7);
111 PatternX++;
112 PatternX %= PatternWidth;
113 }
114 pjMskLine += psoMask->lDelta;
115 PatternY++;
116 PatternY %= PatternHeight;
117 }
118 }
119 else
120 {
121 Pattern = pbo ? pbo->iSolidColor : 0;
122 for (y = prclDest->top; y < prclDest->bottom; y++)
123 {
124 pjMskCurrent = pjMskLine;
125 fjMaskBit = fjMaskBit0;
126
127 for (x = prclDest->left; x < prclDest->right; x++)
128 {
129 if (*pjMskCurrent & fjMaskBit)
130 {
131 fnDest_PutPixel(psoDest, x, y, Pattern);
132 }
133 fjMaskBit = _rotr8(fjMaskBit, 1);
134 pjMskCurrent += (fjMaskBit >> 7);
135 }
136 pjMskLine += psoMask->lDelta;
137 }
138 }
139
140 if (psurfPattern)
141 SURFACE_UnlockSurface(psurfPattern);
142
143 return TRUE;
144 }
145
146 static BOOLEAN APIENTRY
147 BltPatCopy(SURFOBJ* Dest,
148 SURFOBJ* Source,
149 SURFOBJ* Mask,
150 XLATEOBJ* ColorTranslation,
151 RECTL* DestRect,
152 POINTL* SourcePoint,
153 POINTL* MaskPoint,
154 BRUSHOBJ* pbo,
155 POINTL* BrushPoint,
156 ROP4 Rop4)
157 {
158 // These functions are assigned if we're working with a DIB
159 // The assigned functions depend on the bitsPerPixel of the DIB
160
161 DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_ColorFill(Dest, DestRect, pbo ? pbo->iSolidColor : 0);
162
163 return TRUE;
164 }
165
166 static BOOLEAN APIENTRY
167 CallDibBitBlt(SURFOBJ* OutputObj,
168 SURFOBJ* InputObj,
169 SURFOBJ* Mask,
170 XLATEOBJ* ColorTranslation,
171 RECTL* OutputRect,
172 POINTL* InputPoint,
173 POINTL* MaskOrigin,
174 BRUSHOBJ* pbo,
175 POINTL* BrushOrigin,
176 ROP4 Rop4)
177 {
178 BLTINFO BltInfo;
179 PEBRUSHOBJ GdiBrush = NULL;
180 SURFACE *psurfPattern;
181 BOOLEAN Result;
182 HBITMAP hbmPattern;
183
184 BltInfo.DestSurface = OutputObj;
185 BltInfo.SourceSurface = InputObj;
186 BltInfo.PatternSurface = NULL;
187 BltInfo.XlateSourceToDest = ColorTranslation;
188 BltInfo.DestRect = *OutputRect;
189 BltInfo.SourcePoint = *InputPoint;
190
191 if (ROP3_TO_ROP4(SRCCOPY) == Rop4)
192 return DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_BitBltSrcCopy(&BltInfo);
193
194 BltInfo.Brush = pbo;
195 BltInfo.BrushOrigin = *BrushOrigin;
196 BltInfo.Rop4 = Rop4;
197
198 /* Pattern brush */
199 if (ROP4_USES_PATTERN(Rop4) && pbo && pbo->iSolidColor == 0xFFFFFFFF)
200 {
201 GdiBrush = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
202 hbmPattern = EBRUSHOBJ_pvGetEngBrush(GdiBrush);
203 psurfPattern = SURFACE_LockSurface(hbmPattern);
204 if (psurfPattern)
205 {
206 BltInfo.PatternSurface = &psurfPattern->SurfObj;
207 }
208 else
209 {
210 /* FIXME - What to do here? */
211 }
212 }
213 else
214 {
215 psurfPattern = NULL;
216 }
217
218 Result = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_BitBlt(&BltInfo);
219
220 /* Pattern brush */
221 if (psurfPattern)
222 {
223 SURFACE_UnlockSurface(psurfPattern);
224 }
225
226 return Result;
227 }
228
229 INT __cdecl abs(INT nm);
230
231
232 /*
233 * @implemented
234 */
235 BOOL APIENTRY
236 NtGdiEngBitBlt(
237 IN SURFOBJ *psoTrg,
238 IN SURFOBJ *psoSrc,
239 IN SURFOBJ *psoMask,
240 IN CLIPOBJ *pco,
241 IN XLATEOBJ *pxlo,
242 IN RECTL *prclTrg,
243 IN POINTL *pptlSrc,
244 IN POINTL *pptlMask,
245 IN BRUSHOBJ *pbo,
246 IN POINTL *pptlBrush,
247 IN ROP4 rop4 )
248 {
249 RECTL rclTrg;
250 POINTL ptlSrc;
251 POINTL ptlMask;
252 POINTL ptlBrush;
253
254 _SEH2_TRY
255 {
256 ProbeForRead(prclTrg, sizeof(RECTL), 1);
257 RtlCopyMemory(&rclTrg,prclTrg, sizeof(RECTL));
258
259 ProbeForRead(pptlSrc, sizeof(POINTL), 1);
260 RtlCopyMemory(&ptlSrc, pptlSrc, sizeof(POINTL));
261
262 ProbeForRead(pptlMask, sizeof(POINTL), 1);
263 RtlCopyMemory(&ptlMask, pptlMask, sizeof(POINTL));
264
265 ProbeForRead(pptlBrush, sizeof(POINTL), 1);
266 RtlCopyMemory(&ptlBrush, pptlBrush, sizeof(POINTL));
267
268 }
269 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
270 {
271 _SEH2_YIELD(return FALSE);
272 }
273 _SEH2_END;
274
275 return EngBitBlt(psoTrg, psoSrc, psoMask, pco, pxlo, &rclTrg, &ptlSrc, &ptlMask, pbo, &ptlBrush, rop4);
276 }
277
278 /*
279 * @implemented
280 */
281 BOOL APIENTRY
282 EngBitBlt(SURFOBJ *DestObj,
283 SURFOBJ *SourceObj,
284 SURFOBJ *Mask,
285 CLIPOBJ *ClipRegion,
286 XLATEOBJ *ColorTranslation,
287 RECTL *DestRect,
288 POINTL *SourcePoint,
289 POINTL *MaskOrigin,
290 BRUSHOBJ *pbo,
291 POINTL *BrushOrigin,
292 ROP4 rop4)
293 {
294 BYTE clippingType;
295 RECTL CombinedRect;
296 RECT_ENUM RectEnum;
297 BOOL EnumMore;
298 POINTL InputPoint;
299 RECTL InputRect;
300 RECTL OutputRect;
301 SURFOBJ* InputObj = 0;
302 SURFOBJ* OutputObj;
303 PBLTRECTFUNC BltRectFunc;
304 BOOLEAN Ret = TRUE;
305 RECTL ClipRect;
306 unsigned i;
307 POINTL Pt;
308 ULONG Direction;
309 BOOL UsesSource;
310 BOOL UsesPattern;
311 POINTL AdjustedBrushOrigin;
312
313 UsesSource = ROP4_USES_SOURCE(rop4);
314 UsesPattern = ROP4_USES_PATTERN(rop4);
315 if (R4_NOOP == rop4)
316 {
317 /* Copy destination onto itself: nop */
318 return TRUE;
319 }
320
321 OutputRect = *DestRect;
322 if (OutputRect.right < OutputRect.left)
323 {
324 OutputRect.left = DestRect->right;
325 OutputRect.right = DestRect->left;
326 }
327 if (OutputRect.bottom < OutputRect.top)
328 {
329 OutputRect.left = DestRect->right;
330 OutputRect.right = DestRect->left;
331 }
332
333 if (UsesSource)
334 {
335 if (NULL == SourcePoint)
336 {
337 return FALSE;
338 }
339
340 /* Make sure we don't try to copy anything outside the valid source
341 region */
342 InputPoint = *SourcePoint;
343 if (InputPoint.x < 0)
344 {
345 OutputRect.left -= InputPoint.x;
346 InputPoint.x = 0;
347 }
348 if (InputPoint.y < 0)
349 {
350 OutputRect.top -= InputPoint.y;
351 InputPoint.y = 0;
352 }
353 if (SourceObj->sizlBitmap.cx < InputPoint.x +
354 OutputRect.right - OutputRect.left)
355 {
356 OutputRect.right = OutputRect.left +
357 SourceObj->sizlBitmap.cx - InputPoint.x;
358 }
359 if (SourceObj->sizlBitmap.cy < InputPoint.y +
360 OutputRect.bottom - OutputRect.top)
361 {
362 OutputRect.bottom = OutputRect.top +
363 SourceObj->sizlBitmap.cy - InputPoint.y;
364 }
365
366 InputRect.left = InputPoint.x;
367 InputRect.right = InputPoint.x + (OutputRect.right - OutputRect.left);
368 InputRect.top = InputPoint.y;
369 InputRect.bottom = InputPoint.y + (OutputRect.bottom - OutputRect.top);
370
371 InputObj = SourceObj;
372 }
373 else
374 {
375 InputRect.left = 0;
376 InputRect.right = DestRect->right - DestRect->left;
377 InputRect.top = 0;
378 InputRect.bottom = DestRect->bottom - DestRect->top;
379 }
380
381 if (NULL != ClipRegion)
382 {
383 if (OutputRect.left < ClipRegion->rclBounds.left)
384 {
385 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
386 InputPoint.x += ClipRegion->rclBounds.left - OutputRect.left;
387 OutputRect.left = ClipRegion->rclBounds.left;
388 }
389 if (ClipRegion->rclBounds.right < OutputRect.right)
390 {
391 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
392 OutputRect.right = ClipRegion->rclBounds.right;
393 }
394 if (OutputRect.top < ClipRegion->rclBounds.top)
395 {
396 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
397 InputPoint.y += ClipRegion->rclBounds.top - OutputRect.top;
398 OutputRect.top = ClipRegion->rclBounds.top;
399 }
400 if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
401 {
402 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
403 OutputRect.bottom = ClipRegion->rclBounds.bottom;
404 }
405 }
406
407 /* Check for degenerate case: if height or width of OutputRect is 0 pixels
408 there's nothing to do */
409 if (OutputRect.right <= OutputRect.left ||
410 OutputRect.bottom <= OutputRect.top)
411 {
412 return TRUE;
413 }
414
415 OutputObj = DestObj;
416
417 if (BrushOrigin)
418 {
419 AdjustedBrushOrigin.x = BrushOrigin->x;
420 AdjustedBrushOrigin.y = BrushOrigin->y;
421 }
422 else
423 {
424 AdjustedBrushOrigin.x = 0;
425 AdjustedBrushOrigin.y = 0;
426 }
427
428 /* Determine clipping type */
429 if (ClipRegion == (CLIPOBJ *) NULL)
430 {
431 clippingType = DC_TRIVIAL;
432 }
433 else
434 {
435 clippingType = ClipRegion->iDComplexity;
436 }
437
438 if (R4_MASK == rop4)
439 {
440 BltRectFunc = BltMask;
441 }
442 else if (ROP3_TO_ROP4(PATCOPY) == rop4)
443 {
444 if (pbo && pbo->iSolidColor == 0xFFFFFFFF)
445 BltRectFunc = CallDibBitBlt;
446 else
447 BltRectFunc = BltPatCopy;
448 }
449 else
450 {
451 BltRectFunc = CallDibBitBlt;
452 }
453
454
455 switch (clippingType)
456 {
457 case DC_TRIVIAL:
458 Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ColorTranslation,
459 &OutputRect, &InputPoint, MaskOrigin, pbo,
460 &AdjustedBrushOrigin, rop4);
461 break;
462 case DC_RECT:
463 /* Clip the blt to the clip rectangle */
464 ClipRect.left = ClipRegion->rclBounds.left;
465 ClipRect.right = ClipRegion->rclBounds.right;
466 ClipRect.top = ClipRegion->rclBounds.top;
467 ClipRect.bottom = ClipRegion->rclBounds.bottom;
468 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
469 {
470 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
471 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
472 Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ColorTranslation,
473 &CombinedRect, &Pt, MaskOrigin, pbo,
474 &AdjustedBrushOrigin, rop4);
475 }
476 break;
477 case DC_COMPLEX:
478 Ret = TRUE;
479 if (OutputObj == InputObj)
480 {
481 if (OutputRect.top < InputPoint.y)
482 {
483 Direction = OutputRect.left < InputPoint.x ?
484 CD_RIGHTDOWN : CD_LEFTDOWN;
485 }
486 else
487 {
488 Direction = OutputRect.left < InputPoint.x ?
489 CD_RIGHTUP : CD_LEFTUP;
490 }
491 }
492 else
493 {
494 Direction = CD_ANY;
495 }
496 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
497 do
498 {
499 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum),
500 (PVOID) &RectEnum);
501
502 for (i = 0; i < RectEnum.c; i++)
503 {
504 ClipRect.left = RectEnum.arcl[i].left;
505 ClipRect.right = RectEnum.arcl[i].right;
506 ClipRect.top = RectEnum.arcl[i].top;
507 ClipRect.bottom = RectEnum.arcl[i].bottom;
508 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
509 {
510 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
511 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
512 Ret = (*BltRectFunc)(OutputObj, InputObj, Mask,
513 ColorTranslation, &CombinedRect, &Pt,
514 MaskOrigin, pbo, &AdjustedBrushOrigin,
515 rop4) && Ret;
516 }
517 }
518 }
519 while (EnumMore);
520 break;
521 }
522
523 return Ret;
524 }
525
526 BOOL APIENTRY
527 IntEngBitBlt(
528 SURFOBJ *psoTrg,
529 SURFOBJ *psoSrc,
530 SURFOBJ *psoMask,
531 CLIPOBJ *pco,
532 XLATEOBJ *pxlo,
533 RECTL *prclTrg,
534 POINTL *pptlSrc,
535 POINTL *pptlMask,
536 BRUSHOBJ *pbo,
537 POINTL *pptlBrush,
538 ROP4 rop4)
539 {
540 SURFACE *psurfTrg;
541 SURFACE *psurfSrc = NULL;
542 BOOL bResult;
543 RECTL rclClipped;
544 RECTL rclSrc;
545 // INTENG_ENTER_LEAVE EnterLeaveSource;
546 // INTENG_ENTER_LEAVE EnterLeaveDest;
547 PFN_DrvBitBlt pfnBitBlt;
548
549 ASSERT(psoTrg);
550 psurfTrg = CONTAINING_RECORD(psoTrg, SURFACE, SurfObj);
551
552 /* FIXME: Should we really allow to pass non-well-ordered rects? */
553 rclClipped = *prclTrg;
554 RECTL_vMakeWellOrdered(&rclClipped);
555
556 /* Clip target rect against the bounds of the clipping region */
557 if (pco)
558 {
559 if (!RECTL_bIntersectRect(&rclClipped, &rclClipped, &pco->rclBounds))
560 {
561 /* Nothing left */
562 return TRUE;
563 }
564
565 /* Don't pass a clipobj with only a single rect */
566 if (pco->iDComplexity == DC_RECT)
567 pco = NULL;
568 }
569
570 if (ROP4_USES_SOURCE(rop4))
571 {
572 ASSERT(psoSrc);
573 psurfSrc = CONTAINING_RECORD(psoSrc, SURFACE, SurfObj);
574
575 /* Calculate source rect */
576 rclSrc.left = pptlSrc->x + rclClipped.left - prclTrg->left;
577 rclSrc.top = pptlSrc->y + rclClipped.top - prclTrg->top;
578 rclSrc.right = rclSrc.left + rclClipped.right - rclClipped.left;
579 rclSrc.bottom = rclSrc.top + rclClipped.bottom - rclClipped.top;
580 }
581 else
582 {
583 psoSrc = NULL;
584 psurfSrc = NULL;
585 }
586
587 /* Is the target surface device managed? */
588 if (psurfTrg->flags & HOOK_BITBLT)
589 {
590 /* Is the source a different device managed surface? */
591 if (psoSrc && psoSrc->hdev != psoTrg->hdev && psurfSrc->flags & HOOK_BITBLT)
592 {
593 DPRINT1("Need to copy to standard bitmap format!\n");
594 ASSERT(FALSE);
595 }
596
597 pfnBitBlt = GDIDEVFUNCS(psoTrg).BitBlt;
598 }
599
600 /* Is the source surface device managed? */
601 else if (psoSrc && psurfSrc->flags & HOOK_BITBLT)
602 {
603 pfnBitBlt = GDIDEVFUNCS(psoSrc).BitBlt;
604 }
605 else
606 {
607 pfnBitBlt = EngBitBlt;
608 }
609
610 bResult = pfnBitBlt(psoTrg,
611 psoSrc,
612 psoMask,
613 pco,
614 pxlo,
615 &rclClipped,
616 (POINTL*)&rclSrc,
617 pptlMask,
618 pbo,
619 pptlBrush,
620 rop4);
621
622 // FIXME: cleanup temp surface!
623
624 return bResult;
625 }
626
627
628 /**** REACTOS FONT RENDERING CODE *********************************************/
629
630 /* renders the alpha mask bitmap */
631 static BOOLEAN APIENTRY
632 AlphaBltMask(SURFOBJ* psoDest,
633 SURFOBJ* psoSource, // unused
634 SURFOBJ* psoMask,
635 XLATEOBJ* pxloRGB2Dest,
636 XLATEOBJ* pxloBrush,
637 RECTL* prclDest,
638 POINTL* pptlSource, // unused
639 POINTL* pptlMask,
640 BRUSHOBJ* pbo,
641 POINTL* pptlBrush)
642 {
643 LONG i, j, dx, dy;
644 int r, g, b;
645 ULONG Background, BrushColor, NewColor;
646 BYTE *tMask, *lMask;
647
648 ASSERT(psoSource == NULL);
649 ASSERT(pptlSource == NULL);
650
651 dx = prclDest->right - prclDest->left;
652 dy = prclDest->bottom - prclDest->top;
653
654 if (psoMask != NULL)
655 {
656 BrushColor = XLATEOBJ_iXlate(pxloBrush, pbo ? pbo->iSolidColor : 0);
657 r = (int)GetRValue(BrushColor);
658 g = (int)GetGValue(BrushColor);
659 b = (int)GetBValue(BrushColor);
660
661 tMask = (PBYTE)psoMask->pvScan0 + (pptlMask->y * psoMask->lDelta) + pptlMask->x;
662 for (j = 0; j < dy; j++)
663 {
664 lMask = tMask;
665 for (i = 0; i < dx; i++)
666 {
667 if (*lMask > 0)
668 {
669 if (*lMask == 0xff)
670 {
671 DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel(
672 psoDest, prclDest->left + i, prclDest->top + j, pbo ? pbo->iSolidColor : 0);
673 }
674 else
675 {
676 Background = DIB_GetSource(psoDest, prclDest->left + i, prclDest->top + j,
677 pxloBrush);
678
679 NewColor =
680 RGB((*lMask * (r - GetRValue(Background)) >> 8) + GetRValue(Background),
681 (*lMask * (g - GetGValue(Background)) >> 8) + GetGValue(Background),
682 (*lMask * (b - GetBValue(Background)) >> 8) + GetBValue(Background));
683
684 Background = XLATEOBJ_iXlate(pxloRGB2Dest, NewColor);
685 DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel(
686 psoDest, prclDest->left + i, prclDest->top + j, Background);
687 }
688 }
689 lMask++;
690 }
691 tMask += psoMask->lDelta;
692 }
693 return TRUE;
694 }
695 else
696 {
697 return FALSE;
698 }
699 }
700
701 static
702 BOOL APIENTRY
703 EngMaskBitBlt(SURFOBJ *psoDest,
704 SURFOBJ *psoMask,
705 CLIPOBJ *ClipRegion,
706 XLATEOBJ *DestColorTranslation,
707 XLATEOBJ *SourceColorTranslation,
708 RECTL *DestRect,
709 POINTL *pptlMask,
710 BRUSHOBJ *pbo,
711 POINTL *BrushOrigin)
712 {
713 BYTE clippingType;
714 RECTL CombinedRect;
715 RECT_ENUM RectEnum;
716 BOOL EnumMore;
717 POINTL InputPoint;
718 RECTL InputRect;
719 RECTL OutputRect;
720 POINTL Translate;
721 INTENG_ENTER_LEAVE EnterLeaveSource;
722 INTENG_ENTER_LEAVE EnterLeaveDest;
723 SURFOBJ* psoInput;
724 SURFOBJ* psoOutput;
725 BOOLEAN Ret = TRUE;
726 RECTL ClipRect;
727 unsigned i;
728 POINTL Pt;
729 ULONG Direction;
730 POINTL AdjustedBrushOrigin;
731
732 ASSERT(psoMask);
733
734 if (pptlMask)
735 {
736 InputRect.left = pptlMask->x;
737 InputRect.right = pptlMask->x + (DestRect->right - DestRect->left);
738 InputRect.top = pptlMask->y;
739 InputRect.bottom = pptlMask->y + (DestRect->bottom - DestRect->top);
740 }
741 else
742 {
743 InputRect.left = 0;
744 InputRect.right = DestRect->right - DestRect->left;
745 InputRect.top = 0;
746 InputRect.bottom = DestRect->bottom - DestRect->top;
747 }
748
749 OutputRect = *DestRect;
750 if (NULL != ClipRegion)
751 {
752 if (OutputRect.left < ClipRegion->rclBounds.left)
753 {
754 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
755 OutputRect.left = ClipRegion->rclBounds.left;
756 }
757 if (ClipRegion->rclBounds.right < OutputRect.right)
758 {
759 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
760 OutputRect.right = ClipRegion->rclBounds.right;
761 }
762 if (OutputRect.top < ClipRegion->rclBounds.top)
763 {
764 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
765 OutputRect.top = ClipRegion->rclBounds.top;
766 }
767 if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
768 {
769 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
770 OutputRect.bottom = ClipRegion->rclBounds.bottom;
771 }
772 }
773
774 if (! IntEngEnter(&EnterLeaveSource, psoMask, &InputRect, TRUE, &Translate, &psoInput))
775 {
776 return FALSE;
777 }
778
779 InputPoint.x = InputRect.left + Translate.x;
780 InputPoint.y = InputRect.top + Translate.y;
781
782 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
783 nothing to do */
784 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
785 {
786 IntEngLeave(&EnterLeaveSource);
787 return TRUE;
788 }
789
790 if (! IntEngEnter(&EnterLeaveDest, psoDest, &OutputRect, FALSE, &Translate, &psoOutput))
791 {
792 IntEngLeave(&EnterLeaveSource);
793 return FALSE;
794 }
795
796 OutputRect.left = DestRect->left + Translate.x;
797 OutputRect.right = DestRect->right + Translate.x;
798 OutputRect.top = DestRect->top + Translate.y;
799 OutputRect.bottom = DestRect->bottom + Translate.y;
800
801 if (BrushOrigin)
802 {
803 AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
804 AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
805 }
806 else
807 AdjustedBrushOrigin = Translate;
808
809 // Determine clipping type
810 if (ClipRegion == (CLIPOBJ *) NULL)
811 {
812 clippingType = DC_TRIVIAL;
813 } else {
814 clippingType = ClipRegion->iDComplexity;
815 }
816
817 switch (clippingType)
818 {
819 case DC_TRIVIAL:
820 if (psoMask->iBitmapFormat == BMF_8BPP)
821 Ret = AlphaBltMask(psoOutput, NULL , psoInput, DestColorTranslation, SourceColorTranslation,
822 &OutputRect, NULL, &InputPoint, pbo, &AdjustedBrushOrigin);
823 else
824 Ret = BltMask(psoOutput, NULL, psoInput, DestColorTranslation,
825 &OutputRect, NULL, &InputPoint, pbo, &AdjustedBrushOrigin,
826 R4_MASK);
827 break;
828 case DC_RECT:
829 // Clip the blt to the clip rectangle
830 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
831 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
832 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
833 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
834 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
835 {
836 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
837 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
838 if (psoMask->iBitmapFormat == BMF_8BPP)
839 {
840 Ret = AlphaBltMask(psoOutput, NULL, psoInput, DestColorTranslation, SourceColorTranslation,
841 &CombinedRect, NULL, &Pt, pbo, &AdjustedBrushOrigin);
842 }
843 else
844 {
845 Ret = BltMask(psoOutput, NULL, psoInput, DestColorTranslation,
846 &CombinedRect, NULL, &Pt, pbo, &AdjustedBrushOrigin, R4_MASK);
847 }
848 }
849 break;
850 case DC_COMPLEX:
851 Ret = TRUE;
852 if (psoOutput == psoInput)
853 {
854 if (OutputRect.top < InputPoint.y)
855 {
856 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
857 }
858 else
859 {
860 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
861 }
862 }
863 else
864 {
865 Direction = CD_ANY;
866 }
867 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
868 do
869 {
870 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
871
872 for (i = 0; i < RectEnum.c; i++)
873 {
874 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
875 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
876 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
877 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
878 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
879 {
880 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
881 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
882 if (psoMask->iBitmapFormat == BMF_8BPP)
883 {
884 Ret = AlphaBltMask(psoOutput, NULL, psoInput,
885 DestColorTranslation,
886 SourceColorTranslation,
887 &CombinedRect, NULL, &Pt, pbo,
888 &AdjustedBrushOrigin) && Ret;
889 }
890 else
891 {
892 Ret = BltMask(psoOutput, NULL, psoInput,
893 DestColorTranslation, &CombinedRect, NULL,
894 &Pt, pbo, &AdjustedBrushOrigin,
895 R4_MASK) && Ret;
896 }
897 }
898 }
899 }
900 while (EnumMore);
901 break;
902 }
903
904
905 IntEngLeave(&EnterLeaveDest);
906 IntEngLeave(&EnterLeaveSource);
907
908 return Ret;
909 }
910
911 BOOL APIENTRY
912 IntEngMaskBlt(SURFOBJ *psoDest,
913 SURFOBJ *psoMask,
914 CLIPOBJ *ClipRegion,
915 XLATEOBJ *DestColorTranslation,
916 XLATEOBJ *SourceColorTranslation,
917 RECTL *DestRect,
918 POINTL *pptlMask,
919 BRUSHOBJ *pbo,
920 POINTL *BrushOrigin)
921 {
922 BOOLEAN ret;
923 RECTL OutputRect;
924 POINTL InputPoint;
925 SURFACE *psurfDest;
926
927 ASSERT(psoMask);
928
929 if (pptlMask)
930 {
931 InputPoint = *pptlMask;
932 }
933
934 /* Clip against the bounds of the clipping region so we won't try to write
935 * outside the surface */
936 if (NULL != ClipRegion)
937 {
938 if (!RECTL_bIntersectRect(&OutputRect, DestRect, &ClipRegion->rclBounds))
939 {
940 return TRUE;
941 }
942 InputPoint.x += OutputRect.left - DestRect->left;
943 InputPoint.y += OutputRect.top - DestRect->top;
944 }
945 else
946 {
947 OutputRect = *DestRect;
948 }
949
950 /* No success yet */
951 ret = FALSE;
952 ASSERT(psoDest);
953 psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
954
955 /* Dummy BitBlt to let driver know that it should flush its changes.
956 This should really be done using a call to DrvSynchronizeSurface,
957 but the VMware driver doesn't hook that call. */
958 IntEngBitBlt(psoDest, NULL, psoMask, ClipRegion, DestColorTranslation,
959 DestRect, pptlMask, pptlMask, pbo, BrushOrigin,
960 R4_NOOP);
961
962 ret = EngMaskBitBlt(psoDest, psoMask, ClipRegion, DestColorTranslation, SourceColorTranslation,
963 &OutputRect, &InputPoint, pbo, BrushOrigin);
964
965 /* Dummy BitBlt to let driver know that something has changed. */
966 IntEngBitBlt(psoDest, NULL, psoMask, ClipRegion, DestColorTranslation,
967 DestRect, pptlMask, pptlMask, pbo, BrushOrigin,
968 R4_NOOP);
969
970 return ret;
971 }
972
973 /* EOF */