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