From 334262255a66b05a852c90ebc722815b8a0eb7e9 Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Sat, 4 May 2019 19:46:35 +0800
Subject: [PATCH 2/2] comctl32: Paint 32-bpp bitmaps with an alpha channel
 using GdiAlphaBlend.
Content-Type: text/plain; charset=UTF-8
To: wine-devel@winehq.org

Signed-off-by: Dmitry Timoshkov <dmitry@baikal.ru>
---
 dlls/comctl32/static.c | 83 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 79 insertions(+), 4 deletions(-)

diff --git a/dlls/comctl32/static.c b/dlls/comctl32/static.c
index d08710c06f..fe566645d3 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,56 @@ static HICON STATIC_SetIcon( HWND hwnd, HICON hicon, DWORD style )
     return prevIcon;
 }
 
+static HBITMAP create_alpha_bitmap( HBITMAP hbitmap )
+{
+    HBITMAP alpha = 0;
+    BITMAPINFO *info = NULL;
+    BITMAP bm;
+    HDC src, dst;
+    void *bits;
+    DWORD i;
+    const unsigned char *ptr;
+    BOOL has_alpha = FALSE;
+
+    if (!GetObjectW( hbitmap, sizeof(bm), &bm )) return 0;
+    if (bm.bmBitsPixel != 32) return 0;
+
+    if (!(src = CreateCompatibleDC( 0 ))) return 0;
+    if (!(dst = CreateCompatibleDC( src ))) goto done;
+    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 = -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( dst, info, DIB_RGB_COLORS, &bits, NULL, 0 ))) goto done;
+
+    SelectObject( src, hbitmap );
+    SelectObject( dst, alpha );
+    BitBlt(dst, 0, 0, bm.bmWidth, bm.bmHeight, src, 0, 0, SRCCOPY);
+
+    for (i = 0, ptr = bits; i < bm.bmWidth * bm.bmHeight; i++, ptr += 4)
+        if ((has_alpha = (ptr[3] != 0))) break;
+
+done:
+    DeleteDC( src );
+    DeleteDC( dst );
+    HeapFree( GetProcessHeap(), 0, info );
+
+    if (!has_alpha)
+    {
+        DeleteObject( alpha );
+        alpha = 0;
+    }
+    return alpha;
+}
+
 /***********************************************************************
  *           STATIC_SetBitmap
  *
@@ -170,7 +221,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;
@@ -184,7 +235,18 @@ static HBITMAP STATIC_SetBitmap( HWND hwnd, HBITMAP hBitmap, DWORD style )
     if (!extra) return 0;
 
     hOldBitmap = extra->image.hbitmap;
-    extra->image.hbitmap = hBitmap;
+    alpha = create_alpha_bitmap( hBitmap );
+    if (alpha)
+    {
+        extra->image.hbitmap = alpha;
+        extra->image_has_alpha = TRUE;
+    }
+    else
+    {
+        extra->image.hbitmap = hBitmap;
+        extra->image_has_alpha = FALSE;
+    }
+
     if (hBitmap && !(style & SS_CENTERIMAGE) && !(style & SS_REALSIZECONTROL))
     {
         BITMAP bm;
@@ -386,7 +448,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 +832,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 +854,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);
-- 
2.20.1

