8806aa75fc5d1bc5036f21ffc698f4d3f7ac67c4
[reactos.git] / reactos / 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 IntEngBitBltEx(
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 BOOL bRemoveMouse)
540 {
541 SURFACE *psurfTrg;
542 SURFACE *psurfSrc = NULL;
543 BOOL bResult;
544 RECTL rclClipped;
545 RECTL rclSrc;
546 // INTENG_ENTER_LEAVE EnterLeaveSource;
547 // INTENG_ENTER_LEAVE EnterLeaveDest;
548 PFN_DrvBitBlt pfnBitBlt;
549
550 ASSERT(psoTrg);
551 psurfTrg = CONTAINING_RECORD(psoTrg, SURFACE, SurfObj);
552
553 /* FIXME: Should we really allow to pass non-well-ordered rects? */
554 rclClipped = *prclTrg;
555 RECTL_vMakeWellOrdered(&rclClipped);
556
557 /* Clip target rect against the bounds of the clipping region */
558 if (pco)
559 {
560 if (!RECTL_bIntersectRect(&rclClipped, &rclClipped, &pco->rclBounds))
561 {
562 /* Nothing left */
563 return TRUE;
564 }
565
566 /* Don't pass a clipobj with only a single rect */
567 if (pco->iDComplexity == DC_RECT)
568 pco = NULL;
569 }
570
571 if (ROP4_USES_SOURCE(rop4))
572 {
573 ASSERT(psoSrc);
574 psurfSrc = CONTAINING_RECORD(psoSrc, SURFACE, SurfObj);
575
576 /* Calculate source rect */
577 rclSrc.left = pptlSrc->x + rclClipped.left - prclTrg->left;
578 rclSrc.top = pptlSrc->y + rclClipped.top - prclTrg->top;
579 rclSrc.right = rclSrc.left + rclClipped.right - rclClipped.left;
580 rclSrc.bottom = rclSrc.top + rclClipped.bottom - rclClipped.top;
581 }
582 else
583 {
584 psoSrc = NULL;
585 psurfSrc = NULL;
586 }
587
588 if (bRemoveMouse)
589 {
590 SURFACE_LockBitmapBits(psurfTrg);
591
592 if (psoSrc)
593 {
594 if (psoSrc != psoTrg)
595 {
596 SURFACE_LockBitmapBits(psurfSrc);
597 }
598 MouseSafetyOnDrawStart(psoSrc, rclSrc.left, rclSrc.top,
599 rclSrc.right, rclSrc.bottom);
600 }
601 MouseSafetyOnDrawStart(psoTrg, rclClipped.left, rclClipped.top,
602 rclClipped.right, rclClipped.bottom);
603 }
604
605 /* Is the target surface device managed? */
606 if (psurfTrg->flHooks & HOOK_BITBLT)
607 {
608 /* Is the source a different device managed surface? */
609 if (psoSrc && psoSrc->hdev != psoTrg->hdev && psurfSrc->flHooks & HOOK_BITBLT)
610 {
611 DPRINT1("Need to copy to standard bitmap format!\n");
612 ASSERT(FALSE);
613 }
614
615 pfnBitBlt = GDIDEVFUNCS(psoTrg).BitBlt;
616 }
617
618 /* Is the source surface device managed? */
619 else if (psoSrc && psurfSrc->flHooks & HOOK_BITBLT)
620 {
621 pfnBitBlt = GDIDEVFUNCS(psoSrc).BitBlt;
622 }
623 else
624 {
625 pfnBitBlt = EngBitBlt;
626 }
627
628 bResult = pfnBitBlt(psoTrg,
629 psoSrc,
630 psoMask,
631 pco,
632 pxlo,
633 &rclClipped,
634 (POINTL*)&rclSrc,
635 pptlMask,
636 pbo,
637 pptlBrush,
638 rop4);
639
640 // FIXME: cleanup temp surface!
641
642 if (bRemoveMouse)
643 {
644 MouseSafetyOnDrawEnd(psoTrg);
645 if (psoSrc)
646 {
647 MouseSafetyOnDrawEnd(psoSrc);
648 if (psoSrc != psoTrg)
649 {
650 SURFACE_UnlockBitmapBits(psurfSrc);
651 }
652 }
653
654 SURFACE_UnlockBitmapBits(psurfTrg);
655 }
656
657 return bResult;
658 }
659
660
661 /**** REACTOS FONT RENDERING CODE *********************************************/
662
663 /* renders the alpha mask bitmap */
664 static BOOLEAN APIENTRY
665 AlphaBltMask(SURFOBJ* psoDest,
666 SURFOBJ* psoSource, // unused
667 SURFOBJ* psoMask,
668 XLATEOBJ* pxloRGB2Dest,
669 XLATEOBJ* pxloBrush,
670 RECTL* prclDest,
671 POINTL* pptlSource, // unused
672 POINTL* pptlMask,
673 BRUSHOBJ* pbo,
674 POINTL* pptlBrush)
675 {
676 LONG i, j, dx, dy;
677 int r, g, b;
678 ULONG Background, BrushColor, NewColor;
679 BYTE *tMask, *lMask;
680
681 ASSERT(psoSource == NULL);
682 ASSERT(pptlSource == NULL);
683
684 dx = prclDest->right - prclDest->left;
685 dy = prclDest->bottom - prclDest->top;
686
687 if (psoMask != NULL)
688 {
689 BrushColor = XLATEOBJ_iXlate(pxloBrush, pbo ? pbo->iSolidColor : 0);
690 r = (int)GetRValue(BrushColor);
691 g = (int)GetGValue(BrushColor);
692 b = (int)GetBValue(BrushColor);
693
694 tMask = (PBYTE)psoMask->pvScan0 + (pptlMask->y * psoMask->lDelta) + pptlMask->x;
695 for (j = 0; j < dy; j++)
696 {
697 lMask = tMask;
698 for (i = 0; i < dx; i++)
699 {
700 if (*lMask > 0)
701 {
702 if (*lMask == 0xff)
703 {
704 DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel(
705 psoDest, prclDest->left + i, prclDest->top + j, pbo ? pbo->iSolidColor : 0);
706 }
707 else
708 {
709 Background = DIB_GetSource(psoDest, prclDest->left + i, prclDest->top + j,
710 pxloBrush);
711
712 NewColor =
713 RGB((*lMask * (r - GetRValue(Background)) >> 8) + GetRValue(Background),
714 (*lMask * (g - GetGValue(Background)) >> 8) + GetGValue(Background),
715 (*lMask * (b - GetBValue(Background)) >> 8) + GetBValue(Background));
716
717 Background = XLATEOBJ_iXlate(pxloRGB2Dest, NewColor);
718 DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel(
719 psoDest, prclDest->left + i, prclDest->top + j, Background);
720 }
721 }
722 lMask++;
723 }
724 tMask += psoMask->lDelta;
725 }
726 return TRUE;
727 }
728 else
729 {
730 return FALSE;
731 }
732 }
733
734 static
735 BOOL APIENTRY
736 EngMaskBitBlt(SURFOBJ *psoDest,
737 SURFOBJ *psoMask,
738 CLIPOBJ *ClipRegion,
739 XLATEOBJ *DestColorTranslation,
740 XLATEOBJ *SourceColorTranslation,
741 RECTL *DestRect,
742 POINTL *pptlMask,
743 BRUSHOBJ *pbo,
744 POINTL *BrushOrigin)
745 {
746 BYTE clippingType;
747 RECTL CombinedRect;
748 RECT_ENUM RectEnum;
749 BOOL EnumMore;
750 POINTL InputPoint;
751 RECTL InputRect;
752 RECTL OutputRect;
753 POINTL Translate;
754 INTENG_ENTER_LEAVE EnterLeaveSource;
755 INTENG_ENTER_LEAVE EnterLeaveDest;
756 SURFOBJ* psoInput;
757 SURFOBJ* psoOutput;
758 BOOLEAN Ret = TRUE;
759 RECTL ClipRect;
760 unsigned i;
761 POINTL Pt;
762 ULONG Direction;
763 POINTL AdjustedBrushOrigin;
764
765 ASSERT(psoMask);
766
767 if (pptlMask)
768 {
769 InputRect.left = pptlMask->x;
770 InputRect.right = pptlMask->x + (DestRect->right - DestRect->left);
771 InputRect.top = pptlMask->y;
772 InputRect.bottom = pptlMask->y + (DestRect->bottom - DestRect->top);
773 }
774 else
775 {
776 InputRect.left = 0;
777 InputRect.right = DestRect->right - DestRect->left;
778 InputRect.top = 0;
779 InputRect.bottom = DestRect->bottom - DestRect->top;
780 }
781
782 OutputRect = *DestRect;
783 if (NULL != ClipRegion)
784 {
785 if (OutputRect.left < ClipRegion->rclBounds.left)
786 {
787 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
788 OutputRect.left = ClipRegion->rclBounds.left;
789 }
790 if (ClipRegion->rclBounds.right < OutputRect.right)
791 {
792 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
793 OutputRect.right = ClipRegion->rclBounds.right;
794 }
795 if (OutputRect.top < ClipRegion->rclBounds.top)
796 {
797 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
798 OutputRect.top = ClipRegion->rclBounds.top;
799 }
800 if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
801 {
802 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
803 OutputRect.bottom = ClipRegion->rclBounds.bottom;
804 }
805 }
806
807 if (! IntEngEnter(&EnterLeaveSource, psoMask, &InputRect, TRUE, &Translate, &psoInput))
808 {
809 return FALSE;
810 }
811
812 InputPoint.x = InputRect.left + Translate.x;
813 InputPoint.y = InputRect.top + Translate.y;
814
815 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
816 nothing to do */
817 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
818 {
819 IntEngLeave(&EnterLeaveSource);
820 return TRUE;
821 }
822
823 if (! IntEngEnter(&EnterLeaveDest, psoDest, &OutputRect, FALSE, &Translate, &psoOutput))
824 {
825 IntEngLeave(&EnterLeaveSource);
826 return FALSE;
827 }
828
829 OutputRect.left = DestRect->left + Translate.x;
830 OutputRect.right = DestRect->right + Translate.x;
831 OutputRect.top = DestRect->top + Translate.y;
832 OutputRect.bottom = DestRect->bottom + Translate.y;
833
834 if (BrushOrigin)
835 {
836 AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
837 AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
838 }
839 else
840 AdjustedBrushOrigin = Translate;
841
842 // Determine clipping type
843 if (ClipRegion == (CLIPOBJ *) NULL)
844 {
845 clippingType = DC_TRIVIAL;
846 } else {
847 clippingType = ClipRegion->iDComplexity;
848 }
849
850 switch (clippingType)
851 {
852 case DC_TRIVIAL:
853 if (psoMask->iBitmapFormat == BMF_8BPP)
854 Ret = AlphaBltMask(psoOutput, NULL , psoInput, DestColorTranslation, SourceColorTranslation,
855 &OutputRect, NULL, &InputPoint, pbo, &AdjustedBrushOrigin);
856 else
857 Ret = BltMask(psoOutput, NULL, psoInput, DestColorTranslation,
858 &OutputRect, NULL, &InputPoint, pbo, &AdjustedBrushOrigin,
859 R4_MASK);
860 break;
861 case DC_RECT:
862 // Clip the blt to the clip rectangle
863 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
864 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
865 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
866 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
867 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
868 {
869 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
870 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
871 if (psoMask->iBitmapFormat == BMF_8BPP)
872 {
873 Ret = AlphaBltMask(psoOutput, NULL, psoInput, DestColorTranslation, SourceColorTranslation,
874 &CombinedRect, NULL, &Pt, pbo, &AdjustedBrushOrigin);
875 }
876 else
877 {
878 Ret = BltMask(psoOutput, NULL, psoInput, DestColorTranslation,
879 &CombinedRect, NULL, &Pt, pbo, &AdjustedBrushOrigin, R4_MASK);
880 }
881 }
882 break;
883 case DC_COMPLEX:
884 Ret = TRUE;
885 if (psoOutput == psoInput)
886 {
887 if (OutputRect.top < InputPoint.y)
888 {
889 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
890 }
891 else
892 {
893 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
894 }
895 }
896 else
897 {
898 Direction = CD_ANY;
899 }
900 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
901 do
902 {
903 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
904
905 for (i = 0; i < RectEnum.c; i++)
906 {
907 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
908 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
909 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
910 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
911 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
912 {
913 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
914 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
915 if (psoMask->iBitmapFormat == BMF_8BPP)
916 {
917 Ret = AlphaBltMask(psoOutput, NULL, psoInput,
918 DestColorTranslation,
919 SourceColorTranslation,
920 &CombinedRect, NULL, &Pt, pbo,
921 &AdjustedBrushOrigin) && Ret;
922 }
923 else
924 {
925 Ret = BltMask(psoOutput, NULL, psoInput,
926 DestColorTranslation, &CombinedRect, NULL,
927 &Pt, pbo, &AdjustedBrushOrigin,
928 R4_MASK) && Ret;
929 }
930 }
931 }
932 }
933 while (EnumMore);
934 break;
935 }
936
937
938 IntEngLeave(&EnterLeaveDest);
939 IntEngLeave(&EnterLeaveSource);
940
941 return Ret;
942 }
943
944 BOOL APIENTRY
945 IntEngMaskBlt(SURFOBJ *psoDest,
946 SURFOBJ *psoMask,
947 CLIPOBJ *ClipRegion,
948 XLATEOBJ *DestColorTranslation,
949 XLATEOBJ *SourceColorTranslation,
950 RECTL *DestRect,
951 POINTL *pptlMask,
952 BRUSHOBJ *pbo,
953 POINTL *BrushOrigin)
954 {
955 BOOLEAN ret;
956 RECTL OutputRect;
957 POINTL InputPoint;
958 SURFACE *psurfDest;
959
960 ASSERT(psoMask);
961
962 if (pptlMask)
963 {
964 InputPoint = *pptlMask;
965 }
966
967 /* Clip against the bounds of the clipping region so we won't try to write
968 * outside the surface */
969 if (NULL != ClipRegion)
970 {
971 if (!RECTL_bIntersectRect(&OutputRect, DestRect, &ClipRegion->rclBounds))
972 {
973 return TRUE;
974 }
975 InputPoint.x += OutputRect.left - DestRect->left;
976 InputPoint.y += OutputRect.top - DestRect->top;
977 }
978 else
979 {
980 OutputRect = *DestRect;
981 }
982
983 /* No success yet */
984 ret = FALSE;
985 ASSERT(psoDest);
986 psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
987
988 SURFACE_LockBitmapBits(psurfDest);
989 MouseSafetyOnDrawStart(psoDest, OutputRect.left, OutputRect.top,
990 OutputRect.right, OutputRect.bottom);
991
992 /* Dummy BitBlt to let driver know that it should flush its changes.
993 This should really be done using a call to DrvSynchronizeSurface,
994 but the VMware driver doesn't hook that call. */
995 IntEngBitBltEx(psoDest, NULL, psoMask, ClipRegion, DestColorTranslation,
996 DestRect, pptlMask, pptlMask, pbo, BrushOrigin,
997 R4_NOOP, FALSE);
998
999 ret = EngMaskBitBlt(psoDest, psoMask, ClipRegion, DestColorTranslation, SourceColorTranslation,
1000 &OutputRect, &InputPoint, pbo, BrushOrigin);
1001
1002 /* Dummy BitBlt to let driver know that something has changed. */
1003 IntEngBitBltEx(psoDest, NULL, psoMask, ClipRegion, DestColorTranslation,
1004 DestRect, pptlMask, pptlMask, pbo, BrushOrigin,
1005 R4_NOOP, FALSE);
1006
1007 MouseSafetyOnDrawEnd(psoDest);
1008 SURFACE_UnlockBitmapBits(psurfDest);
1009
1010 return ret;
1011 }
1012
1013 /* EOF */