xref: /reactos/win32ss/gdi/eng/bitblt.c (revision 3476cdae)
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS Win32k subsystem
4  * PURPOSE:          GDI BitBlt Functions
5  * FILE:             win32ss/gdi/eng/bitblt.c
6  * PROGRAMERS:       Jason Filby
7  *                   Timo Kreuzer
8  *                   Doug Lyons
9  *
10  * WARNING: Modify this file with extreme caution. It is very sensitive to timing changes.
11  *   Adding code can cause the system to show a Fatal Exception Error and fail to boot!.
12  *   This is especially true in CallDibBitBlt, IntEngBitBlt and EngBitBlt (even DPRINT's).
13  */
14 
15 #include <win32k.h>
16 
17 #define NDEBUG
18 #include <debug.h>
19 
20 XCLIPOBJ gxcoTrivial =
21 {
22     /* CLIPOBJ */
23     {
24         0, /* iUniq */
25         {LONG_MIN, LONG_MIN, LONG_MAX, LONG_MAX}, /* rclBounds */
26         DC_TRIVIAL,    /* idCOmplexity */
27         FC_RECT,       /* iFComplexity */
28         TC_RECTANGLES, /* iMode */
29         0              /* fjOptions */
30     },
31     { 0, {0,0,0,0}, 0},
32     0, {0,0,0,0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
33 };
34 
35 typedef BOOLEAN (APIENTRY *PBLTRECTFUNC)(SURFOBJ* OutputObj,
36                                         SURFOBJ* InputObj,
37                                         SURFOBJ* Mask,
38                                         XLATEOBJ* ColorTranslation,
39                                         RECTL* OutputRect,
40                                         POINTL* InputPoint,
41                                         POINTL* MaskOrigin,
42                                         BRUSHOBJ* pbo,
43                                         POINTL* BrushOrigin,
44                                         ROP4 Rop4);
45 
46 static BOOLEAN APIENTRY
47 BltMask(SURFOBJ* psoDest,
48         SURFOBJ* psoSource,
49         SURFOBJ* psoMask,
50         XLATEOBJ* ColorTranslation,
51         RECTL* prclDest,
52         POINTL* pptlSource,
53         POINTL* pptlMask,
54         BRUSHOBJ* pbo,
55         POINTL* pptlBrush,
56         ROP4 Rop4)
57 {
58     LONG x, y, cx, cy;
59     BYTE *pjMskLine, *pjMskCurrent;
60     BYTE fjMaskBit0, fjMaskBit;
61     /* Pattern brushes */
62     SURFOBJ *psoPattern;
63     ULONG PatternWidth = 0, PatternHeight = 0;
64     LONG PatternX0 = 0, PatternX = 0, PatternY = 0;
65     LONG SrcX = 0, SrcY = 0;
66     PFN_DIB_PutPixel fnDest_PutPixel = NULL;
67     PFN_DIB_GetPixel fnPattern_GetPixel = NULL, fnSrc_GetPixel = NULL, fnDest_GetPixel;
68     ULONG Pattern = 0, Source = 0, Dest = 0;
69     DWORD fgndRop, bkgndRop;
70 
71     ASSERT(IS_VALID_ROP4(Rop4));
72     ASSERT(psoMask->iBitmapFormat == BMF_1BPP);
73 
74     fgndRop = ROP4_FGND(Rop4);
75     bkgndRop = ROP4_BKGND(Rop4);
76 
77     //DPRINT1("Rop4 : 0x%08x\n", Rop4);
78 
79     /* Determine pattern */
80     if (pbo && pbo->iSolidColor == 0xFFFFFFFF)
81     {
82         psoPattern = BRUSHOBJ_psoPattern(pbo);
83         if (psoPattern)
84         {
85             PatternWidth = psoPattern->sizlBitmap.cx;
86             PatternHeight = psoPattern->sizlBitmap.cy;
87             fnPattern_GetPixel = DibFunctionsForBitmapFormat[psoPattern->iBitmapFormat].DIB_GetPixel;
88         }
89     }
90     else
91         psoPattern = NULL;
92 
93     cx = prclDest->right - prclDest->left;
94     cy = prclDest->bottom - prclDest->top;
95     if ((pptlMask->x + cx > psoMask->sizlBitmap.cx) ||
96         (pptlMask->y + cy > psoMask->sizlBitmap.cy))
97     {
98         return FALSE;
99     }
100 
101     pjMskLine = (PBYTE)psoMask->pvScan0 + pptlMask->y * psoMask->lDelta + (pptlMask->x >> 3);
102     fjMaskBit0 = 0x80 >> (pptlMask->x & 0x07);
103 
104     fnDest_PutPixel = DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel;
105     fnDest_GetPixel = DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_GetPixel;
106 
107     /* Do we have a source */
108     if(psoSource)
109     {
110         /* Sanity check */
111         ASSERT(ROP4_USES_SOURCE(Rop4));
112         fnSrc_GetPixel = DibFunctionsForBitmapFormat[psoSource->iBitmapFormat].DIB_GetPixel;
113         SrcY = pptlSource->y;
114         SrcX = pptlSource->x;
115     }
116 
117     if (psoPattern)
118     {
119         PatternY = (prclDest->top - pptlBrush->y) % PatternHeight;
120         if (PatternY < 0)
121         {
122             PatternY += PatternHeight;
123         }
124         PatternX0 = (prclDest->left - pptlBrush->x) % PatternWidth;
125         if (PatternX0 < 0)
126         {
127             PatternX0 += PatternWidth;
128         }
129         PatternX = PatternX0;
130     }
131     else
132     {
133         Pattern = pbo ? pbo->iSolidColor : 0;
134     }
135 
136     for (y = prclDest->top; y < prclDest->bottom; y++)
137     {
138         pjMskCurrent = pjMskLine;
139         fjMaskBit = fjMaskBit0;
140 
141         for (x = prclDest->left; x < prclDest->right; x++)
142         {
143             Rop4 = (*pjMskCurrent & fjMaskBit) ? fgndRop : bkgndRop;
144 
145             if(psoPattern)
146             {
147                 if(ROP4_USES_PATTERN(Rop4))
148                     Pattern = fnPattern_GetPixel(psoPattern, PatternX, PatternY);
149                 PatternX++;
150                 PatternX %= PatternWidth;
151             }
152 
153             if(psoSource)
154             {
155                 if(ROP4_USES_SOURCE(Rop4))
156                 {
157                     Source = XLATEOBJ_iXlate(ColorTranslation,
158                                              fnSrc_GetPixel(psoSource, SrcX, SrcY));
159                 }
160                 SrcX++;
161             }
162 
163             if(ROP4_USES_DEST(Rop4))
164                 Dest = fnDest_GetPixel(psoDest, x, y);
165 
166             fnDest_PutPixel(psoDest,
167                             x,
168                             y,
169                             DIB_DoRop(Rop4,
170                                       Dest,
171                                       Source,
172                                       Pattern));
173             fjMaskBit = _rotr8(fjMaskBit, 1);
174             pjMskCurrent += (fjMaskBit >> 7);
175         }
176         pjMskLine += psoMask->lDelta;
177         if(psoPattern)
178         {
179             PatternY++;
180             PatternY %= PatternHeight;
181             PatternX = PatternX0;
182         }
183         if(psoSource)
184         {
185             SrcY++;
186             SrcX = pptlSource->x;
187         }
188     }
189 
190     return TRUE;
191 }
192 
193 #ifndef _USE_DIBLIB_
194 
195 static BOOLEAN APIENTRY
196 BltPatCopy(SURFOBJ* Dest,
197            SURFOBJ* Source,
198            SURFOBJ* Mask,
199            XLATEOBJ* ColorTranslation,
200            RECTL* DestRect,
201            POINTL* SourcePoint,
202            POINTL* MaskPoint,
203            BRUSHOBJ* pbo,
204            POINTL* BrushPoint,
205            DWORD Rop4)
206 {
207     // These functions are assigned if we're working with a DIB
208     // The assigned functions depend on the bitsPerPixel of the DIB
209 
210     DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_ColorFill(Dest, DestRect, pbo ? pbo->iSolidColor : 0);
211 
212     return TRUE;
213 }
214 
215 static BOOLEAN APIENTRY
216 CallDibBitBlt(SURFOBJ* OutputObj,
217               SURFOBJ* InputObj,
218               SURFOBJ* Mask,
219               XLATEOBJ* ColorTranslation,
220               RECTL* OutputRect,
221               POINTL* InputPoint,
222               POINTL* MaskOrigin,
223               BRUSHOBJ* pbo,
224               POINTL* BrushOrigin,
225               ROP4 Rop4)
226 {
227     BLTINFO BltInfo;
228     SURFOBJ *psoPattern;
229     BOOLEAN Result;
230 
231     BltInfo.DestSurface = OutputObj;
232     BltInfo.SourceSurface = InputObj;
233     BltInfo.PatternSurface = NULL;
234     BltInfo.XlateSourceToDest = ColorTranslation;
235     BltInfo.DestRect = *OutputRect;
236     BltInfo.SourcePoint = *InputPoint;
237 
238     if ((Rop4 & 0xFF) == R3_OPINDEX_SRCCOPY)
239         return DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_BitBltSrcCopy(&BltInfo);
240 
241     BltInfo.Brush = pbo;
242     BltInfo.BrushOrigin = *BrushOrigin;
243     BltInfo.Rop4 = Rop4;
244 
245     /* Pattern brush */
246     if (ROP4_USES_PATTERN(Rop4) && pbo && pbo->iSolidColor == 0xFFFFFFFF)
247     {
248         psoPattern = BRUSHOBJ_psoPattern(pbo);
249         if (psoPattern)
250         {
251             BltInfo.PatternSurface = psoPattern;
252         }
253         else
254         {
255             /* FIXME: What to do here? */
256         }
257     }
258     else
259     {
260         psoPattern = NULL;
261     }
262 
263     /* Make WellOrdered with top < bottom and left < right */
264     RECTL_vMakeWellOrdered(&BltInfo.DestRect);
265 
266     DPRINT("CallDibBitBlt: BltInfo.DestRect: (%d,%d)-(%d,%d)\n",
267            BltInfo.DestRect.left, BltInfo.DestRect.top, BltInfo.DestRect.right, BltInfo.DestRect.bottom);
268 
269     Result = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_BitBlt(&BltInfo);
270 
271     return Result;
272 }
273 
274 INT __cdecl abs(INT nm);
275 
276 
277 /*
278  * @implemented
279  */
280 BOOL APIENTRY
281 NtGdiEngBitBlt(
282                 IN SURFOBJ  *psoTrg,
283                 IN SURFOBJ  *psoSrc,
284                 IN SURFOBJ  *psoMask,
285                 IN CLIPOBJ  *pco,
286                 IN XLATEOBJ  *pxlo,
287                 IN RECTL  *prclTrg,
288                 IN POINTL  *pptlSrc,
289                 IN POINTL  *pptlMask,
290                 IN BRUSHOBJ  *pbo,
291                 IN POINTL  *pptlBrush,
292                 IN ROP4 Rop4)
293 {
294     RECTL  rclTrg;
295     POINTL ptlSrc;
296     POINTL ptlMask;
297     POINTL ptlBrush;
298 
299     _SEH2_TRY
300     {
301         ProbeForRead(prclTrg, sizeof(RECTL), 1);
302         RtlCopyMemory(&rclTrg,prclTrg, sizeof(RECTL));
303 
304         ProbeForRead(pptlSrc, sizeof(POINTL), 1);
305         RtlCopyMemory(&ptlSrc, pptlSrc, sizeof(POINTL));
306 
307         ProbeForRead(pptlMask, sizeof(POINTL), 1);
308         RtlCopyMemory(&ptlMask, pptlMask, sizeof(POINTL));
309 
310         ProbeForRead(pptlBrush, sizeof(POINTL), 1);
311         RtlCopyMemory(&ptlBrush, pptlBrush, sizeof(POINTL));
312 
313     }
314     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
315     {
316         _SEH2_YIELD(return FALSE);
317     }
318     _SEH2_END;
319 
320     return  EngBitBlt(psoTrg, psoSrc, psoMask, pco, pxlo, &rclTrg, &ptlSrc, &ptlMask, pbo, &ptlBrush, Rop4);
321 }
322 
323 /*
324  * @implemented
325  */
326 BOOL
327 APIENTRY
328 EngBitBlt(
329     _Inout_ SURFOBJ *psoTrg,
330     _In_opt_ SURFOBJ *psoSrc,
331     _In_opt_ SURFOBJ *psoMask,
332     _In_opt_ CLIPOBJ *pco,
333     _In_opt_ XLATEOBJ *pxlo,
334     _In_ RECTL *prclTrg,
335     _In_opt_ POINTL *pptlSrc,
336     _In_opt_ POINTL *pptlMask,
337     _In_opt_ BRUSHOBJ *pbo,
338     _In_opt_ POINTL *pptlBrush,
339     _In_ ROP4 rop4)
340 {
341     BYTE               clippingType;
342     RECTL              CombinedRect;
343     RECT_ENUM          RectEnum;
344     BOOL               EnumMore;
345     POINTL             InputPoint;
346     RECTL              InputRect;
347     RECTL              OutputRect;
348     SURFOBJ*           InputObj = 0;
349     SURFOBJ*           OutputObj;
350     PBLTRECTFUNC       BltRectFunc;
351     BOOLEAN            Ret = TRUE;
352     RECTL              ClipRect;
353     ULONG              i;
354     POINTL             Pt;
355     ULONG              Direction;
356     BOOL               UsesSource, UsesMask;
357     POINTL             AdjustedBrushOrigin;
358     LONG               lTmp;
359     BOOLEAN            bTopToBottom, bLeftToRight;
360 
361     UsesSource = ROP4_USES_SOURCE(rop4);
362     UsesMask = ROP4_USES_MASK(rop4);
363 
364     if (prclTrg->left > prclTrg->right)
365     {
366       bLeftToRight = TRUE;
367     }
368     else
369     {
370       bLeftToRight = FALSE;
371     }
372 
373     if (prclTrg->top > prclTrg->bottom)
374     {
375       bTopToBottom = TRUE;
376     }
377     else
378     {
379       bTopToBottom = FALSE;
380     }
381 
382     if (rop4 == ROP4_NOOP)
383     {
384         /* Copy destination onto itself: nop */
385         return TRUE;
386     }
387 
388     //DPRINT1("rop4 : 0x%08x\n", rop4);
389 
390     OutputRect = *prclTrg;
391     RECTL_vMakeWellOrdered(&OutputRect);
392 
393     DPRINT("EngBitBlt: prclTrg: (%d,%d)-(%d,%d)\n",
394            prclTrg->left, prclTrg->top, prclTrg->right, prclTrg->bottom);
395 
396     DPRINT("EngBitBlt: OutputRect: (%d,%d)-(%d,%d)\n",
397            OutputRect.left, OutputRect.top, OutputRect.right, OutputRect.bottom);
398 
399     if (UsesSource)
400     {
401         if (!psoSrc || !pptlSrc)
402         {
403             return FALSE;
404         }
405 
406         /* Make sure we don't try to copy anything outside the valid source
407            region */
408         InputPoint = *pptlSrc;
409         if (InputPoint.x < 0)
410         {
411             OutputRect.left -= InputPoint.x;
412             InputPoint.x = 0;
413         }
414         if (InputPoint.y < 0)
415         {
416             OutputRect.top -= InputPoint.y;
417             InputPoint.y = 0;
418         }
419         if (psoSrc->sizlBitmap.cx < InputPoint.x +
420                 OutputRect.right - OutputRect.left)
421         {
422             OutputRect.right = OutputRect.left +
423                                psoSrc->sizlBitmap.cx - InputPoint.x;
424         }
425         if (psoSrc->sizlBitmap.cy < InputPoint.y +
426                 OutputRect.bottom - OutputRect.top)
427         {
428             OutputRect.bottom = OutputRect.top +
429                                 psoSrc->sizlBitmap.cy - InputPoint.y;
430         }
431 
432         InputRect.left = InputPoint.x;
433         InputRect.right = InputPoint.x + (OutputRect.right - OutputRect.left);
434         InputRect.top = InputPoint.y;
435         InputRect.bottom = InputPoint.y + (OutputRect.bottom - OutputRect.top);
436 
437         InputObj = psoSrc;
438     }
439     else
440     {
441         InputPoint.x = InputPoint.y = 0;
442         InputRect.left = 0;
443         InputRect.right = prclTrg->right - prclTrg->left;
444         InputRect.top = 0;
445         InputRect.bottom = prclTrg->bottom - prclTrg->top;
446     }
447 
448     if (NULL != pco)
449     {
450         if (OutputRect.left < pco->rclBounds.left)
451         {
452             InputRect.left += pco->rclBounds.left - OutputRect.left;
453             InputPoint.x += pco->rclBounds.left - OutputRect.left;
454             OutputRect.left = pco->rclBounds.left;
455         }
456         if (pco->rclBounds.right < OutputRect.right)
457         {
458             InputRect.right -=  OutputRect.right - pco->rclBounds.right;
459             OutputRect.right = pco->rclBounds.right;
460         }
461         if (OutputRect.top < pco->rclBounds.top)
462         {
463             InputRect.top += pco->rclBounds.top - OutputRect.top;
464             InputPoint.y += pco->rclBounds.top - OutputRect.top;
465             OutputRect.top = pco->rclBounds.top;
466         }
467         if (pco->rclBounds.bottom < OutputRect.bottom)
468         {
469             InputRect.bottom -=  OutputRect.bottom - pco->rclBounds.bottom;
470             OutputRect.bottom = pco->rclBounds.bottom;
471         }
472     }
473 
474     /* Check for degenerate case: if height or width of OutputRect is 0 pixels
475        there's nothing to do */
476     if (OutputRect.right <= OutputRect.left ||
477             OutputRect.bottom <= OutputRect.top)
478     {
479         return TRUE;
480     }
481 
482     OutputObj = psoTrg;
483 
484     if (pptlBrush)
485     {
486         AdjustedBrushOrigin.x = pptlBrush->x;
487         AdjustedBrushOrigin.y = pptlBrush->y;
488     }
489     else
490     {
491         AdjustedBrushOrigin.x = 0;
492         AdjustedBrushOrigin.y = 0;
493     }
494 
495     /* Determine clipping type */
496     if (pco == (CLIPOBJ *) NULL)
497     {
498         clippingType = DC_TRIVIAL;
499     }
500     else
501     {
502         clippingType = pco->iDComplexity;
503     }
504 
505     /* Check if we need a mask but have no mask surface */
506     if (UsesMask && (psoMask == NULL))
507     {
508         /* Check if the BRUSHOBJ can provide the mask */
509         psoMask = BRUSHOBJ_psoMask(pbo);
510         if (psoMask == NULL)
511         {
512             /* We have no mask, assume the mask is all foreground */
513             rop4 = (rop4 & 0xFF) | ((rop4 & 0xFF) << 8);
514             UsesMask = FALSE;
515         }
516     }
517 
518     if (UsesMask)
519     {
520         BltRectFunc = BltMask;
521     }
522     else if ((rop4 & 0xFF) == R3_OPINDEX_PATCOPY)
523     {
524         if (pbo && pbo->iSolidColor == 0xFFFFFFFF)
525             BltRectFunc = CallDibBitBlt;
526         else
527             BltRectFunc = BltPatCopy;
528     }
529     else
530     {
531         BltRectFunc = CallDibBitBlt;
532     }
533 
534 
535     switch (clippingType)
536     {
537         case DC_TRIVIAL:
538             /* Fix up OutputRect here */
539             if (bLeftToRight)
540             {
541                 lTmp = OutputRect.left;
542                 OutputRect.left = OutputRect.right;
543                 OutputRect.right = lTmp;
544             }
545 
546             if (bTopToBottom)
547             {
548                 lTmp = OutputRect.top;
549                 OutputRect.top = OutputRect.bottom;
550                 OutputRect.bottom = lTmp;
551             }
552 
553             Ret = (*BltRectFunc)(OutputObj,
554                                  InputObj,
555                                  psoMask,
556                                  pxlo,
557                                  &OutputRect,
558                                  &InputPoint,
559                                  pptlMask,
560                                  pbo,
561                                  &AdjustedBrushOrigin,
562                                  rop4);
563             break;
564         case DC_RECT:
565             /* Clip the blt to the clip rectangle */
566             ClipRect.left = pco->rclBounds.left;
567             ClipRect.right = pco->rclBounds.right;
568             ClipRect.top = pco->rclBounds.top;
569             ClipRect.bottom = pco->rclBounds.bottom;
570             if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
571             {
572 #ifdef _USE_DIBLIB_
573                 if (BrushOrigin)
574                 {
575                     AdjustedBrushOrigin.x = BrushOrigin->x + CombinedRect.left - OutputRect.left;
576                     AdjustedBrushOrigin.y = BrushOrigin->y + CombinedRect.top - OutputRect.top;
577                 }
578 #endif
579                 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
580                 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
581                 Ret = (*BltRectFunc)(OutputObj,
582                                      InputObj,
583                                      psoMask,
584                                      pxlo,
585                                      &CombinedRect,
586                                      &Pt,
587                                      pptlMask,
588                                      pbo,
589                                      &AdjustedBrushOrigin,
590                                      rop4);
591             }
592             break;
593         case DC_COMPLEX:
594             Ret = TRUE;
595             if (OutputObj == InputObj)
596             {
597                 if (OutputRect.top < InputPoint.y)
598                 {
599                     Direction = OutputRect.left < InputPoint.x ?
600                                 CD_RIGHTDOWN : CD_LEFTDOWN;
601                 }
602                 else
603                 {
604                     Direction = OutputRect.left < InputPoint.x ?
605                                 CD_RIGHTUP : CD_LEFTUP;
606                 }
607             }
608             else
609             {
610                 Direction = CD_ANY;
611             }
612             CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, Direction, 0);
613             do
614             {
615                 EnumMore = CLIPOBJ_bEnum(pco, sizeof(RectEnum),
616                                          (PVOID) &RectEnum);
617 
618                 for (i = 0; i < RectEnum.c; i++)
619                 {
620                     ClipRect.left = RectEnum.arcl[i].left;
621                     ClipRect.right = RectEnum.arcl[i].right;
622                     ClipRect.top = RectEnum.arcl[i].top;
623                     ClipRect.bottom = RectEnum.arcl[i].bottom;
624                     if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
625                     {
626 #ifdef _USE_DIBLIB_
627                         if (BrushOrigin)
628                         {
629                             AdjustedBrushOrigin.x = BrushOrigin->x + CombinedRect.left - OutputRect.left;
630                             AdjustedBrushOrigin.y = BrushOrigin->y + CombinedRect.top - OutputRect.top;
631                         }
632 #endif
633                         Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
634                         Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
635                         Ret = (*BltRectFunc)(OutputObj,
636                                              InputObj,
637                                              psoMask,
638                                              pxlo,
639                                              &CombinedRect,
640                                              &Pt,
641                                              pptlMask,
642                                              pbo,
643                                              &AdjustedBrushOrigin,
644                                              rop4) && Ret;
645                     }
646                 }
647             }
648             while (EnumMore);
649             break;
650     }
651 
652     return Ret;
653 }
654 
655 BOOL APIENTRY
656 IntEngBitBlt(
657     SURFOBJ *psoTrg,
658     SURFOBJ *psoSrc,
659     SURFOBJ *psoMask,
660     CLIPOBJ *pco,
661     XLATEOBJ *pxlo,
662     RECTL *prclTrg,
663     POINTL *pptlSrc,
664     POINTL *pptlMask,
665     BRUSHOBJ *pbo,
666     POINTL *pptlBrush,
667     ROP4 Rop4)
668 {
669     SURFACE *psurfTrg;
670     SURFACE *psurfSrc = NULL;
671     BOOL bResult;
672     RECTL rclClipped;
673     RECTL rclSrc;
674     RECTL rclSrcClipped;
675     POINTL ptlBrush;
676     PFN_DrvBitBlt pfnBitBlt;
677     LONG lTmp;
678     BOOLEAN bTopToBottom, bLeftToRight;
679 
680     /* Sanity checks */
681     ASSERT(IS_VALID_ROP4(Rop4));
682     ASSERT(psoTrg);
683 
684     psurfTrg = CONTAINING_RECORD(psoTrg, SURFACE, SurfObj);
685 
686     bLeftToRight = prclTrg->left > prclTrg->right;
687     bTopToBottom = prclTrg->top > prclTrg->bottom;
688 
689     /* Get the target rect and make it well ordered */
690     rclClipped = *prclTrg;
691     RECTL_vMakeWellOrdered(&rclClipped);
692 
693     /* Clip the target rect against the bounds of the target surface */
694     if (!RECTL_bClipRectBySize(&rclClipped, &rclClipped, &psoTrg->sizlBitmap))
695     {
696         /* Nothing left */
697         return TRUE;
698     }
699 
700     if (pco)
701     {
702         /* Clip target rect against the bounds of the clipping region */
703         if (!RECTL_bIntersectRect(&rclClipped, &rclClipped, &pco->rclBounds))
704         {
705             /* Nothing left */
706             return TRUE;
707         }
708 
709         /* Don't pass a clipobj with only a single rect */
710         if (pco->iDComplexity == DC_RECT)
711             pco = NULL;
712     }
713     else
714         pco = (CLIPOBJ *)&gxcoTrivial;
715 
716     if (ROP4_USES_SOURCE(Rop4))
717     {
718         ASSERT(psoSrc);
719         psurfSrc = CONTAINING_RECORD(psoSrc, SURFACE, SurfObj);
720 
721         /* Calculate source rect */
722         rclSrc.left = pptlSrc->x + rclClipped.left - prclTrg->left;
723         rclSrc.top = pptlSrc->y + rclClipped.top - prclTrg->top;
724         rclSrc.right = rclSrc.left + rclClipped.right - rclClipped.left;
725         rclSrc.bottom = rclSrc.top + rclClipped.bottom - rclClipped.top;
726 
727         /* Clip the source rect against the size of the source surface */
728         if (!RECTL_bClipRectBySize(&rclSrcClipped, &rclSrc, &psoSrc->sizlBitmap))
729         {
730             /* Nothing left */
731             return TRUE;
732         }
733 
734         /* Fix up target rect */
735         rclClipped.left += (rclSrcClipped.left - rclSrc.left);
736         rclClipped.top += (rclSrcClipped.top - rclSrc.top);
737         rclClipped.right -= (rclSrc.right - rclSrcClipped.right);
738         rclClipped.bottom -= (rclSrc.bottom - rclSrcClipped.bottom);
739 
740         pptlSrc = (PPOINTL)&rclSrcClipped;
741     }
742     else
743     {
744         psoSrc = NULL;
745         psurfSrc = NULL;
746     }
747 
748     if (pptlBrush)
749     {
750 #ifdef _USE_DIBLIB_
751         ptlBrush.x = pptlBrush->x + rclClipped.left - prclTrg->left;
752         ptlBrush.y = pptlBrush->y + rclClipped.top - prclTrg->top;
753 #else
754         ptlBrush = *pptlBrush;
755 #endif
756     }
757 
758     /* Is the target surface device managed? */
759     if (psurfTrg->flags & HOOK_BITBLT)
760     {
761         /* Is the source a different device managed surface? */
762         if (psoSrc && psoSrc->hdev != psoTrg->hdev && psurfSrc->flags & HOOK_BITBLT)
763         {
764             DPRINT1("Need to copy to standard bitmap format!\n");
765             ASSERT(FALSE);
766         }
767 
768         pfnBitBlt = GDIDEVFUNCS(psoTrg).BitBlt;
769     }
770 
771     /* Is the source surface device managed? */
772     else if (psoSrc && psurfSrc->flags & HOOK_BITBLT)
773     {
774         pfnBitBlt = GDIDEVFUNCS(psoSrc).BitBlt;
775     }
776     else
777     {
778         pfnBitBlt = EngBitBlt;
779     }
780 
781     /* rclClipped needs to be modified in accordance with flips here */
782     if (bLeftToRight)
783     {
784         lTmp = rclClipped.left;
785         rclClipped.left = rclClipped.right;
786         rclClipped.right = lTmp;
787     }
788 
789     if (bTopToBottom)
790     {
791         lTmp = rclClipped.top;
792         rclClipped.top = rclClipped.bottom;
793         rclClipped.bottom = lTmp;
794     }
795 
796     DPRINT("About to call EngBitBlt: rclClipped: (%d,%d)-(%d,%d)\n",
797            rclClipped.left, rclClipped.top, rclClipped.right, rclClipped.bottom);
798 
799     bResult = pfnBitBlt(psoTrg,
800                         psoSrc,
801                         psoMask,
802                         pco,
803                         pxlo,
804                         &rclClipped,
805                         pptlSrc,
806                         pptlMask,
807                         pbo,
808                         pptlBrush ? &ptlBrush : NULL,
809                         Rop4);
810 
811     // FIXME: cleanup temp surface!
812 
813     return bResult;
814 }
815 
816 #endif // !_USE_DIBLIB_
817 
818 /**** REACTOS FONT RENDERING CODE *********************************************/
819 
820 /* renders the alpha mask bitmap */
821 static BOOLEAN APIENTRY
822 AlphaBltMask(SURFOBJ* psoDest,
823              SURFOBJ* psoSource, // unused
824              SURFOBJ* psoMask,
825              XLATEOBJ* pxloRGB2Dest,
826              XLATEOBJ* pxloBrush,
827              RECTL* prclDest,
828              POINTL* pptlSource, // unused
829              POINTL* pptlMask,
830              BRUSHOBJ* pbo,
831              POINTL* pptlBrush)
832 {
833     LONG i, j, dx, dy;
834     int r, g, b;
835     ULONG Background, BrushColor, NewColor;
836     BYTE *tMask, *lMask;
837 
838     ASSERT(psoSource == NULL);
839     ASSERT(pptlSource == NULL);
840 
841     dx = prclDest->right  - prclDest->left;
842     dy = prclDest->bottom - prclDest->top;
843 
844     if (psoMask != NULL)
845     {
846         BrushColor = XLATEOBJ_iXlate(pxloBrush, pbo ? pbo->iSolidColor : 0);
847         r = (int)GetRValue(BrushColor);
848         g = (int)GetGValue(BrushColor);
849         b = (int)GetBValue(BrushColor);
850 
851         tMask = (PBYTE)psoMask->pvScan0 + (pptlMask->y * psoMask->lDelta) + pptlMask->x;
852         for (j = 0; j < dy; j++)
853         {
854             lMask = tMask;
855             for (i = 0; i < dx; i++)
856             {
857                 if (*lMask > 0)
858                 {
859                     if (*lMask == 0xff)
860                     {
861                         DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel(
862                             psoDest, prclDest->left + i, prclDest->top + j, pbo ? pbo->iSolidColor : 0);
863                     }
864                     else
865                     {
866                         Background = DIB_GetSource(psoDest, prclDest->left + i, prclDest->top + j,
867                                                    pxloBrush);
868 
869                         NewColor =
870                             RGB((*lMask * (r - GetRValue(Background)) >> 8) + GetRValue(Background),
871                                 (*lMask * (g - GetGValue(Background)) >> 8) + GetGValue(Background),
872                                 (*lMask * (b - GetBValue(Background)) >> 8) + GetBValue(Background));
873 
874                         Background = XLATEOBJ_iXlate(pxloRGB2Dest, NewColor);
875                         DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel(
876                             psoDest, prclDest->left + i, prclDest->top + j, Background);
877                     }
878                 }
879                 lMask++;
880             }
881             tMask += psoMask->lDelta;
882         }
883         return TRUE;
884     }
885     else
886     {
887         return FALSE;
888     }
889 }
890 
891 static
892 BOOL APIENTRY
893 EngMaskBitBlt(SURFOBJ *psoDest,
894               SURFOBJ *psoMask,
895               CLIPOBJ *ClipRegion,
896               XLATEOBJ *DestColorTranslation,
897               XLATEOBJ *SourceColorTranslation,
898               RECTL *DestRect,
899               POINTL *pptlMask,
900               BRUSHOBJ *pbo,
901               POINTL *BrushOrigin)
902 {
903     BYTE               clippingType;
904     RECTL              CombinedRect;
905     RECT_ENUM          RectEnum;
906     BOOL               EnumMore;
907     POINTL             InputPoint;
908     RECTL              InputRect;
909     RECTL              OutputRect;
910     POINTL             Translate;
911     INTENG_ENTER_LEAVE EnterLeaveSource;
912     INTENG_ENTER_LEAVE EnterLeaveDest;
913     SURFOBJ*           psoInput;
914     SURFOBJ*           psoOutput;
915     BOOLEAN            Ret = TRUE;
916     RECTL              ClipRect;
917     unsigned           i;
918     POINTL             Pt;
919     ULONG              Direction;
920     POINTL             AdjustedBrushOrigin;
921 
922     ASSERT(psoMask);
923 
924     if (pptlMask)
925     {
926         InputRect.left = pptlMask->x;
927         InputRect.right = pptlMask->x + (DestRect->right - DestRect->left);
928         InputRect.top = pptlMask->y;
929         InputRect.bottom = pptlMask->y + (DestRect->bottom - DestRect->top);
930     }
931     else
932     {
933         InputRect.left = 0;
934         InputRect.right = DestRect->right - DestRect->left;
935         InputRect.top = 0;
936         InputRect.bottom = DestRect->bottom - DestRect->top;
937     }
938 
939     OutputRect = *DestRect;
940     if (NULL != ClipRegion)
941     {
942         if (OutputRect.left < ClipRegion->rclBounds.left)
943         {
944             InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
945             OutputRect.left = ClipRegion->rclBounds.left;
946         }
947         if (ClipRegion->rclBounds.right < OutputRect.right)
948         {
949             InputRect.right -=  OutputRect.right - ClipRegion->rclBounds.right;
950             OutputRect.right = ClipRegion->rclBounds.right;
951         }
952         if (OutputRect.top < ClipRegion->rclBounds.top)
953         {
954             InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
955             OutputRect.top = ClipRegion->rclBounds.top;
956         }
957         if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
958         {
959             InputRect.bottom -=  OutputRect.bottom - ClipRegion->rclBounds.bottom;
960             OutputRect.bottom = ClipRegion->rclBounds.bottom;
961         }
962     }
963 
964     if (! IntEngEnter(&EnterLeaveSource, psoMask, &InputRect, TRUE, &Translate, &psoInput))
965     {
966         return FALSE;
967     }
968 
969     InputPoint.x = InputRect.left + Translate.x;
970     InputPoint.y = InputRect.top + Translate.y;
971 
972     /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
973        nothing to do */
974     if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
975     {
976         IntEngLeave(&EnterLeaveSource);
977         return TRUE;
978     }
979 
980     if (! IntEngEnter(&EnterLeaveDest, psoDest, &OutputRect, FALSE, &Translate, &psoOutput))
981     {
982         IntEngLeave(&EnterLeaveSource);
983         return FALSE;
984     }
985 
986     OutputRect.left = DestRect->left + Translate.x;
987     OutputRect.right = DestRect->right + Translate.x;
988     OutputRect.top = DestRect->top + Translate.y;
989     OutputRect.bottom = DestRect->bottom + Translate.y;
990 
991     if (BrushOrigin)
992     {
993         AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
994         AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
995     }
996     else
997         AdjustedBrushOrigin = Translate;
998 
999     // Determine clipping type
1000     if (ClipRegion == (CLIPOBJ *) NULL)
1001     {
1002         clippingType = DC_TRIVIAL;
1003     } else {
1004         clippingType = ClipRegion->iDComplexity;
1005     }
1006 
1007     switch (clippingType)
1008     {
1009         case DC_TRIVIAL:
1010             if (psoMask->iBitmapFormat == BMF_8BPP)
1011                 Ret = AlphaBltMask(psoOutput, NULL , psoInput, DestColorTranslation, SourceColorTranslation,
1012                                    &OutputRect, NULL, &InputPoint, pbo, &AdjustedBrushOrigin);
1013             else
1014                 Ret = BltMask(psoOutput, NULL, psoInput, DestColorTranslation,
1015                               &OutputRect, NULL, &InputPoint, pbo, &AdjustedBrushOrigin,
1016                               ROP4_MASK);
1017             break;
1018         case DC_RECT:
1019             // Clip the blt to the clip rectangle
1020             ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
1021             ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
1022             ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
1023             ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
1024             if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
1025             {
1026                 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
1027                 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
1028                 if (psoMask->iBitmapFormat == BMF_8BPP)
1029                 {
1030                     Ret = AlphaBltMask(psoOutput, NULL, psoInput, DestColorTranslation, SourceColorTranslation,
1031                                        &CombinedRect, NULL, &Pt, pbo, &AdjustedBrushOrigin);
1032                 }
1033                 else
1034                 {
1035                     Ret = BltMask(psoOutput, NULL, psoInput, DestColorTranslation,
1036                                   &CombinedRect, NULL, &Pt, pbo, &AdjustedBrushOrigin, ROP4_MASK);
1037                 }
1038             }
1039             break;
1040         case DC_COMPLEX:
1041             Ret = TRUE;
1042             if (psoOutput == psoInput)
1043             {
1044                 if (OutputRect.top < InputPoint.y)
1045                 {
1046                     Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
1047                 }
1048                 else
1049                 {
1050                     Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
1051                 }
1052             }
1053             else
1054             {
1055                 Direction = CD_ANY;
1056             }
1057             CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
1058             do
1059             {
1060                 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
1061 
1062                 for (i = 0; i < RectEnum.c; i++)
1063                 {
1064                     ClipRect.left = RectEnum.arcl[i].left + Translate.x;
1065                     ClipRect.right = RectEnum.arcl[i].right + Translate.x;
1066                     ClipRect.top = RectEnum.arcl[i].top + Translate.y;
1067                     ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
1068                     if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
1069                     {
1070                         Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
1071                         Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
1072                         if (psoMask->iBitmapFormat == BMF_8BPP)
1073                         {
1074                             Ret = AlphaBltMask(psoOutput, NULL, psoInput,
1075                                                DestColorTranslation,
1076                                                SourceColorTranslation,
1077                                                &CombinedRect, NULL, &Pt, pbo,
1078                                                &AdjustedBrushOrigin) && Ret;
1079                         }
1080                         else
1081                         {
1082                             Ret = BltMask(psoOutput, NULL, psoInput,
1083                                           DestColorTranslation, &CombinedRect, NULL,
1084                                           &Pt, pbo, &AdjustedBrushOrigin,
1085                                           ROP4_MASK) && Ret;
1086                         }
1087                     }
1088                 }
1089             }
1090             while (EnumMore);
1091             break;
1092     }
1093 
1094 
1095     IntEngLeave(&EnterLeaveDest);
1096     IntEngLeave(&EnterLeaveSource);
1097 
1098     return Ret;
1099 }
1100 
1101 BOOL
1102 APIENTRY
1103 IntEngMaskBlt(
1104     _Inout_ SURFOBJ *psoDest,
1105     _In_ SURFOBJ *psoMask,
1106     _In_ CLIPOBJ *pco,
1107     _In_ XLATEOBJ *pxloDest,
1108     _In_ XLATEOBJ *pxloSource,
1109     _In_ RECTL *prclDest,
1110     _In_ POINTL *pptlMask,
1111     _In_ BRUSHOBJ *pbo,
1112     _In_ POINTL *pptlBrushOrg)
1113 {
1114     BOOLEAN ret;
1115     RECTL rcDest;
1116     POINTL ptMask = {0,0};
1117     PSURFACE psurfTemp;
1118     RECTL rcTemp;
1119 
1120     ASSERT(psoDest);
1121     ASSERT(psoMask);
1122 
1123     /* Is this a 1 BPP mask? */
1124     if (psoMask->iBitmapFormat == BMF_1BPP)
1125     {
1126         /* Use IntEngBitBlt with an appropriate ROP4 */
1127         return IntEngBitBlt(psoDest,
1128                             NULL,
1129                             psoMask,
1130                             pco,
1131                             pxloDest,
1132                             prclDest,
1133                             NULL,
1134                             pptlMask,
1135                             pbo,
1136                             pptlBrushOrg,
1137                             ROP4_MASKPAINT);
1138     }
1139 
1140     ASSERT(psoMask->iBitmapFormat == BMF_8BPP);
1141 
1142     if (pptlMask)
1143     {
1144         ptMask = *pptlMask;
1145     }
1146 
1147     /* Clip against the bounds of the clipping region so we won't try to write
1148      * outside the surface */
1149     if (pco != NULL)
1150     {
1151         /* Intersect with the clip bounds and check if everything was clipped */
1152         if (!RECTL_bIntersectRect(&rcDest, prclDest, &pco->rclBounds))
1153         {
1154             return TRUE;
1155         }
1156 
1157         /* Adjust the mask point */
1158         ptMask.x += rcDest.left - prclDest->left;
1159         ptMask.y += rcDest.top - prclDest->top;
1160     }
1161     else
1162     {
1163         rcDest = *prclDest;
1164     }
1165 
1166     /* Check if the target surface is device managed */
1167     if (psoDest->iType != STYPE_BITMAP)
1168     {
1169         rcTemp.left = 0;
1170         rcTemp.top = 0;
1171         rcTemp.right = rcDest.right - rcDest.left;
1172         rcTemp.bottom = rcDest.bottom - rcDest.top;
1173 
1174         /* Allocate a temporary surface */
1175         psurfTemp = SURFACE_AllocSurface(STYPE_BITMAP,
1176                                          rcTemp.right,
1177                                          rcTemp.bottom,
1178                                          psoDest->iBitmapFormat,
1179                                          0,
1180                                          0,
1181                                          0,
1182                                          NULL);
1183         if (psurfTemp == NULL)
1184         {
1185             return FALSE;
1186         }
1187 
1188         /* Copy the current target surface bits to the temp surface */
1189         ret = EngCopyBits(&psurfTemp->SurfObj,
1190                           psoDest,
1191                           NULL, // pco
1192                           NULL, // pxlo
1193                           &rcTemp,
1194                           (PPOINTL)&rcDest);
1195 
1196         if (ret)
1197         {
1198             /* Do the operation on the temp surface */
1199             ret = EngMaskBitBlt(&psurfTemp->SurfObj,
1200                                 psoMask,
1201                                 NULL,
1202                                 pxloDest,
1203                                 pxloSource,
1204                                 &rcTemp,
1205                                 &ptMask,
1206                                 pbo,
1207                                 pptlBrushOrg);
1208         }
1209 
1210         if (ret)
1211         {
1212             /* Copy the result back to the dest surface */
1213             ret = EngCopyBits(psoDest,
1214                               &psurfTemp->SurfObj,
1215                               pco,
1216                               NULL,
1217                               &rcDest,
1218                               (PPOINTL)&rcTemp);
1219         }
1220 
1221         /* Delete the temp surface */
1222         GDIOBJ_vDeleteObject(&psurfTemp->BaseObject);
1223     }
1224     else
1225     {
1226         /* Do the operation on the target surface */
1227         ret = EngMaskBitBlt(psoDest,
1228                             psoMask,
1229                             pco,
1230                             pxloDest,
1231                             pxloSource,
1232                             &rcDest,
1233                             &ptMask,
1234                             pbo,
1235                             pptlBrushOrg);
1236     }
1237 
1238     return ret;
1239 }
1240 
1241 /* EOF */
1242