user32: Add preliminary support for reading and storing multi-rate animated cursor data.

This commit is contained in:
Erich Hoover 2011-03-09 22:56:40 -07:00 committed by Alexandre Julliard
parent 389ffed293
commit 3e35caa7b2
2 changed files with 152 additions and 151 deletions

View File

@ -83,6 +83,7 @@ static struct list icon_cache = LIST_INIT( icon_cache );
struct cursoricon_frame struct cursoricon_frame
{ {
UINT delay; /* frame-specific delay between this frame and the next (in jiffies) */
HBITMAP color; /* color bitmap */ HBITMAP color; /* color bitmap */
HBITMAP alpha; /* pre-multiplied alpha bitmap for 32-bpp icons */ HBITMAP alpha; /* pre-multiplied alpha bitmap for 32-bpp icons */
HBITMAP mask; /* mask bitmap (followed by color for 1-bpp icons) */ HBITMAP mask; /* mask bitmap (followed by color for 1-bpp icons) */
@ -102,7 +103,7 @@ struct cursoricon_object
POINT hotspot; POINT hotspot;
UINT num_frames; /* number of frames in the icon/cursor */ UINT num_frames; /* number of frames in the icon/cursor */
UINT num_steps; /* number of sequence steps in the icon/cursor */ UINT num_steps; /* number of sequence steps in the icon/cursor */
UINT delay; /* delay between frames (in jiffies) */ UINT delay; /* global delay between frames (in jiffies) */
struct cursoricon_frame frames[1]; /* icon frame information */ struct cursoricon_frame frames[1]; /* icon frame information */
}; };
@ -850,6 +851,7 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi, HMODULE module, LPCW
info->hotspot = hotspot; info->hotspot = hotspot;
info->width = width; info->width = width;
info->height = height; info->height = height;
info->frames[0].delay = ~0;
info->frames[0].color = color; info->frames[0].color = color;
info->frames[0].mask = mask; info->frames[0].mask = mask;
info->frames[0].alpha = alpha; info->frames[0].alpha = alpha;
@ -989,6 +991,7 @@ static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
INT width, INT height, INT depth, UINT loadflags ) INT width, INT height, INT depth, UINT loadflags )
{ {
struct cursoricon_object *info; struct cursoricon_object *info;
DWORD *frame_rates = NULL;
ani_header header = {0}; ani_header header = {0};
HCURSOR cursor = 0; HCURSOR cursor = 0;
UINT i, error = 0; UINT i, error = 0;
@ -1029,8 +1032,10 @@ static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
FIXME("Animated icon/cursor sequence data is not currently supported, frames may appear out of sequence.\n"); FIXME("Animated icon/cursor sequence data is not currently supported, frames may appear out of sequence.\n");
riff_find_chunk( ANI_rate_ID, 0, &ACON_chunk, &rate_chunk ); riff_find_chunk( ANI_rate_ID, 0, &ACON_chunk, &rate_chunk );
if (rate_chunk.data) if (rate_chunk.data && header.num_steps == header.num_frames)
FIXME("Animated icon/cursor multiple frame-frate data not currently supported.\n"); frame_rates = (DWORD *) rate_chunk.data;
else if (rate_chunk.data && header.num_steps != 1)
FIXME("Animated icon/cursor rate data for sequence-based cursors not supported.\n");
riff_find_chunk( ANI_fram_ID, ANI_LIST_ID, &ACON_chunk, &fram_chunk ); riff_find_chunk( ANI_fram_ID, ANI_LIST_ID, &ACON_chunk, &fram_chunk );
if (!fram_chunk.data) if (!fram_chunk.data)
@ -1075,6 +1080,10 @@ static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
header.width = entry->bWidth; header.width = entry->bWidth;
header.height = entry->bHeight; header.height = entry->bHeight;
} }
if (frame_rates)
frame->delay = frame_rates[i];
else
frame->delay = ~0;
/* Grab a frame from the animation */ /* Grab a frame from the animation */
if (!create_icon_bitmaps( bmi, header.width, header.height, if (!create_icon_bitmaps( bmi, header.width, header.height,
@ -1419,6 +1428,7 @@ HICON WINAPI CopyIcon( HICON hIcon )
ptrNew->width = ptrOld->width; ptrNew->width = ptrOld->width;
ptrNew->height = ptrOld->height; ptrNew->height = ptrOld->height;
ptrNew->hotspot = ptrOld->hotspot; ptrNew->hotspot = ptrOld->hotspot;
ptrNew->frames[0].delay = ptrOld->frames[0].delay;
ptrNew->frames[0].mask = copy_bitmap( ptrOld->frames[0].mask ); ptrNew->frames[0].mask = copy_bitmap( ptrOld->frames[0].mask );
ptrNew->frames[0].color = copy_bitmap( ptrOld->frames[0].color ); ptrNew->frames[0].color = copy_bitmap( ptrOld->frames[0].color );
ptrNew->frames[0].alpha = copy_bitmap( ptrOld->frames[0].alpha ); ptrNew->frames[0].alpha = copy_bitmap( ptrOld->frames[0].alpha );
@ -1752,7 +1762,11 @@ HCURSOR WINAPI GetCursorFrameInfo(HCURSOR hCursor, DWORD unk1, DWORD istep, DWOR
*num_steps = ~0; *num_steps = ~0;
else else
*num_steps = ptr->num_steps; *num_steps = ptr->num_steps;
*rate_jiffies = ptr->delay; /* If this specific frame does not have a delay then use the global delay */
if (ptr->frames[istep].delay == ~0)
*rate_jiffies = ptr->delay;
else
*rate_jiffies = ptr->frames[istep].delay;
} }
} }
@ -1957,6 +1971,7 @@ HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
info->is_icon = iconinfo->fIcon; info->is_icon = iconinfo->fIcon;
info->width = width; info->width = width;
info->height = height; info->height = height;
info->frames[0].delay = ~0;
info->frames[0].color = color; info->frames[0].color = color;
info->frames[0].mask = mask; info->frames[0].mask = mask;
info->frames[0].alpha = create_alpha_bitmap( iconinfo->hbmColor, mask, NULL, NULL ); info->frames[0].alpha = create_alpha_bitmap( iconinfo->hbmColor, mask, NULL, NULL );

View File

@ -65,6 +65,7 @@ typedef struct
#define ANI_seq__ID RIFF_FOURCC('s', 'e', 'q', ' ') #define ANI_seq__ID RIFF_FOURCC('s', 'e', 'q', ' ')
#define ANI_fram_ID RIFF_FOURCC('f', 'r', 'a', 'm') #define ANI_fram_ID RIFF_FOURCC('f', 'r', 'a', 'm')
#define ANI_icon_ID RIFF_FOURCC('i', 'c', 'o', 'n') #define ANI_icon_ID RIFF_FOURCC('i', 'c', 'o', 'n')
#define ANI_rate_ID RIFF_FOURCC('r', 'a', 't', 'e')
#define ANI_FLAG_ICON 0x1 #define ANI_FLAG_ICON 0x1
#define ANI_FLAG_SEQUENCE 0x2 #define ANI_FLAG_SEQUENCE 0x2
@ -124,9 +125,64 @@ typedef struct {
DWORD chunk_type; /* ANI_ACON_ID */ DWORD chunk_type; /* ANI_ACON_ID */
riff_header_t header; /* RIFF animated cursor header */ riff_header_t header; /* RIFF animated cursor header */
riff_list_t frame_list; /* RIFF animated cursor frame list info */ riff_list_t frame_list; /* RIFF animated cursor frame list info */
riff_icon32x32x32_t frames[3]; /* array of animated cursor frames */ riff_icon32x32x32_t frames[3]; /* array of three animated cursor frames */
} riff_cursor3_t; } riff_cursor3_t;
typedef struct {
DWORD chunk_id; /* ANI_rate_ID */
DWORD chunk_size; /* actual size of data */
DWORD rate[3]; /* animated cursor rate data */
} riff_rate3_t;
typedef struct {
DWORD chunk_id; /* ANI_RIFF_ID */
DWORD chunk_size; /* actual size of data */
DWORD chunk_type; /* ANI_ACON_ID */
riff_header_t header; /* RIFF animated cursor header */
riff_rate3_t rates; /* rate data for three cursor frames */
riff_list_t frame_list; /* RIFF animated cursor frame list info */
riff_icon32x32x32_t frames[3]; /* array of three animated cursor frames */
} riff_cursor3_rate_t;
#define EMPTY_ICON32 \
{ \
ANI_icon_ID, \
sizeof(ani_frame32x32x32), \
{ \
{ \
0x0, /* reserved */ \
0, /* type: icon(1), cursor(2) */ \
1, /* count */ \
{ \
{ \
32, /* width */ \
32, /* height */ \
0, /* color count */ \
0x0, /* reserved */ \
16, /* x hotspot */ \
16, /* y hotspot */ \
sizeof(ani_data32x32x32), /* DIB size */ \
sizeof(CURSORICONFILEDIR) /* DIB offset */ \
} \
} \
}, \
{ \
sizeof(BITMAPINFOHEADER), /* structure for DIB-type data */ \
32, /* width */ \
32*2, /* actual height times two */ \
1, /* planes */ \
32, /* bpp */ \
BI_RGB, /* compression */ \
0, /* image size */ \
0, /* biXPelsPerMeter */ \
0, /* biYPelsPerMeter */ \
0, /* biClrUsed */ \
0 /* biClrImportant */ \
}, \
{ /* DIB data: left uninitialized */ } \
} \
}
riff_cursor1_t empty_anicursor = { riff_cursor1_t empty_anicursor = {
ANI_RIFF_ID, ANI_RIFF_ID,
sizeof(empty_anicursor) - sizeof(DWORD)*2, sizeof(empty_anicursor) - sizeof(DWORD)*2,
@ -152,43 +208,7 @@ riff_cursor1_t empty_anicursor = {
ANI_fram_ID, ANI_fram_ID,
}, },
{ {
{ EMPTY_ICON32
ANI_icon_ID,
sizeof(ani_frame32x32x32),
{
{
0x0, /* reserved */
0, /* type: icon(1), cursor(2) */
1, /* count */
{
{
32, /* width */
32, /* height */
0, /* color count */
0x0, /* reserved */
16, /* x hotspot */
16, /* y hotspot */
sizeof(ani_data32x32x32), /* DIB size */
sizeof(CURSORICONFILEDIR) /* DIB offset */
}
}
},
{
sizeof(BITMAPINFOHEADER), /* structure for DIB-type data */
32, /* width */
32*2, /* actual height times two */
1, /* planes */
32, /* bpp */
BI_RGB, /* compression */
0, /* image size */
0, /* biXPelsPerMeter */
0, /* biYPelsPerMeter */
0, /* biClrUsed */
0 /* biClrImportant */
},
{ /* DIB data: left uninitialized */ }
}
}
} }
}; };
@ -217,117 +237,45 @@ riff_cursor3_t empty_anicursor3 = {
ANI_fram_ID, ANI_fram_ID,
}, },
{ {
EMPTY_ICON32,
EMPTY_ICON32,
EMPTY_ICON32
}
};
riff_cursor3_rate_t empty_anicursor3_rate = {
ANI_RIFF_ID,
sizeof(empty_anicursor3_rate) - sizeof(DWORD)*2,
ANI_ACON_ID,
{
ANI_anih_ID,
sizeof(ani_header),
{ {
ANI_icon_ID, sizeof(ani_header),
sizeof(ani_frame32x32x32), 3, /* frames */
{ 3, /* steps */
{ 32, /* width */
0x0, /* reserved */ 32, /* height */
0, /* type: icon(1), cursor(2) */ 32, /* depth */
1, /* count */ 1, /* planes */
{ 0xbeef, /* display rate in jiffies */
{ ANI_FLAG_ICON /* flags */
32, /* width */
32, /* height */
0, /* color count */
0x0, /* reserved */
16, /* x hotspot */
16, /* y hotspot */
sizeof(ani_data32x32x32), /* DIB size */
sizeof(CURSORICONFILEDIR) /* DIB offset */
}
}
},
{
sizeof(BITMAPINFOHEADER), /* structure for DIB-type data */
32, /* width */
32*2, /* actual height times two */
1, /* planes */
32, /* bpp */
BI_RGB, /* compression */
0, /* image size */
0, /* biXPelsPerMeter */
0, /* biYPelsPerMeter */
0, /* biClrUsed */
0 /* biClrImportant */
},
{ /* DIB data: left uninitialized */ }
}
},
{
ANI_icon_ID,
sizeof(ani_frame32x32x32),
{
{
0x0, /* reserved */
0, /* type: icon(1), cursor(2) */
1, /* count */
{
{
32, /* width */
32, /* height */
0, /* color count */
0x0, /* reserved */
16, /* x hotspot */
16, /* y hotspot */
sizeof(ani_data32x32x32), /* DIB size */
sizeof(CURSORICONFILEDIR) /* DIB offset */
}
}
},
{
sizeof(BITMAPINFOHEADER), /* structure for DIB-type data */
32, /* width */
32*2, /* actual height times two */
1, /* planes */
32, /* bpp */
BI_RGB, /* compression */
0, /* image size */
0, /* biXPelsPerMeter */
0, /* biYPelsPerMeter */
0, /* biClrUsed */
0 /* biClrImportant */
},
{ /* DIB data: left uninitialized */ }
}
},
{
ANI_icon_ID,
sizeof(ani_frame32x32x32),
{
{
0x0, /* reserved */
0, /* type: icon(1), cursor(2) */
1, /* count */
{
{
32, /* width */
32, /* height */
0, /* color count */
0x0, /* reserved */
16, /* x hotspot */
16, /* y hotspot */
sizeof(ani_data32x32x32), /* DIB size */
sizeof(CURSORICONFILEDIR) /* DIB offset */
}
}
},
{
sizeof(BITMAPINFOHEADER), /* structure for DIB-type data */
32, /* width */
32*2, /* actual height times two */
1, /* planes */
32, /* bpp */
BI_RGB, /* compression */
0, /* image size */
0, /* biXPelsPerMeter */
0, /* biYPelsPerMeter */
0, /* biClrUsed */
0 /* biClrImportant */
},
{ /* DIB data: left uninitialized */ }
}
} }
},
{
ANI_rate_ID,
sizeof(riff_rate3_t) - sizeof(DWORD)*2,
{ 0xc0de, 0xcafe, 0xbabe}
},
{
ANI_LIST_ID,
sizeof(riff_icon32x32x32_t)*(3 /*frames*/) + sizeof(DWORD),
ANI_fram_ID,
},
{
EMPTY_ICON32,
EMPTY_ICON32,
EMPTY_ICON32
} }
}; };
@ -1633,6 +1581,44 @@ static void test_GetCursorFrameInfo(void)
ret = DestroyCursor(h1); ret = DestroyCursor(h1);
ok(ret, "DestroyCursor() failed.\n"); ok(ret, "DestroyCursor() failed.\n");
/* Creating a multi-frame animated cursor with rate data. */
for (i=0; i<empty_anicursor3_rate.header.header.num_frames; i++)
{
empty_anicursor3_rate.frames[i].data.icon_info.idType = 2; /* type: cursor */
empty_anicursor3_rate.frames[i].data.icon_info.idEntries[0].xHotspot = 3;
empty_anicursor3_rate.frames[i].data.icon_info.idEntries[0].yHotspot = 3;
}
h1 = CreateIconFromResource((PBYTE) &empty_anicursor3_rate, sizeof(empty_anicursor3_rate), FALSE, 0x00030000);
ok(h1 != NULL, "Create cursor failed.\n");
/* Check number of steps in multi-frame animated cursor with rate data */
i=0;
while (DrawIconEx(hdc, 0, 0, h1, 32, 32, i, NULL, DI_NORMAL))
i++;
ok(i == empty_anicursor3_rate.header.header.num_steps,
"Unexpected number of steps in cursor (%d != %d)\n",
i, empty_anicursor3_rate.header.header.num_steps);
/* Check GetCursorFrameInfo behavior on a multi-frame animated cursor with rate data */
for (i=0; i<empty_anicursor3_rate.header.header.num_frames; i++)
{
unk1 = unk2 = unk3 = unk4 = 0xdead;
h2 = pGetCursorFrameInfo(h1, &unk1, (VOID*)i, &unk3, &unk4);
ok(h2 != 0, "GetCursorFrameInfo() failed for cursor %p: (%p != 0).\n", h1, h2);
ok(unk1 == 0xdead, "GetCursorFrameInfo() unexpected param 2 value (0x%x != 0xdead).\n", unk1);
ok(unk2 == 0xdead, "GetCursorFrameInfo() unexpected param 3 value (0x%x != 0xdead).\n", unk2);
ok(unk3 == empty_anicursor3_rate.rates.rate[i],
"GetCursorFrameInfo() unexpected param 4 value (0x%x != 0x%x).\n",
unk3, empty_anicursor3_rate.rates.rate[i]);
ok(unk4 == empty_anicursor3_rate.header.header.num_steps,
"GetCursorFrameInfo() unexpected param 5 value (%d != %d).\n",
unk4, empty_anicursor3_rate.header.header.num_steps);
}
/* Clean up multi-frame animated cursor with rate data. */
ret = DestroyCursor(h1);
ok(ret, "DestroyCursor() failed.\n");
cleanup: cleanup:
if(bmpOld) SelectObject(hdc, bmpOld); if(bmpOld) SelectObject(hdc, bmpOld);
if(bmp) DeleteObject(bmp); if(bmp) DeleteObject(bmp);