user32: Store color and mask bitmaps in the cursor data.
This commit is contained in:
parent
e58afcfb2d
commit
f78c5c940a
@ -135,6 +135,8 @@ struct cursoricon_object
|
||||
{
|
||||
struct user_object obj; /* object header */
|
||||
ULONG_PTR param; /* opaque param used by 16-bit code */
|
||||
HBITMAP color; /* color bitmap */
|
||||
HBITMAP mask; /* mask bitmap (followed by color for 1-bpp icons) */
|
||||
CURSORICONINFO data;
|
||||
/* followed by cursor bits in CURSORICONINFO format */
|
||||
};
|
||||
@ -144,6 +146,8 @@ static HICON alloc_icon_handle( unsigned int size )
|
||||
struct cursoricon_object *obj = HeapAlloc( GetProcessHeap(), 0, sizeof(*obj) + size );
|
||||
if (!obj) return 0;
|
||||
obj->param = 0;
|
||||
obj->color = 0;
|
||||
obj->mask = 0;
|
||||
return alloc_user_handle( &obj->obj, USER_ICON );
|
||||
}
|
||||
|
||||
@ -171,6 +175,8 @@ static BOOL free_icon_handle( HICON handle )
|
||||
else if (obj)
|
||||
{
|
||||
ULONG_PTR param = obj->param;
|
||||
if (obj->color) DeleteObject( obj->color );
|
||||
DeleteObject( obj->mask );
|
||||
HeapFree( GetProcessHeap(), 0, obj );
|
||||
if (wow_handlers.free_icon_param && param) wow_handlers.free_icon_param( param );
|
||||
USER_Driver->pDestroyCursorIcon( handle );
|
||||
@ -328,6 +334,32 @@ static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* copy_bitmap
|
||||
*
|
||||
* Helper function to duplicate a bitmap.
|
||||
*/
|
||||
static HBITMAP copy_bitmap( HBITMAP bitmap )
|
||||
{
|
||||
HDC src, dst;
|
||||
HBITMAP new_bitmap;
|
||||
BITMAP bmp;
|
||||
|
||||
if (!bitmap) return 0;
|
||||
if (!GetObjectW( bitmap, sizeof(bmp), &bmp )) return 0;
|
||||
|
||||
src = CreateCompatibleDC( 0 );
|
||||
dst = CreateCompatibleDC( 0 );
|
||||
SelectObject( src, bitmap );
|
||||
new_bitmap = CreateCompatibleBitmap( src, bmp.bmWidth, bmp.bmHeight );
|
||||
SelectObject( dst, new_bitmap );
|
||||
BitBlt( dst, 0, 0, bmp.bmWidth, bmp.bmHeight, src, 0, 0, SRCCOPY );
|
||||
DeleteDC( dst );
|
||||
DeleteDC( src );
|
||||
return new_bitmap;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* is_dib_monochrome
|
||||
*
|
||||
@ -742,6 +774,90 @@ static BOOL stretch_blt_icon(HBITMAP hDest, BITMAPINFO *pDestInfo, BITMAPINFO *p
|
||||
return res;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* create_icon_bitmaps
|
||||
*
|
||||
* Create the color and mask bitmaps from the DIB info.
|
||||
*/
|
||||
static BOOL create_icon_bitmaps( const BITMAPINFO *bmi, int width, int height,
|
||||
HBITMAP *color, HBITMAP *mask )
|
||||
{
|
||||
BOOL monochrome = is_dib_monochrome( bmi );
|
||||
unsigned int size = bitmap_info_size( bmi, DIB_RGB_COLORS );
|
||||
BITMAPINFO *info;
|
||||
void *color_bits, *mask_bits;
|
||||
BOOL ret = FALSE;
|
||||
HDC hdc = 0;
|
||||
|
||||
if (!(info = HeapAlloc( GetProcessHeap(), 0, max( size, FIELD_OFFSET( BITMAPINFO, bmiColors[2] )))))
|
||||
return FALSE;
|
||||
if (!(hdc = CreateCompatibleDC( 0 ))) goto done;
|
||||
|
||||
memcpy( info, bmi, size );
|
||||
info->bmiHeader.biHeight /= 2;
|
||||
|
||||
color_bits = (char *)bmi + size;
|
||||
mask_bits = (char *)color_bits +
|
||||
get_dib_width_bytes( bmi->bmiHeader.biWidth,
|
||||
bmi->bmiHeader.biBitCount ) * abs(info->bmiHeader.biHeight);
|
||||
|
||||
if (monochrome)
|
||||
{
|
||||
if (!(*mask = CreateBitmap( width, height * 2, 1, 1, NULL ))) goto done;
|
||||
*color = 0;
|
||||
|
||||
/* copy color data into second half of mask bitmap */
|
||||
SelectObject( hdc, *mask );
|
||||
StretchDIBits( hdc, 0, height, width, height,
|
||||
0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight,
|
||||
color_bits, info, DIB_RGB_COLORS, SRCCOPY );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(*mask = CreateBitmap( width, height, 1, 1, NULL ))) goto done;
|
||||
if (!(*color = CreateBitmap( width, height, GetDeviceCaps( screen_dc, PLANES ),
|
||||
GetDeviceCaps( screen_dc, BITSPIXEL ), NULL )))
|
||||
{
|
||||
DeleteObject( *mask );
|
||||
goto done;
|
||||
}
|
||||
SelectObject( hdc, *color );
|
||||
StretchDIBits( hdc, 0, 0, width, height,
|
||||
0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight,
|
||||
color_bits, info, DIB_RGB_COLORS, SRCCOPY );
|
||||
|
||||
/* convert info to monochrome to copy the mask */
|
||||
info->bmiHeader.biBitCount = 1;
|
||||
if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
|
||||
{
|
||||
RGBQUAD *rgb = info->bmiColors;
|
||||
|
||||
info->bmiHeader.biClrUsed = info->bmiHeader.biClrImportant = 2;
|
||||
rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
|
||||
rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
|
||||
rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)info) + 1);
|
||||
|
||||
rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
|
||||
rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
SelectObject( hdc, *mask );
|
||||
StretchDIBits( hdc, 0, 0, width, height,
|
||||
0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight,
|
||||
mask_bits, info, DIB_RGB_COLORS, SRCCOPY );
|
||||
ret = TRUE;
|
||||
|
||||
done:
|
||||
DeleteDC( hdc );
|
||||
HeapFree( GetProcessHeap(), 0, info );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
|
||||
POINT16 hotspot, BOOL bIcon,
|
||||
DWORD dwVersion,
|
||||
@ -750,7 +866,7 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
|
||||
{
|
||||
HICON hObj;
|
||||
int sizeAnd, sizeXor;
|
||||
HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
|
||||
HBITMAP color = 0, mask = 0, hAndBits = 0, hXorBits = 0; /* error condition for later */
|
||||
BITMAP bmpXor, bmpAnd;
|
||||
BOOL do_stretch;
|
||||
INT size;
|
||||
@ -787,7 +903,9 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
|
||||
}
|
||||
|
||||
if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
|
||||
if (screen_dc)
|
||||
if (!screen_dc) return 0;
|
||||
|
||||
if (create_icon_bitmaps( bmi, width, height, &color, &mask ))
|
||||
{
|
||||
/* Make sure we have room for the monochrome bitmap later on.
|
||||
* Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
|
||||
@ -914,6 +1032,8 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
|
||||
if( !hXorBits || !hAndBits )
|
||||
{
|
||||
WARN_(cursor)("\tunable to create an icon bitmap.\n");
|
||||
DeleteObject( color );
|
||||
DeleteObject( mask );
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -928,6 +1048,8 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
|
||||
{
|
||||
struct cursoricon_object *info = get_icon_ptr( hObj );
|
||||
|
||||
info->color = color;
|
||||
info->mask = mask;
|
||||
info->data.ptHotSpot.x = hotspot.x;
|
||||
info->data.ptHotSpot.y = hotspot.y;
|
||||
info->data.nWidth = bmpXor.bmWidth;
|
||||
@ -943,6 +1065,11 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
|
||||
release_icon_ptr( hObj, info );
|
||||
USER_Driver->pCreateCursorIcon( hObj, &info->data );
|
||||
}
|
||||
else
|
||||
{
|
||||
DeleteObject( color );
|
||||
DeleteObject( mask );
|
||||
}
|
||||
|
||||
DeleteObject( hAndBits );
|
||||
DeleteObject( hXorBits );
|
||||
@ -1550,6 +1677,8 @@ HICON WINAPI CopyIcon( HICON hIcon )
|
||||
hNew = alloc_icon_handle( size );
|
||||
ptrNew = get_icon_ptr( hNew );
|
||||
memcpy( &ptrNew->data, &ptrOld->data, sizeof(ptrNew->data) + size );
|
||||
ptrNew->color = copy_bitmap( ptrOld->color );
|
||||
ptrNew->mask = copy_bitmap( ptrOld->mask );
|
||||
release_icon_ptr( hIcon, ptrOld );
|
||||
release_icon_ptr( hNew, ptrNew );
|
||||
USER_Driver->pCreateCursorIcon( hNew, &ptrNew->data );
|
||||
@ -1946,7 +2075,9 @@ HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
|
||||
DIBSECTION bmpXor;
|
||||
BITMAP bmpAnd;
|
||||
HICON hObj;
|
||||
int xor_objsize = 0, sizeXor = 0, sizeAnd, planes, bpp;
|
||||
HBITMAP color = 0, mask;
|
||||
int xor_objsize = 0, sizeXor = 0, sizeAnd, width, height, planes, bpp;
|
||||
HDC src, dst;
|
||||
|
||||
TRACE("color %p, mask %p, hotspot %ux%u, fIcon %d\n",
|
||||
iconinfo->hbmColor, iconinfo->hbmMask,
|
||||
@ -1957,6 +2088,11 @@ HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
|
||||
planes = GetDeviceCaps( screen_dc, PLANES );
|
||||
bpp = GetDeviceCaps( screen_dc, BITSPIXEL );
|
||||
|
||||
GetObjectW( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd );
|
||||
TRACE("mask: width %d, height %d, width bytes %d, planes %u, bpp %u\n",
|
||||
bmpAnd.bmWidth, bmpAnd.bmHeight, bmpAnd.bmWidthBytes,
|
||||
bmpAnd.bmPlanes, bmpAnd.bmBitsPixel);
|
||||
|
||||
if (iconinfo->hbmColor)
|
||||
{
|
||||
xor_objsize = GetObjectW( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor );
|
||||
@ -1966,19 +2102,54 @@ HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
|
||||
/* we can use either depth 1 or screen depth for xor bitmap */
|
||||
if (bmpXor.dsBm.bmPlanes == 1 && bmpXor.dsBm.bmBitsPixel == 1) planes = bpp = 1;
|
||||
sizeXor = bmpXor.dsBm.bmHeight * planes * get_bitmap_width_bytes( bmpXor.dsBm.bmWidth, bpp );
|
||||
}
|
||||
GetObjectW( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd );
|
||||
TRACE("mask: width %d, height %d, width bytes %d, planes %u, bpp %u\n",
|
||||
bmpAnd.bmWidth, bmpAnd.bmHeight, bmpAnd.bmWidthBytes,
|
||||
bmpAnd.bmPlanes, bmpAnd.bmBitsPixel);
|
||||
|
||||
sizeAnd = bmpAnd.bmHeight * get_bitmap_width_bytes(bmpAnd.bmWidth, 1);
|
||||
width = bmpXor.dsBm.bmWidth;
|
||||
height = bmpXor.dsBm.bmHeight;
|
||||
if (bmpXor.dsBm.bmPlanes * bmpXor.dsBm.bmBitsPixel != 1)
|
||||
{
|
||||
color = CreateCompatibleBitmap( screen_dc, width, height );
|
||||
mask = CreateBitmap( width, height, 1, 1, NULL );
|
||||
}
|
||||
else mask = CreateBitmap( width, height * 2, 1, 1, NULL );
|
||||
}
|
||||
else
|
||||
{
|
||||
width = bmpAnd.bmWidth;
|
||||
height = bmpAnd.bmHeight;
|
||||
mask = CreateBitmap( width, height, 1, 1, NULL );
|
||||
}
|
||||
|
||||
sizeAnd = height * get_bitmap_width_bytes(width, 1);
|
||||
|
||||
src = CreateCompatibleDC( 0 );
|
||||
dst = CreateCompatibleDC( 0 );
|
||||
|
||||
SelectObject( src, iconinfo->hbmMask );
|
||||
SelectObject( dst, mask );
|
||||
StretchBlt( dst, 0, 0, width, height, src, 0, 0, bmpAnd.bmWidth, bmpAnd.bmHeight, SRCCOPY );
|
||||
|
||||
if (color)
|
||||
{
|
||||
SelectObject( src, iconinfo->hbmColor );
|
||||
SelectObject( dst, color );
|
||||
BitBlt( dst, 0, 0, width, height, src, 0, 0, SRCCOPY );
|
||||
}
|
||||
else if (iconinfo->hbmColor)
|
||||
{
|
||||
SelectObject( src, iconinfo->hbmColor );
|
||||
BitBlt( dst, 0, height, width, height, src, 0, 0, SRCCOPY );
|
||||
}
|
||||
DeleteDC( src );
|
||||
DeleteDC( dst );
|
||||
|
||||
hObj = alloc_icon_handle( sizeXor + sizeAnd );
|
||||
if (hObj)
|
||||
{
|
||||
struct cursoricon_object *info = get_icon_ptr( hObj );
|
||||
|
||||
info->color = color;
|
||||
info->mask = mask;
|
||||
|
||||
/* If we are creating an icon, the hotspot is unused */
|
||||
if (iconinfo->fIcon)
|
||||
{
|
||||
@ -2010,37 +2181,9 @@ HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
|
||||
|
||||
/* Transfer the bitmap bits to the CURSORICONINFO structure */
|
||||
|
||||
/* Some apps pass a color bitmap as a mask, convert it to b/w */
|
||||
if (bmpAnd.bmBitsPixel == 1)
|
||||
{
|
||||
GetBitmapBits( iconinfo->hbmMask, sizeAnd, info + 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
HDC hdc_mem, hdc_mem2;
|
||||
HBITMAP hbmp_mem_old, hbmp_mem2_old, hbmp_mono;
|
||||
GetBitmapBits( mask, sizeAnd, info + 1 );
|
||||
|
||||
hdc_mem = CreateCompatibleDC( 0 );
|
||||
hdc_mem2 = CreateCompatibleDC( 0 );
|
||||
|
||||
hbmp_mono = CreateBitmap( bmpAnd.bmWidth, bmpAnd.bmHeight, 1, 1, NULL );
|
||||
|
||||
hbmp_mem_old = SelectObject( hdc_mem, iconinfo->hbmMask );
|
||||
hbmp_mem2_old = SelectObject( hdc_mem2, hbmp_mono );
|
||||
|
||||
BitBlt( hdc_mem2, 0, 0, bmpAnd.bmWidth, bmpAnd.bmHeight, hdc_mem, 0, 0, SRCCOPY );
|
||||
|
||||
SelectObject( hdc_mem, hbmp_mem_old );
|
||||
SelectObject( hdc_mem2, hbmp_mem2_old );
|
||||
|
||||
DeleteDC( hdc_mem );
|
||||
DeleteDC( hdc_mem2 );
|
||||
|
||||
GetBitmapBits( hbmp_mono, sizeAnd, info + 1 );
|
||||
DeleteObject( hbmp_mono );
|
||||
}
|
||||
|
||||
if (iconinfo->hbmColor)
|
||||
if (color)
|
||||
{
|
||||
char *dst_bits = (char*)(info + 1) + sizeAnd;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user