[PATCH] Fixed CURSORICON_CreateIconFromBMI to preserve the alpha channel

Joel Holdsworth joel at airwebreathe.org.uk
Tue Jun 2 16:05:14 CDT 2009


---
 dlls/user32/cursoricon.c |  159 ++++++++++++++++++++++++++++++++--------------
 1 files changed, 112 insertions(+), 47 deletions(-)

diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c
index 92446e1..e13bb0c 100644
--- a/dlls/user32/cursoricon.c
+++ b/dlls/user32/cursoricon.c
@@ -659,6 +659,39 @@ static CURSORICONFILEDIRENTRY *CURSORICON_FindBestIconFile( CURSORICONFILEDIR *d
     return &dir->idEntries[n];
 }
 
+/***********************************************************************
+ *          stretch_blt_icon
+ *
+ * A helper function that stretches a bitmap buffer into an HBITMAP.
+ * 
+ * PARAMS
+ *      hDest       [I] The handle of the destination bitmap.
+ *      pDestInfo   [I] The BITMAPINFO of the destination bitmap.
+ *      pSrcInfo    [I] The BITMAPINFO of the source bitmap.
+ *      pSrcBits    [I] A pointer to the source bitmap buffer.
+ **/
+static BOOL stretch_blt_icon(HBITMAP hDest, BITMAPINFO *pDestInfo, BITMAPINFO *pSrcInfo, char *pSrcBits)
+{
+    HBITMAP hOld;
+    BOOL res = FALSE;
+    static HDC hdcMem = NULL;
+
+    if (!hdcMem)
+        hdcMem = CreateCompatibleDC(screen_dc);
+
+    if (hdcMem)
+    {
+        hOld = SelectObject(hdcMem, hDest);
+        res = StretchDIBits(hdcMem,
+                            0, 0, pDestInfo->bmiHeader.biWidth, pDestInfo->bmiHeader.biHeight,
+                            0, 0, pSrcInfo->bmiHeader.biWidth, pSrcInfo->bmiHeader.biHeight,
+                            pSrcBits, pSrcInfo, DIB_RGB_COLORS, SRCCOPY);
+        SelectObject(hdcMem, hOld);
+    }
+
+    return res;
+}
+
 static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
 					   POINT16 hotspot, BOOL bIcon,
 					   DWORD dwVersion,
@@ -666,7 +699,6 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
 					   UINT cFlag )
 {
     HGLOBAL16 hObj;
-    static HDC hdcMem;
     int sizeAnd, sizeXor;
     HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
     BITMAP bmpXor, bmpAnd;
@@ -706,7 +738,7 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
     if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
     if (screen_dc)
     {
-        BITMAPINFO* pInfo;
+        BITMAPINFO *pSrcInfo, *pDestInfo;
 
         /* Make sure we have room for the monochrome bitmap later on.
          * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
@@ -719,40 +751,78 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
          *   BYTE            icAND[]      // DIB bits for AND mask
          */
 
-        if ((pInfo = HeapAlloc( GetProcessHeap(), 0,
-                                max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))))
+        pSrcInfo = HeapAlloc( GetProcessHeap(), 0,
+                              max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)));
+        pDestInfo = HeapAlloc( GetProcessHeap(), 0,
+                              max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)));
+        if (pSrcInfo && pDestInfo)
         {
-            memcpy( pInfo, bmi, size );
-            pInfo->bmiHeader.biHeight /= 2;
+            memcpy( pSrcInfo, bmi, size );
+            pSrcInfo->bmiHeader.biHeight /= 2;
+            memcpy( pDestInfo, bmi, size );
+
+            pDestInfo->bmiHeader.biWidth = width;
+            pDestInfo->bmiHeader.biHeight = height;
+            pDestInfo->bmiHeader.biSizeImage = 0;
 
             /* Create the XOR bitmap */
+            if(pSrcInfo->bmiHeader.biBitCount == 32)
+            {
+                UINT32 *dibBuffer = NULL;
+
+                pDestInfo->bmiHeader.biSizeImage = get_dib_width_bytes( pDestInfo->bmiHeader.biWidth,
+                    pDestInfo->bmiHeader.biBitCount ) * abs( pDestInfo->bmiHeader.biHeight );
+
+                /* If this is a 32-bpp bitmap, we need to use a dib section
+                   so that the alpha channel is preserved */
+                hXorBits = CreateDIBSection(screen_dc, pDestInfo, DIB_RGB_COLORS, (void**)&dibBuffer, NULL, 0);
 
-            if (DoStretch) {
-                hXorBits = CreateCompatibleBitmap(screen_dc, width, height);
                 if(hXorBits)
                 {
-                HBITMAP hOld;
-                BOOL res = FALSE;
-
-                if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
-                if (hdcMem) {
-                    hOld = SelectObject(hdcMem, hXorBits);
-                    res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
-                                        bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
-                                        (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
-                    SelectObject(hdcMem, hOld);
+                    if(DoStretch)
+                    {
+                        if(pSrcInfo->bmiHeader.biBitCount == 32)
+                        {
+                            /* FIXME: StretchDIBits currently draws via X11, which does
+                             * not preserve the alpha channel.
+                             */
+                            FIXME("StretchDIBits will not preserve the alpha channel.\n");
+                        }
+
+                        if (!stretch_blt_icon(hXorBits, pDestInfo, pSrcInfo, (char*)bmi + size))
+                        {
+                            DeleteObject(hXorBits);
+                            hXorBits = 0;
+                        }
+                    }
+                    else
+                    {
+                        if(dibBuffer)
+                            memcpy(dibBuffer, (char*)bmi + size, pDestInfo->bmiHeader.biSizeImage);
+                        else
+                        {
+                            DeleteObject(hXorBits);
+                            hXorBits = 0;
+                            ERR("dibBuffer should not have been NULL");
+                        }
+                    }
+                }
+            }
+            else
+            {
+                if(DoStretch)
+                {
+                    hXorBits = CreateCompatibleBitmap(screen_dc, width, height);
+
+                    if (!stretch_blt_icon(hXorBits, pDestInfo, pSrcInfo, (char*)bmi + size))
+                    {
+                        DeleteObject(hXorBits);
+                        hXorBits = 0;
+                    }
                 }
-                if (!res) { DeleteObject(hXorBits); hXorBits = 0; }
-              }
-            } else {
-              if (is_dib_monochrome(bmi)) {
-                  hXorBits = CreateBitmap(width, height, 1, 1, NULL);
-                  SetDIBits(screen_dc, hXorBits, 0, height,
-                     (char*)bmi + size, pInfo, DIB_RGB_COLORS);
-              }
-              else
-                  hXorBits = CreateDIBitmap(screen_dc, &pInfo->bmiHeader,
-                     CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS); 
+                else
+                    hXorBits = CreateDIBitmap(screen_dc, &pSrcInfo->bmiHeader,
+                        CBM_INIT, (char*)bmi + size, pSrcInfo, DIB_RGB_COLORS);
             }
 
             if( hXorBits )
@@ -761,19 +831,19 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
                     get_dib_width_bytes( bmi->bmiHeader.biWidth,
                                          bmi->bmiHeader.biBitCount ) * abs( bmi->bmiHeader.biHeight ) / 2;
 
-                pInfo->bmiHeader.biBitCount = 1;
-                if (pInfo->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
+                pSrcInfo->bmiHeader.biBitCount = 1;
+                if (pSrcInfo->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
                 {
-                    RGBQUAD *rgb = pInfo->bmiColors;
+                    RGBQUAD *rgb = pSrcInfo->bmiColors;
 
-                    pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
+                    pSrcInfo->bmiHeader.biClrUsed = pSrcInfo->bmiHeader.biClrImportant = 2;
                     rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
                     rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
                     rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
                 }
                 else
                 {
-                    RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
+                    RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pSrcInfo) + 1);
 
                     rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
                     rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
@@ -783,29 +853,24 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
 
             if (DoStretch) {
               if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL))) {
-                HBITMAP hOld;
-                BOOL res = FALSE;
-
-                if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
-                if (hdcMem) {
-                    hOld = SelectObject(hdcMem, hAndBits);
-                    res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
-                                        pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight,
-                                        xbits, pInfo, DIB_RGB_COLORS, SRCCOPY);
-                    SelectObject(hdcMem, hOld);
+                if (!stretch_blt_icon(hAndBits, pDestInfo, pSrcInfo, xbits))
+                {
+                    DeleteObject(hAndBits);
+                    hAndBits = 0;
                 }
-                if (!res) { DeleteObject(hAndBits); hAndBits = 0; }
               }
             } else {
               hAndBits = CreateBitmap(width, height, 1, 1, NULL);
 
               if (hAndBits) SetDIBits(screen_dc, hAndBits, 0, height,
-                             xbits, pInfo, DIB_RGB_COLORS);
+                             xbits, pSrcInfo, DIB_RGB_COLORS);
 
             }
                 if( !hAndBits ) DeleteObject( hXorBits );
             }
-            HeapFree( GetProcessHeap(), 0, pInfo );
+
+            HeapFree( GetProcessHeap(), 0, pSrcInfo );
+            HeapFree( GetProcessHeap(), 0, pDestInfo );
         }
     }
 
-- 
1.6.0.4


--=-BZQCtUG7Nz/qsg8UfIfN--





More information about the wine-devel mailing list