Alexandre Julliard : comctl32: Generate an alpha channel if necessary when adding images to a 32-bit imagelist .

Alexandre Julliard julliard at winehq.org
Fri May 14 11:17:28 CDT 2010


Module: wine
Branch: master
Commit: f02adf3e2b3efc23f62c38b9c8f43f169888434f
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=f02adf3e2b3efc23f62c38b9c8f43f169888434f

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Fri May 14 13:38:54 2010 +0200

comctl32: Generate an alpha channel if necessary when adding images to a 32-bit imagelist.

---

 dlls/comctl32/imagelist.c       |  110 +++++++++++++++++++++++++++++++++++----
 dlls/comctl32/tests/imagelist.c |    2 +-
 2 files changed, 101 insertions(+), 11 deletions(-)

diff --git a/dlls/comctl32/imagelist.c b/dlls/comctl32/imagelist.c
index d1bf7f6..acad6c2 100644
--- a/dlls/comctl32/imagelist.c
+++ b/dlls/comctl32/imagelist.c
@@ -138,6 +138,92 @@ static inline void imagelist_copy_images( HIMAGELIST himl, HDC hdcSrc, HDC hdcDe
     }
 }
 
+/* add images with an alpha channel when the image list is 32 bpp */
+static BOOL add_with_alpha( HIMAGELIST himl, HDC hdc, int pos, int count,
+                            int width, int height, HBITMAP hbmImage, HBITMAP hbmMask )
+{
+    BOOL ret = FALSE;
+    HDC hdcMask = 0;
+    BITMAP bm;
+    BITMAPINFO *info;
+    DWORD *bits = NULL;
+    BYTE *mask_bits = NULL;
+    int i, j, n;
+    POINT pt;
+    DWORD mask_width;
+
+    if (himl->uBitsPixel != 32) return FALSE;
+    if (!GetObjectW( hbmImage, sizeof(bm), &bm )) return FALSE;
+    SelectObject( hdc, hbmImage );
+    mask_width = (bm.bmWidth + 31) / 32 * 4;
+
+    if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
+    info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+    info->bmiHeader.biWidth = bm.bmWidth;
+    info->bmiHeader.biHeight = -height;
+    info->bmiHeader.biPlanes = 1;
+    info->bmiHeader.biBitCount = 32;
+    info->bmiHeader.biCompression = BI_RGB;
+    info->bmiHeader.biSizeImage = bm.bmWidth * height * 4;
+    info->bmiHeader.biXPelsPerMeter = 0;
+    info->bmiHeader.biYPelsPerMeter = 0;
+    info->bmiHeader.biClrUsed = 0;
+    info->bmiHeader.biClrImportant = 0;
+    if (!(bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage ))) goto done;
+    if (!GetDIBits( hdc, hbmImage, 0, height, bits, info, DIB_RGB_COLORS )) goto done;
+
+    if (hbmMask)
+    {
+        info->bmiHeader.biBitCount = 1;
+        info->bmiHeader.biSizeImage = mask_width * height;
+        if (!(mask_bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage ))) goto done;
+        if (!GetDIBits( hdc, hbmMask, 0, height, mask_bits, info, DIB_RGB_COLORS )) goto done;
+        /* restore values for color info */
+        info->bmiHeader.biBitCount = 32;
+        info->bmiHeader.biSizeImage = bm.bmWidth * height * 4;
+        hdcMask = CreateCompatibleDC( 0 );
+        SelectObject( hdcMask, hbmMask );
+    }
+
+    for (n = 0; n < count; n++)
+    {
+        int has_alpha = 0;
+
+        imagelist_point_from_index( himl, pos + n, &pt );
+
+        /* check if bitmap has an alpha channel */
+        for (i = 0; i < height && !has_alpha; i++)
+            for (j = n * width; j < (n + 1) * width; j++)
+                if ((has_alpha = ((bits[i * bm.bmWidth + j] & 0xff000000) != 0))) break;
+
+        if (!has_alpha)  /* generate alpha channel from the mask */
+        {
+            for (i = 0; i < height; i++)
+                for (j = n * width; j < (n + 1) * width; j++)
+                    if (!mask_bits || !((mask_bits[i * mask_width + j / 8] << (j % 8)) & 0x80))
+                        bits[i * bm.bmWidth + j] |= 0xff000000;
+            StretchDIBits( himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
+                           n * width, 0, width, height, bits, info, DIB_RGB_COLORS, SRCCOPY );
+        }
+        else
+        {
+            StretchBlt( himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
+                        hdc, n * width, 0, width, height, SRCCOPY );
+        }
+
+        if (hdcMask) StretchBlt( himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
+                                 hdcMask, n * width, 0, width, height, SRCCOPY );
+    }
+    ret = TRUE;
+
+done:
+    if (hdcMask) DeleteDC( hdcMask );
+    HeapFree( GetProcessHeap(), 0, info );
+    HeapFree( GetProcessHeap(), 0, bits );
+    HeapFree( GetProcessHeap(), 0, mask_bits );
+    return ret;
+}
+
 /*************************************************************************
  * IMAGELIST_InternalExpandBitmaps [Internal]
  *
@@ -232,10 +318,9 @@ IMAGELIST_InternalExpandBitmaps(HIMAGELIST himl, INT nImageCount)
 INT WINAPI
 ImageList_Add (HIMAGELIST himl,	HBITMAP hbmImage, HBITMAP hbmMask)
 {
-    HDC     hdcBitmap, hdcTemp;
+    HDC     hdcBitmap, hdcTemp = 0;
     INT     nFirstIndex, nImageCount, i;
     BITMAP  bmp;
-    HBITMAP hOldBitmap, hOldBitmapTemp;
     POINT   pt;
 
     TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
@@ -256,7 +341,17 @@ ImageList_Add (HIMAGELIST himl,	HBITMAP hbmImage, HBITMAP hbmMask)
 
     hdcBitmap = CreateCompatibleDC(0);
 
-    hOldBitmap = SelectObject(hdcBitmap, hbmImage);
+    SelectObject(hdcBitmap, hbmImage);
+
+    if (add_with_alpha( himl, hdcBitmap, himl->cCurImage, nImageCount,
+                        himl->cx, min( himl->cy, bmp.bmHeight), hbmImage, hbmMask ))
+        goto done;
+
+    if (himl->hbmMask)
+    {
+        hdcTemp = CreateCompatibleDC(0);
+        SelectObject(hdcTemp, hbmMask);
+    }
 
     for (i=0; i<nImageCount; i++)
     {
@@ -270,22 +365,17 @@ ImageList_Add (HIMAGELIST himl,	HBITMAP hbmImage, HBITMAP hbmMask)
         if (!himl->hbmMask)
              continue;
 
-        hdcTemp   = CreateCompatibleDC(0);
-        hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
-
         BitBlt( himl->hdcMask, pt.x, pt.y, himl->cx, bmp.bmHeight,
                 hdcTemp, i*himl->cx, 0, SRCCOPY );
 
-        SelectObject(hdcTemp, hOldBitmapTemp);
-        DeleteDC(hdcTemp);
-
         /* Remove the background from the image
         */
         BitBlt( himl->hdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
                 himl->hdcMask, pt.x, pt.y, 0x220326 ); /* NOTSRCAND */
     }
+    if (hdcTemp) DeleteDC(hdcTemp);
 
-    SelectObject(hdcBitmap, hOldBitmap);
+done:
     DeleteDC(hdcBitmap);
 
     nFirstIndex = himl->cCurImage;
diff --git a/dlls/comctl32/tests/imagelist.c b/dlls/comctl32/tests/imagelist.c
index 9542e64..b80f351 100644
--- a/dlls/comctl32/tests/imagelist.c
+++ b/dlls/comctl32/tests/imagelist.c
@@ -1216,7 +1216,7 @@ static void test_ImageList_DrawIndirect(void)
     check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_GLOW, 0, 0x00ABCDEF, __LINE__);
     check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_SHADOW, 0, 0x00ABCDEF, __LINE__);
 
-    todo_wine check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_ALPHA, 127, 0x00D5E6F7, __LINE__);
+    check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_ALPHA, 127, 0x00D5E6F7, __LINE__);
     todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_NORMAL, ILS_ALPHA, 127, 0x00E9F2FB, 0x00AEB7C0, __LINE__);
     todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_NORMAL, ILS_NORMAL, 127, 0x00E9F2FB, 0x00D3E5F7, __LINE__);
 




More information about the wine-cvs mailing list