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