user32: Add support for multiple frames in cursor format.

This commit is contained in:
Erich Hoover 2010-09-26 12:26:23 -06:00 committed by Alexandre Julliard
parent ca7163e438
commit 7bba6234e3
1 changed files with 113 additions and 66 deletions

View File

@ -119,23 +119,24 @@ struct cursoricon_frame
struct cursoricon_object
{
struct user_object obj; /* object header */
ULONG_PTR param; /* opaque param used by 16-bit code */
BOOL is_icon; /* whether icon or cursor */
struct user_object obj; /* object header */
ULONG_PTR param; /* opaque param used by 16-bit code */
BOOL is_icon; /* whether icon or cursor */
UINT width;
UINT height;
POINT hotspot;
struct cursoricon_frame frame; /* icon frame information */
UINT num_frames; /* number of frames in the icon/cursor */
UINT ms_delay; /* delay between frames (in milliseconds) */
struct cursoricon_frame frames[1]; /* icon frame information */
};
static HICON alloc_icon_handle(void)
static HICON alloc_icon_handle( UINT num_frames )
{
struct cursoricon_object *obj = HeapAlloc( GetProcessHeap(), 0, sizeof(*obj) );
struct cursoricon_object *obj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
FIELD_OFFSET( struct cursoricon_object, frames[num_frames] ));
if (!obj) return 0;
obj->param = 0;
obj->frame.color = 0;
obj->frame.mask = 0;
obj->frame.alpha = 0;
obj->num_frames = num_frames;
return alloc_user_handle( &obj->obj, USER_ICON );
}
@ -163,9 +164,14 @@ static BOOL free_icon_handle( HICON handle )
else if (obj)
{
ULONG_PTR param = obj->param;
if (obj->frame.alpha) DeleteObject( obj->frame.alpha );
if (obj->frame.color) DeleteObject( obj->frame.color );
DeleteObject( obj->frame.mask );
UINT i;
for (i=0; i<obj->num_frames; i++)
{
if (obj->frames[i].alpha) DeleteObject( obj->frames[i].alpha );
if (obj->frames[i].color) DeleteObject( obj->frames[i].color );
DeleteObject( obj->frames[i].mask );
}
HeapFree( GetProcessHeap(), 0, obj );
if (wow_handlers.free_icon_param && param) wow_handlers.free_icon_param( param );
USER_Driver->pDestroyCursorIcon( handle );
@ -921,7 +927,7 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
if (!create_icon_bitmaps( bmi, width, height, &color, &mask, &alpha )) return 0;
hObj = alloc_icon_handle();
hObj = alloc_icon_handle(1);
if (hObj)
{
struct cursoricon_object *info = get_icon_ptr( hObj );
@ -930,9 +936,9 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
info->hotspot = hotspot;
info->width = width;
info->height = height;
info->frame.color = color;
info->frame.mask = mask;
info->frame.alpha = alpha;
info->frames[0].color = color;
info->frames[0].mask = mask;
info->frames[0].alpha = alpha;
release_icon_ptr( hObj, info );
USER_Driver->pCreateCursorIcon( hObj );
}
@ -1055,16 +1061,16 @@ static void riff_find_chunk( DWORD chunk_id, DWORD chunk_type, const riff_chunk_
static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
INT width, INT height, INT depth )
{
HCURSOR cursor;
struct cursoricon_object *info;
ani_header header = {0};
LPBYTE frame_bits = 0;
POINT hotspot;
CURSORICONFILEDIRENTRY *entry;
HCURSOR cursor = 0;
UINT i, error = 0;
riff_chunk_t root_chunk = { bits_size, bits };
riff_chunk_t ACON_chunk = {0};
riff_chunk_t anih_chunk = {0};
riff_chunk_t fram_chunk = {0};
const unsigned char *icon_chunk;
const unsigned char *icon_data;
TRACE("bits %p, bits_size %d\n", bits, bits_size);
@ -1092,37 +1098,74 @@ static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
return 0;
}
/* FIXME: For now, just load the first frame. Before we can load all the
* frames, we need to write the needed code in wineserver, etc. to handle
* cursors. Once this code is written, we can extend it to support .ani
* cursors and then update user32 and winex11.drv to load all frames.
*
* Hopefully this will at least make some games (C&C3, etc.) more playable
* in the meantime.
*/
FIXME("Loading all frames for .ani cursors not implemented.\n");
cursor = alloc_icon_handle( header.num_frames );
if (!cursor) return 0;
info = get_icon_ptr( cursor );
info->is_icon = FALSE;
/* The .ANI stores the display rate in 1/60s, we store the delay between frames in ms */
info->ms_delay = (100 * header.display_rate) / 6;
icon_chunk = fram_chunk.data;
icon_data = fram_chunk.data + (2 * sizeof(DWORD));
entry = CURSORICON_FindBestIconFile( (CURSORICONFILEDIR *) icon_data,
width, height, depth );
frame_bits = HeapAlloc( GetProcessHeap(), 0, entry->dwDIBSize );
if (!frame_bits) return 0;
memcpy( frame_bits, icon_data + entry->dwDIBOffset, entry->dwDIBSize );
if (!header.width || !header.height)
for (i=0; i<header.num_frames; i++)
{
header.width = entry->bWidth;
header.height = entry->bHeight;
DWORD chunk_size = *(DWORD *)(icon_chunk + sizeof(DWORD));
struct cursoricon_frame *frame = &info->frames[i];
CURSORICONFILEDIRENTRY *entry;
BITMAPINFO *bmi;
entry = CURSORICON_FindBestIconFile( (CURSORICONFILEDIR *) icon_data,
width, height, depth );
bmi = (BITMAPINFO *) (icon_data + entry->dwDIBOffset);
info->hotspot.x = entry->xHotspot;
info->hotspot.y = entry->yHotspot;
if (!header.width || !header.height)
{
header.width = entry->bWidth;
header.height = entry->bHeight;
}
/* Grab a frame from the animation */
if (!create_icon_bitmaps( bmi, header.width, header.height,
&frame->color, &frame->mask, &frame->alpha ))
{
FIXME_(cursor)("failed to convert animated cursor frame.\n");
error = TRUE;
if (i == 0)
{
FIXME_(cursor)("Completely failed to create animated cursor!\n");
info->num_frames = 0;
release_icon_ptr( cursor, info );
free_icon_handle( cursor );
return 0;
}
break;
}
/* Advance to the next chunk */
icon_chunk += chunk_size + (2 * sizeof(DWORD));
icon_data = icon_chunk + (2 * sizeof(DWORD));
}
hotspot.x = entry->xHotspot;
hotspot.y = entry->yHotspot;
cursor = CURSORICON_CreateIconFromBMI( (BITMAPINFO *) frame_bits, hotspot,
FALSE, 0x00030000, header.width, header.height, 0 );
HeapFree( GetProcessHeap(), 0, frame_bits );
/* There was an error but we at least decoded the first frame, so just use that frame */
if (error)
{
FIXME_(cursor)("Error creating animated cursor, only using first frame!\n");
for (i=1; i<info->num_frames; i++)
{
if (info->frames[i].mask) DeleteObject( info->frames[i].mask );
if (info->frames[i].color) DeleteObject( info->frames[i].color );
if (info->frames[i].alpha) DeleteObject( info->frames[i].alpha );
}
info->num_frames = 1;
info->ms_delay = 0;
}
info->width = header.width;
info->height = header.height;
release_icon_ptr( cursor, info );
return cursor;
}
@ -1534,16 +1577,16 @@ HICON WINAPI CopyIcon( HICON hIcon )
HICON hNew;
if (!(ptrOld = get_icon_ptr( hIcon ))) return 0;
if ((hNew = alloc_icon_handle()))
if ((hNew = alloc_icon_handle(1)))
{
ptrNew = get_icon_ptr( hNew );
ptrNew->is_icon = ptrOld->is_icon;
ptrNew->width = ptrOld->width;
ptrNew->height = ptrOld->height;
ptrNew->hotspot = ptrOld->hotspot;
ptrNew->frame.mask = copy_bitmap( ptrOld->frame.mask );
ptrNew->frame.color = copy_bitmap( ptrOld->frame.color );
ptrNew->frame.alpha = copy_bitmap( ptrOld->frame.alpha );
ptrNew->frames[0].mask = copy_bitmap( ptrOld->frames[0].mask );
ptrNew->frames[0].color = copy_bitmap( ptrOld->frames[0].color );
ptrNew->frames[0].alpha = copy_bitmap( ptrOld->frames[0].alpha );
release_icon_ptr( hNew, ptrNew );
}
release_icon_ptr( hIcon, ptrOld );
@ -1829,8 +1872,8 @@ BOOL WINAPI GetIconInfo(HICON hIcon, PICONINFO iconinfo)
iconinfo->fIcon = ptr->is_icon;
iconinfo->xHotspot = ptr->hotspot.x;
iconinfo->yHotspot = ptr->hotspot.y;
iconinfo->hbmColor = copy_bitmap( ptr->frame.color );
iconinfo->hbmMask = copy_bitmap( ptr->frame.mask );
iconinfo->hbmColor = copy_bitmap( ptr->frames[0].color );
iconinfo->hbmMask = copy_bitmap( ptr->frames[0].mask );
release_icon_ptr( hIcon, ptr );
return TRUE;
@ -1935,7 +1978,7 @@ HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
DeleteDC( hdc );
hObj = alloc_icon_handle();
hObj = alloc_icon_handle(1);
if (hObj)
{
struct cursoricon_object *info = get_icon_ptr( hObj );
@ -1943,9 +1986,9 @@ HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
info->is_icon = iconinfo->fIcon;
info->width = width;
info->height = height;
info->frame.color = color;
info->frame.mask = mask;
info->frame.alpha = create_alpha_bitmap( iconinfo->hbmColor, mask, NULL, NULL );
info->frames[0].color = color;
info->frames[0].mask = mask;
info->frames[0].alpha = create_alpha_bitmap( iconinfo->hbmColor, mask, NULL, NULL );
if (info->is_icon)
{
info->hotspot.x = width / 2;
@ -2005,8 +2048,12 @@ BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
return FALSE;
}
if (istep)
FIXME_(icon)("Ignoring istep=%d\n", istep);
if (istep >= ptr->num_frames)
{
TRACE_(icon)("Stepped past end of animated frames=%d\n", istep);
release_icon_ptr( hIcon, ptr );
return FALSE;
}
if (flags & DI_NOMIRROR)
FIXME_(icon)("Ignoring flag DI_NOMIRROR\n");
@ -2058,7 +2105,7 @@ BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
oldFg = SetTextColor( hdc, RGB(0,0,0) );
oldBg = SetBkColor( hdc, RGB(255,255,255) );
if (ptr->frame.alpha && (flags & DI_IMAGE))
if (ptr->frames[istep].alpha && (flags & DI_IMAGE))
{
BOOL is_mono = FALSE;
@ -2071,7 +2118,7 @@ BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
if (!is_mono)
{
BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
SelectObject( hMemDC, ptr->frame.alpha );
SelectObject( hMemDC, ptr->frames[istep].alpha );
if (GdiAlphaBlend( hdc_dest, x, y, cxWidth, cyWidth, hMemDC,
0, 0, ptr->width, ptr->height, pixelblend )) goto done;
}
@ -2079,24 +2126,24 @@ BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
if (flags & DI_MASK)
{
SelectObject( hMemDC, ptr->frame.mask );
SelectObject( hMemDC, ptr->frames[istep].mask );
StretchBlt( hdc_dest, x, y, cxWidth, cyWidth,
hMemDC, 0, 0, ptr->width, ptr->height, SRCAND );
}
if (flags & DI_IMAGE)
{
if (ptr->frame.color)
if (ptr->frames[istep].color)
{
DWORD rop = (flags & DI_MASK) ? SRCINVERT : SRCCOPY;
SelectObject( hMemDC, ptr->frame.color );
SelectObject( hMemDC, ptr->frames[istep].color );
StretchBlt( hdc_dest, x, y, cxWidth, cyWidth,
hMemDC, 0, 0, ptr->width, ptr->height, rop );
}
else
{
DWORD rop = (flags & DI_MASK) ? SRCINVERT : SRCCOPY;
SelectObject( hMemDC, ptr->frame.mask );
SelectObject( hMemDC, ptr->frames[istep].mask );
StretchBlt( hdc_dest, x, y, cxWidth, cyWidth,
hMemDC, 0, ptr->height, ptr->width, ptr->height, rop );
}