Use correct dest rect when preventing copy outside source surf
[reactos.git] / reactos / subsys / win32k / eng / bitblt.c
index a8183cb..dcfb6da 100644 (file)
@@ -16,7 +16,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: bitblt.c,v 1.36 2003/12/26 00:31:22 weiden Exp $
+/* $Id$
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
  * REVISION HISTORY:
  *        2/10/1999: Created
  */
-
-#include <ddk/winddi.h>
-#include <ddk/ntddk.h>
-#include <ddk/ntddmou.h>
-#include <ntos/minmax.h>
-#include "brush.h"
-#include "clip.h"
-#include "objects.h"
-#include "../dib/dib.h"
-#include "misc.h"
-#include <include/mouse.h>
-#include <include/object.h>
-#include <include/dib.h>
-#include <include/surface.h>
-#include <include/inteng.h>
-
-//#define NDEBUG
-#include <win32k/debug1.h>
+#include <w32k.h>
 
 typedef BOOLEAN STDCALL (*PBLTRECTFUNC)(SURFOBJ* OutputObj,
-                                        SURFGDI* OutputGDI,
                                         SURFOBJ* InputObj,
-                                        SURFGDI* InputGDI,
                                         SURFOBJ* Mask,
                                         XLATEOBJ* ColorTranslation,
                                         RECTL* OutputRect,
@@ -58,10 +39,9 @@ typedef BOOLEAN STDCALL (*PBLTRECTFUNC)(SURFOBJ* OutputObj,
                                         POINTL* BrushOrigin,
                                         ROP4 Rop4);
 typedef BOOLEAN STDCALL (*PSTRETCHRECTFUNC)(SURFOBJ* OutputObj,
-                                            SURFGDI* OutputGDI,
                                             SURFOBJ* InputObj,
-                                            SURFGDI* InputGDI,
                                             SURFOBJ* Mask,
+                                            CLIPOBJ* ClipRegion,
                                             XLATEOBJ* ColorTranslation,
                                             RECTL* OutputRect,
                                             RECTL* InputRect,
@@ -94,10 +74,8 @@ BOOL STDCALL EngIntersectRect(RECTL* prcDst, RECTL* prcSrc1, RECTL* prcSrc2)
 
 static BOOLEAN STDCALL
 BltMask(SURFOBJ* Dest,
-       SURFGDI* DestGDI,
        SURFOBJ* Source,
-       SURFGDI* SourceGDI,
-       SURFOBJ* Mask, 
+       SURFOBJ* Mask,
        XLATEOBJ* ColorTranslation,
        RECTL* DestRect,
        POINTL* SourcePoint,
@@ -106,49 +84,86 @@ BltMask(SURFOBJ* Dest,
        POINTL* BrushPoint,
        ROP4 Rop4)
 {
-  LONG i, j, dx, dy, c8;
-  BYTE *tMask, *lMask;
-  static BYTE maskbit[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
-  
-  dx = DestRect->right  - DestRect->left;
-  dy = DestRect->bottom - DestRect->top;
-
-  if (Mask != NULL)
-    {
-      tMask = Mask->pvBits + SourcePoint->y * Mask->lDelta + (SourcePoint->x >> 3);
-      for (j = 0; j < dy; j++)
-       {
-         lMask = tMask;
-         c8 = SourcePoint->x & 0x07;
-         for (i = 0; i < dx; i++)
-           {
-             if (0 != (*lMask & maskbit[c8]))
-               {
-                 DestGDI->DIB_PutPixel(Dest, DestRect->left + i, DestRect->top + j, Brush->iSolidColor);
-               }
-             c8++;
-             if (8 == c8)
-               {
-                 lMask++;
-                 c8=0;
-               }
-           }
-         tMask += Mask->lDelta;
-       }
-      return TRUE;
-    }
-  else
-    {
-    return FALSE;
-    }
+   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)
+   {
+      return FALSE;
+   }
+
+   dx = DestRect->right  - DestRect->left;
+   dy = DestRect->bottom - DestRect->top;
+
+   if (Brush->iSolidColor == 0xFFFFFFFF)
+   {
+      GdiBrush = CONTAINING_RECORD(
+         Brush,
+         GDIBRUSHINST,
+         BrushObject);
+
+      PatternBitmap = BITMAPOBJ_LockBitmap(GdiBrush->GdiBrushObject->hbmPattern);
+      if(PatternBitmap != NULL)
+      {
+        PatternObj = &PatternBitmap->SurfObj;
+        PatternWidth = PatternObj->sizlBitmap.cx;
+        PatternHeight = PatternObj->sizlBitmap.cy;
+      }
+   }
+   else
+     PatternBitmap = NULL;
+
+   tMask = Mask->pvScan0 + SourcePoint->y * Mask->lDelta + (SourcePoint->x >> 3);
+   for (j = 0; j < dy; j++)
+   {
+      lMask = tMask;
+      c8 = SourcePoint->x & 0x07;
+
+      if(PatternBitmap != NULL)
+         PatternY = (DestRect->top + j) % PatternHeight;
+
+      for (i = 0; i < dx; i++)
+      {
+         if (0 != (*lMask & maskbit[c8]))
+         {
+            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));
+            }
+         }
+         c8++;
+         if (8 == c8)
+         {
+            lMask++;
+            c8 = 0;
+         }
+      }
+      tMask += Mask->lDelta;
+   }
+
+   if (PatternBitmap != NULL)
+      BITMAPOBJ_UnlockBitmap(PatternBitmap);
+
+   return TRUE;
 }
 
 static BOOLEAN STDCALL
 BltPatCopy(SURFOBJ* Dest,
-          SURFGDI* DestGDI,
           SURFOBJ* Source,
-          SURFGDI* SourceGDI,
-          SURFOBJ* Mask, 
+          SURFOBJ* Mask,
           XLATEOBJ* ColorTranslation,
           RECTL* DestRect,
           POINTL* SourcePoint,
@@ -159,23 +174,15 @@ BltPatCopy(SURFOBJ* Dest,
 {
   // These functions are assigned if we're working with a DIB
   // The assigned functions depend on the bitsPerPixel of the DIB
-  LONG y;
-  ULONG LineWidth;
 
-  LineWidth  = DestRect->right - DestRect->left;
-  for (y = DestRect->top; y < DestRect->bottom; y++)
-  {
-    DestGDI->DIB_HLine(Dest, DestRect->left, DestRect->right, y,  Brush->iSolidColor);
-  }
+  DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_ColorFill(Dest, DestRect, Brush->iSolidColor);
 
   return TRUE;
 }
 
 static BOOLEAN STDCALL
 CallDibBitBlt(SURFOBJ* OutputObj,
-              SURFGDI* OutputGDI,
               SURFOBJ* InputObj,
-              SURFGDI* InputGDI,
               SURFOBJ* Mask,
               XLATEOBJ* ColorTranslation,
               RECTL* OutputRect,
@@ -185,7 +192,54 @@ CallDibBitBlt(SURFOBJ* OutputObj,
               POINTL* BrushOrigin,
               ROP4 Rop4)
 {
-  return OutputGDI->DIB_BitBlt(OutputObj, InputObj, OutputGDI, InputGDI, OutputRect, InputPoint, Brush, BrushOrigin, ColorTranslation, Rop4);
+   BLTINFO BltInfo;
+   PGDIBRUSHINST GdiBrush = NULL;
+   BITMAPOBJ *bmPattern;
+   BOOLEAN Result;
+
+   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);
+
+   BltInfo.XlatePatternToDest = NULL;
+   BltInfo.Brush = Brush;
+   BltInfo.BrushOrigin = *BrushOrigin;
+   BltInfo.Rop4 = Rop4;
+
+   /* Pattern brush */
+   if (ROP4_USES_PATTERN(Rop4) && Brush->iSolidColor == 0xFFFFFFFF)
+   {
+      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;
+   }
+
+   Result = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_BitBlt(&BltInfo);
+
+   /* Pattern brush */
+   if (bmPattern != NULL)
+   {
+      BITMAPOBJ_UnlockBitmap(bmPattern);
+   }
+
+   return Result;
 }
 
 INT abs(INT nm);
@@ -210,8 +264,6 @@ EngBitBlt(SURFOBJ *DestObj,
   RECTL              CombinedRect;
   RECT_ENUM          RectEnum;
   BOOL               EnumMore;
-  SURFGDI*           OutputGDI;
-  SURFGDI*           InputGDI;
   POINTL             InputPoint;
   RECTL              InputRect;
   RECTL              OutputRect;
@@ -221,13 +273,24 @@ EngBitBlt(SURFOBJ *DestObj,
   SURFOBJ*           InputObj;
   SURFOBJ*           OutputObj;
   PBLTRECTFUNC       BltRectFunc;
-  BOOLEAN            Ret;
+  BOOLEAN            Ret = TRUE;
   RECTL              ClipRect;
   unsigned           i;
   POINTL             Pt;
   ULONG              Direction;
+  BOOL               UsesSource;
+  BOOL               UsesPattern;
+  POINTL             AdjustedBrushOrigin;
 
-  if (NULL != SourcePoint)
+  UsesSource = ROP4_USES_SOURCE(Rop4);
+  UsesPattern = ROP4_USES_PATTERN(Rop4);
+  if (R4_NOOP == Rop4)
+    {
+    /* Copy destination onto itself: nop */
+    return TRUE;
+    }
+
+  if (UsesSource && NULL != SourcePoint)
     {
     InputRect.left = SourcePoint->x;
     InputRect.right = SourcePoint->x + (DestRect->right - DestRect->left);
@@ -258,15 +321,6 @@ EngBitBlt(SURFOBJ *DestObj,
     InputPoint.y = 0;
     }
 
-  if (NULL != InputObj)
-    {
-    InputGDI = (SURFGDI*) AccessInternalObjectFromUserObject(InputObj);
-    }
-  else
-    {
-      InputGDI = NULL;
-    }
-
   OutputRect = *DestRect;
   if (NULL != ClipRegion)
     {
@@ -308,15 +362,18 @@ EngBitBlt(SURFOBJ *DestObj,
     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;
+  OutputRect.left += Translate.x;
+  OutputRect.right += Translate.x;
+  OutputRect.top += Translate.y;
+  OutputRect.bottom += Translate.y;
 
-  if (NULL != OutputObj)
-    {
-    OutputGDI = (SURFGDI*)AccessInternalObjectFromUserObject(OutputObj);
-    }
+  if(BrushOrigin)
+  {
+    AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
+    AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
+  }
+  else
+    AdjustedBrushOrigin = Translate;
 
   // Determine clipping type
   if (ClipRegion == (CLIPOBJ *) NULL)
@@ -326,13 +383,16 @@ EngBitBlt(SURFOBJ *DestObj,
     clippingType = ClipRegion->iDComplexity;
   }
 
-  if (0xaacc == Rop4)
+  if (R4_MASK == Rop4)
     {
       BltRectFunc = BltMask;
     }
-  else if (PATCOPY == Rop4)
+  else if (ROP3_TO_ROP4(PATCOPY) == Rop4)
     {
-      BltRectFunc = BltPatCopy;
+      if (Brush->iSolidColor == 0xFFFFFFFF)
+        BltRectFunc = CallDibBitBlt;
+      else
+        BltRectFunc = BltPatCopy;
     }
   else
     {
@@ -343,8 +403,8 @@ EngBitBlt(SURFOBJ *DestObj,
   switch(clippingType)
   {
     case DC_TRIVIAL:
-      Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
-                           &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin, Rop4);
+      Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ColorTranslation,
+                           &OutputRect, &InputPoint, MaskOrigin, Brush, &AdjustedBrushOrigin, Rop4);
       break;
     case DC_RECT:
       // Clip the blt to the clip rectangle
@@ -352,11 +412,13 @@ EngBitBlt(SURFOBJ *DestObj,
       ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
       ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
       ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
-      EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
-      Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
-      Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
-      Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
-                           &CombinedRect, &Pt, MaskOrigin, Brush, BrushOrigin, Rop4);
+      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;
@@ -375,7 +437,7 @@ EngBitBlt(SURFOBJ *DestObj,
        {
          Direction = CD_ANY;
        }
-      CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, ENUM_RECT_LIMIT);
+      CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
       do
        {
          EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
@@ -386,12 +448,15 @@ EngBitBlt(SURFOBJ *DestObj,
              ClipRect.right = RectEnum.arcl[i].right + Translate.x;
              ClipRect.top = RectEnum.arcl[i].top + Translate.y;
              ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
-             EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
-             Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
-             Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
-             Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
-                                  &CombinedRect, &Pt, MaskOrigin, Brush, BrushOrigin, Rop4) &&
-                   Ret;
+             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);
@@ -406,9 +471,9 @@ EngBitBlt(SURFOBJ *DestObj,
 }
 
 BOOL STDCALL
-IntEngBitBlt(SURFOBJ *DestObj,
-             SURFOBJ *SourceObj,
-             SURFOBJ *Mask,
+IntEngBitBlt(BITMAPOBJ *DestObj,
+             BITMAPOBJ *SourceObj,
+             BITMAPOBJ *MaskObj,
              CLIPOBJ *ClipRegion,
              XLATEOBJ *ColorTranslation,
              RECTL *DestRect,
@@ -419,65 +484,114 @@ IntEngBitBlt(SURFOBJ *DestObj,
              ROP4 Rop4)
 {
   BOOLEAN ret;
-  SURFGDI *DestGDI;
-  SURFGDI *SourceGDI;
+  RECTL InputClippedRect;
   RECTL OutputRect;
   POINTL InputPoint;
+  BOOLEAN UsesSource;
+  SURFOBJ *DestSurf;
+  SURFOBJ *SourceSurf = SourceObj ? &SourceObj->SurfObj : NULL;
+  SURFOBJ *MaskSurf = MaskObj ? &MaskObj->SurfObj : NULL;
 
-  if (NULL != SourcePoint)
+  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, DestRect, &ClipRegion->rclBounds))
+      if (! EngIntersectRect(&OutputRect, &InputClippedRect, &ClipRegion->rclBounds))
        {
          return TRUE;
        }
-      InputPoint.x += OutputRect.left - DestRect->left;
-      InputPoint.y += OutputRect.top - DestRect->top;
+      InputPoint.x += OutputRect.left - InputClippedRect.left;
+      InputPoint.y += OutputRect.top - InputClippedRect.top;
     }
   else
     {
-      OutputRect = *DestRect;
+      OutputRect = InputClippedRect;
     }
 
-  if (NULL != SourceObj)
+  if (UsesSource)
     {
-    SourceGDI = (SURFGDI*) AccessInternalObjectFromUserObject(SourceObj);
-    MouseSafetyOnDrawStart(SourceObj, SourceGDI, InputPoint.x, InputPoint.y,
+    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;
-  DestGDI = (SURFGDI*)AccessInternalObjectFromUserObject(DestObj);
-  MouseSafetyOnDrawStart(DestObj, DestGDI, OutputRect.left, OutputRect.top,
+  MouseSafetyOnDrawStart(DestSurf, OutputRect.left, OutputRect.top,
                          OutputRect.right, OutputRect.bottom);
 
   /* Call the driver's DrvBitBlt if available */
-  if (NULL != DestGDI->BitBlt)
+  if (DestObj->flHooks & HOOK_BITBLT)
     {
-      ret = DestGDI->BitBlt(DestObj, SourceObj, Mask, ClipRegion, ColorTranslation,
+      ret = GDIDEVFUNCS(DestSurf).BitBlt(
+                            DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
                             &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin,
                             Rop4);
     }
 
   if (! ret)
     {
-      ret = EngBitBlt(DestObj, SourceObj, Mask, ClipRegion, ColorTranslation,
+      ret = EngBitBlt(DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
                       &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin,
                       Rop4);
     }
 
-  MouseSafetyOnDrawEnd(DestObj, DestGDI);
-  if (NULL != SourceObj)
+  MouseSafetyOnDrawEnd(DestSurf);
+  if (UsesSource)
     {
-    MouseSafetyOnDrawEnd(SourceObj, SourceGDI);
+    MouseSafetyOnDrawEnd(SourceSurf);
     }
 
   return ret;
@@ -485,10 +599,9 @@ IntEngBitBlt(SURFOBJ *DestObj,
 
 static BOOLEAN STDCALL
 CallDibStretchBlt(SURFOBJ* OutputObj,
-                  SURFGDI* OutputGDI,
                   SURFOBJ* InputObj,
-                  SURFGDI* InputGDI,
                   SURFOBJ* Mask,
+                 CLIPOBJ* ClipRegion,
                   XLATEOBJ* ColorTranslation,
                   RECTL* OutputRect,
                   RECTL* InputRect,
@@ -496,7 +609,17 @@ CallDibStretchBlt(SURFOBJ* OutputObj,
                   POINTL* BrushOrigin,
                   ULONG Mode)
 {
-  return OutputGDI->DIB_StretchBlt(OutputObj, InputObj, OutputGDI, InputGDI, OutputRect, InputRect, MaskOrigin, BrushOrigin, ColorTranslation, 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);
 }
 
 
@@ -517,13 +640,7 @@ EngStretchBlt(
        )
 {
   // www.osr.com/ddk/graphics/gdifncs_0bs7.htm
-  
-  BYTE               clippingType;
-  RECTL              CombinedRect;
-//  RECT_ENUM          RectEnum;
-//  BOOL               EnumMore;
-  SURFGDI*           OutputGDI;
-  SURFGDI*           InputGDI;
+
   POINTL             InputPoint;
   RECTL              InputRect;
   RECTL              OutputRect;
@@ -532,74 +649,37 @@ EngStretchBlt(
   INTENG_ENTER_LEAVE EnterLeaveDest;
   SURFOBJ*           InputObj;
   SURFOBJ*           OutputObj;
-  PSTRETCHRECTFUNC       BltRectFunc;
+  PSTRETCHRECTFUNC   BltRectFunc;
   BOOLEAN            Ret;
-  RECTL              ClipRect;
-//  unsigned           i;
-  POINTL             Pt;
-//  ULONG              Direction;
+  POINTL             AdjustedBrushOrigin;
 
-    InputRect.left = prclSrc->left;
-    InputRect.right = prclSrc->right;
-    InputRect.top = prclSrc->top;
-    InputRect.bottom = prclSrc->bottom;
+  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;
+      return FALSE;
     }
 
-   InputPoint.x = InputRect.left + Translate.x;
-   InputPoint.y = InputRect.top + Translate.y;
-  if (NULL != InputObj)
-    {
-    InputGDI = (SURFGDI*) AccessInternalObjectFromUserObject(InputObj);
-    }
-  else
-    {
-      InputGDI = NULL;
-    }
+  InputPoint.x = InputRect.left + Translate.x;
+  InputPoint.y = InputRect.top + Translate.y;
 
   OutputRect = *prclDest;
-  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;
+      IntEngLeave(&EnterLeaveSource);
+      return TRUE;
     }
 
   if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate, &OutputObj))
     {
-    IntEngLeave(&EnterLeaveSource);
-    return FALSE;
+      IntEngLeave(&EnterLeaveSource);
+      return FALSE;
     }
 
   OutputRect.left = prclDest->left + Translate.x;
@@ -607,27 +687,24 @@ EngStretchBlt(
   OutputRect.top = prclDest->top + Translate.y;
   OutputRect.bottom = prclDest->bottom + Translate.y;
 
-  if (NULL != OutputObj)
+  if (NULL != BrushOrigin)
     {
-    OutputGDI = (SURFGDI*)AccessInternalObjectFromUserObject(OutputObj);
+      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;
-  }
-
-  if (Mask != NULL)//(0xaacc == Rop4)
+  if (Mask != NULL)
     {
       //BltRectFunc = BltMask;
       DPRINT("EngStretchBlt isn't capable of handling mask yet.\n");
       IntEngLeave(&EnterLeaveDest);
       IntEngLeave(&EnterLeaveSource);
-      
-      return FALSE;      
+
+      return FALSE;
     }
   else
     {
@@ -635,70 +712,9 @@ EngStretchBlt(
     }
 
 
-  switch(clippingType)
-  {
-    case DC_TRIVIAL:
-      Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
-                          &OutputRect, &InputRect, MaskOrigin, BrushOrigin, Mode);
-      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;
-      EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
-      Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
-      Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
-      Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
-                           &OutputRect, &InputRect, MaskOrigin, BrushOrigin, Mode);
-      //Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
-      //                     &CombinedRect, &Pt, MaskOrigin, Brush, BrushOrigin, Rop4);
-      DPRINT("EngStretchBlt() doesn't support DC_RECT clipping yet, so blitting w/o clip.\n");
-      break;
-      // TODO: Complex clipping
-    /*
-    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, ENUM_RECT_LIMIT);
-      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;
-             EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
-             Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
-             Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
-             Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
-                                  &CombinedRect, &Pt, MaskOrigin, Brush, BrushOrigin, Rop4) &&
-                   Ret;
-           }
-       }
-      while(EnumMore);
-      break;
-      */
-  }
-
+  Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ClipRegion,
+                       ColorTranslation, &OutputRect, &InputRect, MaskOrigin,
+                       &AdjustedBrushOrigin, Mode);
 
   IntEngLeave(&EnterLeaveDest);
   IntEngLeave(&EnterLeaveSource);
@@ -707,92 +723,71 @@ EngStretchBlt(
 }
 
 BOOL STDCALL
-IntEngStretchBlt(SURFOBJ *DestObj,
-             SURFOBJ *SourceObj,
-             SURFOBJ *Mask,
-             CLIPOBJ *ClipRegion,
-             XLATEOBJ *ColorTranslation,
-             RECTL *DestRect,
-             RECTL *SourceRect,
-             POINTL *pMaskOrigin,
-             BRUSHOBJ *Brush,
-             POINTL *BrushOrigin,
-             ULONG Mode)
+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;
-  SURFGDI *DestGDI;
-  SURFGDI *SourceGDI;
-  RECTL OutputRect;
-  RECTL InputRect;
   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 != SourceRect)
+  if (NULL != SourceSurf)
     {
-      InputRect = *SourceRect;
-    }
-
-  // FIXME: Clipping is taken from IntEngBitBlt w/o modifications!
-  
-  /* 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;
-       }
-         DPRINT("Clipping isn't handled in IntEngStretchBlt() correctly yet\n");
-      //InputPoint.x += OutputRect.left - DestRect->left;
-      //InputPoint.y += OutputRect.top - DestRect->top;
-    }
-  else
-    {
-      OutputRect = *DestRect;
-    }
-
-  if (NULL != SourceObj)
-    {
-    SourceGDI = (SURFGDI*) AccessInternalObjectFromUserObject(SourceObj);
-    MouseSafetyOnDrawStart(SourceObj, SourceGDI, InputRect.left, InputRect.top,
-                           (InputRect.left + abs(InputRect.right - InputRect.left)),
-                          (InputRect.top + abs(InputRect.bottom - InputRect.top)));
+    ASSERT(SourceRect);
+    MouseSafetyOnDrawStart(SourceSurf, SourceRect->left, SourceRect->top,
+                           SourceRect->right, SourceRect->bottom);
     }
 
   /* No success yet */
   ret = FALSE;
-  DestGDI = (SURFGDI*)AccessInternalObjectFromUserObject(DestObj);
-  MouseSafetyOnDrawStart(DestObj, DestGDI, OutputRect.left, OutputRect.top,
-                         OutputRect.right, OutputRect.bottom);
+  ASSERT(DestRect);
+  MouseSafetyOnDrawStart(DestSurf, DestRect->left, DestRect->top,
+                         DestRect->right, DestRect->bottom);
 
   /* Prepare color adjustment */
 
   /* Call the driver's DrvStretchBlt if available */
-  if (NULL != DestGDI->StretchBlt)
+  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 = DestGDI->StretchBlt(DestObj, SourceObj, Mask, ClipRegion, ColorTranslation,
-                            &ca, BrushOrigin, &OutputRect, &InputRect, NULL, Mode);
+      ret = GDIDEVFUNCS(DestSurf).StretchBlt(
+                            DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
+                            &ca, BrushOrigin, DestRect, SourceRect, NULL, Mode);
     }
 
   if (! ret)
     {
       // FIXME: see previous fixme
-      ret = EngStretchBlt(DestObj, SourceObj, Mask, ClipRegion, ColorTranslation,
-                          &ca, BrushOrigin, &OutputRect, &InputRect, NULL, Mode);
+      ret = EngStretchBlt(DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
+                          &ca, BrushOrigin, DestRect, SourceRect, NULL, Mode);
     }
 
-  MouseSafetyOnDrawEnd(DestObj, DestGDI);
-  if (NULL != SourceObj)
+  MouseSafetyOnDrawEnd(DestSurf);
+  if (NULL != SourceSurf)
     {
-    MouseSafetyOnDrawEnd(SourceObj, SourceGDI);
+    MouseSafetyOnDrawEnd(SourceSurf);
     }
 
   return ret;
@@ -803,10 +798,8 @@ IntEngStretchBlt(SURFOBJ *DestObj,
 /* renders the alpha mask bitmap */
 static BOOLEAN STDCALL
 AlphaBltMask(SURFOBJ* Dest,
-       SURFGDI* DestGDI,
        SURFOBJ* Source,
-       SURFGDI* SourceGDI,
-       SURFOBJ* Mask, 
+       SURFOBJ* Mask,
        XLATEOBJ* ColorTranslation,
        XLATEOBJ* SrcColorTranslation,
        RECTL* DestRect,
@@ -829,41 +822,44 @@ AlphaBltMask(SURFOBJ* Dest,
       r = (int)GetRValue(BrushColor);
       g = (int)GetGValue(BrushColor);
       b = (int)GetBValue(BrushColor);
-      
-      tMask = Mask->pvBits + MaskPoint->y * Mask->lDelta + MaskPoint->x;
+
+      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)
-                       {
-                               DestGDI->DIB_PutPixel(Dest, DestRect->left + i, DestRect->top + j, Brush->iSolidColor);
-                       }
-                       else
-                       {
-                               Background = DIB_GetSource(Dest, DestGDI, 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);
-                               DestGDI->DIB_PutPixel(Dest, DestRect->left + i, DestRect->top + j, Background);
-                       }
-               }
-                 lMask++;
-           }
-         tMask += Mask->lDelta;
-       }
+        {
+          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;
+      return FALSE;
     }
 }
 
@@ -883,8 +879,6 @@ EngMaskBitBlt(SURFOBJ *DestObj,
   RECTL              CombinedRect;
   RECT_ENUM          RectEnum;
   BOOL               EnumMore;
-  SURFGDI*           OutputGDI;
-  SURFGDI*           InputGDI;
   POINTL             InputPoint;
   RECTL              InputRect;
   RECTL              OutputRect;
@@ -893,11 +887,14 @@ EngMaskBitBlt(SURFOBJ *DestObj,
   INTENG_ENTER_LEAVE EnterLeaveDest;
   SURFOBJ*           InputObj;
   SURFOBJ*           OutputObj;
-  BOOLEAN            Ret;
+  BOOLEAN            Ret = TRUE;
   RECTL              ClipRect;
   unsigned           i;
   POINTL             Pt;
   ULONG              Direction;
+  POINTL             AdjustedBrushOrigin;
+
+  ASSERT ( Mask );
 
   if (NULL != SourcePoint)
     {
@@ -914,7 +911,7 @@ EngMaskBitBlt(SURFOBJ *DestObj,
     InputRect.bottom = DestRect->bottom - DestRect->top;
     }
 
-  if (! IntEngEnter(&EnterLeaveSource, NULL, &InputRect, TRUE, &Translate, &InputObj))
+  if (! IntEngEnter(&EnterLeaveSource, DestObj, &InputRect, TRUE, &Translate, &InputObj))
     {
     return FALSE;
     }
@@ -930,15 +927,6 @@ EngMaskBitBlt(SURFOBJ *DestObj,
     InputPoint.y = 0;
     }
 
-  if (NULL != InputObj)
-    {
-    InputGDI = (SURFGDI*) AccessInternalObjectFromUserObject(InputObj);
-    }
-  else
-    {
-      InputGDI = NULL;
-    }
-
   OutputRect = *DestRect;
   if (NULL != ClipRegion)
     {
@@ -985,10 +973,13 @@ EngMaskBitBlt(SURFOBJ *DestObj,
   OutputRect.top = DestRect->top + Translate.y;
   OutputRect.bottom = DestRect->bottom + Translate.y;
 
-  if (NULL != OutputObj)
-    {
-    OutputGDI = (SURFGDI*)AccessInternalObjectFromUserObject(OutputObj);
-    }
+  if(BrushOrigin)
+  {
+    AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
+    AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
+  }
+  else
+    AdjustedBrushOrigin = Translate;
 
   // Determine clipping type
   if (ClipRegion == (CLIPOBJ *) NULL)
@@ -1002,11 +993,12 @@ EngMaskBitBlt(SURFOBJ *DestObj,
   {
     case DC_TRIVIAL:
       if(Mask->iBitmapFormat == BMF_8BPP)
-        Ret = AlphaBltMask(OutputObj, OutputGDI, InputObj, InputGDI, Mask, DestColorTranslation, SourceColorTranslation,
-                           &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin);
+        Ret = AlphaBltMask(OutputObj, InputObj, Mask, DestColorTranslation, SourceColorTranslation,
+                           &OutputRect, &InputPoint, MaskOrigin, Brush, &AdjustedBrushOrigin);
       else
-        Ret = BltMask(OutputObj, OutputGDI, InputObj, InputGDI, Mask, DestColorTranslation,
-                           &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin, 0xAACC);
+        Ret = BltMask(OutputObj, InputObj, Mask, DestColorTranslation,
+                           &OutputRect, &InputPoint, MaskOrigin, Brush, &AdjustedBrushOrigin,
+                           R4_MASK);
       break;
     case DC_RECT:
       // Clip the blt to the clip rectangle
@@ -1014,15 +1006,21 @@ EngMaskBitBlt(SURFOBJ *DestObj,
       ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
       ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
       ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
-      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, OutputGDI, InputObj, InputGDI, Mask, DestColorTranslation, SourceColorTranslation,
-                           &CombinedRect, &Pt, MaskOrigin, Brush, BrushOrigin);
-      else
-        Ret = BltMask(OutputObj, OutputGDI, InputObj, InputGDI, Mask, DestColorTranslation,
-                           &CombinedRect, &Pt, MaskOrigin, Brush, BrushOrigin, 0xAACC);
+      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;
@@ -1041,7 +1039,7 @@ EngMaskBitBlt(SURFOBJ *DestObj,
        {
          Direction = CD_ANY;
        }
-      CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, ENUM_RECT_LIMIT);
+      CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
       do
        {
          EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
@@ -1052,15 +1050,26 @@ EngMaskBitBlt(SURFOBJ *DestObj,
              ClipRect.right = RectEnum.arcl[i].right + Translate.x;
              ClipRect.top = RectEnum.arcl[i].top + Translate.y;
              ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
-             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, OutputGDI, InputObj, InputGDI, Mask, DestColorTranslation, SourceColorTranslation,
-                                  &CombinedRect, &Pt, MaskOrigin, Brush, BrushOrigin) && Ret;
-              else
-                Ret = BltMask(OutputObj, OutputGDI, InputObj, InputGDI, Mask, DestColorTranslation,
-                                   &CombinedRect, &Pt, MaskOrigin, Brush, BrushOrigin, 0xAACC) && Ret;
+             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);
@@ -1076,21 +1085,22 @@ EngMaskBitBlt(SURFOBJ *DestObj,
 
 BOOL STDCALL
 IntEngMaskBlt(SURFOBJ *DestObj,
-             SURFOBJ *Mask,
-             CLIPOBJ *ClipRegion,
-             XLATEOBJ *DestColorTranslation,
-             XLATEOBJ *SourceColorTranslation,
-             RECTL *DestRect,
-             POINTL *SourcePoint,
-             POINTL *MaskOrigin,
-             BRUSHOBJ *Brush,
-             POINTL *BrushOrigin)
+              SURFOBJ *Mask,
+              CLIPOBJ *ClipRegion,
+              XLATEOBJ *DestColorTranslation,
+              XLATEOBJ *SourceColorTranslation,
+              RECTL *DestRect,
+              POINTL *SourcePoint,
+              POINTL *MaskOrigin,
+              BRUSHOBJ *Brush,
+              POINTL *BrushOrigin)
 {
   BOOLEAN ret;
-  SURFGDI *DestGDI;
   RECTL OutputRect;
   POINTL InputPoint;
 
+  ASSERT(Mask);
+
   if (NULL != SourcePoint)
     {
       InputPoint = *SourcePoint;
@@ -1114,14 +1124,26 @@ IntEngMaskBlt(SURFOBJ *DestObj,
 
   /* No success yet */
   ret = FALSE;
-  DestGDI = (SURFGDI*)AccessInternalObjectFromUserObject(DestObj);
-  MouseSafetyOnDrawStart(DestObj, DestGDI, OutputRect.left, OutputRect.top,
+  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);
 
-  MouseSafetyOnDrawEnd(DestObj, DestGDI);
+  /* 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;
 }