- Correctly translate output rect
[reactos.git] / reactos / subsys / win32k / eng / bitblt.c
index c22ff58..79349c8 100644 (file)
@@ -1,4 +1,23 @@
 /*
+ *  ReactOS W32 Subsystem
+ *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/* $Id$
+ *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
  * PURPOSE:          GDI BitBlt Functions
  * REVISION HISTORY:
  *        2/10/1999: Created
  */
+#include <w32k.h>
 
-#include <ddk/winddi.h>
-#include <ddk/ntddk.h>
-#include "brush.h"
-#include "enum.h"
-#include "objects.h"
-
-VOID BitBltCopy(SURFOBJ *DestSurf, SURFOBJ *SourceSurf,
-                SURFGDI *DestGDI,  SURFGDI *SourceGDI,
-                PRECTL  DestRect,  POINTL  *SourcePoint,
-                ULONG   Delta)
-{
-   ULONG dy, leftOfSource, leftOfDest, Width, CopyPos;
-
-   // FIXME: Get ColorTranslation passed here and do something with it
-
-   leftOfSource = SourcePoint->x * SourceGDI->BytesPerPixel;
-   leftOfDest   = DestRect->left * DestGDI->BytesPerPixel;
-   Width        = (DestRect->right - DestRect->left) * DestGDI->BytesPerPixel;
-   CopyPos      = leftOfDest;
-
-   for(dy=DestRect->top; dy<DestRect->bottom; dy++)
-   {
-      RtlCopyMemory(DestSurf->pvBits+CopyPos,
-                    SourceSurf->pvBits+CopyPos,
-                    Width);
-
-      CopyPos += Delta;
-   }
-}
-
-BOOL EngIntersectRect(PRECTL prcDst, PRECTL prcSrc1, PRECTL prcSrc2)
+typedef BOOLEAN STDCALL (*PBLTRECTFUNC)(SURFOBJ* OutputObj,
+                                        SURFOBJ* InputObj,
+                                        SURFOBJ* Mask,
+                                        XLATEOBJ* ColorTranslation,
+                                        RECTL* OutputRect,
+                                        POINTL* InputPoint,
+                                        POINTL* MaskOrigin,
+                                        BRUSHOBJ* Brush,
+                                        POINTL* BrushOrigin,
+                                        ROP4 Rop4);
+typedef BOOLEAN STDCALL (*PSTRETCHRECTFUNC)(SURFOBJ* OutputObj,
+                                            SURFOBJ* InputObj,
+                                            SURFOBJ* Mask,
+                                            CLIPOBJ* ClipRegion,
+                                            XLATEOBJ* ColorTranslation,
+                                            RECTL* OutputRect,
+                                            RECTL* InputRect,
+                                            POINTL* MaskOrigin,
+                                            POINTL* BrushOrigin,
+                                            ULONG Mode);
 
+BOOL STDCALL EngIntersectRect(RECTL* prcDst, RECTL* prcSrc1, RECTL* prcSrc2)
 {
-   static const RECTL rclEmpty = { 0, 0, 0, 0 };
+  static const RECTL rclEmpty = { 0, 0, 0, 0 };
 
-   prcDst->left  = max(prcSrc1->left, prcSrc2->left);
-   prcDst->right = min(prcSrc1->right, prcSrc2->right);
+  prcDst->left  = max(prcSrc1->left, prcSrc2->left);
+  prcDst->right = min(prcSrc1->right, prcSrc2->right);
 
-   if (prcDst->left < prcDst->right)
-   {
+  if (prcDst->left < prcDst->right)
+    {
       prcDst->top    = max(prcSrc1->top, prcSrc2->top);
       prcDst->bottom = min(prcSrc1->bottom, prcSrc2->bottom);
 
       if (prcDst->top < prcDst->bottom)
-         return(TRUE);
-   }
+       {
+         return TRUE;
+       }
+    }
 
-   *prcDst = rclEmpty;
+  *prcDst = rclEmpty;
 
-   return(FALSE);
+  return FALSE;
 }
 
-BOOL EngBitBlt(SURFOBJ *Dest, SURFOBJ *Source,
-               SURFOBJ *Mask, CLIPOBJ *ClipRegion,
-               XLATEOBJ *ColorTranslation, RECTL *DestRect,
-               POINTL *SourcePoint, POINTL *MaskRect,
-               BRUSHOBJ *Brush, POINTL *BrushOrigin, ROP4 rop4)
+static BOOLEAN STDCALL
+BltMask(SURFOBJ* Dest,
+       SURFOBJ* Source,
+       SURFOBJ* Mask,
+       XLATEOBJ* ColorTranslation,
+       RECTL* DestRect,
+       POINTL* SourcePoint,
+       POINTL* MaskPoint,
+       BRUSHOBJ* Brush,
+       POINTL* BrushPoint,
+       ROP4 Rop4)
 {
-   BYTE      clippingType;
-   RECTL     rclTmp;
-   POINTL    ptlTmp;
-   RECT_ENUM RectEnum;
-   BOOL      EnumMore;
-   SURFGDI   *DestGDI, *SourceGDI;
-   BOOLEAN   canCopyBits;
-
-   // If we don't have to do anything special, we can punt to DrvCopyBits
-   // if it exists
-   if( (Mask == NULL)        && (MaskRect == NULL) && (Brush == NULL) &&
-       (BrushOrigin == NULL) && (rop4 == NULL) )
+   LONG i, j, dx, dy, c8;
+   BYTE *tMask, *lMask;
+   static BYTE maskbit[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
+   /* Pattern brushes */
+   PGDIBRUSHINST GdiBrush = NULL;
+   SURFOBJ *PatternObj = NULL;
+   PBITMAPOBJ PatternBitmap;
+   ULONG PatternWidth = 0, PatternHeight = 0, PatternY = 0;
+
+   if (Mask == NULL)
    {
-     canCopyBits = TRUE;
-   } else
-     canCopyBits = FALSE;
+      return FALSE;
+   }
 
-   // FIXME: Use XLATEOBJ to translate source bitmap into destination bitmap's
-   //        format. Call DrvDitherColor function where necessary and if available
+   dx = DestRect->right  - DestRect->left;
+   dy = DestRect->bottom - DestRect->top;
 
-   // FIXME: If canCopyBits == TRUE AND the driver has a DrvCopyBits then
-   //        punt to EngCopyBits and not the driver's DrvCopyBits just yet so
-   //        that the EngCopyBits can take care of the clipping drivers
-   //        DrvCopyBits
+   if (Brush->iSolidColor == 0xFFFFFFFF)
+   {
+      GdiBrush = CONTAINING_RECORD(
+         Brush,
+         GDIBRUSHINST,
+         BrushObject);
 
-   // FIXME: Don't punt to DrvBitBlt straight away. Instead, mark a typedef'd
-   //        function to go there instead of the Engine's bltting function
-   //        so as to do the clipping for the driver
+      PatternBitmap = BITMAPOBJ_LockBitmap(GdiBrush->GdiBrushObject->hbmPattern);
+      if(PatternBitmap != NULL)
+      {
+        PatternObj = &PatternBitmap->SurfObj;
+        PatternWidth = PatternObj->sizlBitmap.cx;
+        PatternHeight = PatternObj->sizlBitmap.cy;
+      }
+   }
+   else
+     PatternBitmap = NULL;
 
-   // Check for CopyBits or BitBlt hooks if one is not a GDI managed bitmap
-   if((Dest->iType!=STYPE_BITMAP) || (Source->iType!=STYPE_BITMAP))
+   tMask = Mask->pvScan0 + SourcePoint->y * Mask->lDelta + (SourcePoint->x >> 3);
+   for (j = 0; j < dy; j++)
    {
+      lMask = tMask;
+      c8 = SourcePoint->x & 0x07;
 
-      // Destination surface is device managed
-      if(Dest->iType!=STYPE_BITMAP)
-      {
-         DestGDI = AccessInternalObjectFromUserObject(Dest);
+      if(PatternBitmap != NULL)
+         PatternY = (DestRect->top + j) % PatternHeight;
 
-         if ((DestGDI->CopyBits!=NULL) && (canCopyBits == TRUE))
+      for (i = 0; i < dx; i++)
+      {
+         if (0 != (*lMask & maskbit[c8]))
          {
-            return DestGDI->CopyBits(Dest, Source, ClipRegion,
-                                     ColorTranslation, DestRect, SourcePoint);
+            if (PatternBitmap == NULL)
+            {
+               DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_PutPixel(
+                  Dest, DestRect->left + i, DestRect->top + j, Brush->iSolidColor);
+            }
+            else
+            {
+               DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_PutPixel(
+                  Dest, DestRect->left + i, DestRect->top + j,
+                  DIB_GetSource(PatternObj, (DestRect->left + i) % PatternWidth, PatternY, GdiBrush->XlateObject));
+            }
          }
-
-         if (DestGDI->BitBlt!=NULL)
+         c8++;
+         if (8 == c8)
          {
-            return DestGDI->BitBlt(Dest, Source, Mask, ClipRegion,
-                                   ColorTranslation, DestRect, SourcePoint,
-                                   MaskRect, Brush, BrushOrigin, rop4);
+            lMask++;
+            c8 = 0;
          }
       }
+      tMask += Mask->lDelta;
+   }
 
-      // Source surface is device managed
-      if(Source->iType!=STYPE_BITMAP)
-      {
-         SourceGDI = AccessInternalObjectFromUserObject(Source);
+   if (PatternBitmap != NULL)
+      BITMAPOBJ_UnlockBitmap(PatternBitmap);
 
-         if ((SourceGDI->CopyBits!=NULL) && (canCopyBits == TRUE))
-         {
-            return SourceGDI->CopyBits(Dest, Source, ClipRegion,
-                                       ColorTranslation, DestRect, SourcePoint);
-         }
+   return TRUE;
+}
 
-         if (SourceGDI->BitBlt!=NULL)
-         {
-            return SourceGDI->BitBlt(Dest, Source, Mask, ClipRegion,
-                                     ColorTranslation, DestRect, SourcePoint,
-                                     MaskRect, Brush, BrushOrigin, rop4);
-         }
+static BOOLEAN STDCALL
+BltPatCopy(SURFOBJ* Dest,
+          SURFOBJ* Source,
+          SURFOBJ* Mask,
+          XLATEOBJ* ColorTranslation,
+          RECTL* DestRect,
+          POINTL* SourcePoint,
+          POINTL* MaskPoint,
+          BRUSHOBJ* Brush,
+          POINTL* BrushPoint,
+          ROP4 Rop4)
+{
+  // These functions are assigned if we're working with a DIB
+  // The assigned functions depend on the bitsPerPixel of the DIB
+
+  DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_ColorFill(Dest, DestRect, Brush->iSolidColor);
 
+  return TRUE;
+}
 
-         // Should never get here, if it's not GDI managed then the device
-         // should take care of it
+static BOOLEAN STDCALL
+CallDibBitBlt(SURFOBJ* OutputObj,
+              SURFOBJ* InputObj,
+              SURFOBJ* Mask,
+              XLATEOBJ* ColorTranslation,
+              RECTL* OutputRect,
+              POINTL* InputPoint,
+              POINTL* MaskOrigin,
+              BRUSHOBJ* Brush,
+              POINTL* BrushOrigin,
+              ROP4 Rop4)
+{
+   BLTINFO BltInfo;
+   PGDIBRUSHINST GdiBrush = NULL;
+   BITMAPOBJ *bmPattern;
+   BOOLEAN Result;
 
-         // FIXME: Error message here
-      }
+   BltInfo.DestSurface = OutputObj;
+   BltInfo.SourceSurface = InputObj;
+   BltInfo.PatternSurface = NULL;
+   BltInfo.XlateSourceToDest = ColorTranslation;
+   BltInfo.DestRect = *OutputRect;
+   BltInfo.SourcePoint = *InputPoint;
 
-   }
+   if (ROP3_TO_ROP4(SRCCOPY) == Rop4)
+      return DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_BitBltSrcCopy(&BltInfo);
 
-   DestGDI   = AccessInternalObjectFromUserObject(Dest);
-   SourceGDI = AccessInternalObjectFromUserObject(Source);
+   BltInfo.XlatePatternToDest = NULL;
+   BltInfo.Brush = Brush;
+   BltInfo.BrushOrigin = *BrushOrigin;
+   BltInfo.Rop4 = Rop4;
 
-   // Determine clipping type
-   if (ClipRegion == (CLIPOBJ *) NULL)
+   /* Pattern brush */
+   if (ROP4_USES_PATTERN(Rop4) && Brush->iSolidColor == 0xFFFFFFFF)
    {
-      clippingType = DC_TRIVIAL;
-   } else {
-      clippingType = ClipRegion->iDComplexity;
+      GdiBrush = CONTAINING_RECORD(Brush, GDIBRUSHINST, BrushObject);
+      if((bmPattern = BITMAPOBJ_LockBitmap(GdiBrush->GdiBrushObject->hbmPattern)))
+      {
+        BltInfo.PatternSurface = &bmPattern->SurfObj;
+      }
+      else
+      {
+        /* FIXME - What to do here? */
+      }
+      BltInfo.XlatePatternToDest = GdiBrush->XlateObject;
+   }
+   else
+   {
+     bmPattern = NULL;
    }
 
-   // We don't handle color translation just yet
+   Result = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_BitBlt(&BltInfo);
 
-   if ((rop4 == 0x0000CCCC) &&
-       ((ColorTranslation == NULL) || (ColorTranslation->flXlate & XO_TRIVIAL)))
+   /* Pattern brush */
+   if (bmPattern != NULL)
    {
-      switch(clippingType)
-      {
-         case DC_TRIVIAL:
-            BitBltCopy(Dest,     Source,
-                       DestGDI,  SourceGDI,
-                       DestRect, SourcePoint, Source->lDelta);
+      BITMAPOBJ_UnlockBitmap(bmPattern);
+   }
 
-            return(TRUE);
+   return Result;
+}
 
-         case DC_RECT:
+INT abs(INT nm);
 
-            // Clip the blt to the clip rectangle
+/*
+ * @implemented
+ */
+BOOL STDCALL
+EngBitBlt(SURFOBJ *DestObj,
+         SURFOBJ *SourceObj,
+         SURFOBJ *Mask,
+         CLIPOBJ *ClipRegion,
+         XLATEOBJ *ColorTranslation,
+         RECTL *DestRect,
+         POINTL *SourcePoint,
+         POINTL *MaskOrigin,
+         BRUSHOBJ *Brush,
+         POINTL *BrushOrigin,
+         ROP4 Rop4)
+{
+  BYTE               clippingType;
+  RECTL              CombinedRect;
+  RECT_ENUM          RectEnum;
+  BOOL               EnumMore;
+  POINTL             InputPoint;
+  RECTL              InputRect;
+  RECTL              OutputRect;
+  POINTL             Translate;
+  INTENG_ENTER_LEAVE EnterLeaveSource;
+  INTENG_ENTER_LEAVE EnterLeaveDest;
+  SURFOBJ*           InputObj;
+  SURFOBJ*           OutputObj;
+  PBLTRECTFUNC       BltRectFunc;
+  BOOLEAN            Ret = TRUE;
+  RECTL              ClipRect;
+  unsigned           i;
+  POINTL             Pt;
+  ULONG              Direction;
+  BOOL               UsesSource;
+  BOOL               UsesPattern;
+  POINTL             AdjustedBrushOrigin;
 
-            EngIntersectRect(&rclTmp, DestRect, &ClipRegion->rclBounds);
+  UsesSource = ROP4_USES_SOURCE(Rop4);
+  UsesPattern = ROP4_USES_PATTERN(Rop4);
+  if (R4_NOOP == Rop4)
+    {
+    /* Copy destination onto itself: nop */
+    return TRUE;
+    }
 
-            ptlTmp.x = SourcePoint->x + rclTmp.left - DestRect->left;
-            ptlTmp.y = SourcePoint->y + rclTmp.top  - DestRect->top;
+  if (UsesSource && NULL != SourcePoint)
+    {
+    InputRect.left = SourcePoint->x;
+    InputRect.right = SourcePoint->x + (DestRect->right - DestRect->left);
+    InputRect.top = SourcePoint->y;
+    InputRect.bottom = SourcePoint->y + (DestRect->bottom - DestRect->top);
+    }
+  else
+    {
+    InputRect.left = 0;
+    InputRect.right = DestRect->right - DestRect->left;
+    InputRect.top = 0;
+    InputRect.bottom = DestRect->bottom - DestRect->top;
+    }
 
-            BitBltCopy(Dest,    Source,
-                       DestGDI, SourceGDI,
-                       &rclTmp, &ptlTmp, Source->lDelta);
+  if (! IntEngEnter(&EnterLeaveSource, SourceObj, &InputRect, TRUE, &Translate, &InputObj))
+    {
+    return FALSE;
+    }
 
-            return(TRUE);
+  if (NULL != SourcePoint)
+    {
+    InputPoint.x = SourcePoint->x + Translate.x;
+    InputPoint.y = SourcePoint->y + Translate.y;
+    }
+  else
+    {
+    InputPoint.x = 0;
+    InputPoint.y = 0;
+    }
 
-         case DC_COMPLEX:
+  OutputRect = *DestRect;
+  if (NULL != ClipRegion)
+    {
+      if (OutputRect.left < ClipRegion->rclBounds.left)
+       {
+         InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
+         InputPoint.x += ClipRegion->rclBounds.left - OutputRect.left;
+         OutputRect.left = ClipRegion->rclBounds.left;
+       }
+      if (ClipRegion->rclBounds.right < OutputRect.right)
+       {
+         InputRect.right -=  OutputRect.right - ClipRegion->rclBounds.right;
+         OutputRect.right = ClipRegion->rclBounds.right;
+       }
+      if (OutputRect.top < ClipRegion->rclBounds.top)
+       {
+         InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
+         InputPoint.y += ClipRegion->rclBounds.top - OutputRect.top;
+         OutputRect.top = ClipRegion->rclBounds.top;
+       }
+      if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
+       {
+         InputRect.bottom -=  OutputRect.bottom - ClipRegion->rclBounds.bottom;
+         OutputRect.bottom = ClipRegion->rclBounds.bottom;
+       }
+    }
 
-            CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES,
-            CD_ANY, ENUM_RECT_LIMIT);
+  /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
+     nothing to do */
+  if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
+    {
+    IntEngLeave(&EnterLeaveSource);
+    return TRUE;
+    }
 
-            do {
-               EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum),
-               (PVOID) &RectEnum);
+  if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate, &OutputObj))
+    {
+    IntEngLeave(&EnterLeaveSource);
+    return FALSE;
+    }
 
-               if (RectEnum.c > 0)
-               {
-                  RECTL* prclEnd = &RectEnum.arcl[RectEnum.c];
-                  RECTL* prcl    = &RectEnum.arcl[0];
+  OutputRect.left += Translate.x;
+  OutputRect.right += Translate.x;
+  OutputRect.top += Translate.y;
+  OutputRect.bottom += Translate.y;
 
-                  do {
-                     EngIntersectRect(prcl, prcl, DestRect);
+  if(BrushOrigin)
+  {
+    AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
+    AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
+  }
+  else
+    AdjustedBrushOrigin = Translate;
 
-                     ptlTmp.x = SourcePoint->x + prcl->left
-                                - DestRect->left;
-                     ptlTmp.y = SourcePoint->y + prcl->top
-                                - DestRect->top;
+  // Determine clipping type
+  if (ClipRegion == (CLIPOBJ *) NULL)
+  {
+    clippingType = DC_TRIVIAL;
+  } else {
+    clippingType = ClipRegion->iDComplexity;
+  }
 
-                     BitBltCopy(Dest,    Source,
-                                DestGDI, SourceGDI,
-                                prcl, &ptlTmp, Source->lDelta);
+  if (R4_MASK == Rop4)
+    {
+      BltRectFunc = BltMask;
+    }
+  else if (ROP3_TO_ROP4(PATCOPY) == Rop4)
+    {
+      if (Brush->iSolidColor == 0xFFFFFFFF)
+        BltRectFunc = CallDibBitBlt;
+      else
+        BltRectFunc = BltPatCopy;
+    }
+  else
+    {
+      BltRectFunc = CallDibBitBlt;
+    }
 
-                     prcl++;
 
-                  } while (prcl < prclEnd);
-               }
+  switch(clippingType)
+  {
+    case DC_TRIVIAL:
+      Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ColorTranslation,
+                           &OutputRect, &InputPoint, MaskOrigin, Brush, &AdjustedBrushOrigin, Rop4);
+      break;
+    case DC_RECT:
+      // Clip the blt to the clip rectangle
+      ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
+      ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
+      ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
+      ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
+      if (EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
+        {
+          Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
+          Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
+          Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ColorTranslation,
+                               &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin, Rop4);
+        }
+      break;
+    case DC_COMPLEX:
+      Ret = TRUE;
+      if (OutputObj == InputObj)
+       {
+         if (OutputRect.top < InputPoint.y)
+           {
+             Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
+           }
+         else
+           {
+             Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
+           }
+       }
+      else
+       {
+         Direction = CD_ANY;
+       }
+      CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
+      do
+       {
+         EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
 
-            } while(EnumMore);
+         for (i = 0; i < RectEnum.c; i++)
+           {
+             ClipRect.left = RectEnum.arcl[i].left + Translate.x;
+             ClipRect.right = RectEnum.arcl[i].right + Translate.x;
+             ClipRect.top = RectEnum.arcl[i].top + Translate.y;
+             ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
+             if (EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
+                {
+                  Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
+                  Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
+                  Ret = (*BltRectFunc)(OutputObj, InputObj, Mask,
+                                       ColorTranslation, &CombinedRect, &Pt,
+                                       MaskOrigin, Brush, &AdjustedBrushOrigin,
+                                       Rop4) && Ret;
+                }
+           }
+       }
+      while(EnumMore);
+      break;
+  }
 
-            return(TRUE);
-      }
-   }
 
-   return(FALSE);
+  IntEngLeave(&EnterLeaveDest);
+  IntEngLeave(&EnterLeaveSource);
+
+  return Ret;
+}
+
+BOOL STDCALL
+IntEngBitBlt(BITMAPOBJ *DestObj,
+             BITMAPOBJ *SourceObj,
+             BITMAPOBJ *MaskObj,
+             CLIPOBJ *ClipRegion,
+             XLATEOBJ *ColorTranslation,
+             RECTL *DestRect,
+             POINTL *SourcePoint,
+             POINTL *MaskOrigin,
+             BRUSHOBJ *Brush,
+             POINTL *BrushOrigin,
+             ROP4 Rop4)
+{
+  BOOLEAN ret;
+  RECTL InputClippedRect;
+  RECTL OutputRect;
+  POINTL InputPoint;
+  BOOLEAN UsesSource;
+  SURFOBJ *DestSurf;
+  SURFOBJ *SourceSurf = SourceObj ? &SourceObj->SurfObj : NULL;
+  SURFOBJ *MaskSurf = MaskObj ? &MaskObj->SurfObj : NULL;
+
+  ASSERT(DestObj);
+  DestSurf = &DestObj->SurfObj;
+  ASSERT(DestSurf);
+
+  InputClippedRect = *DestRect;
+  if (InputClippedRect.right < InputClippedRect.left)
+    {
+      InputClippedRect.left = DestRect->right;
+      InputClippedRect.right = DestRect->left;
+    }
+  if (InputClippedRect.bottom < InputClippedRect.top)
+    {
+      InputClippedRect.top = DestRect->bottom;
+      InputClippedRect.bottom = DestRect->top;
+    }
+  UsesSource = ROP4_USES_SOURCE(Rop4);
+  if (UsesSource)
+    {
+      if (NULL == SourcePoint || NULL == SourceSurf)
+        {
+          return FALSE;
+        }
+      InputPoint = *SourcePoint;
+
+      /* Make sure we don't try to copy anything outside the valid source region */
+      if (InputPoint.x < 0)
+        {
+          InputClippedRect.left -= InputPoint.x;
+          InputPoint.x = 0;
+        }
+      if (InputPoint.y < 0)
+        {
+          InputClippedRect.top -= InputPoint.y;
+          InputPoint.y = 0;
+        }
+      if (SourceSurf->sizlBitmap.cx < InputPoint.x + InputClippedRect.right - InputClippedRect.left)
+        {
+          InputClippedRect.right = InputClippedRect.left + SourceSurf->sizlBitmap.cx - InputPoint.x;
+        }
+      if (SourceSurf->sizlBitmap.cy < InputPoint.y + InputClippedRect.bottom - InputClippedRect.top)
+        {
+          InputClippedRect.bottom = InputClippedRect.top + SourceSurf->sizlBitmap.cy - InputPoint.y;
+        }
+
+      if (InputClippedRect.right < InputClippedRect.left ||
+          InputClippedRect.bottom < InputClippedRect.top)
+        {
+          /* Everything clipped away, nothing to do */
+          return TRUE;
+        }
+    }
+
+  /* Clip against the bounds of the clipping region so we won't try to write
+   * outside the surface */
+  if (NULL != ClipRegion)
+    {
+      if (! EngIntersectRect(&OutputRect, &InputClippedRect, &ClipRegion->rclBounds))
+       {
+         return TRUE;
+       }
+      InputPoint.x += OutputRect.left - DestRect->left;
+      InputPoint.y += OutputRect.top - DestRect->top;
+    }
+  else
+    {
+      OutputRect = InputClippedRect;
+    }
+
+  if (UsesSource)
+    {
+    MouseSafetyOnDrawStart(SourceSurf, InputPoint.x, InputPoint.y,
+                           (InputPoint.x + abs(DestRect->right - DestRect->left)),
+                          (InputPoint.y + abs(DestRect->bottom - DestRect->top)));
+    }
+
+  /* No success yet */
+  ret = FALSE;
+  MouseSafetyOnDrawStart(DestSurf, OutputRect.left, OutputRect.top,
+                         OutputRect.right, OutputRect.bottom);
+
+  /* Call the driver's DrvBitBlt if available */
+  if (DestObj->flHooks & HOOK_BITBLT)
+    {
+      ret = GDIDEVFUNCS(DestSurf).BitBlt(
+                            DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
+                            &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin,
+                            Rop4);
+    }
+
+  if (! ret)
+    {
+      ret = EngBitBlt(DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
+                      &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin,
+                      Rop4);
+    }
+
+  MouseSafetyOnDrawEnd(DestSurf);
+  if (UsesSource)
+    {
+    MouseSafetyOnDrawEnd(SourceSurf);
+    }
+
+  return ret;
+}
+
+static BOOLEAN STDCALL
+CallDibStretchBlt(SURFOBJ* OutputObj,
+                  SURFOBJ* InputObj,
+                  SURFOBJ* Mask,
+                 CLIPOBJ* ClipRegion,
+                  XLATEOBJ* ColorTranslation,
+                  RECTL* OutputRect,
+                  RECTL* InputRect,
+                  POINTL* MaskOrigin,
+                  POINTL* BrushOrigin,
+                  ULONG Mode)
+{
+  POINTL RealBrushOrigin;
+  if (BrushOrigin == NULL)
+    {
+      RealBrushOrigin.x = RealBrushOrigin.y = 0;
+    }
+  else
+    {
+      RealBrushOrigin = *BrushOrigin;
+    }
+  return DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_StretchBlt(
+    OutputObj, InputObj, OutputRect, InputRect, MaskOrigin, RealBrushOrigin, ClipRegion, ColorTranslation, Mode);
+}
+
+
+BOOL
+STDCALL
+EngStretchBlt(
+       IN SURFOBJ  *DestObj,
+       IN SURFOBJ  *SourceObj,
+       IN SURFOBJ  *Mask,
+       IN CLIPOBJ  *ClipRegion,
+       IN XLATEOBJ  *ColorTranslation,
+       IN COLORADJUSTMENT  *pca,
+       IN POINTL  *BrushOrigin,
+       IN RECTL  *prclDest,
+       IN RECTL  *prclSrc,
+       IN POINTL  *MaskOrigin,
+       IN ULONG  Mode
+       )
+{
+  // www.osr.com/ddk/graphics/gdifncs_0bs7.htm
+
+  POINTL             InputPoint;
+  RECTL              InputRect;
+  RECTL              OutputRect;
+  POINTL             Translate;
+  INTENG_ENTER_LEAVE EnterLeaveSource;
+  INTENG_ENTER_LEAVE EnterLeaveDest;
+  SURFOBJ*           InputObj;
+  SURFOBJ*           OutputObj;
+  PSTRETCHRECTFUNC   BltRectFunc;
+  BOOLEAN            Ret;
+  POINTL             AdjustedBrushOrigin;
+
+  InputRect.left = prclSrc->left;
+  InputRect.right = prclSrc->right;
+  InputRect.top = prclSrc->top;
+  InputRect.bottom = prclSrc->bottom;
+
+  if (! IntEngEnter(&EnterLeaveSource, SourceObj, &InputRect, TRUE, &Translate, &InputObj))
+    {
+      return FALSE;
+    }
+
+  InputPoint.x = InputRect.left + Translate.x;
+  InputPoint.y = InputRect.top + Translate.y;
+
+  OutputRect = *prclDest;
+
+  /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
+     nothing to do */
+  if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
+    {
+      IntEngLeave(&EnterLeaveSource);
+      return TRUE;
+    }
+
+  if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate, &OutputObj))
+    {
+      IntEngLeave(&EnterLeaveSource);
+      return FALSE;
+    }
+
+  OutputRect.left = prclDest->left + Translate.x;
+  OutputRect.right = prclDest->right + Translate.x;
+  OutputRect.top = prclDest->top + Translate.y;
+  OutputRect.bottom = prclDest->bottom + Translate.y;
+
+  if (NULL != BrushOrigin)
+    {
+      AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
+      AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
+    }
+  else
+    {
+      AdjustedBrushOrigin = Translate;
+    }
+
+  if (Mask != NULL)
+    {
+      //BltRectFunc = BltMask;
+      DPRINT("EngStretchBlt isn't capable of handling mask yet.\n");
+      IntEngLeave(&EnterLeaveDest);
+      IntEngLeave(&EnterLeaveSource);
+
+      return FALSE;
+    }
+  else
+    {
+      BltRectFunc = CallDibStretchBlt;
+    }
+
+
+  Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ClipRegion,
+                       ColorTranslation, &OutputRect, &InputRect, MaskOrigin,
+                       &AdjustedBrushOrigin, Mode);
+
+  IntEngLeave(&EnterLeaveDest);
+  IntEngLeave(&EnterLeaveSource);
+
+  return Ret;
+}
+
+BOOL STDCALL
+IntEngStretchBlt(BITMAPOBJ *DestObj,
+                 BITMAPOBJ *SourceObj,
+                 BITMAPOBJ *MaskObj,
+                 CLIPOBJ *ClipRegion,
+                 XLATEOBJ *ColorTranslation,
+                 RECTL *DestRect,
+                 RECTL *SourceRect,
+                 POINTL *pMaskOrigin,
+                 BRUSHOBJ *Brush,
+                 POINTL *BrushOrigin,
+                 ULONG Mode)
+{
+  BOOLEAN ret;
+  COLORADJUSTMENT ca;
+  POINT MaskOrigin;
+  SURFOBJ *DestSurf;
+  SURFOBJ *SourceSurf = SourceObj ? &SourceObj->SurfObj : NULL;
+  SURFOBJ *MaskSurf = MaskObj ? &MaskObj->SurfObj : NULL;
+
+  ASSERT(DestObj);
+  DestSurf = &DestObj->SurfObj;
+  ASSERT(DestSurf);
+
+  if (pMaskOrigin != NULL)
+    {
+      MaskOrigin.x = pMaskOrigin->x; MaskOrigin.y = pMaskOrigin->y;
+    }
+
+  if (NULL != SourceSurf)
+    {
+    ASSERT(SourceRect);
+    MouseSafetyOnDrawStart(SourceSurf, SourceRect->left, SourceRect->top,
+                           SourceRect->right, SourceRect->bottom);
+    }
+
+  /* No success yet */
+  ret = FALSE;
+  ASSERT(DestRect);
+  MouseSafetyOnDrawStart(DestSurf, DestRect->left, DestRect->top,
+                         DestRect->right, DestRect->bottom);
+
+  /* Prepare color adjustment */
+
+  /* Call the driver's DrvStretchBlt if available */
+  if (DestObj->flHooks & HOOK_STRETCHBLT)
+    {
+      /* Drv->StretchBlt (look at http://www.osr.com/ddk/graphics/ddifncs_3ew7.htm )
+      SURFOBJ *psoMask // optional, if it exists, then rop4=0xCCAA, otherwise rop4=0xCCCC */
+      // FIXME: MaskOrigin is always NULL !
+      ret = GDIDEVFUNCS(DestSurf).StretchBlt(
+                            DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
+                            &ca, BrushOrigin, DestRect, SourceRect, NULL, Mode);
+    }
+
+  if (! ret)
+    {
+      // FIXME: see previous fixme
+      ret = EngStretchBlt(DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
+                          &ca, BrushOrigin, DestRect, SourceRect, NULL, Mode);
+    }
+
+  MouseSafetyOnDrawEnd(DestSurf);
+  if (NULL != SourceSurf)
+    {
+    MouseSafetyOnDrawEnd(SourceSurf);
+    }
+
+  return ret;
+}
+
+/**** REACTOS FONT RENDERING CODE *********************************************/
+
+/* renders the alpha mask bitmap */
+static BOOLEAN STDCALL
+AlphaBltMask(SURFOBJ* Dest,
+       SURFOBJ* Source,
+       SURFOBJ* Mask,
+       XLATEOBJ* ColorTranslation,
+       XLATEOBJ* SrcColorTranslation,
+       RECTL* DestRect,
+       POINTL* SourcePoint,
+       POINTL* MaskPoint,
+       BRUSHOBJ* Brush,
+       POINTL* BrushPoint)
+{
+  LONG i, j, dx, dy;
+  int r, g, b;
+  ULONG Background, BrushColor, NewColor;
+  BYTE *tMask, *lMask;
+
+  dx = DestRect->right  - DestRect->left;
+  dy = DestRect->bottom - DestRect->top;
+
+  if (Mask != NULL)
+    {
+      BrushColor = XLATEOBJ_iXlate(SrcColorTranslation, Brush->iSolidColor);
+      r = (int)GetRValue(BrushColor);
+      g = (int)GetGValue(BrushColor);
+      b = (int)GetBValue(BrushColor);
+
+      tMask = Mask->pvScan0 + (SourcePoint->y * Mask->lDelta) + SourcePoint->x;
+      for (j = 0; j < dy; j++)
+        {
+          lMask = tMask;
+          for (i = 0; i < dx; i++)
+            {
+              if (*lMask > 0)
+                {
+                  if (*lMask == 0xff)
+                    {
+                      DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_PutPixel(
+                          Dest, DestRect->left + i, DestRect->top + j, Brush->iSolidColor);
+                    }
+                  else
+                    {
+                      Background = DIB_GetSource(Dest, DestRect->left + i, DestRect->top + j,
+                                                 SrcColorTranslation);
+
+                      NewColor =
+                          RGB((*lMask * (r - GetRValue(Background)) >> 8) + GetRValue(Background),
+                              (*lMask * (g - GetGValue(Background)) >> 8) + GetGValue(Background),
+                              (*lMask * (b - GetBValue(Background)) >> 8) + GetBValue(Background));
+
+                      Background = XLATEOBJ_iXlate(ColorTranslation, NewColor);
+                      DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_PutPixel(
+                        Dest, DestRect->left + i, DestRect->top + j, Background);
+                    }
+                }
+              lMask++;
+            }
+          tMask += Mask->lDelta;
+        }
+      return TRUE;
+    }
+  else
+    {
+      return FALSE;
+    }
+}
+
+BOOL STDCALL
+EngMaskBitBlt(SURFOBJ *DestObj,
+         SURFOBJ *Mask,
+         CLIPOBJ *ClipRegion,
+         XLATEOBJ *DestColorTranslation,
+         XLATEOBJ *SourceColorTranslation,
+         RECTL *DestRect,
+         POINTL *SourcePoint,
+         POINTL *MaskOrigin,
+         BRUSHOBJ *Brush,
+         POINTL *BrushOrigin)
+{
+  BYTE               clippingType;
+  RECTL              CombinedRect;
+  RECT_ENUM          RectEnum;
+  BOOL               EnumMore;
+  POINTL             InputPoint;
+  RECTL              InputRect;
+  RECTL              OutputRect;
+  POINTL             Translate;
+  INTENG_ENTER_LEAVE EnterLeaveSource;
+  INTENG_ENTER_LEAVE EnterLeaveDest;
+  SURFOBJ*           InputObj;
+  SURFOBJ*           OutputObj;
+  BOOLEAN            Ret = TRUE;
+  RECTL              ClipRect;
+  unsigned           i;
+  POINTL             Pt;
+  ULONG              Direction;
+  POINTL             AdjustedBrushOrigin;
+
+  ASSERT ( Mask );
+
+  if (NULL != SourcePoint)
+    {
+    InputRect.left = SourcePoint->x;
+    InputRect.right = SourcePoint->x + (DestRect->right - DestRect->left);
+    InputRect.top = SourcePoint->y;
+    InputRect.bottom = SourcePoint->y + (DestRect->bottom - DestRect->top);
+    }
+  else
+    {
+    InputRect.left = 0;
+    InputRect.right = DestRect->right - DestRect->left;
+    InputRect.top = 0;
+    InputRect.bottom = DestRect->bottom - DestRect->top;
+    }
+
+  if (! IntEngEnter(&EnterLeaveSource, DestObj, &InputRect, TRUE, &Translate, &InputObj))
+    {
+    return FALSE;
+    }
+
+  if (NULL != SourcePoint)
+    {
+    InputPoint.x = SourcePoint->x + Translate.x;
+    InputPoint.y = SourcePoint->y + Translate.y;
+    }
+  else
+    {
+    InputPoint.x = 0;
+    InputPoint.y = 0;
+    }
+
+  OutputRect = *DestRect;
+  if (NULL != ClipRegion)
+    {
+      if (OutputRect.left < ClipRegion->rclBounds.left)
+       {
+         InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
+         InputPoint.x += ClipRegion->rclBounds.left - OutputRect.left;
+         OutputRect.left = ClipRegion->rclBounds.left;
+       }
+      if (ClipRegion->rclBounds.right < OutputRect.right)
+       {
+         InputRect.right -=  OutputRect.right - ClipRegion->rclBounds.right;
+         OutputRect.right = ClipRegion->rclBounds.right;
+       }
+      if (OutputRect.top < ClipRegion->rclBounds.top)
+       {
+         InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
+         InputPoint.y += ClipRegion->rclBounds.top - OutputRect.top;
+         OutputRect.top = ClipRegion->rclBounds.top;
+       }
+      if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
+       {
+         InputRect.bottom -=  OutputRect.bottom - ClipRegion->rclBounds.bottom;
+         OutputRect.bottom = ClipRegion->rclBounds.bottom;
+       }
+    }
+
+  /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
+     nothing to do */
+  if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
+    {
+    IntEngLeave(&EnterLeaveSource);
+    return TRUE;
+    }
+
+  if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate, &OutputObj))
+    {
+    IntEngLeave(&EnterLeaveSource);
+    return FALSE;
+    }
+
+  OutputRect.left = DestRect->left + Translate.x;
+  OutputRect.right = DestRect->right + Translate.x;
+  OutputRect.top = DestRect->top + Translate.y;
+  OutputRect.bottom = DestRect->bottom + Translate.y;
+
+  if(BrushOrigin)
+  {
+    AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
+    AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
+  }
+  else
+    AdjustedBrushOrigin = Translate;
+
+  // Determine clipping type
+  if (ClipRegion == (CLIPOBJ *) NULL)
+  {
+    clippingType = DC_TRIVIAL;
+  } else {
+    clippingType = ClipRegion->iDComplexity;
+  }
+
+  switch(clippingType)
+  {
+    case DC_TRIVIAL:
+      if(Mask->iBitmapFormat == BMF_8BPP)
+        Ret = AlphaBltMask(OutputObj, InputObj, Mask, DestColorTranslation, SourceColorTranslation,
+                           &OutputRect, &InputPoint, MaskOrigin, Brush, &AdjustedBrushOrigin);
+      else
+        Ret = BltMask(OutputObj, InputObj, Mask, DestColorTranslation,
+                           &OutputRect, &InputPoint, MaskOrigin, Brush, &AdjustedBrushOrigin,
+                           R4_MASK);
+      break;
+    case DC_RECT:
+      // Clip the blt to the clip rectangle
+      ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
+      ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
+      ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
+      ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
+      if (EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
+        {
+          Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
+          Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
+          if(Mask->iBitmapFormat == BMF_8BPP)
+            {
+              Ret = AlphaBltMask(OutputObj, InputObj, Mask, DestColorTranslation, SourceColorTranslation,
+                                 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin);
+            }
+          else
+            {
+              Ret = BltMask(OutputObj, InputObj, Mask, DestColorTranslation,
+                            &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin, R4_MASK);
+            }
+        }
+      break;
+    case DC_COMPLEX:
+      Ret = TRUE;
+      if (OutputObj == InputObj)
+       {
+         if (OutputRect.top < InputPoint.y)
+           {
+             Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
+           }
+         else
+           {
+             Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
+           }
+       }
+      else
+       {
+         Direction = CD_ANY;
+       }
+      CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
+      do
+       {
+         EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
+
+         for (i = 0; i < RectEnum.c; i++)
+           {
+             ClipRect.left = RectEnum.arcl[i].left + Translate.x;
+             ClipRect.right = RectEnum.arcl[i].right + Translate.x;
+             ClipRect.top = RectEnum.arcl[i].top + Translate.y;
+             ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
+             if (EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
+                {
+                  Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
+                  Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
+                  if(Mask->iBitmapFormat == BMF_8BPP)
+                    {
+                      Ret = AlphaBltMask(OutputObj, InputObj, Mask,
+                                         DestColorTranslation,
+                                         SourceColorTranslation,
+                                         &CombinedRect, &Pt, MaskOrigin, Brush,
+                                         &AdjustedBrushOrigin) && Ret;
+                    }
+                  else
+                    {
+                      Ret = BltMask(OutputObj, InputObj, Mask,
+                                    DestColorTranslation, &CombinedRect, &Pt,
+                                    MaskOrigin, Brush, &AdjustedBrushOrigin,
+                                    R4_MASK) && Ret;
+                    }
+                }
+           }
+       }
+      while(EnumMore);
+      break;
+  }
+
+
+  IntEngLeave(&EnterLeaveDest);
+  IntEngLeave(&EnterLeaveSource);
+
+  return Ret;
+}
+
+BOOL STDCALL
+IntEngMaskBlt(SURFOBJ *DestObj,
+              SURFOBJ *Mask,
+              CLIPOBJ *ClipRegion,
+              XLATEOBJ *DestColorTranslation,
+              XLATEOBJ *SourceColorTranslation,
+              RECTL *DestRect,
+              POINTL *SourcePoint,
+              POINTL *MaskOrigin,
+              BRUSHOBJ *Brush,
+              POINTL *BrushOrigin)
+{
+  BOOLEAN ret;
+  RECTL OutputRect;
+  POINTL InputPoint;
+
+  ASSERT(Mask);
+
+  if (NULL != SourcePoint)
+    {
+      InputPoint = *SourcePoint;
+    }
+
+  /* Clip against the bounds of the clipping region so we won't try to write
+   * outside the surface */
+  if (NULL != ClipRegion)
+    {
+      if (! EngIntersectRect(&OutputRect, DestRect, &ClipRegion->rclBounds))
+       {
+         return TRUE;
+       }
+      InputPoint.x += OutputRect.left - DestRect->left;
+      InputPoint.y += OutputRect.top - DestRect->top;
+    }
+  else
+    {
+      OutputRect = *DestRect;
+    }
+
+  /* No success yet */
+  ret = FALSE;
+  ASSERT(DestObj);
+  MouseSafetyOnDrawStart(DestObj, OutputRect.left, OutputRect.top,
+                         OutputRect.right, OutputRect.bottom);
+
+  /* Dummy BitBlt to let driver know that it should flush its changes.
+     This should really be done using a call to DrvSynchronizeSurface,
+     but the VMware driver doesn't hook that call. */
+  /* FIXME: Remove the typecast! */
+  IntEngBitBlt((BITMAPOBJ*)DestObj, NULL, (BITMAPOBJ*)Mask, ClipRegion, DestColorTranslation,
+               DestRect, SourcePoint, MaskOrigin, Brush, BrushOrigin, R4_NOOP);
+
+  ret = EngMaskBitBlt(DestObj, Mask, ClipRegion, DestColorTranslation, SourceColorTranslation,
+                      &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin);
+
+  /* Dummy BitBlt to let driver know that something has changed. */
+  /* FIXME: Remove the typecast! */
+  IntEngBitBlt((BITMAPOBJ*)DestObj, NULL, (BITMAPOBJ*)Mask, ClipRegion, DestColorTranslation,
+               DestRect, SourcePoint, MaskOrigin, Brush, BrushOrigin, R4_NOOP);
+
+  MouseSafetyOnDrawEnd(DestObj);
+
+  return ret;
 }
+/* EOF */