Transform correctly the coordinates.
[reactos.git] / reactos / subsys / win32k / objects / brush.c
index 5d9011f..8b36b4e 100644 (file)
  *
  * $Id$
  */
+
 #include <w32k.h>
 
+#define NDEBUG
+#include <debug.h>
+
 static const USHORT HatchBrushes[NB_HATCH_STYLES][8] =
 {
   {0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00}, /* HS_HORIZONTAL */
@@ -41,7 +45,7 @@ BRUSH_Cleanup(PVOID ObjectBody)
     GDIOBJ_SetOwnership(pBrush->hbmPattern, PsGetCurrentProcess());
     NtGdiDeleteObject(pBrush->hbmPattern);
   }
-  
+
   return TRUE;
 }
 
@@ -72,8 +76,12 @@ IntGdiCreateBrushXlate(PDC Dc, GDIBRUSHOBJ *BrushObj, BOOLEAN *Failed)
          if (Dc->w.bitsPerPixel != 1)
             Result = IntEngCreateSrcMonoXlate(Dc->w.hPalette, Dc->w.textColor, Dc->w.backgroundColor);
       }
+      else if (BrushObj->flAttrs & GDIBRUSH_IS_DIB)
+      {
+         Result = IntEngCreateXlate(0, 0, Dc->w.hPalette, Pattern->hDIBPalette);
+      }
 
-      BITMAPOBJ_UnlockBitmap(BrushObj->hbmPattern);
+      BITMAPOBJ_UnlockBitmap(Pattern);
       *Failed = FALSE;
    }
 
@@ -97,80 +105,329 @@ IntGdiInitBrushInstance(GDIBRUSHINST *BrushInst, PGDIBRUSHOBJ BrushObj, XLATEOBJ
    BrushInst->XlateObject = XlateObj;
 }
 
-HBRUSH FASTCALL
-IntGdiCreateBrushIndirect(PLOGBRUSH LogBrush)
+/**
+ * @name CalculateColorTableSize
+ *
+ * Internal routine to calculate the number of color table entries.
+ *
+ * @param BitmapInfoHeader
+ *        Input bitmap information header, can be any version of
+ *        BITMAPINFOHEADER or BITMAPCOREHEADER.
+ *
+ * @param ColorSpec
+ *        Pointer to variable which specifiing the color mode (DIB_RGB_COLORS
+ *        or DIB_RGB_COLORS). On successful return this value is normalized
+ *        according to the bitmap info.
+ *
+ * @param ColorTableSize
+ *        On successful return this variable is filled with number of
+ *        entries in color table for the image with specified parameters.
+ *
+ * @return
+ *    TRUE if the input values together form a valid image, FALSE otherwise.
+ */
+
+BOOL STDCALL
+CalculateColorTableSize(
+   CONST BITMAPINFOHEADER *BitmapInfoHeader,
+   UINT *ColorSpec,
+   UINT *ColorTableSize)
 {
-   PGDIBRUSHOBJ BrushObject;
-   HBRUSH hBrush;
-   HBITMAP hPattern = 0;
-   
-   switch (LogBrush->lbStyle)
+   WORD BitCount;
+   DWORD ClrUsed;
+   DWORD Compression;
+
+   /*
+    * At first get some basic parameters from the passed BitmapInfoHeader
+    * structure. It can have one of the following formats:
+    * - BITMAPCOREHEADER (the oldest one with totally different layout
+    *                     from the others)
+    * - BITMAPINFOHEADER (the standard and most common header)
+    * - BITMAPV4HEADER (extension of BITMAPINFOHEADER)
+    * - BITMAPV5HEADER (extension of BITMAPV4HEADER)
+    */
+
+   if (BitmapInfoHeader->biSize == sizeof(BITMAPCOREHEADER))
    {
-      case BS_HATCHED:
-         hPattern = NtGdiCreateBitmap(8, 8, 1, 1, HatchBrushes[LogBrush->lbHatch]);
-         if (hPattern == NULL)
+      BitCount = ((LPBITMAPCOREHEADER)BitmapInfoHeader)->bcBitCount;
+      ClrUsed = 0;
+      Compression = BI_RGB;
+   }
+   else
+   {
+      BitCount = BitmapInfoHeader->biBitCount;
+      ClrUsed = BitmapInfoHeader->biClrUsed;
+      Compression = BitmapInfoHeader->biCompression;
+   }
+
+   switch (Compression)
+   {
+      case BI_BITFIELDS:
+         if (*ColorSpec == DIB_PAL_COLORS)
+            *ColorSpec = DIB_RGB_COLORS;
+
+         if (BitCount != 16 && BitCount != 32)
+            return FALSE;
+
+         /*
+          * For BITMAPV4HEADER/BITMAPV5HEADER the masks are included in
+          * the structure itself (bV4RedMask, bV4GreenMask, and bV4BlueMask).
+          * For BITMAPINFOHEADER the color masks are stored in the palette.
+          */
+
+         if (BitmapInfoHeader->biSize > sizeof(BITMAPINFOHEADER))
+            *ColorTableSize = 0;
+         else
+            *ColorTableSize = 3;
+
+         return TRUE;
+
+      case BI_RGB:
+         switch (BitCount)
          {
-            SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
-            return NULL;
+            case 1:
+               *ColorTableSize = ClrUsed ? min(ClrUsed, 2) : 2;
+               return TRUE;
+
+            case 4:
+               *ColorTableSize = ClrUsed ? min(ClrUsed, 16) : 16;
+               return TRUE;
+
+            case 8:
+               *ColorTableSize = ClrUsed ? min(ClrUsed, 256) : 256;
+               return TRUE;
+
+            default:
+               if (*ColorSpec == DIB_PAL_COLORS)
+                  *ColorSpec = DIB_RGB_COLORS;
+               if (BitCount != 16 && BitCount != 24 && BitCount != 32)
+                  return FALSE;
+               *ColorTableSize = ClrUsed;
+               return TRUE;
          }
-         break;
-     
-      case BS_PATTERN:
-         hPattern = BITMAPOBJ_CopyBitmap((HBITMAP)LogBrush->lbHatch);
-         if (hPattern == NULL)
+
+      case BI_RLE4:
+         if (BitCount == 4)
          {
-            SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
-            return NULL;
+            *ColorTableSize = ClrUsed ? min(ClrUsed, 16) : 16;
+            return TRUE;
          }
-         break;
+         return FALSE;
+
+      case BI_RLE8:
+         if (BitCount == 8)
+         {
+            *ColorTableSize = ClrUsed ? min(ClrUsed, 256) : 256;
+            return TRUE;
+         }
+         return FALSE;
+
+      case BI_JPEG:
+      case BI_PNG:
+         *ColorTableSize = ClrUsed;
+         return TRUE;
+
+      default:
+         return FALSE;
    }
-   
+}
+
+HBRUSH STDCALL
+IntGdiCreateDIBBrush(
+   CONST BITMAPINFO *BitmapInfo,
+   UINT ColorSpec,
+   UINT BitmapInfoSize,
+   CONST VOID *PackedDIB)
+{
+   HBRUSH hBrush;
+   PGDIBRUSHOBJ BrushObject;
+   HBITMAP hPattern;
+   ULONG_PTR DataPtr;
+   UINT PaletteEntryCount;
+   PBITMAPOBJ BitmapObject;
+   INT PaletteType;
+
+   if (BitmapInfo->bmiHeader.biSize < sizeof(BITMAPINFOHEADER))
+   {
+      SetLastWin32Error(ERROR_INVALID_PARAMETER);
+      return NULL;
+   }
+
+   if (!CalculateColorTableSize(&BitmapInfo->bmiHeader, &ColorSpec,
+                                &PaletteEntryCount))
+   {
+      SetLastWin32Error(ERROR_INVALID_PARAMETER);
+      return NULL;
+   }
+
+   DataPtr = (ULONG_PTR)BitmapInfo + BitmapInfo->bmiHeader.biSize;
+   if (ColorSpec == DIB_RGB_COLORS)
+      DataPtr += PaletteEntryCount * sizeof(RGBQUAD);
+   else
+      DataPtr += PaletteEntryCount * sizeof(USHORT);
+
+   hPattern = NtGdiCreateBitmap(BitmapInfo->bmiHeader.biWidth,
+                                BitmapInfo->bmiHeader.biHeight,
+                                BitmapInfo->bmiHeader.biPlanes,
+                                BitmapInfo->bmiHeader.biBitCount,
+                                (PVOID)DataPtr);
+   if (hPattern == NULL)
+   {
+      SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+      return NULL;
+   }
+
+   BitmapObject = BITMAPOBJ_LockBitmap(hPattern);
+   ASSERT(BitmapObject != NULL);
+   BitmapObject->hDIBPalette = BuildDIBPalette(BitmapInfo, &PaletteType);
+   BITMAPOBJ_UnlockBitmap(BitmapObject);
+
    hBrush = BRUSHOBJ_AllocBrush();
    if (hBrush == NULL)
    {
+      NtGdiDeleteObject(hPattern);
       SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
       return NULL;
    }
 
    BrushObject = BRUSHOBJ_LockBrush(hBrush);
-   if(BrushObject != NULL)
-   {
-     switch (LogBrush->lbStyle)
-     {
-        case BS_NULL:
-           BrushObject->flAttrs |= GDIBRUSH_IS_NULL;
-           break;
-
-        case BS_SOLID:
-           BrushObject->flAttrs |= GDIBRUSH_IS_SOLID;
-           BrushObject->BrushAttr.lbColor = LogBrush->lbColor & 0xFFFFFF;
-           /* FIXME: Fill in the rest of fields!!! */
-           break;
-
-        case BS_HATCHED:
-           BrushObject->flAttrs |= GDIBRUSH_IS_HATCH;
-           BrushObject->hbmPattern = hPattern;
-           BrushObject->BrushAttr.lbColor = LogBrush->lbColor & 0xFFFFFF;
-           break;
-
-        case BS_PATTERN:
-           BrushObject->flAttrs |= GDIBRUSH_IS_BITMAP;
-           BrushObject->hbmPattern = hPattern;
-           /* FIXME: Fill in the rest of fields!!! */
-           break;
-
-        default:
-           DPRINT1("Brush Style: %d\n", LogBrush->lbStyle);
-           UNIMPLEMENTED;
-           break;
-     }
-     
-     BRUSHOBJ_UnlockBrush(hBrush);
-   }
-
-   if (hPattern != 0)
-      GDIOBJ_SetOwnership(hPattern, NULL);
-   
+   ASSERT(BrushObject != NULL);
+
+   BrushObject->flAttrs |= GDIBRUSH_IS_BITMAP | GDIBRUSH_IS_DIB;
+   BrushObject->hbmPattern = hPattern;
+   /* FIXME: Fill in the rest of fields!!! */
+
+   GDIOBJ_SetOwnership(hPattern, NULL);
+
+   BRUSHOBJ_UnlockBrush(BrushObject);
+
+   return hBrush;
+}
+
+HBRUSH STDCALL
+IntGdiCreateHatchBrush(
+   INT Style,
+   COLORREF Color)
+{
+   HBRUSH hBrush;
+   PGDIBRUSHOBJ BrushObject;
+   HBITMAP hPattern;
+
+   if (Style < 0 || Style >= NB_HATCH_STYLES)
+   {
+      return 0;
+   }
+
+   hPattern = NtGdiCreateBitmap(8, 8, 1, 1, (LPBYTE)HatchBrushes[Style]);
+   if (hPattern == NULL)
+   {
+      SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+      return NULL;
+   }
+
+   hBrush = BRUSHOBJ_AllocBrush();
+   if (hBrush == NULL)
+   {
+      NtGdiDeleteObject(hPattern);
+      SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+      return NULL;
+   }
+
+   BrushObject = BRUSHOBJ_LockBrush(hBrush);
+   ASSERT(BrushObject != NULL);
+
+   BrushObject->flAttrs |= GDIBRUSH_IS_HATCH;
+   BrushObject->hbmPattern = hPattern;
+   BrushObject->BrushAttr.lbColor = Color & 0xFFFFFF;
+
+   GDIOBJ_SetOwnership(hPattern, NULL);
+
+   BRUSHOBJ_UnlockBrush(BrushObject);
+
+   return hBrush;
+}
+
+HBRUSH STDCALL
+IntGdiCreatePatternBrush(
+   HBITMAP hBitmap)
+{
+   HBRUSH hBrush;
+   PGDIBRUSHOBJ BrushObject;
+   HBITMAP hPattern;
+
+   hPattern = BITMAPOBJ_CopyBitmap(hBitmap);
+   if (hPattern == NULL)
+   {
+      SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+      return NULL;
+   }
+
+   hBrush = BRUSHOBJ_AllocBrush();
+   if (hBrush == NULL)
+   {
+      NtGdiDeleteObject(hPattern);
+      SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+      return NULL;
+   }
+
+   BrushObject = BRUSHOBJ_LockBrush(hBrush);
+   ASSERT(BrushObject != NULL);
+
+   BrushObject->flAttrs |= GDIBRUSH_IS_BITMAP;
+   BrushObject->hbmPattern = hPattern;
+   /* FIXME: Fill in the rest of fields!!! */
+
+   GDIOBJ_SetOwnership(hPattern, NULL);
+
+   BRUSHOBJ_UnlockBrush(BrushObject);
+
+   return hBrush;
+}
+
+HBRUSH STDCALL
+IntGdiCreateSolidBrush(
+   COLORREF Color)
+{
+   HBRUSH hBrush;
+   PGDIBRUSHOBJ BrushObject;
+
+   hBrush = BRUSHOBJ_AllocBrush();
+   if (hBrush == NULL)
+   {
+      SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+      return NULL;
+   }
+
+   BrushObject = BRUSHOBJ_LockBrush(hBrush);
+   ASSERT(BrushObject != NULL);
+
+   BrushObject->flAttrs |= GDIBRUSH_IS_SOLID;
+   BrushObject->BrushAttr.lbColor = Color & 0xFFFFFF;
+   /* FIXME: Fill in the rest of fields!!! */
+
+   BRUSHOBJ_UnlockBrush(BrushObject);
+
+   return hBrush;
+}
+
+HBRUSH STDCALL
+IntGdiCreateNullBrush(VOID)
+{
+   HBRUSH hBrush;
+   PGDIBRUSHOBJ BrushObject;
+
+   hBrush = BRUSHOBJ_AllocBrush();
+   if (hBrush == NULL)
+   {
+      SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+      return NULL;
+   }
+
+   BrushObject = BRUSHOBJ_LockBrush(hBrush);
+   ASSERT(BrushObject != NULL);
+   BrushObject->flAttrs |= GDIBRUSH_IS_NULL;
+   BRUSHOBJ_UnlockBrush(BrushObject);
+
    return hBrush;
 }
 
@@ -222,14 +479,16 @@ IntPatBlt(
          DestRect.top = YLeft + Height + dc->w.DCOrgY + 1;
          DestRect.bottom = YLeft + dc->w.DCOrgY + 1;
       }
-      
+
+      IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
+
       BrushOrigin.x = BrushObj->ptOrigin.x + dc->w.DCOrgX;
       BrushOrigin.y = BrushObj->ptOrigin.y + dc->w.DCOrgY;
 
       IntGdiInitBrushInstance(&BrushInst, BrushObj, dc->XlateBrush);
 
       ret = IntEngBitBlt(
-         BitmapObj,
+         &BitmapObj->SurfObj,
          NULL,
          NULL,
          dc->CombinedClip,
@@ -239,10 +498,10 @@ IntPatBlt(
          NULL,
          &BrushInst.BrushObject,
          &BrushOrigin,
-         ROP);
+         ROP3_TO_ROP4(ROP));
    }
 
-   BITMAPOBJ_UnlockBitmap(dc->w.hBitmap);
+   BITMAPOBJ_UnlockBitmap(BitmapObj);
 
    return ret;
 }
@@ -259,14 +518,20 @@ IntGdiPolyPatBlt(
    PPATRECT r;
    PGDIBRUSHOBJ BrushObj;
    DC *dc;
-       
+
    dc = DC_LockDc(hDC);
    if (dc == NULL)
    {
       SetLastWin32Error(ERROR_INVALID_HANDLE);
       return FALSE;
    }
-       
+   if (dc->IsIC)
+   {
+      DC_UnlockDc(dc);
+      /* Yes, Windows really returns TRUE in this case */
+      return TRUE;
+   }
+
    for (r = pRects, i = 0; i < cRects; i++)
    {
       BrushObj = BRUSHOBJ_LockBrush(r->hBrush);
@@ -280,100 +545,95 @@ IntGdiPolyPatBlt(
            r->r.bottom,
            dwRop,
            BrushObj);
-        BRUSHOBJ_UnlockBrush(r->hBrush);
+        BRUSHOBJ_UnlockBrush(BrushObj);
       }
       r++;
    }
 
-   DC_UnlockDc( hDC );
-       
+   DC_UnlockDc(dc);
+
    return TRUE;
 }
 
 /* PUBLIC FUNCTIONS ***********************************************************/
 
 HBRUSH STDCALL
-NtGdiCreateBrushIndirect(CONST LOGBRUSH *LogBrush)
+NtGdiCreateDIBBrush(
+   IN PVOID BitmapInfoAndData,
+   IN FLONG ColorSpec,
+   IN UINT BitmapInfoSize,
+   IN BOOL  b8X8,
+   IN BOOL bPen,
+   IN PVOID PackedDIB)
 {
-   LOGBRUSH SafeLogBrush;
-   NTSTATUS Status;
-  
-   Status = MmCopyFromCaller(&SafeLogBrush, LogBrush, sizeof(LOGBRUSH));
-   if (!NT_SUCCESS(Status))
+   BITMAPINFO *SafeBitmapInfoAndData;
+   NTSTATUS Status = STATUS_SUCCESS;
+   HBRUSH hBrush;
+
+   SafeBitmapInfoAndData = EngAllocMem(0, BitmapInfoSize, 0);
+   if (SafeBitmapInfoAndData == NULL)
    {
-      SetLastNtError(Status);
-      return 0;
+      SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+      return NULL;
    }
-  
-   return IntGdiCreateBrushIndirect(&SafeLogBrush);
-}
 
-HBRUSH STDCALL
-NtGdiCreateDIBPatternBrush(HGLOBAL hDIBPacked, UINT ColorSpec)
-{
-   UNIMPLEMENTED;
-   return 0;
-}
-
-HBRUSH STDCALL
-NtGdiCreateDIBPatternBrushPt(CONST VOID *PackedDIB, UINT Usage)
-{
-   UNIMPLEMENTED;
-   return 0;
-}
-
-HBRUSH STDCALL
-NtGdiCreateHatchBrush(INT Style, COLORREF Color)
-{
-   LOGBRUSH LogBrush;
-
-   if (Style < 0 || Style >= NB_HATCH_STYLES)
+   _SEH_TRY
+   {
+      ProbeForRead(BitmapInfoAndData,
+                   BitmapInfoSize,
+                   1);
+      RtlCopyMemory(SafeBitmapInfoAndData,
+                    BitmapInfoAndData,
+                    BitmapInfoSize);
+   }
+   _SEH_HANDLE
+   {
+      Status = _SEH_GetExceptionCode();
+   }
+   _SEH_END;
+   
+   if (!NT_SUCCESS(Status))
    {
+      EngFreeMem(SafeBitmapInfoAndData);
+      SetLastNtError(Status);
       return 0;
    }
 
-   LogBrush.lbStyle = BS_HATCHED;
-   LogBrush.lbColor = Color;
-   LogBrush.lbHatch = Style;
+   hBrush = IntGdiCreateDIBBrush(SafeBitmapInfoAndData, ColorSpec,
+                                 BitmapInfoSize, PackedDIB);
+
+   EngFreeMem(SafeBitmapInfoAndData);
 
-   return IntGdiCreateBrushIndirect(&LogBrush);
+   return hBrush;
 }
 
 HBRUSH STDCALL
-NtGdiCreatePatternBrush(HBITMAP hBitmap)
+NtGdiCreateHatchBrush(
+   INT Style,
+   COLORREF Color)
 {
-   LOGBRUSH LogBrush;
-
-   LogBrush.lbStyle = BS_PATTERN;
-   LogBrush.lbColor = 0;
-   LogBrush.lbHatch = (ULONG)hBitmap;
-
-   return IntGdiCreateBrushIndirect(&LogBrush);
+   return IntGdiCreateHatchBrush(Style, Color);
 }
 
 HBRUSH STDCALL
-NtGdiCreateSolidBrush(COLORREF Color)
+NtGdiCreatePatternBrush(
+   HBITMAP hBitmap)
 {
-   LOGBRUSH LogBrush;
-
-   LogBrush.lbStyle = BS_SOLID;
-   LogBrush.lbColor = Color;
-   LogBrush.lbHatch = 0;
-
-   return IntGdiCreateBrushIndirect(&LogBrush);
+   return IntGdiCreatePatternBrush(hBitmap);
 }
 
-BOOL STDCALL
-NtGdiFixBrushOrgEx(VOID)
+HBRUSH STDCALL
+NtGdiCreateSolidBrush(COLORREF Color,
+                      IN OPTIONAL HBRUSH hbr)
 {
-   return FALSE;
+   return IntGdiCreateSolidBrush(Color);
 }
 
 /*
  * NtGdiSetBrushOrgEx
  *
  * The NtGdiSetBrushOrgEx function sets the brush origin that GDI assigns to
- * the next brush an application selects into the specified device context. 
+ * the next brush an application selects into the specified device context.
  *
  * Status
  *    @implemented
@@ -391,14 +651,26 @@ NtGdiSetBrushOrgEx(HDC hDC, INT XOrg, INT YOrg, LPPOINT Point)
 
    if (Point != NULL)
    {
-      NTSTATUS Status;
+      NTSTATUS Status = STATUS_SUCCESS;
       POINT SafePoint;
       SafePoint.x = dc->w.brushOrgX;
       SafePoint.y = dc->w.brushOrgY;
-      Status = MmCopyToCaller(Point, &SafePoint, sizeof(POINT));
+      _SEH_TRY
+      {
+         ProbeForWrite(Point,
+                       sizeof(POINT),
+                       1);
+         *Point = SafePoint;
+      }
+      _SEH_HANDLE
+      {
+         Status = _SEH_GetExceptionCode();
+      }
+      _SEH_END;
+
       if(!NT_SUCCESS(Status))
       {
-        DC_UnlockDc(hDC);
+        DC_UnlockDc(dc);
         SetLastNtError(Status);
         return FALSE;
       }
@@ -406,7 +678,7 @@ NtGdiSetBrushOrgEx(HDC hDC, INT XOrg, INT YOrg, LPPOINT Point)
 
    dc->w.brushOrgX = XOrg;
    dc->w.brushOrgY = YOrg;
-   DC_UnlockDc(hDC);
+   DC_UnlockDc(dc);
 
    return TRUE;
 }
@@ -415,14 +687,14 @@ BOOL STDCALL
 NtGdiPolyPatBlt(
    HDC hDC,
    DWORD dwRop,
-   PPATRECT pRects,
-   INT cRects,
-   ULONG Reserved)
+   IN PPOLYPATBLT pRects,
+   IN DWORD cRects,
+   IN DWORD Mode)
 {
    PPATRECT rb = NULL;
-   NTSTATUS Status;
+   NTSTATUS Status = STATUS_SUCCESS;
    BOOL Ret;
-    
+
    if (cRects > 0)
    {
       rb = ExAllocatePoolWithTag(PagedPool, sizeof(PATRECT) * cRects, TAG_PATBLT);
@@ -431,7 +703,21 @@ NtGdiPolyPatBlt(
          SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
          return FALSE;
       }
-      Status = MmCopyFromCaller(rb, pRects, sizeof(PATRECT) * cRects);
+      _SEH_TRY
+      {
+         ProbeForRead(pRects,
+                      cRects * sizeof(PATRECT),
+                      1);
+         RtlCopyMemory(rb,
+                       pRects,
+                       cRects * sizeof(PATRECT));
+      }
+      _SEH_HANDLE
+      {
+         Status = _SEH_GetExceptionCode();
+      }
+      _SEH_END;
+
       if (!NT_SUCCESS(Status))
       {
          ExFreePool(rb);
@@ -439,9 +725,9 @@ NtGdiPolyPatBlt(
          return FALSE;
       }
    }
-    
-   Ret = IntGdiPolyPatBlt(hDC, dwRop, pRects, cRects, Reserved);
-       
+
+   Ret = IntGdiPolyPatBlt(hDC, dwRop, (PPATRECT)pRects, cRects, Mode);
+
    if (cRects > 0)
       ExFreePool(rb);
 
@@ -466,12 +752,18 @@ NtGdiPatBlt(
       SetLastWin32Error(ERROR_INVALID_HANDLE);
       return FALSE;
    }
+   if (dc->IsIC)
+   {
+      DC_UnlockDc(dc);
+      /* Yes, Windows really returns TRUE in this case */
+      return TRUE;
+   }
 
    BrushObj = BRUSHOBJ_LockBrush(dc->w.hBrush);
    if (BrushObj == NULL)
    {
       SetLastWin32Error(ERROR_INVALID_HANDLE);
-      DC_UnlockDc(hDC);
+      DC_UnlockDc(dc);
       return FALSE;
    }
 
@@ -484,8 +776,8 @@ NtGdiPatBlt(
       ROP,
       BrushObj);
 
-   BRUSHOBJ_UnlockBrush(dc->w.hBrush);
-   DC_UnlockDc(hDC);
+   BRUSHOBJ_UnlockBrush(BrushObj);
+   DC_UnlockDc(dc);
 
    return ret;
 }