From 334262255a66b05a852c90ebc722815b8a0eb7e9 Mon Sep 17 00:00:00 2001 From: Dmitry Timoshkov 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 --- 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