[PATCH] Added DrawIconEx alpha blending support

Joel Holdsworth joel at airwebreathe.org.uk
Sun May 31 10:52:48 CDT 2009


---
 dlls/user32/cursoricon.c       |  102 +++++++++++++++++++++++++++++-----------
 dlls/user32/tests/cursoricon.c |   26 ++++------
 2 files changed, 85 insertions(+), 43 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 1e6d87e..d57395b 100644
--- a/dlls/user32/tests/cursoricon.c
+++ b/dlls/user32/tests/cursoricon.c
@@ -1172,11 +1172,8 @@ static void test_DrawIconEx(void)
     bmpOld = SelectObject(hdcDst, bmpDst);
 
     /* Test null, image only, and mask only drawing */
-    todo_wine
-    {
-        check_DrawIconEx(hdcDst, FALSE, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, 0x00102030, __LINE__);
-        check_DrawIconEx(hdcDst, TRUE, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, 0x00102030, __LINE__);
-    }
+    check_DrawIconEx(hdcDst, FALSE, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, 0x00102030, __LINE__);
+    check_DrawIconEx(hdcDst, TRUE, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, 0x00102030, __LINE__);
 
     check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_MASK, 0x00FFFFFF, 0x00000000, 0x00000000, __LINE__);
     check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_MASK, 0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF, __LINE__);
@@ -1194,25 +1191,22 @@ static void test_DrawIconEx(void)
 
     /* Test alpha blending */
     /* Windows 2000 and up will alpha blend, earlier Windows versions will not */
-    todo_wine check_DrawIconEx(hdcDst, TRUE, 0xFFA0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00C0B0A0, 0x003F4F5F, __LINE__);
+    check_DrawIconEx(hdcDst, TRUE, 0xFFA0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00C0B0A0, 0x003F4F5F, __LINE__);
 
-    todo_wine
-    {
-        check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_NORMAL, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__);
-        check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_NORMAL, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__);
-        check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00DFD7CF, 0x00C0B0A0, __LINE__);
-        check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00DFD7CF, 0x003F4F5F, __LINE__);
+    check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_NORMAL, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__);
+    check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_NORMAL, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__);
+    check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00DFD7CF, 0x00C0B0A0, __LINE__);
+    check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00DFD7CF, 0x003F4F5F, __LINE__);
 
-        check_DrawIconEx(hdcDst, FALSE, 0x01FFFFFF, 32, DI_NORMAL, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__);
-        check_DrawIconEx(hdcDst, TRUE, 0x01FFFFFF, 32, DI_NORMAL, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__);
-    }
+    check_DrawIconEx(hdcDst, FALSE, 0x01FFFFFF, 32, DI_NORMAL, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__);
+    check_DrawIconEx(hdcDst, TRUE, 0x01FFFFFF, 32, DI_NORMAL, 0x00000000, 0x00010101, 0x00FFFFFF, __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__);
 
     SelectObject(hdcDst, bmpOld);
     DeleteObject(bmpDst);
-- 
1.6.0.4


--=-FjwtPMFc52X68FRxpeQV--





More information about the wine-patches mailing list