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