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