update for HEAD-2003091401
[reactos.git] / subsys / win32k / eng / bitblt.c
index 53f8046..16a1074 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
@@ -10,6 +29,7 @@
 
 #include <ddk/winddi.h>
 #include <ddk/ntddk.h>
+#include <ddk/ntddmou.h>
 #include <ntos/minmax.h>
 #include "brush.h"
 #include "clip.h"
 #include <include/copybits.h>
 #include <include/inteng.h>
 
-#define NDEBUG
+//#define NDEBUG
 #include <win32k/debug1.h>
 
-BOOL EngIntersectRect(PRECTL prcDst, PRECTL prcSrc1, PRECTL prcSrc2)
+typedef BOOLEAN STDCALL (*PBLTRECTFUNC)(PSURFOBJ OutputObj,
+                                        PSURFGDI OutputGDI,
+                                        PSURFOBJ InputObj,
+                                        PSURFGDI InputGDI,
+                                        PSURFOBJ Mask,
+                                        PXLATEOBJ ColorTranslation,
+                                        PRECTL OutputRect,
+                                        PPOINTL InputPoint,
+                                        PPOINTL MaskOrigin,
+                                        PBRUSHOBJ Brush,
+                                        PPOINTL BrushOrigin,
+                                        ROP4 Rop4);
+
+BOOL STDCALL EngIntersectRect(PRECTL prcDst, PRECTL prcSrc1, PRECTL prcSrc2)
 {
   static const RECTL rclEmpty = { 0, 0, 0, 0 };
 
@@ -34,22 +67,34 @@ BOOL EngIntersectRect(PRECTL prcDst, PRECTL prcSrc1, PRECTL prcSrc2)
   prcDst->right = min(prcSrc1->right, prcSrc2->right);
 
   if (prcDst->left < prcDst->right)
-  {
-    prcDst->top    = max(prcSrc1->top, prcSrc2->top);
-    prcDst->bottom = min(prcSrc1->bottom, prcSrc2->bottom);
+    {
+      prcDst->top    = max(prcSrc1->top, prcSrc2->top);
+      prcDst->bottom = min(prcSrc1->bottom, prcSrc2->bottom);
 
-    if (prcDst->top < prcDst->bottom) return(TRUE);
-  }
+      if (prcDst->top < prcDst->bottom)
+       {
+         return TRUE;
+       }
+    }
 
   *prcDst = rclEmpty;
 
-  return(FALSE);
+  return FALSE;
 }
 
-static BOOL STDCALL
-BltMask(SURFOBJ *Dest, PSURFGDI DestGDI, SURFOBJ *Mask, 
-       RECTL *DestRect, POINTL *MaskPoint, BRUSHOBJ* Brush,
-       POINTL* BrushPoint)
+static BOOLEAN STDCALL
+BltMask(PSURFOBJ Dest,
+       PSURFGDI DestGDI,
+       PSURFOBJ Source,
+       PSURFGDI SourceGDI,
+       PSURFOBJ Mask, 
+       PXLATEOBJ ColorTranslation,
+       PRECTL DestRect,
+       PPOINTL SourcePoint,
+       PPOINTL MaskPoint,
+       PBRUSHOBJ Brush,
+       PPOINTL BrushPoint,
+       ROP4 Rop4)
 {
   LONG i, j, dx, dy, c8;
   BYTE *tMask, *lMask;
@@ -60,11 +105,11 @@ BltMask(SURFOBJ *Dest, PSURFGDI DestGDI, SURFOBJ *Mask,
 
   if (Mask != NULL)
     {
-      tMask = Mask->pvBits;
+      tMask = Mask->pvBits + SourcePoint->y * Mask->lDelta + (SourcePoint->x >> 3);
       for (j = 0; j < dy; j++)
        {
          lMask = tMask;
-         c8 = 0;
+         c8 = SourcePoint->x & 0x07;
          for (i = 0; i < dx; i++)
            {
              if (0 != (*lMask & maskbit[c8]))
@@ -88,10 +133,19 @@ BltMask(SURFOBJ *Dest, PSURFGDI DestGDI, SURFOBJ *Mask,
     }
 }
 
-static BOOL STDCALL
-BltPatCopy(SURFOBJ *Dest, PSURFGDI DestGDI, SURFOBJ *Mask, 
-          RECTL *DestRect, POINTL *MaskPoint, BRUSHOBJ* Brush,
-          POINTL* BrushPoint)
+static BOOLEAN STDCALL
+BltPatCopy(PSURFOBJ Dest,
+          PSURFGDI DestGDI,
+          PSURFOBJ Source,
+          PSURFGDI SourceGDI,
+          PSURFOBJ Mask, 
+          PXLATEOBJ ColorTranslation,
+          PRECTL DestRect,
+          PPOINTL SourcePoint,
+          PPOINTL MaskPoint,
+          PBRUSHOBJ Brush,
+          PPOINTL BrushPoint,
+          ROP4 Rop4)
 {
   // These functions are assigned if we're working with a DIB
   // The assigned functions depend on the bitsPerPixel of the DIB
@@ -107,8 +161,28 @@ BltPatCopy(SURFOBJ *Dest, PSURFGDI DestGDI, SURFOBJ *Mask,
   return TRUE;
 }
 
+static BOOLEAN STDCALL
+CallDibBitBlt(PSURFOBJ OutputObj,
+              PSURFGDI OutputGDI,
+              PSURFOBJ InputObj,
+              PSURFGDI InputGDI,
+              PSURFOBJ Mask,
+              PXLATEOBJ ColorTranslation,
+              PRECTL OutputRect,
+              PPOINTL InputPoint,
+              PPOINTL MaskOrigin,
+              PBRUSHOBJ Brush,
+              PPOINTL BrushOrigin,
+              ROP4 Rop4)
+{
+  return OutputGDI->DIB_BitBlt(OutputObj, InputObj, OutputGDI, InputGDI, OutputRect, InputPoint, Brush, BrushOrigin, ColorTranslation, Rop4);
+}
+
 INT abs(INT nm);
 
+/*
+ * @implemented
+ */
 BOOL STDCALL
 EngBitBlt(SURFOBJ *DestObj,
          SURFOBJ *SourceObj,
@@ -120,12 +194,10 @@ EngBitBlt(SURFOBJ *DestObj,
          POINTL *MaskOrigin,
          BRUSHOBJ *Brush,
          POINTL *BrushOrigin,
-         ROP4 rop4)
+         ROP4 Rop4)
 {
-  BOOLEAN            ret;
   BYTE               clippingType;
-  RECTL              rclTmp;
-  POINTL             ptlTmp;
+  RECTL              CombinedRect;
   RECT_ENUM          RectEnum;
   BOOL               EnumMore;
   PSURFGDI           OutputGDI, InputGDI;
@@ -137,13 +209,12 @@ EngBitBlt(SURFOBJ *DestObj,
   INTENG_ENTER_LEAVE EnterLeaveDest;
   PSURFOBJ           InputObj;
   PSURFOBJ           OutputObj;
-
-  /* Check for degenerate case: if height or width of DestRect is 0 pixels there's
-     nothing to do */
-  if (DestRect->right == DestRect->left || DestRect->bottom == DestRect->top)
-    {
-    return TRUE;
-    }
+  PBLTRECTFUNC       BltRectFunc;
+  BOOLEAN            Ret;
+  RECTL              ClipRect;
+  unsigned           i;
+  POINTL             Pt;
+  ULONG              Direction;
 
   if (NULL != SourcePoint)
     {
@@ -180,8 +251,45 @@ EngBitBlt(SURFOBJ *DestObj,
     {
     InputGDI = (PSURFGDI) AccessInternalObjectFromUserObject(InputObj);
     }
+  else
+    {
+      InputGDI = NULL;
+    }
 
   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))
     {
@@ -194,20 +302,11 @@ EngBitBlt(SURFOBJ *DestObj,
   OutputRect.top = DestRect->top + Translate.y;
   OutputRect.bottom = DestRect->bottom + Translate.y;
 
-
   if (NULL != OutputObj)
     {
     OutputGDI = (PSURFGDI)AccessInternalObjectFromUserObject(OutputObj);
     }
 
-  /* The code currently assumes there will be a source bitmap. This is not true when, for example, using this function to
-   * paint a brush pattern on the destination. */
-  if (NULL == InputObj && 0xaacc != rop4 && PATCOPY != rop4)
-  {
-    DbgPrint("EngBitBlt: A source is currently required, even though not all operations require one (FIXME)\n");
-    return FALSE;
-  }
-
   // Determine clipping type
   if (ClipRegion == (CLIPOBJ *) NULL)
   {
@@ -216,79 +315,83 @@ EngBitBlt(SURFOBJ *DestObj,
     clippingType = ClipRegion->iDComplexity;
   }
 
-  if (0xaacc == rop4)
-  {
-    ret = BltMask(OutputObj, OutputGDI, Mask, &OutputRect, MaskOrigin, Brush, BrushOrigin);
-    IntEngLeave(&EnterLeaveDest);
-    IntEngLeave(&EnterLeaveSource);
-    return ret;
-  } else if (PATCOPY == rop4) {
-    ret = BltPatCopy(OutputObj, OutputGDI, Mask, &OutputRect, MaskOrigin, Brush, BrushOrigin);
-    IntEngLeave(&EnterLeaveDest);
-    IntEngLeave(&EnterLeaveSource);
-    return ret;
-  }
+  if (0xaacc == Rop4)
+    {
+      BltRectFunc = BltMask;
+    }
+  else if (PATCOPY == Rop4)
+    {
+      BltRectFunc = BltPatCopy;
+    }
+  else
+    {
+      BltRectFunc = CallDibBitBlt;
+    }
 
 
-  // We don't handle color translation just yet [we dont have to.. REMOVE REMOVE REMOVE]
   switch(clippingType)
   {
     case DC_TRIVIAL:
-      OutputGDI->DIB_BitBlt(OutputObj, InputObj, OutputGDI, InputGDI, &OutputRect, &InputPoint, ColorTranslation);
-
-      IntEngLeave(&EnterLeaveDest);
-      IntEngLeave(&EnterLeaveSource);
-
-      return(TRUE);
-
+      Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
+                           &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin, Rop4);
+      break;
     case DC_RECT:
-
       // Clip the blt to the clip rectangle
-      EngIntersectRect(&rclTmp, &OutputRect, &ClipRegion->rclBounds);
-
-      ptlTmp.x = InputPoint.x + rclTmp.left - OutputRect.left;
-      ptlTmp.y = InputPoint.y + rclTmp.top  - OutputRect.top;
-
-      IntEngLeave(&EnterLeaveDest);
-      IntEngLeave(&EnterLeaveSource);
-
-      return(TRUE);
-
+      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,
+                           &CombinedRect, &Pt, MaskOrigin, Brush, BrushOrigin, 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, ENUM_RECT_LIMIT);
+      do
+       {
+         EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
 
-      CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, CD_ANY, ENUM_RECT_LIMIT);
-
-      do {
-        EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
-
-        if (RectEnum.c > 0)
-        {
-          RECTL* prclEnd = &RectEnum.arcl[RectEnum.c];
-          RECTL* prcl    = &RectEnum.arcl[0];
-
-          do {
-            EngIntersectRect(prcl, prcl, &OutputRect);
-
-            ptlTmp.x = InputPoint.x + prcl->left - OutputRect.left;
-            ptlTmp.y = InputPoint.y + prcl->top - OutputRect.top;
-
-            prcl++;
-
-          } while (prcl < prclEnd);
-        }
-
-      } while(EnumMore);
-
-    IntEngLeave(&EnterLeaveDest);
-    IntEngLeave(&EnterLeaveSource);
-
-    return(TRUE);
+         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;
   }
 
+
   IntEngLeave(&EnterLeaveDest);
   IntEngLeave(&EnterLeaveSource);
 
-  return(FALSE);
+  return Ret;
 }
 
 BOOL STDCALL
@@ -302,36 +405,63 @@ IntEngBitBlt(SURFOBJ *DestObj,
              POINTL *MaskOrigin,
              BRUSHOBJ *Brush,
              POINTL *BrushOrigin,
-             ROP4 rop4)
+             ROP4 Rop4)
 {
   BOOLEAN ret;
   SURFGDI *DestGDI;
   SURFGDI *SourceGDI;
+  RECTL OutputRect;
+  POINTL InputPoint;
+
+  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;
+    }
 
   if (NULL != SourceObj)
     {
     SourceGDI = (PSURFGDI) AccessInternalObjectFromUserObject(SourceObj);
-    MouseSafetyOnDrawStart(SourceObj, SourceGDI, SourcePoint->x, SourcePoint->y,
-                           (SourcePoint->x + abs(DestRect->right - DestRect->left)),
-                          (SourcePoint->y + abs(DestRect->bottom - DestRect->top)));
+    MouseSafetyOnDrawStart(SourceObj, SourceGDI, 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, DestRect->left, DestRect->top,
-                         DestRect->right, DestRect->bottom);
+  MouseSafetyOnDrawStart(DestObj, DestGDI, OutputRect.left, OutputRect.top,
+                         OutputRect.right, OutputRect.bottom);
 
   /* Call the driver's DrvBitBlt if available */
-  if (NULL != DestGDI->BitBlt) {
-    ret = DestGDI->BitBlt(DestObj, SourceObj, Mask, ClipRegion, ColorTranslation,
-                          DestRect, SourcePoint, MaskOrigin, Brush, BrushOrigin, rop4);
-  }
+  if (NULL != DestGDI->BitBlt)
+    {
+      ret = DestGDI->BitBlt(DestObj, SourceObj, Mask, ClipRegion, ColorTranslation,
+                            &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin,
+                            Rop4);
+    }
 
-  if (! ret) {
-    ret = EngBitBlt(DestObj, SourceObj, Mask, ClipRegion, ColorTranslation,
-                    DestRect, SourcePoint, MaskOrigin, Brush, BrushOrigin, rop4);
-  }
+  if (! ret)
+    {
+      ret = EngBitBlt(DestObj, SourceObj, Mask, ClipRegion, ColorTranslation,
+                      &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin,
+                      Rop4);
+    }
 
   MouseSafetyOnDrawEnd(DestObj, DestGDI);
   if (NULL != SourceObj)
@@ -341,3 +471,4 @@ IntEngBitBlt(SURFOBJ *DestObj,
 
   return ret;
 }
+/* EOF */