Alexandre Julliard : user32: Store a pre-computed alpha bitmap for 32-bpp icons with an alpha channel.
Alexandre Julliard
julliard at winehq.org
Thu May 20 11:03:01 CDT 2010
Module: wine
Branch: master
Commit: bb33cebe3f7b24759aa47238a33197bbf73cfcb1
URL: http://source.winehq.org/git/wine.git/?a=commit;h=bb33cebe3f7b24759aa47238a33197bbf73cfcb1
Author: Alexandre Julliard <julliard at winehq.org>
Date: Wed May 19 12:14:03 2010 +0200
user32: Store a pre-computed alpha bitmap for 32-bpp icons with an alpha channel.
---
dlls/user32/cursoricon.c | 104 ++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 100 insertions(+), 4 deletions(-)
diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c
index 24099a8..1454260 100644
--- a/dlls/user32/cursoricon.c
+++ b/dlls/user32/cursoricon.c
@@ -136,6 +136,7 @@ struct cursoricon_object
struct user_object obj; /* object header */
ULONG_PTR param; /* opaque param used by 16-bit code */
HBITMAP color; /* color bitmap */
+ HBITMAP alpha; /* pre-multiplied alpha bitmap for 32-bpp icons */
HBITMAP mask; /* mask bitmap (followed by color for 1-bpp icons) */
CURSORICONINFO data;
/* followed by cursor bits in CURSORICONINFO format */
@@ -147,6 +148,7 @@ static HICON alloc_icon_handle( unsigned int size )
if (!obj) return 0;
obj->param = 0;
obj->color = 0;
+ obj->alpha = 0;
obj->mask = 0;
return alloc_user_handle( &obj->obj, USER_ICON );
}
@@ -176,6 +178,7 @@ static BOOL free_icon_handle( HICON handle )
{
ULONG_PTR param = obj->param;
if (obj->color) DeleteObject( obj->color );
+ if (obj->alpha) DeleteObject( obj->alpha );
DeleteObject( obj->mask );
HeapFree( GetProcessHeap(), 0, obj );
if (wow_handlers.free_icon_param && param) wow_handlers.free_icon_param( param );
@@ -775,12 +778,96 @@ static BOOL stretch_blt_icon(HBITMAP hDest, BITMAPINFO *pDestInfo, BITMAPINFO *p
}
/***********************************************************************
+ * bmi_has_alpha
+ */
+static BOOL bmi_has_alpha( const BITMAPINFO *info, const void *bits )
+{
+ int i;
+ BOOL has_alpha = FALSE;
+ const unsigned char *ptr = bits;
+
+ if (info->bmiHeader.biBitCount != 32) return FALSE;
+ for (i = 0; i < info->bmiHeader.biWidth * abs(info->bmiHeader.biHeight); i++, ptr += 4)
+ if ((has_alpha = (ptr[3] != 0))) break;
+ return has_alpha;
+}
+
+/***********************************************************************
+ * create_alpha_bitmap
+ *
+ * Create the alpha bitmap for a 32-bpp icon that has an alpha channel.
+ */
+static HBITMAP create_alpha_bitmap( HBITMAP color, HBITMAP mask,
+ const BITMAPINFO *src_info, const void *color_bits )
+{
+ HBITMAP alpha = 0;
+ BITMAPINFO *info = NULL;
+ BITMAP bm;
+ HDC hdc;
+ void *bits;
+ unsigned char *ptr;
+ int i;
+
+ if (!GetObjectW( color, sizeof(bm), &bm )) return 0;
+ if (bm.bmBitsPixel != 32) return 0;
+
+ if (!(hdc = CreateCompatibleDC( 0 ))) return 0;
+ 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( hdc, info, DIB_RGB_COLORS, &bits, NULL, 0 ))) goto done;
+
+ if (src_info)
+ {
+ SelectObject( hdc, alpha );
+ StretchDIBits( hdc, 0, 0, bm.bmWidth, bm.bmHeight,
+ 0, 0, src_info->bmiHeader.biWidth, src_info->bmiHeader.biHeight,
+ color_bits, src_info, DIB_RGB_COLORS, SRCCOPY );
+
+ }
+ else
+ {
+ GetDIBits( hdc, color, 0, bm.bmHeight, bits, info, DIB_RGB_COLORS );
+ if (!bmi_has_alpha( info, bits ))
+ {
+ DeleteObject( alpha );
+ alpha = 0;
+ goto done;
+ }
+ }
+
+ /* pre-multiply by alpha */
+ for (i = 0, ptr = bits; i < bm.bmWidth * bm.bmHeight; i++, ptr += 4)
+ {
+ unsigned int alpha = ptr[3];
+ ptr[0] = ptr[0] * alpha / 255;
+ ptr[1] = ptr[1] * alpha / 255;
+ ptr[2] = ptr[2] * alpha / 255;
+ }
+
+done:
+ DeleteDC( hdc );
+ HeapFree( GetProcessHeap(), 0, info );
+ return alpha;
+}
+
+
+/***********************************************************************
* create_icon_bitmaps
*
- * Create the color and mask bitmaps from the DIB info.
+ * Create the color, mask and alpha bitmaps from the DIB info.
*/
static BOOL create_icon_bitmaps( const BITMAPINFO *bmi, int width, int height,
- HBITMAP *color, HBITMAP *mask )
+ HBITMAP *color, HBITMAP *mask, HBITMAP *alpha )
{
BOOL monochrome = is_dib_monochrome( bmi );
unsigned int size = bitmap_info_size( bmi, DIB_RGB_COLORS );
@@ -801,6 +888,7 @@ static BOOL create_icon_bitmaps( const BITMAPINFO *bmi, int width, int height,
get_dib_width_bytes( bmi->bmiHeader.biWidth,
bmi->bmiHeader.biBitCount ) * abs(info->bmiHeader.biHeight);
+ *alpha = 0;
if (monochrome)
{
if (!(*mask = CreateBitmap( width, height * 2, 1, 1, NULL ))) goto done;
@@ -826,6 +914,9 @@ static BOOL create_icon_bitmaps( const BITMAPINFO *bmi, int width, int height,
0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight,
color_bits, info, DIB_RGB_COLORS, SRCCOPY );
+ if (bmi_has_alpha( info, color_bits ))
+ *alpha = create_alpha_bitmap( *color, *mask, info, color_bits );
+
/* convert info to monochrome to copy the mask */
info->bmiHeader.biBitCount = 1;
if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
@@ -866,7 +957,7 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
{
HICON hObj;
int sizeAnd, sizeXor;
- HBITMAP color = 0, mask = 0, hAndBits = 0, hXorBits = 0; /* error condition for later */
+ HBITMAP color = 0, mask = 0, alpha = 0, hAndBits = 0, hXorBits = 0; /* error condition for later */
BITMAP bmpXor, bmpAnd;
BOOL do_stretch;
INT size;
@@ -905,7 +996,7 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
if (!screen_dc) return 0;
- if (create_icon_bitmaps( bmi, width, height, &color, &mask ))
+ if (create_icon_bitmaps( bmi, width, height, &color, &mask, &alpha ))
{
/* Make sure we have room for the monochrome bitmap later on.
* Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
@@ -1033,6 +1124,7 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
{
WARN_(cursor)("\tunable to create an icon bitmap.\n");
DeleteObject( color );
+ DeleteObject( alpha );
DeleteObject( mask );
return 0;
}
@@ -1050,6 +1142,7 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
info->color = color;
info->mask = mask;
+ info->alpha = alpha;
info->data.ptHotSpot.x = hotspot.x;
info->data.ptHotSpot.y = hotspot.y;
info->data.nWidth = bmpXor.bmWidth;
@@ -1068,6 +1161,7 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
else
{
DeleteObject( color );
+ DeleteObject( alpha );
DeleteObject( mask );
}
@@ -1678,6 +1772,7 @@ HICON WINAPI CopyIcon( HICON hIcon )
ptrNew = get_icon_ptr( hNew );
memcpy( &ptrNew->data, &ptrOld->data, sizeof(ptrNew->data) + size );
ptrNew->color = copy_bitmap( ptrOld->color );
+ ptrNew->alpha = copy_bitmap( ptrOld->alpha );
ptrNew->mask = copy_bitmap( ptrOld->mask );
release_icon_ptr( hIcon, ptrOld );
release_icon_ptr( hNew, ptrNew );
@@ -2149,6 +2244,7 @@ HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
info->color = color;
info->mask = mask;
+ info->alpha = create_alpha_bitmap( iconinfo->hbmColor, mask, NULL, NULL );
/* If we are creating an icon, the hotspot is unused */
if (iconinfo->fIcon)
More information about the wine-cvs
mailing list