[WIN32K]
[reactos.git] / reactos / win32ss / gdi / ntgdi / dibobj.c
index 78eb3d8..83252a9 100644 (file)
@@ -111,13 +111,23 @@ CreateDIBPalette(
     _In_ ULONG iUsage)
 {
     PPALETTE ppal;
-    ULONG i, cColors;
+    ULONG i, cBitsPixel, cColors;
+
+    if (pbmi->bmiHeader.biSize < sizeof(BITMAPINFOHEADER))
+    {
+        PBITMAPCOREINFO pbci = (PBITMAPCOREINFO)pbmi;
+        cBitsPixel = pbci->bmciHeader.bcBitCount;
+    }
+    else
+    {
+        cBitsPixel = pbmi->bmiHeader.biBitCount;
+    }
 
     /* Check if the colors are indexed */
-    if (pbmi->bmiHeader.biBitCount <= 8)
+    if (cBitsPixel <= 8)
     {
         /* We create a "full" palette */
-        cColors = 1 << pbmi->bmiHeader.biBitCount;
+        cColors = 1 << cBitsPixel;
 
         /* Allocate the palette */
         ppal = PALETTE_AllocPalette(PAL_INDEXED,
@@ -128,7 +138,8 @@ CreateDIBPalette(
                                     0);
 
         /* Check if the BITMAPINFO specifies how many colors to use */
-        if (pbmi->bmiHeader.biClrUsed != 0)
+        if ((pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) &&
+            (pbmi->bmiHeader.biClrUsed != 0))
         {
             /* This is how many colors we can actually process */
             cColors = min(cColors, pbmi->bmiHeader.biClrUsed);
@@ -148,9 +159,12 @@ CreateDIBPalette(
             /* Loop all color indices in the DIB */
             for (i = 0; i < cColors; i++)
             {
-                /* Get the RGB value from the DC palette, indexed by the DIB
-                   color table value */
-                crColor = PALETTE_ulGetRGBColorFromIndex(ppalDC, pwColors[i]);
+                /* Get the palette index and handle wraparound when exceeding
+                   the number of colors in the DC palette */
+                WORD wIndex = pwColors[i] % ppalDC->NumColors;
+
+                /* USe the RGB value from the DC palette */
+                crColor = PALETTE_ulGetRGBColorFromIndex(ppalDC, wIndex);
                 PALETTE_vSetRGBColorForIndex(ppal, i, crColor);
             }
         }
@@ -176,7 +190,7 @@ CreateDIBPalette(
             // FIXME: this one is undocumented
 //            ASSERT(FALSE);
 //        }
-        else // if (iUsage == DIB_RGB_COLORS)
+        else if (pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER))
         {
             /* The colors are an array of RGBQUAD values */
             RGBQUAD *prgb = (RGBQUAD*)((PCHAR)pbmi + pbmi->bmiHeader.biSize);
@@ -190,6 +204,22 @@ CreateDIBPalette(
                 RGBQUAD rgb = prgb[i];
                 COLORREF crColor = RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue);
 
+                /* Set the RGB value in the palette */
+                PALETTE_vSetRGBColorForIndex(ppal, i, crColor);
+            }
+        }
+        else
+        {
+            /* The colors are an array of RGBTRIPLE values */
+            RGBTRIPLE *prgb = (RGBTRIPLE*)((PCHAR)pbmi + pbmi->bmiHeader.biSize);
+
+            /* Loop all color indices in the DIB */
+            for (i = 0; i < cColors; i++)
+            {
+                /* Get the color value and translate it to a COLORREF */
+                RGBTRIPLE rgb = prgb[i];
+                COLORREF crColor = RGB(rgb.rgbtRed, rgb.rgbtGreen, rgb.rgbtBlue);
+
                 /* Set the RGB value in the palette */
                 PALETTE_vSetRGBColorForIndex(ppal, i, crColor);
             }
@@ -201,7 +231,8 @@ CreateDIBPalette(
         ULONG flRedMask, flGreenMask, flBlueMask;
 
         /* Check if the DIB contains bitfield values */
-        if (pbmi->bmiHeader.biCompression == BI_BITFIELDS)
+        if ((pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) &&
+            (pbmi->bmiHeader.biCompression == BI_BITFIELDS))
         {
             /* Check if we have a v4/v5 header */
             if (pbmi->bmiHeader.biSize >= sizeof(BITMAPV4HEADER))
@@ -225,7 +256,7 @@ CreateDIBPalette(
         {
             /* Check what bit depth we have. Note: optimization flags are
                calculated in PALETTE_AllocPalette()  */
-            if (pbmi->bmiHeader.biBitCount == 16)
+            if (cBitsPixel == 16)
             {
                 /* This is an RGB 555 palette */
                 flRedMask = 0x7C00;
@@ -254,136 +285,6 @@ CreateDIBPalette(
     return ppal;
 }
 
-
-UINT
-APIENTRY
-IntSetDIBColorTable(
-    HDC hDC,
-    UINT StartIndex,
-    UINT Entries,
-    CONST RGBQUAD *Colors)
-{
-    PDC dc;
-    PSURFACE psurf;
-    PPALETTE PalGDI;
-    UINT Index;
-    ULONG biBitCount;
-
-    if (!(dc = DC_LockDc(hDC))) return 0;
-    if (dc->dctype == DC_TYPE_INFO)
-    {
-        DC_UnlockDc(dc);
-        return 0;
-    }
-
-    psurf = dc->dclevel.pSurface;
-    if (psurf == NULL)
-    {
-        DC_UnlockDc(dc);
-        EngSetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-
-    if (psurf->hSecure == NULL)
-    {
-        DC_UnlockDc(dc);
-        EngSetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-
-    biBitCount = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
-    if ((biBitCount <= 8) && (StartIndex < (1UL << biBitCount)))
-    {
-        if (StartIndex + Entries > (1UL << biBitCount))
-            Entries = (1 << biBitCount) - StartIndex;
-
-        if (psurf->ppal == NULL)
-        {
-            DC_UnlockDc(dc);
-            EngSetLastError(ERROR_INVALID_HANDLE);
-            return 0;
-        }
-
-        PalGDI = psurf->ppal;
-
-        for (Index = StartIndex;
-                Index < StartIndex + Entries && Index < PalGDI->NumColors;
-                Index++)
-        {
-            PalGDI->IndexedColors[Index].peRed = Colors[Index - StartIndex].rgbRed;
-            PalGDI->IndexedColors[Index].peGreen = Colors[Index - StartIndex].rgbGreen;
-            PalGDI->IndexedColors[Index].peBlue = Colors[Index - StartIndex].rgbBlue;
-        }
-    }
-    else
-        Entries = 0;
-
-    /* Mark the brushes invalid */
-    dc->pdcattr->ulDirty_ |= DIRTY_FILL|DIRTY_LINE|DIRTY_BACKGROUND|DIRTY_TEXT;
-
-    DC_UnlockDc(dc);
-
-    return Entries;
-}
-
-UINT
-APIENTRY
-IntGetDIBColorTable(
-    HDC hDC,
-    UINT StartIndex,
-    UINT Entries,
-    RGBQUAD *Colors)
-{
-    PDC dc;
-    PSURFACE psurf;
-    PPALETTE ppal;
-    UINT Index, Count = 0;
-
-    if (!(dc = DC_LockDc(hDC))) return 0;
-    if (dc->dctype == DC_TYPE_INFO)
-    {
-        DC_UnlockDc(dc);
-        return 0;
-    }
-
-    psurf = dc->dclevel.pSurface;
-    if (psurf == NULL)
-    {
-        DC_UnlockDc(dc);
-        EngSetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-
-    if (psurf->hSecure == NULL)
-    {
-        DC_UnlockDc(dc);
-        EngSetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-
-    ppal = psurf->ppal;
-    ASSERT(ppal);
-
-    if (ppal->flFlags & PAL_INDEXED)
-    {
-
-        for (Index = StartIndex;
-                Index < StartIndex + Entries && Index < ppal->NumColors;
-                Index++)
-        {
-            Colors[Index - StartIndex].rgbRed = ppal->IndexedColors[Index].peRed;
-            Colors[Index - StartIndex].rgbGreen = ppal->IndexedColors[Index].peGreen;
-            Colors[Index - StartIndex].rgbBlue = ppal->IndexedColors[Index].peBlue;
-            Colors[Index - StartIndex].rgbReserved = 0;
-            Count++;
-        }
-    }
-
-    DC_UnlockDc(dc);
-
-    return Count;
-}
-
 // Converts a DIB to a device-dependent bitmap
 static INT
 FASTCALL
@@ -404,6 +305,8 @@ IntSetDIBits(
     EXLATEOBJ  exlo;
     PPALETTE    ppalDIB = 0;
 
+    if (!bmi) return 0;
+
     SourceBitmap = GreCreateBitmapEx(bmi->bmiHeader.biWidth,
                                      ScanLines,
                                      0,
@@ -472,6 +375,115 @@ cleanup:
     return result;
 }
 
+static
+HBITMAP
+IntGdiCreateMaskFromRLE(
+    DWORD Width,
+    DWORD Height,
+    ULONG Compression,
+    const BYTE* Bits,
+    DWORD BitsSize)
+{
+    HBITMAP Mask;
+    DWORD x, y;
+    SURFOBJ* SurfObj;
+    UINT i = 0;
+    BYTE Data, NumPixels, ToSkip;
+
+    ASSERT((Compression == BI_RLE8) || (Compression == BI_RLE4));
+
+    /* Create the bitmap */
+    Mask = GreCreateBitmapEx(Width, Height, 0, BMF_1BPP, 0, 0, NULL, 0);
+    if (!Mask)
+        return NULL;
+
+    SurfObj = EngLockSurface((HSURF)Mask);
+    if (!SurfObj)
+    {
+        GreDeleteObject(Mask);
+        return NULL;
+    }
+    ASSERT(SurfObj->pvBits != NULL);
+
+    x = y = 0;
+
+    while (i < BitsSize)
+    {
+        NumPixels = Bits[i];
+        Data = Bits[i + 1];
+        i += 2;
+
+        if (NumPixels != 0)
+        {
+            if ((x + NumPixels) > Width)
+                NumPixels = Width - x;
+
+            if (NumPixels == 0)
+                continue;
+
+            DIB_1BPP_HLine(SurfObj, x, x + NumPixels, y, 1);
+            x += NumPixels;
+            continue;
+        }
+
+        if (Data < 3)
+        {
+            switch (Data)
+            {
+                case 0:
+                    /* End of line */
+                    y++;
+                    if (y == Height)
+                        goto done;
+                    x = 0;
+                    break;
+                case 1:
+                    /* End of file */
+                    goto done;
+                case 2:
+                    /* Jump */
+                    if (i >= (BitsSize - 1))
+                        goto done;
+                    x += Bits[i];
+                    if (x > Width)
+                        x = Width;
+                    y += Bits[i + 1];
+                    if (y >= Height)
+                        goto done;
+                    i += 2;
+                    break;
+            }
+            /* Done for this run */
+            continue;
+        }
+
+        /* Embedded data into the RLE */
+        NumPixels = Data;
+        if (Compression == BI_RLE8)
+            ToSkip = NumPixels;
+        else
+            ToSkip = (NumPixels / 2) + (NumPixels & 1);
+
+        if ((i + ToSkip) > BitsSize)
+            goto done;
+        ToSkip = (ToSkip + 1) & ~1;
+
+        if ((x + NumPixels) > Width)
+            NumPixels = Width - x;
+
+        if (NumPixels != 0)
+        {
+            DIB_1BPP_HLine(SurfObj, x, x + NumPixels, y, 1);
+            x += NumPixels;
+        }
+        i += ToSkip;
+    }
+
+done:
+    EngUnlockSurface(SurfObj);
+    return Mask;
+}
+
 W32KAPI
 INT
 APIENTRY
@@ -496,8 +508,8 @@ NtGdiSetDIBitsToDeviceInternal(
     INT ret = 0;
     NTSTATUS Status = STATUS_SUCCESS;
     PDC pDC;
-    HBITMAP hSourceBitmap = NULL;
-    SURFOBJ *pDestSurf, *pSourceSurf = NULL;
+    HBITMAP hSourceBitmap = NULL, hMaskBitmap = NULL;
+    SURFOBJ *pDestSurf, *pSourceSurf = NULL, *pMaskSurf = NULL;
     SURFACE *pSurf;
     RECTL rcDest;
     POINTL ptSource;
@@ -530,24 +542,21 @@ NtGdiSetDIBitsToDeviceInternal(
         goto Exit2;
     }
 
+    ScanLines = min(ScanLines, abs(bmi->bmiHeader.biHeight) - StartScan);
+
     pDC = DC_LockDc(hDC);
     if (!pDC)
     {
         EngSetLastError(ERROR_INVALID_HANDLE);
         goto Exit2;
     }
+
     if (pDC->dctype == DC_TYPE_INFO)
     {
         DC_UnlockDc(pDC);
-        goto Exit2;
+        goto Exit;
     }
 
-    pSurf = pDC->dclevel.pSurface;
-
-    pDestSurf = pSurf ? &pSurf->SurfObj : NULL;
-
-    ScanLines = min(ScanLines, abs(bmi->bmiHeader.biHeight) - StartScan);
-
     rcDest.left = XDest;
     rcDest.top = YDest;
     if (bTransformCoordinates)
@@ -592,7 +601,27 @@ NtGdiSetDIBitsToDeviceInternal(
         goto Exit;
     }
 
-    ASSERT(pSurf->ppal);
+    /* HACK: If this is a RLE bitmap, only the relevant pixels must be set. */
+    if ((bmi->bmiHeader.biCompression == BI_RLE8) || (bmi->bmiHeader.biCompression == BI_RLE4))
+    {
+        hMaskBitmap = IntGdiCreateMaskFromRLE(bmi->bmiHeader.biWidth,
+            ScanLines,
+            bmi->bmiHeader.biCompression,
+            Bits,
+            cjMaxBits);
+        if (!hMaskBitmap)
+        {
+            EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
+            Status = STATUS_NO_MEMORY;
+            goto Exit;
+        }
+        pMaskSurf = EngLockSurface((HSURF)hMaskBitmap);
+        if (!pMaskSurf)
+        {
+            Status = STATUS_UNSUCCESSFUL;
+            goto Exit;
+        }
+    }
 
     /* Create a palette for the DIB */
     ppalDIB = CreateDIBPalette(bmi, pDC, ColorUse);
@@ -603,6 +632,18 @@ NtGdiSetDIBitsToDeviceInternal(
         goto Exit;
     }
 
+    /* This is actually a blit */
+    DC_vPrepareDCsForBlit(pDC, &rcDest, NULL, NULL);
+    pSurf = pDC->dclevel.pSurface;
+    if (!pSurf)
+    {
+        DC_vFinishBlit(pDC, NULL);
+        ret = ScanLines;
+        goto Exit;
+    }
+
+    ASSERT(pSurf->ppal);
+
     /* Initialize EXLATEOBJ */
     EXLATEOBJ_vInitialize(&exlo,
                           ppalDIB,
@@ -611,25 +652,30 @@ NtGdiSetDIBitsToDeviceInternal(
                           pDC->pdcattr->crBackgroundClr,
                           pDC->pdcattr->crForegroundClr);
 
+    pDestSurf = &pSurf->SurfObj;
+
     /* Copy the bits */
     DPRINT("BitsToDev with dstsurf=(%d|%d) (%d|%d), src=(%d|%d) w=%d h=%d\n",
            rcDest.left, rcDest.top, rcDest.right, rcDest.bottom,
            ptSource.x, ptSource.y, SourceSize.cx, SourceSize.cy);
     Status = IntEngBitBlt(pDestSurf,
                           pSourceSurf,
-                          NULL,
-                          pDC->rosdc.CombinedClip,
+                          pMaskSurf,
+                          &pDC->co.ClipObj,
                           &exlo.xlo,
                           &rcDest,
                           &ptSource,
+                          pMaskSurf ? &ptSource : NULL,
                           NULL,
                           NULL,
-                          NULL,
-                          ROP4_FROM_INDEX(R3_OPINDEX_SRCCOPY));
+                          pMaskSurf ? ROP4_MASK : ROP4_FROM_INDEX(R3_OPINDEX_SRCCOPY));
 
     /* Cleanup EXLATEOBJ */
     EXLATEOBJ_vCleanup(&exlo);
 
+    /* We're done */
+    DC_vFinishBlit(pDC, NULL);
+
 Exit:
     if (NT_SUCCESS(Status))
     {
@@ -640,9 +686,11 @@ Exit:
 
     if (pSourceSurf) EngUnlockSurface(pSourceSurf);
     if (hSourceBitmap) EngDeleteSurface((HSURF)hSourceBitmap);
+    if (pMaskSurf) EngUnlockSurface(pMaskSurf);
+    if (hMaskBitmap) EngDeleteSurface((HSURF)hMaskBitmap);
     DC_UnlockDc(pDC);
 Exit2:
-    ExFreePool(pbmiSafe);
+    ExFreePoolWithTag(pbmiSafe, 'pmTG');
     return ret;
 }
 
@@ -650,7 +698,7 @@ Exit2:
 /* Converts a device-dependent bitmap to a DIB */
 INT
 APIENTRY
-NtGdiGetDIBitsInternal(
+GreGetDIBitsInternal(
     HDC hDC,
     HBITMAP hBitmap,
     UINT StartScan,
@@ -669,36 +717,15 @@ NtGdiGetDIBitsInternal(
     DWORD compr, size ;
     USHORT i;
     int bitmap_type;
-    RGBTRIPLE* rgbTriples;
     RGBQUAD* rgbQuads;
     VOID* colorPtr;
-    NTSTATUS Status = STATUS_SUCCESS;
 
     DPRINT("Entered NtGdiGetDIBitsInternal()\n");
 
     if ((Usage && Usage != DIB_PAL_COLORS) || !Info || !hBitmap)
         return 0;
 
-    _SEH2_TRY
-    {
-        /* Probe for read and write */
-        ProbeForRead(Info, MaxInfo, 1);
-        ProbeForWrite(Info, MaxInfo, 1);
-        if (Bits) ProbeForWrite(Bits, MaxBits, 1);
-    }
-    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-    {
-        Status = _SEH2_GetExceptionCode();
-    }
-    _SEH2_END
-
-    if (!NT_SUCCESS(Status))
-    {
-        return 0;
-    }
-
     colorPtr = (LPBYTE)Info + Info->bmiHeader.biSize;
-    rgbTriples = colorPtr;
     rgbQuads = colorPtr;
 
     bitmap_type = DIB_GetBitmapInfo(&Info->bmiHeader,
@@ -747,15 +774,6 @@ NtGdiGetDIBitsInternal(
     switch(bpp)
     {
     case 0: /* Only info */
-        if(pbmci)
-        {
-            pbmci->bmciHeader.bcWidth = (WORD)psurf->SurfObj.sizlBitmap.cx;
-            pbmci->bmciHeader.bcHeight = (WORD)((psurf->SurfObj.fjBitmap & BMF_TOPDOWN) ?
-                                         -psurf->SurfObj.sizlBitmap.cy :
-                                         psurf->SurfObj.sizlBitmap.cy);
-            pbmci->bmciHeader.bcPlanes = 1;
-            pbmci->bmciHeader.bcBitCount = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
-        }
         Info->bmiHeader.biWidth = psurf->SurfObj.sizlBitmap.cx;
         Info->bmiHeader.biHeight = (psurf->SurfObj.fjBitmap & BMF_TOPDOWN) ?
                                    -psurf->SurfObj.sizlBitmap.cy :
@@ -806,31 +824,19 @@ NtGdiGetDIBitsInternal(
             if(Usage == DIB_RGB_COLORS)
             {
                 ULONG colors = min(psurf->ppal->NumColors, 256);
-
-                if(pbmci)
-                {
-                    for(i = 0; i < colors; i++)
-                    {
-                        rgbTriples[i].rgbtRed = psurf->ppal->IndexedColors[i].peRed;
-                        rgbTriples[i].rgbtGreen = psurf->ppal->IndexedColors[i].peGreen;
-                        rgbTriples[i].rgbtBlue = psurf->ppal->IndexedColors[i].peBlue;
-                    }
-                }
                 if(colors != 256) Info->bmiHeader.biClrUsed = colors;
                 for(i = 0; i < colors; i++)
                 {
                     rgbQuads[i].rgbRed = psurf->ppal->IndexedColors[i].peRed;
                     rgbQuads[i].rgbGreen = psurf->ppal->IndexedColors[i].peGreen;
                     rgbQuads[i].rgbBlue = psurf->ppal->IndexedColors[i].peBlue;
+                    rgbQuads[i].rgbReserved = 0;
                 }
             }
             else
             {
                 for(i = 0; i < 256; i++)
-                {
-                    if(pbmci) ((WORD*)rgbTriples)[i] = i;
                     ((WORD*)rgbQuads)[i] = i;
-                }
             }
         }
         else
@@ -839,7 +845,6 @@ NtGdiGetDIBitsInternal(
             {
                 for(i = 0; i < 256; i++)
                 {
-                    if(pbmci) ((WORD*)rgbTriples)[i] = i;
                     ((WORD*)rgbQuads)[i] = i;
                 }
             }
@@ -856,13 +861,6 @@ NtGdiGetDIBitsInternal(
                 }
                 for (i = 0; i < pDcPal->NumColors; i++)
                 {
-                    if (pbmci)
-                    {
-                        rgbTriples[i].rgbtRed   = pDcPal->IndexedColors[i].peRed;
-                        rgbTriples[i].rgbtGreen = pDcPal->IndexedColors[i].peGreen;
-                        rgbTriples[i].rgbtBlue  = pDcPal->IndexedColors[i].peBlue;
-                    }
-
                     rgbQuads[i].rgbRed      = pDcPal->IndexedColors[i].peRed;
                     rgbQuads[i].rgbGreen    = pDcPal->IndexedColors[i].peGreen;
                     rgbQuads[i].rgbBlue     = pDcPal->IndexedColors[i].peBlue;
@@ -875,55 +873,20 @@ NtGdiGetDIBitsInternal(
                 switch (bpp)
                 {
                 case 1:
-                    if (pbmci)
-                    {
-                        rgbTriples[0].rgbtRed = rgbTriples[0].rgbtGreen =
-                                                    rgbTriples[0].rgbtBlue = 0;
-                        rgbTriples[1].rgbtRed = rgbTriples[1].rgbtGreen =
-                                                    rgbTriples[1].rgbtBlue = 0xff;
-                    }
-                    rgbQuads[0].rgbRed = rgbQuads[0].rgbGreen =
-                                             rgbQuads[0].rgbBlue = 0;
+                    rgbQuads[0].rgbRed = rgbQuads[0].rgbGreen = rgbQuads[0].rgbBlue = 0;
                     rgbQuads[0].rgbReserved = 0;
-                    rgbQuads[1].rgbRed = rgbQuads[1].rgbGreen =
-                                             rgbQuads[1].rgbBlue = 0xff;
+                    rgbQuads[1].rgbRed = rgbQuads[1].rgbGreen = rgbQuads[1].rgbBlue = 0xff;
                     rgbQuads[1].rgbReserved = 0;
                     break;
 
                 case 4:
-                    if (pbmci)
-                        RtlCopyMemory(rgbTriples, EGAColorsTriples, sizeof(EGAColorsTriples));
                     RtlCopyMemory(rgbQuads, EGAColorsQuads, sizeof(EGAColorsQuads));
-
                     break;
 
                 case 8:
                 {
                     INT r, g, b;
                     RGBQUAD *color;
-                    if (pbmci)
-                    {
-                        RGBTRIPLE *colorTriple;
-
-                        RtlCopyMemory(rgbTriples, DefLogPaletteTriples,
-                                      10 * sizeof(RGBTRIPLE));
-                        RtlCopyMemory(rgbTriples + 246, DefLogPaletteTriples + 10,
-                                      10 * sizeof(RGBTRIPLE));
-                        colorTriple = rgbTriples + 10;
-                        for(r = 0; r <= 5; r++) /* FIXME */
-                        {
-                            for(g = 0; g <= 5; g++)
-                            {
-                                for(b = 0; b <= 5; b++)
-                                {
-                                    colorTriple->rgbtRed =   (r * 0xff) / 5;
-                                    colorTriple->rgbtGreen = (g * 0xff) / 5;
-                                    colorTriple->rgbtBlue =  (b * 0xff) / 5;
-                                    color++;
-                                }
-                            }
-                        }
-                    }
                     memcpy(rgbQuads, DefLogPaletteQuads,
                            10 * sizeof(RGBQUAD));
                     memcpy(rgbQuads + 246, DefLogPaletteQuads + 10,
@@ -1038,10 +1001,7 @@ NtGdiGetDIBitsInternal(
 
         psurfDest = SURFACE_ShareLockSurface(hBmpDest);
 
-        rcDest.left = 0;
-        rcDest.top = 0;
-        rcDest.bottom = ScanLines;
-        rcDest.right = psurf->SurfObj.sizlBitmap.cx;
+        RECTL_vSetRect(&rcDest, 0, 0, psurf->SurfObj.sizlBitmap.cx, ScanLines);
 
         srcPoint.x = 0;
 
@@ -1079,22 +1039,7 @@ NtGdiGetDIBitsInternal(
             ScanLines = 0;
         else
         {
-            Status = STATUS_SUCCESS;
-            _SEH2_TRY
-            {
-                RtlCopyMemory(Bits, pDIBits, DIB_GetDIBImageBytes (width, ScanLines, bpp));
-            }
-            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-            {
-                Status = _SEH2_GetExceptionCode();
-            }
-            _SEH2_END
-
-            if(!NT_SUCCESS(Status))
-            {
-                DPRINT1("Unable to copy bits to the user provided pointer\n");
-                ScanLines = 0;
-            }
+            RtlCopyMemory(Bits, pDIBits, DIB_GetDIBImageBytes (width, ScanLines, bpp));
         }
 
         GreDeleteObject(hBmpDest);
@@ -1106,11 +1051,120 @@ done:
 
     if(pDC) DC_UnlockDc(pDC);
     if(psurf) SURFACE_ShareUnlockSurface(psurf);
-    if(pbmci) DIB_FreeConvertedBitmapInfo(Info, (BITMAPINFO*)pbmci);
+    if(pbmci) DIB_FreeConvertedBitmapInfo(Info, (BITMAPINFO*)pbmci, Usage);
 
     return ScanLines;
 }
 
+INT
+APIENTRY
+NtGdiGetDIBitsInternal(
+    _In_ HDC hdc,
+    _In_ HBITMAP hbm,
+    _In_ UINT iStartScan,
+    _In_ UINT cScans,
+    _Out_opt_ LPBYTE pjBits,
+    _Inout_ LPBITMAPINFO pbmiUser,
+    _In_ UINT iUsage,
+    _In_ UINT cjMaxBits,
+    _In_ UINT cjMaxInfo)
+{
+    PBITMAPINFO pbmi;
+    HANDLE hSecure = NULL;
+    INT iResult = 0;
+    UINT cjAlloc;
+
+    /* Check for bad iUsage */
+    if (iUsage > 2) return 0;
+
+    /* Check if the size of the bitmap info is large enough */
+    if (cjMaxInfo < sizeof(BITMAPCOREHEADER))
+    {
+        return 0;
+    }
+
+    /* Use maximum size */
+    cjMaxInfo = min(cjMaxInfo, sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD));
+
+    // HACK: the underlying code sucks and doesn't care for the size, so we
+    // give it the maximum ever needed
+    cjAlloc = sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD);
+
+    /* Allocate a buffer the bitmapinfo */
+    pbmi = ExAllocatePoolWithTag(PagedPool, cjAlloc, 'imBG');
+    if (!pbmi)
+    {
+        /* Fail */
+        return 0;
+    }
+
+    /* Use SEH */
+    _SEH2_TRY
+    {
+        /* Probe and copy the BITMAPINFO */
+        ProbeForRead(pbmiUser, cjMaxInfo, 1);
+        RtlCopyMemory(pbmi, pbmiUser, cjMaxInfo);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        _SEH2_YIELD(goto cleanup;)
+    }
+    _SEH2_END;
+
+    /* Check if the header size is large enough */
+    if ((pbmi->bmiHeader.biSize < sizeof(BITMAPCOREHEADER)) ||
+        (pbmi->bmiHeader.biSize > cjMaxInfo))
+    {
+        goto cleanup;
+    }
+
+    /* Check if the caller provided bitmap bits */
+    if (pjBits)
+    {
+        /* Secure the user mode memory */
+        hSecure = EngSecureMem(pjBits, cjMaxBits);
+        if (!hSecure)
+        {
+            goto cleanup;
+        }
+    }
+
+    /* Now call the internal function */
+    iResult = GreGetDIBitsInternal(hdc,
+                                   hbm,
+                                   iStartScan,
+                                   cScans,
+                                   pjBits,
+                                   pbmi,
+                                   iUsage,
+                                   cjMaxBits,
+                                   cjMaxInfo);
+
+    /* Check for success */
+    if (iResult)
+    {
+        /* Use SEH to copy back to user mode */
+        _SEH2_TRY
+        {
+            /* Copy the data back */
+            ProbeForWrite(pbmiUser, cjMaxInfo, 1);
+            RtlCopyMemory(pbmiUser, pbmi, cjMaxInfo);
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Ignore */
+        }
+        _SEH2_END;
+    }
+
+cleanup:
+    if (hSecure) EngUnsecureMem(hSecure);
+    ExFreePoolWithTag(pbmi, 'imBG');
+
+    return iResult;
+}
+
+
 #define ROP_TO_ROP4(Rop) ((Rop) >> 16)
 
 W32KAPI
@@ -1150,6 +1204,14 @@ NtGdiStretchDIBitsInternal(
         return 0;
     }
 
+    /* Check for info / mem DC without surface */
+    if (!pdc->dclevel.pSurface)
+    {
+        DC_UnlockDc(pdc);
+        // CHECKME
+        return TRUE;
+    }
+
     /* Transform dest size */
     sizel.cx = cxDst;
     sizel.cy = cyDst;
@@ -1178,22 +1240,30 @@ NtGdiStretchDIBitsInternal(
                                               hcmXform);
     }
 
-    pvBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, 'pmeT');
-    if (!pvBits)
+    if (pjInit && (cjMaxBits > 0))
     {
-        return 0;
-    }
+        pvBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, 'pmeT');
+        if (!pvBits)
+        {
+            return 0;
+        }
 
-    _SEH2_TRY
-    {
-        ProbeForRead(pjInit, cjMaxBits, 1);
-        RtlCopyMemory(pvBits, pjInit, cjMaxBits);
+        _SEH2_TRY
+        {
+            ProbeForRead(pjInit, cjMaxBits, 1);
+            RtlCopyMemory(pvBits, pjInit, cjMaxBits);
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            ExFreePoolWithTag(pvBits, 'pmeT');
+            _SEH2_YIELD(return 0);
+        }
+        _SEH2_END
     }
-    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    else
     {
-        _SEH2_YIELD(return 0);
+        pvBits = NULL;
     }
-    _SEH2_END
 
     /* FIXME: Locking twice is cheesy, coord tranlation in UM will fix it */
     if (!(pdc = DC_LockDc(hdc)))
@@ -1203,14 +1273,6 @@ NtGdiStretchDIBitsInternal(
         goto cleanup;
     }
 
-    psurfDst = pdc->dclevel.pSurface;
-    if (!psurfDst)
-    {
-        // CHECKME
-        bResult = TRUE;
-        goto cleanup;
-    }
-
     /* Calculate source and destination rect */
     rcSrc.left = xSrc;
     rcSrc.top = ySrc;
@@ -1254,6 +1316,11 @@ NtGdiStretchDIBitsInternal(
         goto cleanup;
     }
 
+    /* Prepare DC for blit */
+    DC_vPrepareDCsForBlit(pdc, &rcDst, NULL, NULL);
+
+    psurfDst = pdc->dclevel.pSurface;
+
     /* Initialize XLATEOBJ */
     EXLATEOBJ_vInitialize(&exlo,
                           ppalDIB,
@@ -1262,15 +1329,13 @@ NtGdiStretchDIBitsInternal(
                           pdc->pdcattr->crBackgroundClr,
                           pdc->pdcattr->crForegroundClr);
 
-    /* Prepare DC for blit */
-    DC_vPrepareDCsForBlit(pdc, rcDst, NULL, rcSrc);
-
     /* Perform the stretch operation */
     bResult = IntEngStretchBlt(&psurfDst->SurfObj,
                                &psurfTmp->SurfObj,
                                NULL,
-                               pdc->rosdc.CombinedClip,
+                               &pdc->co.ClipObj,
                                &exlo.xlo,
+                               &pdc->dclevel.ca,
                                &rcDst,
                                &rcSrc,
                                NULL,
@@ -1286,7 +1351,7 @@ cleanup:
     if (psurfTmp) SURFACE_ShareUnlockSurface(psurfTmp);
     if (hbmTmp) GreDeleteObject(hbmTmp);
     if (pdc) DC_UnlockDc(pdc);
-    ExFreePoolWithTag(pvBits, 'pmeT');
+    if (pvBits) ExFreePoolWithTag(pvBits, 'pmeT');
 
     return bResult;
 }
@@ -1377,6 +1442,7 @@ NtGdiCreateDIBitmapInternal(
 
     if(pjInit && (fInit == CBM_INIT))
     {
+        if (cjMaxBits == 0) return NULL;
         safeBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, TAG_DIB);
         if(!safeBits)
         {
@@ -1559,7 +1625,7 @@ DIB_CreateDIBSection(
     HBITMAP res = 0;
     SURFACE *bmp = NULL;
     void *mapBits = NULL;
-    PPALETTE ppalDIB;
+    PPALETTE ppalDIB = NULL;
 
     // Fill BITMAP32 structure with DIB data
     CONST BITMAPINFOHEADER *bi = &bmi->bmiHeader;
@@ -1569,7 +1635,7 @@ DIB_CreateDIBSection(
     //SIZEL Size;
     HANDLE hSecure;
 
-    DPRINT("format (%ld,%ld), planes %d, bpp %d, size %ld, colors %ld (%s)\n",
+    DPRINT("format (%ld,%ld), planes %u, bpp %u, size %lu, colors %lu (%s)\n",
            bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount,
            bi->biSizeImage, bi->biClrUsed, usage == DIB_PAL_COLORS? "PAL" : "RGB");
 
@@ -1693,17 +1759,12 @@ DIB_CreateDIBSection(
 
     /* Create a palette for the DIB */
     ppalDIB = CreateDIBPalette(bmi, dc, usage);
-    if (ppalDIB)
-    {
-        if (bmp->ppal) PALETTE_ShareUnlockPalette(bmp->ppal);
-        bmp->ppal = ppalDIB;
-    }
 
     // Clean up in case of errors
 cleanup:
-    if (!res || !bmp || !bm.bmBits)
+    if (!res || !bmp || !bm.bmBits || !ppalDIB)
     {
-        DPRINT("Got an error res=%08x, bmp=%p, bm.bmBits=%p\n", res, bmp, bm.bmBits);
+        DPRINT("Got an error res=%p, bmp=%p, bm.bmBits=%p\n", res, bmp, bm.bmBits);
         if (bm.bmBits)
         {
             // MmUnsecureVirtualMemory(hSecure); // FIXME: Implement this!
@@ -1717,17 +1778,28 @@ cleanup:
         }
 
         if (bmp)
+        {
+            SURFACE_ShareUnlockSurface(bmp);
             bmp = NULL;
+        }
 
         if (res)
         {
             GreDeleteObject(res);
             res = 0;
         }
+
+        if(ppalDIB)
+        {
+            PALETTE_ShareUnlockPalette(ppalDIB);
+        }
     }
 
     if (bmp)
     {
+        /* If we're here, everything went fine */
+        SURFACE_vSetPalette(bmp, ppalDIB);
+        PALETTE_ShareUnlockPalette(ppalDIB);
         SURFACE_ShareUnlockSurface(bmp);
     }
 
@@ -1772,7 +1844,7 @@ DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
         *size   = header->biSizeImage;
         return 1;
     }
-    DPRINT1("(%d): unknown/wrong size for header\n", header->biSize );
+    DPRINT1("(%u): unknown/wrong size for header\n", header->biSize );
     return -1;
 }
 
@@ -1927,10 +1999,51 @@ DIB_ConvertBitmapInfo (CONST BITMAPINFO* pbmi, DWORD Usage)
 /* Frees a BITMAPINFO created with DIB_ConvertBitmapInfo */
 VOID
 FASTCALL
-DIB_FreeConvertedBitmapInfo(BITMAPINFO* converted, BITMAPINFO* orig)
+DIB_FreeConvertedBitmapInfo(BITMAPINFO* converted, BITMAPINFO* orig, DWORD usage)
 {
-    if(converted != orig)
+    BITMAPCOREINFO* pbmci;
+    if(converted == orig)
+        return;
+
+    if(usage == -1)
+    {
+        /* Caller don't want any conversion */
         ExFreePoolWithTag(converted, TAG_DIB);
+        return;
+    }
+
+    /* Perform inverse conversion */
+    pbmci = (BITMAPCOREINFO*)orig;
+
+    ASSERT(pbmci->bmciHeader.bcSize == sizeof(BITMAPCOREHEADER));
+    pbmci->bmciHeader.bcBitCount = converted->bmiHeader.biBitCount;
+    pbmci->bmciHeader.bcWidth = converted->bmiHeader.biWidth;
+    pbmci->bmciHeader.bcHeight = converted->bmiHeader.biHeight;
+    pbmci->bmciHeader.bcPlanes = converted->bmiHeader.biPlanes;
+
+    if(pbmci->bmciHeader.bcBitCount <= 8)
+    {
+        UINT numColors = converted->bmiHeader.biClrUsed;
+        if(!numColors) numColors = 1 << pbmci->bmciHeader.bcBitCount;
+        if(usage == DIB_PAL_COLORS)
+        {
+            RtlZeroMemory(pbmci->bmciColors, (1 << pbmci->bmciHeader.bcBitCount) * sizeof(WORD));
+            RtlCopyMemory(pbmci->bmciColors, converted->bmiColors, numColors * sizeof(WORD));
+        }
+        else
+        {
+            UINT i;
+            RtlZeroMemory(pbmci->bmciColors, (1 << pbmci->bmciHeader.bcBitCount) * sizeof(RGBTRIPLE));
+            for(i=0; i<numColors; i++)
+            {
+                pbmci->bmciColors[i].rgbtRed = converted->bmiColors[i].rgbRed;
+                pbmci->bmciColors[i].rgbtGreen = converted->bmiColors[i].rgbGreen;
+                pbmci->bmciColors[i].rgbtBlue = converted->bmiColors[i].rgbBlue;
+            }
+        }
+    }
+    /* Now free it, it's not needed anymore */
+    ExFreePoolWithTag(converted, TAG_DIB);
 }
 
 /* EOF */