Hi All,

I've been working on alpha support in HICONs and HIMAGELISTs. This patch
set includes my earlier test patch (plus modifications as per the
comments), and fixes up DrawIcon, DrawIconEx and
CURSORICON_CreateIconFromBMI.

I've tested the test patch on 2k, XP, and Vista - but any other test
platforms would be welcome, and any comments on the other 4 patches
before I submit them.

Best Regards
Joel Holdsworth 
>From d22ba983b85028f667a7754858f35c7e219847e9 Mon Sep 17 00:00:00 2001
From: Joel Holdsworth <j...@airwebreathe.org.uk>
Date: Tue, 2 Jun 2009 21:13:47 +0100
Subject: [PATCH] Added tests for DrawIcon and DrawIconEx

---
 dlls/user32/tests/cursoricon.c |  355 ++++++++++++++++++++++++++++++++++++++++
 1 files changed, 355 insertions(+), 0 deletions(-)

diff --git a/dlls/user32/tests/cursoricon.c b/dlls/user32/tests/cursoricon.c
index 9475534..4caf442 100644
--- a/dlls/user32/tests/cursoricon.c
+++ b/dlls/user32/tests/cursoricon.c
@@ -956,6 +956,359 @@ static void test_CreateIconFromResource(void)
     HeapFree(GetProcessHeap(), 0, hotspot);
 }
 
+static HICON create_test_icon(HDC hdc, int width, int height, int bpp,
+                              BOOL maskvalue, UINT32 *color, int colorSize)
+{
+    ICONINFO iconInfo;
+    BITMAPINFO bitmapInfo;
+    UINT32 *buffer = NULL;
+    UINT32 mask = maskvalue ? 0xFFFFFFFF : 0x00000000;
+
+    memset(&bitmapInfo, 0, sizeof(bitmapInfo));
+    bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+    bitmapInfo.bmiHeader.biWidth = width;
+    bitmapInfo.bmiHeader.biHeight = height;
+    bitmapInfo.bmiHeader.biPlanes = 1;
+    bitmapInfo.bmiHeader.biBitCount = bpp;
+    bitmapInfo.bmiHeader.biCompression = BI_RGB;
+    bitmapInfo.bmiHeader.biSizeImage = colorSize;
+
+    iconInfo.fIcon = TRUE;
+    iconInfo.xHotspot = 0;
+    iconInfo.yHotspot = 0;
+
+    iconInfo.hbmMask = CreateBitmap( width, height, 1, 1, &mask );
+    if(!iconInfo.hbmMask) return NULL;
+
+    iconInfo.hbmColor = CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, (void**)&buffer, NULL, 0);
+    if(!iconInfo.hbmColor || !buffer)
+    {
+        DeleteObject(iconInfo.hbmMask);
+        return NULL;
+    }
+
+    memcpy(buffer, color, colorSize);
+
+    return CreateIconIndirect(&iconInfo);
+}
+
+static void flood_background(HDC hdc, int width, int height, COLORREF color)
+{
+    RECT rect = {0, 0, 1, 1};
+    HBRUSH backgroundBrush = CreateSolidBrush(color);
+    FillRect(hdc, &rect, backgroundBrush);
+    DeleteObject(backgroundBrush);
+}
+
+static void check_DrawIcon(HDC hdc, BOOL maskvalue, UINT32 color, int bpp,
+                            COLORREF background, COLORREF expected, int line)
+{
+    COLORREF result;
+    HICON hicon = create_test_icon(hdc, 1, 1, bpp, maskvalue, &color, sizeof(color));
+    if (!hicon) return;
+    flood_background(hdc, 1, 1, background);
+    DrawIcon(hdc, 0, 0, hicon);
+    result = GetPixel(hdc, 0, 0);
+
+    ok (result == expected,
+        "Overlaying Mask %d on Color %08X with DrawIcon. Expected %08X. Got %08X from line %d\n",
+        maskvalue, (unsigned int)color, (unsigned int)expected, (unsigned int)result, line);
+}
+
+static void check_DrawIconEx(HDC hdc, BOOL maskvalue, UINT32 color, int bpp, UINT flags, 
+                               COLORREF background, COLORREF expected, int line)
+{
+    COLORREF result;
+    HICON hicon = create_test_icon(hdc, 1, 1, bpp, maskvalue, &color, sizeof(color));
+    if (!hicon) return;
+    flood_background(hdc, 1, 1, background);
+    DrawIconEx(hdc, 0, 0, hicon, 1, 1, 0, NULL, flags);
+    result = GetPixel(hdc, 0, 0);
+
+    ok (result == expected,
+        "Overlaying Mask %d on Color %08X with DrawIconEx flags %08X. Expected %08X. Got %08X from line %d\n",
+        maskvalue, (unsigned int)color, flags, (unsigned int)expected, (unsigned int)result, line);
+}
+
+static void check_alpha_draw(HDC hdc, BOOL drawiconex, BOOL alpha, int bpp, int line)
+{
+    HICON hicon;
+    UINT32 mask;
+    UINT32 color[2];
+    COLORREF expected, result;
+
+    mask = 0x00000000;
+    color[0] = 0x00A0B0C0;
+    color[1] = alpha ? 0xFF000000 : 0x00000000;
+    expected = alpha ? 0x00FFFFFF : 0x00C0B0A0;
+
+    hicon = create_test_icon(hdc, 2, 1, bpp, 0, (UINT32*)&color, sizeof(color));
+    if (!hicon) return;
+
+    flood_background(hdc, 1, 1, 0x00FFFFFF);
+
+    if(drawiconex)
+        DrawIconEx(hdc, 0, 0, hicon, 2, 1, 0, NULL, DI_NORMAL);
+    else
+        DrawIcon(hdc, 0, 0, hicon);
+
+    result = GetPixel(hdc, 0, 0);
+    ok (result == expected,
+        "%s. Expected %08X with %s. Got %08X from line %d\n",
+        alpha ? "Alpha blending" : "Not alpha blending",
+        (unsigned int)expected, drawiconex ? "DrawIconEx" : "DrawIcon",
+        (unsigned int)result, line);
+}
+
+static void test_DrawIcon_true_color(HDC hdcDst)
+{
+    DWORD dwVersion = GetVersion();
+    DWORD dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
+    DWORD dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
+
+    /* Mask is only heeded if alpha channel is always zero */
+    check_DrawIcon(hdcDst, FALSE, 0x00A0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, __LINE__);
+    check_DrawIcon(hdcDst, TRUE, 0x00A0B0C0, 32, 0x00FFFFFF, 0x003F4F5F, __LINE__);
+
+    /* Test alpha blending */
+    /* Applicable to XP and up */
+    if(dwMajorVersion > 5 || dwMinorVersion >= 1)
+    {
+        check_DrawIcon(hdcDst, FALSE, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, __LINE__);
+
+        todo_wine
+        {
+            check_DrawIcon(hdcDst, TRUE, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, __LINE__);
+
+            check_DrawIcon(hdcDst, FALSE, 0x80A0B0C0, 32, 0x00000000, 0x00605850, __LINE__);
+            check_DrawIcon(hdcDst, TRUE, 0x80A0B0C0, 32, 0x00000000, 0x00605850, __LINE__);
+            check_DrawIcon(hdcDst, FALSE, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, __LINE__);
+            check_DrawIcon(hdcDst, TRUE, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, __LINE__);
+
+            check_DrawIcon(hdcDst, FALSE, 0x01FFFFFF, 32, 0x00000000, 0x00010101, __LINE__);
+            check_DrawIcon(hdcDst, TRUE, 0x01FFFFFF, 32, 0x00000000, 0x00010101, __LINE__);
+            check_DrawIcon(hdcDst, FALSE, 0xFEFFFFFF, 32, 0x00000000, 0x00FEFEFE, __LINE__);
+            check_DrawIcon(hdcDst, TRUE, 0xFEFFFFFF, 32, 0x00000000, 0x00FEFEFE, __LINE__);
+        }
+
+        /* Test detecting of alpha channel */
+        /* If a single pixel's alpha channel is non-zero, the icon
+           will be alpha blended, otherwise it will be draw with
+           and + xor blts. */
+        check_alpha_draw(hdcDst, FALSE, FALSE, 32, __LINE__);
+        todo_wine check_alpha_draw(hdcDst, FALSE, TRUE, 32, __LINE__);
+    }
+}
+
+static void test_DrawIcon()
+{
+    BITMAPINFO bitmapInfo;
+    HDC hdcDst = NULL;
+    HBITMAP bmpDst = NULL;
+    HBITMAP bmpOld = NULL;
+    UINT32 *bits = 0;
+
+    hdcDst = CreateCompatibleDC(0);
+    if (!hdcDst)
+        return;
+
+    memset(&bitmapInfo, 0, sizeof(bitmapInfo));
+    bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+    bitmapInfo.bmiHeader.biWidth = 1;
+    bitmapInfo.bmiHeader.biHeight = 1;
+    bitmapInfo.bmiHeader.biPlanes = 1;
+    bitmapInfo.bmiHeader.biCompression = BI_RGB;
+    bitmapInfo.bmiHeader.biSizeImage = sizeof(UINT32);
+
+    /* 16-bit Tests */
+    bitmapInfo.bmiHeader.biBitCount = 16;
+    bmpDst = CreateDIBSection(hdcDst, &bitmapInfo, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+    if (!bmpDst || !bits)
+        goto cleanup;
+    bmpOld = SelectObject(hdcDst, bmpDst);
+
+    check_DrawIcon(hdcDst, FALSE, 0x00A0B0C0, 16, 0x00FFFFFF, 0x00003163, __LINE__);
+    check_DrawIcon(hdcDst, TRUE, 0x00A0B0C0, 16, 0x00FFFFFF, 0x00FFCE9C, __LINE__);
+
+    check_DrawIcon(hdcDst, FALSE, 0xFFA0B0C0, 16, 0x00FFFFFF, 0x00003163, __LINE__);
+    check_DrawIcon(hdcDst, TRUE, 0xFFA0B0C0, 16, 0x00FFFFFF, 0x00FFCE9C, __LINE__);
+    check_DrawIcon(hdcDst, FALSE, 0x80A0B0C0, 16, 0x00FFFFFF, 0x00003163, __LINE__);
+    check_DrawIcon(hdcDst, TRUE, 0x80A0B0C0, 16, 0x00FFFFFF, 0x00FFCE9C, __LINE__);
+
+    SelectObject(hdcDst, bmpOld);
+    DeleteObject(bmpDst);
+    bmpOld = NULL;
+    bmpDst = NULL;
+
+    /* 24-bit Tests */
+    bitmapInfo.bmiHeader.biBitCount = 24;
+    bmpDst = CreateDIBSection(hdcDst, &bitmapInfo, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+    if (!bmpDst || !bits)
+        goto cleanup;
+    bmpOld = SelectObject(hdcDst, bmpDst);
+
+    test_DrawIcon_true_color(hdcDst);
+
+    SelectObject(hdcDst, bmpOld);
+    DeleteObject(bmpDst);
+    bmpOld = NULL;
+    bmpDst = NULL;
+
+    /* 32-bit Tests */
+    bitmapInfo.bmiHeader.biBitCount = 32;
+    bmpDst = CreateDIBSection(hdcDst, &bitmapInfo, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+    if (!bmpDst || !bits)
+        goto cleanup;
+    bmpOld = SelectObject(hdcDst, bmpDst);
+
+    test_DrawIcon_true_color(hdcDst);
+
+    SelectObject(hdcDst, bmpOld);
+    DeleteObject(bmpDst);
+    bmpOld = NULL;
+    bmpDst = NULL;
+
+cleanup:
+    if(bmpOld)
+        SelectObject(hdcDst, bmpOld);
+    if(bmpDst)
+        DeleteObject(bmpDst);
+    if(hdcDst)
+        DeleteDC(hdcDst);
+}
+
+static void test_DrawIconEx_true_color(HDC hdcDst)
+{
+    DWORD dwVersion = GetVersion();
+    DWORD dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
+    DWORD dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
+
+    /* Test null, image only, and mask only drawing */
+    todo_wine
+    {
+        check_DrawIconEx(hdcDst, FALSE, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, __LINE__);
+        check_DrawIconEx(hdcDst, TRUE, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, __LINE__);
+    }
+
+    check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_MASK, 0x00FFFFFF, 0x00000000, __LINE__);
+    check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_MASK, 0x00FFFFFF, 0x00FFFFFF, __LINE__);
+
+    todo_wine
+    {
+        check_DrawIconEx(hdcDst, FALSE, 0x00A0B0C0, 32, DI_IMAGE, 0x00FFFFFF, 0x00C0B0A0, __LINE__);
+        check_DrawIconEx(hdcDst, TRUE, 0x00A0B0C0, 32, DI_IMAGE, 0x00FFFFFF, 0x00C0B0A0, __LINE__);
+    }
+
+    /* Test normal drawing */
+    check_DrawIconEx(hdcDst, FALSE, 0x00A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00C0B0A0, __LINE__);
+    todo_wine check_DrawIconEx(hdcDst, TRUE, 0x00A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x003F4F5F, __LINE__);
+    check_DrawIconEx(hdcDst, FALSE, 0xFFA0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00C0B0A0, __LINE__);
+
+    /* Test alpha blending */
+    /* Applicable to XP and up */
+    if(dwMajorVersion > 5 || dwMinorVersion >= 1)
+    {
+        todo_wine
+        {
+            check_DrawIconEx(hdcDst, TRUE, 0xFFA0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00C0B0A0, __LINE__);
+
+            check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_NORMAL, 0x00000000, 0x00605850, __LINE__);
+            check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_NORMAL, 0x00000000, 0x00605850, __LINE__);
+            check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00DFD7CF, __LINE__);
+            check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00DFD7CF, __LINE__);
+
+            check_DrawIconEx(hdcDst, FALSE, 0x01FFFFFF, 32, DI_NORMAL, 0x00000000, 0x00010101, __LINE__);
+            check_DrawIconEx(hdcDst, TRUE, 0x01FFFFFF, 32, DI_NORMAL, 0x00000000, 0x00010101, __LINE__);
+            check_DrawIconEx(hdcDst, FALSE, 0xFEFFFFFF, 32, DI_NORMAL, 0x00000000, 0x00FEFEFE, __LINE__);
+            check_DrawIconEx(hdcDst, TRUE, 0xFEFFFFFF, 32, DI_NORMAL, 0x00000000, 0x00FEFEFE, __LINE__);
+        }
+
+        /* Test detecting of alpha channel */
+        /* If a single pixel's alpha channel is non-zero, the icon
+           will be alpha blended, otherwise it will be draw with
+           and + xor blts. */
+        check_alpha_draw(hdcDst, TRUE, FALSE, 32, __LINE__);
+        todo_wine check_alpha_draw(hdcDst, TRUE, TRUE, 32, __LINE__);
+    }
+}
+
+static void test_DrawIconEx()
+{
+    BITMAPINFO bitmapInfo;
+    HDC hdcDst = NULL;
+    HBITMAP bmpDst = NULL;
+    HBITMAP bmpOld = NULL;
+    UINT32 bits = 0;
+
+    hdcDst = CreateCompatibleDC(0);
+    if (!hdcDst)
+        return;
+
+    memset(&bitmapInfo, 0, sizeof(bitmapInfo));
+    bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+    bitmapInfo.bmiHeader.biWidth = 1;
+    bitmapInfo.bmiHeader.biHeight = 1;
+    bitmapInfo.bmiHeader.biPlanes = 1;
+    bitmapInfo.bmiHeader.biCompression = BI_RGB;
+    bitmapInfo.bmiHeader.biSizeImage = sizeof(UINT32);
+
+    /* 16-bit Tests */
+    bitmapInfo.bmiHeader.biBitCount = 16;
+    bmpDst = CreateDIBSection(hdcDst, &bitmapInfo, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+    if (!bmpDst || !bits)
+        goto cleanup;
+    bmpOld = SelectObject(hdcDst, bmpDst);
+
+    check_DrawIconEx(hdcDst, FALSE, 0x00A0B0C0, 16, DI_NORMAL, 0x00FFFFFF, 0x00003163, __LINE__);
+    todo_wine check_DrawIconEx(hdcDst, TRUE, 0x00A0B0C0, 16, DI_NORMAL, 0x00FFFFFF, 0x00FFCE9C, __LINE__);
+
+    check_DrawIconEx(hdcDst, FALSE, 0xFFA0B0C0, 16, DI_NORMAL, 0x00FFFFFF, 0x00003163, __LINE__);
+    todo_wine check_DrawIconEx(hdcDst, TRUE, 0xFFA0B0C0, 16, DI_NORMAL, 0x00FFFFFF, 0x00FFCE9C, __LINE__);
+    check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 16, DI_NORMAL, 0x00FFFFFF, 0x00003163, __LINE__);
+    todo_wine check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 16, DI_NORMAL, 0x00FFFFFF, 0x00FFCE9C, __LINE__);
+
+    SelectObject(hdcDst, bmpOld);
+    DeleteObject(bmpDst);
+    bmpOld = NULL;
+    bmpDst = NULL;
+
+    /* 24-bit Tests */
+    bitmapInfo.bmiHeader.biBitCount = 24;
+    bmpDst = CreateDIBSection(hdcDst, &bitmapInfo, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+    if (!bmpDst || !bits)
+        goto cleanup;
+    bmpOld = SelectObject(hdcDst, bmpDst);
+
+    test_DrawIconEx_true_color(hdcDst);
+
+    SelectObject(hdcDst, bmpOld);
+    DeleteObject(bmpDst);
+    bmpOld = NULL;
+    bmpDst = NULL;
+
+    /* 32-bit Tests */
+    bitmapInfo.bmiHeader.biBitCount = 32;
+    bmpDst = CreateDIBSection(hdcDst, &bitmapInfo, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+    if (!bmpDst || !bits)
+        goto cleanup;
+    bmpOld = SelectObject(hdcDst, bmpDst);
+
+    test_DrawIconEx_true_color(hdcDst);
+
+    SelectObject(hdcDst, bmpOld);
+    DeleteObject(bmpDst);
+    bmpOld = NULL;
+    bmpDst = NULL;
+
+cleanup:
+    if(bmpOld)
+        SelectObject(hdcDst, bmpOld);
+    if(bmpDst)
+        DeleteObject(bmpDst);
+    if(hdcDst)
+        DeleteDC(hdcDst);
+}
+
 static void test_DestroyCursor(void)
 {
     static const BYTE bmp_bits[4096];
@@ -1063,6 +1416,8 @@ START_TEST(cursoricon)
     test_CreateIcon();
     test_LoadImage();
     test_CreateIconFromResource();
+    test_DrawIcon();
+    test_DrawIconEx();
     test_DestroyCursor();
     do_parent();
     test_child_process();
-- 
1.6.0.4

>From f4fb02ea0039539c04ad1757ac57ce59fe08bc91 Mon Sep 17 00:00:00 2001
From: Joel Holdsworth <j...@airwebreathe.org.uk>
Date: Sun, 31 May 2009 17:00:17 +0100
Subject: [PATCH] Added icon alpha blend support functions

---
 dlls/user32/cursoricon.c |   68 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 68 insertions(+), 0 deletions(-)

diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c
index 707d2bb..3cdd623 100644
--- a/dlls/user32/cursoricon.c
+++ b/dlls/user32/cursoricon.c
@@ -1598,6 +1598,74 @@ BOOL WINAPI DestroyCursor( HCURSOR hCursor )
     return DestroyIcon32(HCURSOR_16(hCursor), CID_WIN32);
 }
 
+/***********************************************************************
+ *      bitmap_has_alpha_channel
+ *
+ * Analyses bits bitmap to determine if alpha data is present.
+ *
+ * PARAMS
+ *      bpp          [I] The bits-per-pixel of the bitmap
+ *      bitmapBits   [I] A pointer to the bitmap data
+ *      bitmapLength [I] The length of the bitmap in bytes
+ *
+ * RETURNS
+ *      TRUE if an alpha channel is discovered, FALSE
+ *
+ * NOTE
+ *      Windows' behaviour is that if the icon bitmap is 32-bit and at
+ *      least one pixel has a non-zero alpha, then the bitmap is a
+ *      treated as having an alpha channel transparentcy. Otherwise,
+ *      it's treated as being completely opaque.
+ *
+ */
+static BOOL bitmap_has_alpha_channel( int bpp, unsigned char *bitmapBits,
+                                      unsigned int bitmapLength )
+{
+    /* Detect an alpha channel by looking for non-zero alpha pixels */
+    if(bpp == 32)
+    {
+        unsigned int offset;
+        for(offset = 3; offset < bitmapLength; offset += 4)
+        {
+            if(bitmapBits[offset] != 0)
+            {
+                return TRUE;
+                break;
+            }
+        }
+    }
+    return FALSE;
+}
+
+/***********************************************************************
+ *          premultiply_alpha_channel
+ *
+ * Premultiplies the color channels of a 32-bit bitmap by the alpha
+ * channel. This is a necessary step that must be carried out on
+ * the image before it is passed to GdiAlphaBlend
+ *
+ * PARAMS
+ *      destBitmap   [I] The destination bitmap buffer
+ *      srcBitmap    [I] The source bitmap buffer
+ *      bitmapLength [I] The length of the bitmap in bytes
+ *
+ */
+static void premultiply_alpha_channel( unsigned char *destBitmap,
+                                       unsigned char *srcBitmap,
+                                       unsigned int bitmapLength )
+{
+    unsigned char *destPixel = destBitmap;
+    unsigned char *srcPixel = srcBitmap;
+
+    while(destPixel < destBitmap + bitmapLength)
+    {
+        unsigned char alpha = srcPixel[3];
+        *(destPixel++) = *(srcPixel++) * alpha / 255;
+        *(destPixel++) = *(srcPixel++) * alpha / 255;
+        *(destPixel++) = *(srcPixel++) * alpha / 255;
+        *(destPixel++) = *(srcPixel++);
+    }
+}
 
 /***********************************************************************
  *		DrawIcon (USER32.@)
-- 
1.6.0.4

>From 1141b32bd30537159feed223f6ca0265add58bed Mon Sep 17 00:00:00 2001
From: Joel Holdsworth <j...@airwebreathe.org.uk>
Date: Sun, 31 May 2009 16:55:39 +0100
Subject: [PATCH] Added DrawIcon alpha blending support

---
 dlls/user32/cursoricon.c       |   63 +++++++++++++++++++++++++++++++++-------
 dlls/user32/tests/cursoricon.c |   23 ++++++--------
 2 files changed, 62 insertions(+), 24 deletions(-)

diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c
index 3cdd623..7f56648 100644
--- a/dlls/user32/cursoricon.c
+++ b/dlls/user32/cursoricon.c
@@ -1674,28 +1674,69 @@ BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
 {
     CURSORICONINFO *ptr;
     HDC hMemDC;
-    HBITMAP hXorBits, hAndBits;
+    HBITMAP hXorBits = NULL, hAndBits = NULL, hBitTemp = NULL;
     COLORREF oldFg, oldBg;
+    unsigned char *xorBitmapBits;
+    unsigned int dibLength;
 
     TRACE("%p, (%d,%d), %p\n", hdc, x, y, hIcon);
 
     if (!(ptr = GlobalLock16(HICON_16(hIcon)))) return FALSE;
     if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
-    hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1, ptr + 1 );
-    hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
-                               ptr->bBitsPerPixel, (char *)(ptr + 1)
-                        + ptr->nHeight * get_bitmap_width_bytes(ptr->nWidth,1) );
+
+    dibLength = ptr->nHeight * get_bitmap_width_bytes(
+        ptr->nWidth, ptr->bBitsPerPixel);
+
+    xorBitmapBits = (unsigned char *)(ptr + 1) + ptr->nHeight *
+                    get_bitmap_width_bytes(ptr->nWidth, 1);
+
     oldFg = SetTextColor( hdc, RGB(0,0,0) );
     oldBg = SetBkColor( hdc, RGB(255,255,255) );
 
-    if (hXorBits && hAndBits)
+    if(bitmap_has_alpha_channel(ptr->bBitsPerPixel, xorBitmapBits, dibLength))
+    {
+        BITMAPINFOHEADER bmih;
+        unsigned char *dibBits;
+
+        memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
+        bmih.biSize = sizeof(BITMAPINFOHEADER);
+        bmih.biWidth = ptr->nWidth;
+        bmih.biHeight = -ptr->nHeight;
+        bmih.biPlanes = ptr->bPlanes;
+        bmih.biBitCount = 32;
+        bmih.biCompression = BI_RGB;
+
+        hXorBits = CreateDIBSection(hdc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS,
+                                    (void*)&dibBits, NULL, 0);
+
+        if (hXorBits && dibBits)
+        {
+            BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
+
+            /* Do the alpha blending render */
+            premultiply_alpha_channel(dibBits, xorBitmapBits, dibLength);
+            hBitTemp = SelectObject( hMemDC, hXorBits );
+            GdiAlphaBlend(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC,
+                            0, 0, ptr->nWidth, ptr->nHeight, pixelblend);
+            SelectObject( hMemDC, hBitTemp );
+        }
+    }
+    else
     {
-        HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
-        BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
-        SelectObject( hMemDC, hXorBits );
-        BitBlt(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
-        SelectObject( hMemDC, hBitTemp );
+        hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1, ptr + 1 );
+        hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
+                               ptr->bBitsPerPixel, xorBitmapBits);
+
+        if (hXorBits && hAndBits)
+        {
+            hBitTemp = SelectObject( hMemDC, hAndBits );
+            BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
+            SelectObject( hMemDC, hXorBits );
+            BitBlt(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
+            SelectObject( hMemDC, hBitTemp );
+        }
     }
+
     DeleteDC( hMemDC );
     if (hXorBits) DeleteObject( hXorBits );
     if (hAndBits) DeleteObject( hAndBits );
diff --git a/dlls/user32/tests/cursoricon.c b/dlls/user32/tests/cursoricon.c
index 4caf442..23c1d3b 100644
--- a/dlls/user32/tests/cursoricon.c
+++ b/dlls/user32/tests/cursoricon.c
@@ -1076,27 +1076,24 @@ static void test_DrawIcon_true_color(HDC hdcDst)
     {
         check_DrawIcon(hdcDst, FALSE, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, __LINE__);
 
-        todo_wine
-        {
-            check_DrawIcon(hdcDst, TRUE, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, __LINE__);
+        check_DrawIcon(hdcDst, TRUE, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, __LINE__);
 
-            check_DrawIcon(hdcDst, FALSE, 0x80A0B0C0, 32, 0x00000000, 0x00605850, __LINE__);
-            check_DrawIcon(hdcDst, TRUE, 0x80A0B0C0, 32, 0x00000000, 0x00605850, __LINE__);
-            check_DrawIcon(hdcDst, FALSE, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, __LINE__);
-            check_DrawIcon(hdcDst, TRUE, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, __LINE__);
+        check_DrawIcon(hdcDst, FALSE, 0x80A0B0C0, 32, 0x00000000, 0x00605850, __LINE__);
+        check_DrawIcon(hdcDst, TRUE, 0x80A0B0C0, 32, 0x00000000, 0x00605850, __LINE__);
+        check_DrawIcon(hdcDst, FALSE, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, __LINE__);
+        check_DrawIcon(hdcDst, TRUE, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, __LINE__);
 
-            check_DrawIcon(hdcDst, FALSE, 0x01FFFFFF, 32, 0x00000000, 0x00010101, __LINE__);
-            check_DrawIcon(hdcDst, TRUE, 0x01FFFFFF, 32, 0x00000000, 0x00010101, __LINE__);
-            check_DrawIcon(hdcDst, FALSE, 0xFEFFFFFF, 32, 0x00000000, 0x00FEFEFE, __LINE__);
-            check_DrawIcon(hdcDst, TRUE, 0xFEFFFFFF, 32, 0x00000000, 0x00FEFEFE, __LINE__);
-        }
+        check_DrawIcon(hdcDst, FALSE, 0x01FFFFFF, 32, 0x00000000, 0x00010101, __LINE__);
+        check_DrawIcon(hdcDst, TRUE, 0x01FFFFFF, 32, 0x00000000, 0x00010101, __LINE__);
+        check_DrawIcon(hdcDst, FALSE, 0xFEFFFFFF, 32, 0x00000000, 0x00FEFEFE, __LINE__);
+        check_DrawIcon(hdcDst, TRUE, 0xFEFFFFFF, 32, 0x00000000, 0x00FEFEFE, __LINE__);
 
         /* Test detecting of alpha channel */
         /* If a single pixel's alpha channel is non-zero, the icon
            will be alpha blended, otherwise it will be draw with
            and + xor blts. */
         check_alpha_draw(hdcDst, FALSE, FALSE, 32, __LINE__);
-        todo_wine check_alpha_draw(hdcDst, FALSE, TRUE, 32, __LINE__);
+        check_alpha_draw(hdcDst, FALSE, TRUE, 32, __LINE__);
     }
 }
 
-- 
1.6.0.4

>From 936d4340692fa9ffe31d3f8bbf054ab29ac56295 Mon Sep 17 00:00:00 2001
From: Joel Holdsworth <j...@airwebreathe.org.uk>
Date: Sun, 31 May 2009 16:52:48 +0100
Subject: [PATCH] Added DrawIconEx alpha blending support

---
 dlls/user32/cursoricon.c       |  102 +++++++++++++++++++++++++++++-----------
 dlls/user32/tests/cursoricon.c |   30 +++++-------
 2 files changed, 87 insertions(+), 45 deletions(-)

diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c
index 7f56648..92446e1 100644
--- a/dlls/user32/cursoricon.c
+++ b/dlls/user32/cursoricon.c
@@ -2273,25 +2273,33 @@ BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
                             INT cxWidth, INT cyWidth, UINT istep,
                             HBRUSH hbr, UINT flags )
 {
-    CURSORICONINFO *ptr = GlobalLock16(HICON_16(hIcon));
+    CURSORICONINFO *ptr;
     HDC hDC_off = 0, hMemDC;
     BOOL result = FALSE, DoOffscreen;
     HBITMAP hB_off = 0, hOld = 0;
+    unsigned char *xorBitmapBits;
+    unsigned int xorLength;
+    BOOL has_alpha = FALSE;
 
-    if (!ptr) return FALSE;
     TRACE_(icon)("(hdc=%p,pos=%d.%d,hicon=%p,extend=%d.%d,istep=%d,br=%p,flags=0x%08x)\n",
                  hdc,x0,y0,hIcon,cxWidth,cyWidth,istep,hbr,flags );
 
-    hMemDC = CreateCompatibleDC (hdc);
+    if (!(ptr = GlobalLock16(HICON_16(hIcon)))) return FALSE;
+    if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
+
     if (istep)
         FIXME_(icon)("Ignoring istep=%d\n", istep);
     if (flags & DI_NOMIRROR)
         FIXME_(icon)("Ignoring flag DI_NOMIRROR\n");
 
-    if (!flags) {
-        FIXME_(icon)("no flags set? setting to DI_NORMAL\n");
-        flags = DI_NORMAL;
-    }
+    xorLength = ptr->nHeight * get_bitmap_width_bytes(
+        ptr->nWidth, ptr->bBitsPerPixel);
+    xorBitmapBits = (unsigned char *)(ptr + 1) + ptr->nHeight *
+                    get_bitmap_width_bytes(ptr->nWidth, 1);
+
+    if (flags & DI_IMAGE)
+        has_alpha = bitmap_has_alpha_channel(
+            ptr->bBitsPerPixel, xorBitmapBits, xorLength);
 
     /* Calculate the size of the destination image.  */
     if (cxWidth == 0)
@@ -2329,50 +2337,90 @@ BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
 
     if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
     {
-        HBITMAP hXorBits, hAndBits;
+        HBITMAP hBitTemp;
+        HBITMAP hXorBits = NULL, hAndBits = NULL;
         COLORREF  oldFg, oldBg;
         INT     nStretchMode;
 
         nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
 
-        hXorBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
-                                  ptr->bPlanes, ptr->bBitsPerPixel,
-                                  (char *)(ptr + 1)
-                                  + ptr->nHeight *
-                                  get_bitmap_width_bytes(ptr->nWidth,1) );
-        hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight, 1, 1, ptr + 1 );
         oldFg = SetTextColor( hdc, RGB(0,0,0) );
         oldBg = SetBkColor( hdc, RGB(255,255,255) );
 
-        if (hXorBits && hAndBits)
+        if (((flags & DI_MASK) && !(flags & DI_IMAGE)) ||
+            ((flags & DI_MASK) && !has_alpha))
         {
-            HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
-            if (flags & DI_MASK)
+            hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight, 1, 1, ptr + 1 );
+            if (hAndBits)
             {
+                hBitTemp = SelectObject( hMemDC, hAndBits );
                 if (DoOffscreen)
                     StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
                                 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
                 else
                     StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
                                 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
+                SelectObject( hMemDC, hBitTemp );
             }
-            SelectObject( hMemDC, hXorBits );
-            if (flags & DI_IMAGE)
+        }
+
+        if (flags & DI_IMAGE)
+        {
+            BITMAPINFOHEADER bmih;
+            unsigned char *dibBits;
+
+            memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
+            bmih.biSize = sizeof(BITMAPINFOHEADER);
+            bmih.biWidth = ptr->nWidth;
+            bmih.biHeight = -ptr->nHeight;
+            bmih.biPlanes = ptr->bPlanes;
+            bmih.biBitCount = ptr->bBitsPerPixel;
+            bmih.biCompression = BI_RGB;
+
+            hXorBits = CreateDIBSection(hdc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS,
+                                        (void*)&dibBits, NULL, 0);
+
+            if (hXorBits && dibBits)
             {
-                if (DoOffscreen)
-                    StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
-                                hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
+                if(has_alpha)
+                {
+                    BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
+
+                    /* Do the alpha blending render */
+                    premultiply_alpha_channel(dibBits, xorBitmapBits, xorLength);
+                    hBitTemp = SelectObject( hMemDC, hXorBits );
+
+                    if (DoOffscreen)
+                        GdiAlphaBlend(hDC_off, 0, 0, cxWidth, cyWidth, hMemDC,
+                                        0, 0, ptr->nWidth, ptr->nHeight, pixelblend);
+                    else
+                        GdiAlphaBlend(hdc, x0, y0, cxWidth, cyWidth, hMemDC,
+                                        0, 0, ptr->nWidth, ptr->nHeight, pixelblend);
+
+                    SelectObject( hMemDC, hBitTemp );
+                }
                 else
-                    StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
-                                hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
+                {
+                    memcpy(dibBits, xorBitmapBits, xorLength);
+                    hBitTemp = SelectObject( hMemDC, hXorBits );
+                    if (DoOffscreen)
+                        StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
+                                    hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
+                    else
+                        StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
+                                    hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
+                    SelectObject( hMemDC, hBitTemp );
+                }
+
+                DeleteObject( hXorBits );
             }
-            SelectObject( hMemDC, hBitTemp );
-            result = TRUE;
         }
 
+        result = TRUE;
+
         SetTextColor( hdc, oldFg );
         SetBkColor( hdc, oldBg );
-        if (hXorBits) DeleteObject( hXorBits );
+
         if (hAndBits) DeleteObject( hAndBits );
         SetStretchBltMode (hdc, nStretchMode);
         if (DoOffscreen) {
diff --git a/dlls/user32/tests/cursoricon.c b/dlls/user32/tests/cursoricon.c
index 23c1d3b..a2313a6 100644
--- a/dlls/user32/tests/cursoricon.c
+++ b/dlls/user32/tests/cursoricon.c
@@ -1181,11 +1181,8 @@ static void test_DrawIconEx_true_color(HDC hdcDst)
     DWORD dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
 
     /* Test null, image only, and mask only drawing */
-    todo_wine
-    {
-        check_DrawIconEx(hdcDst, FALSE, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, __LINE__);
-        check_DrawIconEx(hdcDst, TRUE, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, __LINE__);
-    }
+    check_DrawIconEx(hdcDst, FALSE, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, __LINE__);
+    check_DrawIconEx(hdcDst, TRUE, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, __LINE__);
 
     check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_MASK, 0x00FFFFFF, 0x00000000, __LINE__);
     check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_MASK, 0x00FFFFFF, 0x00FFFFFF, __LINE__);
@@ -1205,27 +1202,24 @@ static void test_DrawIconEx_true_color(HDC hdcDst)
     /* Applicable to XP and up */
     if(dwMajorVersion > 5 || dwMinorVersion >= 1)
     {
-        todo_wine
-        {
-            check_DrawIconEx(hdcDst, TRUE, 0xFFA0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00C0B0A0, __LINE__);
+        check_DrawIconEx(hdcDst, TRUE, 0xFFA0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00C0B0A0, __LINE__);
 
-            check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_NORMAL, 0x00000000, 0x00605850, __LINE__);
-            check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_NORMAL, 0x00000000, 0x00605850, __LINE__);
-            check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00DFD7CF, __LINE__);
-            check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00DFD7CF, __LINE__);
+        check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_NORMAL, 0x00000000, 0x00605850, __LINE__);
+        check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_NORMAL, 0x00000000, 0x00605850, __LINE__);
+        check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00DFD7CF, __LINE__);
+        check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00DFD7CF, __LINE__);
 
-            check_DrawIconEx(hdcDst, FALSE, 0x01FFFFFF, 32, DI_NORMAL, 0x00000000, 0x00010101, __LINE__);
-            check_DrawIconEx(hdcDst, TRUE, 0x01FFFFFF, 32, DI_NORMAL, 0x00000000, 0x00010101, __LINE__);
-            check_DrawIconEx(hdcDst, FALSE, 0xFEFFFFFF, 32, DI_NORMAL, 0x00000000, 0x00FEFEFE, __LINE__);
-            check_DrawIconEx(hdcDst, TRUE, 0xFEFFFFFF, 32, DI_NORMAL, 0x00000000, 0x00FEFEFE, __LINE__);
-        }
+        check_DrawIconEx(hdcDst, FALSE, 0x01FFFFFF, 32, DI_NORMAL, 0x00000000, 0x00010101, __LINE__);
+        check_DrawIconEx(hdcDst, TRUE, 0x01FFFFFF, 32, DI_NORMAL, 0x00000000, 0x00010101, __LINE__);
+        check_DrawIconEx(hdcDst, FALSE, 0xFEFFFFFF, 32, DI_NORMAL, 0x00000000, 0x00FEFEFE, __LINE__);
+        check_DrawIconEx(hdcDst, TRUE, 0xFEFFFFFF, 32, DI_NORMAL, 0x00000000, 0x00FEFEFE, __LINE__);
 
         /* Test detecting of alpha channel */
         /* If a single pixel's alpha channel is non-zero, the icon
            will be alpha blended, otherwise it will be draw with
            and + xor blts. */
         check_alpha_draw(hdcDst, TRUE, FALSE, 32, __LINE__);
-        todo_wine check_alpha_draw(hdcDst, TRUE, TRUE, 32, __LINE__);
+        check_alpha_draw(hdcDst, TRUE, TRUE, 32, __LINE__);
     }
 }
 
-- 
1.6.0.4

>From ec8d43d4b705150e4a7b29aaec9e4d39d87dc0a6 Mon Sep 17 00:00:00 2001
From: Joel Holdsworth <j...@airwebreathe.org.uk>
Date: Tue, 2 Jun 2009 22:05:14 +0100
Subject: [PATCH] Fixed CURSORICON_CreateIconFromBMI to preserve the alpha channel

---
 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



Reply via email to