Dmitry Timoshkov : comctl32: Create an internal copy for 32-bpp bitmaps with an alpha channel for Static control.

Alexandre Julliard julliard at winehq.org
Tue Feb 11 15:44:54 CST 2020


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

Author: Dmitry Timoshkov <dmitry at baikal.ru>
Date:   Mon Feb 10 16:31:41 2020 +0800

comctl32: Create an internal copy for 32-bpp bitmaps with an alpha channel for Static control.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47018
Signed-off-by: Dmitry Timoshkov <dmitry at baikal.ru>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/comctl32/static.c       | 79 ++++++++++++++++++++++++++++++++++++++++++--
 dlls/comctl32/tests/static.c |  7 +---
 2 files changed, 77 insertions(+), 9 deletions(-)

diff --git a/dlls/comctl32/static.c b/dlls/comctl32/static.c
index d08710c06f..b3254e5761 100644
--- a/dlls/comctl32/static.c
+++ b/dlls/comctl32/static.c
@@ -60,6 +60,7 @@ struct static_extra_info
         HBITMAP hbitmap;
         HENHMETAFILE hemf;
     } image;
+    BOOL image_has_alpha;
 };
 
 typedef void (*pfPaint)( HWND hwnd, HDC hdc, DWORD style );
@@ -163,6 +164,52 @@ static HICON STATIC_SetIcon( HWND hwnd, HICON hicon, DWORD style )
     return prevIcon;
 }
 
+static HBITMAP create_alpha_bitmap( HBITMAP hbitmap )
+{
+    BITMAP bm;
+    HBITMAP alpha;
+    BITMAPINFO info;
+    HDC hdc;
+    void *bits;
+    DWORD i;
+    BYTE *ptr;
+    BOOL has_alpha = FALSE;
+
+    GetObjectW( hbitmap, sizeof(bm), &bm );
+    if (bm.bmBitsPixel != 32) return 0;
+
+    if (!(hdc = CreateCompatibleDC( 0 ))) return 0;
+
+    info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+    info.bmiHeader.biWidth = bm.bmWidth;
+    info.bmiHeader.biHeight = -bm.bmHeight;
+    info.bmiHeader.biPlanes = 1;
+    info.bmiHeader.biBitCount = 32;
+    info.bmiHeader.biCompression = BI_RGB;
+    info.bmiHeader.biSizeImage = bm.bmWidth * bm.bmHeight * 4;
+    info.bmiHeader.biXPelsPerMeter = 0;
+    info.bmiHeader.biYPelsPerMeter = 0;
+    info.bmiHeader.biClrUsed = 0;
+    info.bmiHeader.biClrImportant = 0;
+    if ((alpha = CreateDIBSection( hdc, &info, DIB_RGB_COLORS, &bits, NULL, 0 )))
+    {
+        GetDIBits( hdc, hbitmap, 0, bm.bmHeight, bits, &info, DIB_RGB_COLORS );
+
+        for (i = 0, ptr = bits; i < bm.bmWidth * bm.bmHeight; i++, ptr += 4)
+            if ((has_alpha = (ptr[3] != 0))) break;
+
+        if (!has_alpha)
+        {
+            DeleteObject( alpha );
+            alpha = 0;
+        }
+    }
+
+    DeleteDC( hdc );
+
+    return alpha;
+}
+
 /***********************************************************************
  *           STATIC_SetBitmap
  *
@@ -170,7 +217,7 @@ static HICON STATIC_SetIcon( HWND hwnd, HICON hicon, DWORD style )
  */
 static HBITMAP STATIC_SetBitmap( HWND hwnd, HBITMAP hBitmap, DWORD style )
 {
-    HBITMAP hOldBitmap;
+    HBITMAP hOldBitmap, alpha;
     struct static_extra_info *extra;
 
     if ((style & SS_TYPEMASK) != SS_BITMAP) return 0;
@@ -185,10 +232,23 @@ static HBITMAP STATIC_SetBitmap( HWND hwnd, HBITMAP hBitmap, DWORD style )
 
     hOldBitmap = extra->image.hbitmap;
     extra->image.hbitmap = hBitmap;
+    extra->image_has_alpha = FALSE;
+
+    if (hBitmap)
+    {
+        alpha = create_alpha_bitmap( hBitmap );
+        if (alpha)
+        {
+            extra->image.hbitmap = alpha;
+            extra->image_has_alpha = TRUE;
+        }
+    }
+
     if (hBitmap && !(style & SS_CENTERIMAGE) && !(style & SS_REALSIZECONTROL))
     {
         BITMAP bm;
         GetObjectW(hBitmap, sizeof(bm), &bm);
+
         /* Windows currently doesn't implement SS_RIGHTJUST */
         /*
         if ((style & SS_RIGHTJUST) != 0)
@@ -386,7 +446,12 @@ static LRESULT CALLBACK STATIC_WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam,
         if (style == SS_ICON)
         {
             struct static_extra_info *extra = get_extra_ptr( hwnd, FALSE );
-            heap_free( extra );
+            if (extra)
+            {
+                if (extra->image_has_alpha)
+                    DeleteObject( extra->image.hbitmap );
+                heap_free( extra );
+            }
 /*
  * FIXME
  *           DestroyIcon32( STATIC_SetIcon( wndPtr, 0 ) );
@@ -765,6 +830,8 @@ static void STATIC_PaintBitmapfn(HWND hwnd, HDC hdc, DWORD style )
         BITMAP bm;
         RECT rcClient;
         LOGBRUSH brush;
+        BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
+        struct static_extra_info *extra = get_extra_ptr( hwnd, FALSE );
 
         GetObjectW(hBitmap, sizeof(bm), &bm);
         oldbitmap = SelectObject(hMemDC, hBitmap);
@@ -785,7 +852,13 @@ static void STATIC_PaintBitmapfn(HWND hwnd, HDC hdc, DWORD style )
             rcClient.right = rcClient.left + bm.bmWidth;
             rcClient.bottom = rcClient.top + bm.bmHeight;
         }
-        StretchBlt(hdc, rcClient.left, rcClient.top, rcClient.right - rcClient.left,
+
+        if (extra->image_has_alpha)
+            GdiAlphaBlend(hdc, rcClient.left, rcClient.top, rcClient.right - rcClient.left,
+                   rcClient.bottom - rcClient.top, hMemDC,
+                   0, 0, bm.bmWidth, bm.bmHeight, blend);
+        else
+            StretchBlt(hdc, rcClient.left, rcClient.top, rcClient.right - rcClient.left,
                    rcClient.bottom - rcClient.top, hMemDC,
                    0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
         SelectObject(hMemDC, oldbitmap);
diff --git a/dlls/comctl32/tests/static.c b/dlls/comctl32/tests/static.c
index 0e44c4ed7a..0b990d6b39 100644
--- a/dlls/comctl32/tests/static.c
+++ b/dlls/comctl32/tests/static.c
@@ -147,18 +147,15 @@ static void test_image(HBITMAP image, BOOL is_dib, BOOL is_premult)
     ok(bm.bmBitsPixel == 32, "got %d\n", bm.bmBitsPixel);
     if (is_dib)
     {
-todo_wine
         ok(bm.bmBits != NULL, "bmBits is NULL\n");
-if (bm.bmBits)
-{
         memcpy(bits, bm.bmBits, 4);
         if (is_premult)
+todo_wine
             ok(bits[0] == 0x05 &&  bits[1] == 0x09 &&  bits[2] == 0x0e && bits[3] == 0x44,
                "bits: %02x %02x %02x %02x\n", bits[0], bits[1], bits[2], bits[3]);
         else
             ok(bits[0] == 0x11 &&  bits[1] == 0x22 &&  bits[2] == 0x33 && bits[3] == 0x44,
                "bits: %02x %02x %02x %02x\n", bits[0], bits[1], bits[2], bits[3]);
-}
     }
     else
         ok(bm.bmBits == NULL, "bmBits is not NULL\n");
@@ -206,13 +203,11 @@ static void test_set_image(void)
 
     bmp1 = (HBITMAP)SendMessageW(hwnd, STM_GETIMAGE, IMAGE_BITMAP, 0);
     ok(bmp1 != NULL, "got NULL\n");
-todo_wine
     ok(bmp1 != image, "bmp == image\n");
     test_image(bmp1, TRUE, TRUE);
 
     bmp2 = (HBITMAP)SendMessageW(hwnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)image);
     ok(bmp2 != NULL, "got NULL\n");
-todo_wine
     ok(bmp2 != image, "bmp == image\n");
     ok(bmp1 == bmp2, "bmp1 != bmp2\n");
     test_image(bmp2, TRUE, TRUE);




More information about the wine-cvs mailing list