user32: Add preliminary support for reading and storing multi-rate animated cursor data.
This commit is contained in:
parent
389ffed293
commit
3e35caa7b2
|
@ -83,6 +83,7 @@ static struct list icon_cache = LIST_INIT( icon_cache );
|
|||
|
||||
struct cursoricon_frame
|
||||
{
|
||||
UINT delay; /* frame-specific delay between this frame and the next (in jiffies) */
|
||||
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) */
|
||||
|
@ -102,7 +103,7 @@ struct cursoricon_object
|
|||
POINT hotspot;
|
||||
UINT num_frames; /* number of frames 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 */
|
||||
};
|
||||
|
||||
|
@ -850,6 +851,7 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi, HMODULE module, LPCW
|
|||
info->hotspot = hotspot;
|
||||
info->width = width;
|
||||
info->height = height;
|
||||
info->frames[0].delay = ~0;
|
||||
info->frames[0].color = color;
|
||||
info->frames[0].mask = mask;
|
||||
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 )
|
||||
{
|
||||
struct cursoricon_object *info;
|
||||
DWORD *frame_rates = NULL;
|
||||
ani_header header = {0};
|
||||
HCURSOR cursor = 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");
|
||||
|
||||
riff_find_chunk( ANI_rate_ID, 0, &ACON_chunk, &rate_chunk );
|
||||
if (rate_chunk.data)
|
||||
FIXME("Animated icon/cursor multiple frame-frate data not currently supported.\n");
|
||||
if (rate_chunk.data && header.num_steps == header.num_frames)
|
||||
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 );
|
||||
if (!fram_chunk.data)
|
||||
|
@ -1075,6 +1080,10 @@ static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
|
|||
header.width = entry->bWidth;
|
||||
header.height = entry->bHeight;
|
||||
}
|
||||
if (frame_rates)
|
||||
frame->delay = frame_rates[i];
|
||||
else
|
||||
frame->delay = ~0;
|
||||
|
||||
/* Grab a frame from the animation */
|
||||
if (!create_icon_bitmaps( bmi, header.width, header.height,
|
||||
|
@ -1419,6 +1428,7 @@ HICON WINAPI CopyIcon( HICON hIcon )
|
|||
ptrNew->width = ptrOld->width;
|
||||
ptrNew->height = ptrOld->height;
|
||||
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].color = copy_bitmap( ptrOld->frames[0].color );
|
||||
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;
|
||||
else
|
||||
*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->width = width;
|
||||
info->height = height;
|
||||
info->frames[0].delay = ~0;
|
||||
info->frames[0].color = color;
|
||||
info->frames[0].mask = mask;
|
||||
info->frames[0].alpha = create_alpha_bitmap( iconinfo->hbmColor, mask, NULL, NULL );
|
||||
|
|
|
@ -65,6 +65,7 @@ typedef struct
|
|||
#define ANI_seq__ID RIFF_FOURCC('s', 'e', 'q', ' ')
|
||||
#define ANI_fram_ID RIFF_FOURCC('f', 'r', 'a', 'm')
|
||||
#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_SEQUENCE 0x2
|
||||
|
@ -124,9 +125,64 @@ typedef struct {
|
|||
DWORD chunk_type; /* ANI_ACON_ID */
|
||||
riff_header_t header; /* RIFF animated cursor header */
|
||||
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;
|
||||
|
||||
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 = {
|
||||
ANI_RIFF_ID,
|
||||
sizeof(empty_anicursor) - sizeof(DWORD)*2,
|
||||
|
@ -152,43 +208,7 @@ riff_cursor1_t empty_anicursor = {
|
|||
ANI_fram_ID,
|
||||
},
|
||||
{
|
||||
{
|
||||
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 */ }
|
||||
}
|
||||
}
|
||||
EMPTY_ICON32
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -217,117 +237,45 @@ riff_cursor3_t empty_anicursor3 = {
|
|||
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_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_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 */ }
|
||||
}
|
||||
sizeof(ani_header),
|
||||
3, /* frames */
|
||||
3, /* steps */
|
||||
32, /* width */
|
||||
32, /* height */
|
||||
32, /* depth */
|
||||
1, /* planes */
|
||||
0xbeef, /* display rate in jiffies */
|
||||
ANI_FLAG_ICON /* flags */
|
||||
}
|
||||
},
|
||||
{
|
||||
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);
|
||||
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:
|
||||
if(bmpOld) SelectObject(hdc, bmpOld);
|
||||
if(bmp) DeleteObject(bmp);
|
||||
|
|
Loading…
Reference in New Issue