user32: Fix GetCursorFrameInfo when passed the proper number of steps.

This commit is contained in:
Erich Hoover 2011-03-09 22:56:16 -07:00 committed by Alexandre Julliard
parent 477702c829
commit 86a9f20aa2
2 changed files with 141 additions and 38 deletions

View File

@ -101,6 +101,7 @@ struct cursoricon_object
UINT height; UINT height;
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 delay; /* delay between frames (in jiffies) */ UINT delay; /* delay between frames (in jiffies) */
struct cursoricon_frame frames[1]; /* icon frame information */ struct cursoricon_frame frames[1]; /* icon frame information */
}; };
@ -112,6 +113,7 @@ static HICON alloc_icon_handle( UINT num_frames )
if (!obj) return 0; if (!obj) return 0;
obj->delay = 0; obj->delay = 0;
obj->num_steps = num_frames; /* changed later for some animated cursors */
obj->num_frames = num_frames; obj->num_frames = num_frames;
return alloc_user_handle( &obj->obj, USER_ICON ); return alloc_user_handle( &obj->obj, USER_ICON );
} }
@ -1027,6 +1029,13 @@ static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
info = get_icon_ptr( cursor ); info = get_icon_ptr( cursor );
info->is_icon = FALSE; info->is_icon = FALSE;
if (header.num_steps > header.num_frames)
{
FIXME("More steps than frames and sequence-based cursors not yet supported.\n");
info->num_steps = header.num_frames;
}
else
info->num_steps = header.num_steps;
/* The .ANI stores the display rate in jiffies (1/60s) */ /* The .ANI stores the display rate in jiffies (1/60s) */
info->delay = header.display_rate; info->delay = header.display_rate;
@ -1085,6 +1094,7 @@ static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
if (info->frames[i].alpha) DeleteObject( info->frames[i].alpha ); if (info->frames[i].alpha) DeleteObject( info->frames[i].alpha );
} }
info->num_frames = 1; info->num_frames = 1;
info->num_steps = 1;
info->delay = 0; info->delay = 0;
} }
info->width = header.width; info->width = header.width;
@ -1700,28 +1710,33 @@ HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
/********************************************************************** /**********************************************************************
* GetCursorFrameInfo (USER32.@) * GetCursorFrameInfo (USER32.@)
*/ */
HCURSOR WINAPI GetCursorFrameInfo(HCURSOR hCursor, DWORD unk1, DWORD rate_index_num, DWORD *rate_jiffies, DWORD *is_static) HCURSOR WINAPI GetCursorFrameInfo(HCURSOR hCursor, DWORD unk1, DWORD istep, DWORD *rate_jiffies, DWORD *num_steps)
{ {
struct cursoricon_object *ptr; struct cursoricon_object *ptr;
HCURSOR ret = 0; HCURSOR ret = 0;
if (rate_jiffies == NULL || is_static == NULL) return 0; if (rate_jiffies == NULL || num_steps == NULL) return 0;
if (!(ptr = get_icon_ptr( hCursor ))) return 0; if (!(ptr = get_icon_ptr( hCursor ))) return 0;
FIXME("semi-stub! %p => %d %d %p %p\n", hCursor, unk1, rate_index_num, rate_jiffies, is_static); FIXME("semi-stub! %p => %d %d %p %p\n", hCursor, unk1, istep, rate_jiffies, num_steps);
if (ptr->num_frames == 1 || rate_index_num == 0) /* Important Note: Sequences are not currently supported, so this implementation
* will not properly handle all cases. */
if (istep < ptr->num_steps || ptr->num_frames == 1)
{ {
ret = hCursor; ret = hCursor;
if (ptr->num_frames == 1) if (ptr->num_frames == 1)
{ {
*rate_jiffies = 0; *rate_jiffies = 0;
*is_static = 1; *num_steps = 1;
} }
else else
{ {
*is_static = ~0; if (ptr->num_steps == 1)
*num_steps = ~0;
else
*num_steps = ptr->num_steps;
*rate_jiffies = ptr->delay; *rate_jiffies = ptr->delay;
} }
} }
@ -1983,7 +1998,7 @@ BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
hdc,x0,y0,hIcon,cxWidth,cyWidth,istep,hbr,flags ); hdc,x0,y0,hIcon,cxWidth,cyWidth,istep,hbr,flags );
if (!(ptr = get_icon_ptr( hIcon ))) return FALSE; if (!(ptr = get_icon_ptr( hIcon ))) return FALSE;
if (istep >= ptr->num_frames) if (istep >= ptr->num_steps)
{ {
TRACE_(icon)("Stepped past end of animated frames=%d\n", istep); TRACE_(icon)("Stepped past end of animated frames=%d\n", istep);
release_icon_ptr( hIcon, ptr ); release_icon_ptr( hIcon, ptr );

View File

@ -148,7 +148,7 @@ riff_cursor1_t empty_anicursor = {
}, },
{ {
ANI_LIST_ID, ANI_LIST_ID,
sizeof(riff_icon32x32x32_t)*1 + sizeof(DWORD), sizeof(riff_icon32x32x32_t)*(1 /*frames*/) + sizeof(DWORD),
ANI_fram_ID, ANI_fram_ID,
}, },
{ {
@ -202,7 +202,7 @@ riff_cursor3_t empty_anicursor3 = {
{ {
sizeof(ani_header), sizeof(ani_header),
3, /* frames */ 3, /* frames */
1, /* steps */ 3, /* steps */
32, /* width */ 32, /* width */
32, /* height */ 32, /* height */
32, /* depth */ 32, /* depth */
@ -1442,17 +1442,42 @@ static void test_CreateIconFromResource(void)
static HCURSOR WINAPI (*pGetCursorFrameInfo)(HCURSOR hCursor, VOID *unk1, VOID *unk2, VOID *unk3, VOID *unk4); static HCURSOR WINAPI (*pGetCursorFrameInfo)(HCURSOR hCursor, VOID *unk1, VOID *unk2, VOID *unk3, VOID *unk4);
static void test_GetCursorFrameInfo(void) static void test_GetCursorFrameInfo(void)
{ {
HBITMAP bmp = NULL, bmpOld = NULL;
DWORD unk1, unk2, unk3, unk4; DWORD unk1, unk2, unk3, unk4;
BITMAPINFOHEADER *icon_header; BITMAPINFOHEADER *icon_header;
BITMAPINFO bitmapInfo;
HDC hdc = NULL;
void *bits = 0;
INT16 *hotspot; INT16 *hotspot;
HANDLE h1, h2; HANDLE h1, h2;
BOOL ret; BOOL ret;
int i;
if (!pGetCursorFrameInfo) if (!pGetCursorFrameInfo)
{ {
win_skip( "GetCursorFrameInfo not supported, skipping tests.\n" ); win_skip( "GetCursorFrameInfo not supported, skipping tests.\n" );
return; return;
} }
hdc = CreateCompatibleDC(0);
ok(hdc != 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
if (!hdc)
return;
memset(&bitmapInfo, 0, sizeof(bitmapInfo));
bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfo.bmiHeader.biWidth = 3;
bitmapInfo.bmiHeader.biHeight = 3;
bitmapInfo.bmiHeader.biBitCount = 32;
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biCompression = BI_RGB;
bitmapInfo.bmiHeader.biSizeImage = sizeof(UINT32);
bmp = CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, &bits, NULL, 0);
ok (bmp && bits, "CreateDIBSection failed to return a valid bitmap and buffer\n");
if (!bmp || !bits)
goto cleanup;
bmpOld = SelectObject(hdc, bmp);
#define ICON_RES_WIDTH 32 #define ICON_RES_WIDTH 32
#define ICON_RES_HEIGHT 32 #define ICON_RES_HEIGHT 32
#define ICON_RES_AND_SIZE (ICON_WIDTH*ICON_HEIGHT/8) #define ICON_RES_AND_SIZE (ICON_WIDTH*ICON_HEIGHT/8)
@ -1485,8 +1510,8 @@ static void test_GetCursorFrameInfo(void)
unk1 = unk2 = unk3 = unk4 = 0xdead; unk1 = unk2 = unk3 = unk4 = 0xdead;
h2 = pGetCursorFrameInfo(h1, &unk1, &unk2, &unk3, &unk4); h2 = pGetCursorFrameInfo(h1, &unk1, &unk2, &unk3, &unk4);
ok(h1 == h2, "GetCursorFrameInfo() failed: (%p != %p).\n", h1, h2); ok(h1 == h2, "GetCursorFrameInfo() failed: (%p != %p).\n", h1, h2);
ok(unk1 == 0xdead, "GetCursorFrameInfo() unexpected param 2 value (%d != 0xdead).\n", unk1); ok(unk1 == 0xdead, "GetCursorFrameInfo() unexpected param 2 value (0x%x != 0xdead).\n", unk1);
ok(unk2 == 0xdead, "GetCursorFrameInfo() unexpected param 3 value (%d != 0xdead).\n", unk2); ok(unk2 == 0xdead, "GetCursorFrameInfo() unexpected param 3 value (0x%x != 0xdead).\n", unk2);
ok(unk3 == 0, "GetCursorFrameInfo() unexpected param 4 value (0x%x != 0x0).\n", unk3); ok(unk3 == 0, "GetCursorFrameInfo() unexpected param 4 value (0x%x != 0x0).\n", unk3);
ok(unk4 == 1, "GetCursorFrameInfo() unexpected param 5 value (%d != 1).\n", unk4); ok(unk4 == 1, "GetCursorFrameInfo() unexpected param 5 value (%d != 1).\n", unk4);
@ -1498,57 +1523,120 @@ static void test_GetCursorFrameInfo(void)
empty_anicursor.frames[0].data.icon_info.idType = 2; /* type: cursor */ empty_anicursor.frames[0].data.icon_info.idType = 2; /* type: cursor */
empty_anicursor.frames[0].data.icon_info.idEntries[0].xHotspot = 3; empty_anicursor.frames[0].data.icon_info.idEntries[0].xHotspot = 3;
empty_anicursor.frames[0].data.icon_info.idEntries[0].yHotspot = 3; empty_anicursor.frames[0].data.icon_info.idEntries[0].yHotspot = 3;
h1 = CreateIconFromResource((PBYTE) &empty_anicursor, sizeof(empty_anicursor3), FALSE, 0x00030000); h1 = CreateIconFromResource((PBYTE) &empty_anicursor, sizeof(empty_anicursor), FALSE, 0x00030000);
ok(h1 != NULL, "Create cursor failed.\n"); ok(h1 != NULL, "Create cursor failed.\n");
/* Check GetCursorFrameInfo behavior on a single-frame animated cursor */ /* Check GetCursorFrameInfo behavior on a single-frame animated cursor */
unk1 = unk2 = unk3 = unk4 = 0xdead; unk1 = unk2 = unk3 = unk4 = 0xdead;
h2 = pGetCursorFrameInfo(h1, &unk1, (VOID*)0, &unk3, &unk4); h2 = pGetCursorFrameInfo(h1, &unk1, (VOID*)0, &unk3, &unk4);
ok(h1 == h2, "GetCursorFrameInfo() failed: (%p != %p).\n", h1, h2); ok(h1 == h2, "GetCursorFrameInfo() failed: (%p != %p).\n", h1, h2);
ok(unk1 == 0xdead, "GetCursorFrameInfo() unexpected param 2 value (%d != 0xdead).\n", unk1); ok(unk1 == 0xdead, "GetCursorFrameInfo() unexpected param 2 value (0x%x != 0xdead).\n", unk1);
ok(unk2 == 0xdead, "GetCursorFrameInfo() unexpected param 3 value (%d != 0xdead).\n", unk2); ok(unk2 == 0xdead, "GetCursorFrameInfo() unexpected param 3 value (0x%x != 0xdead).\n", unk2);
ok(unk3 == 0x0, "GetCursorFrameInfo() unexpected param 4 value (0x%x != 0x0).\n", unk3); ok(unk3 == 0x0, "GetCursorFrameInfo() unexpected param 4 value (0x%x != 0x0).\n", unk3);
ok(unk4 == 1, "GetCursorFrameInfo() unexpected param 5 value (%d != 1).\n", unk4); ok(unk4 == empty_anicursor.header.header.num_steps,
"GetCursorFrameInfo() unexpected param 5 value (%d != 1).\n", unk4);
/* Clean up single-frame animated cursor. */ /* Clean up single-frame animated cursor. */
ret = DestroyCursor(h1); ret = DestroyCursor(h1);
ok(ret, "DestroyCursor() failed.\n"); ok(ret, "DestroyCursor() failed.\n");
/* Creating a multi-frame animated cursor. */ /* Creating a multi-frame animated cursor. */
empty_anicursor3.frames[0].data.icon_info.idType = 2; /* type: cursor */ for (i=0; i<empty_anicursor3.header.header.num_frames; i++)
empty_anicursor3.frames[0].data.icon_info.idEntries[0].xHotspot = 3; {
empty_anicursor3.frames[0].data.icon_info.idEntries[0].yHotspot = 3; empty_anicursor3.frames[i].data.icon_info.idType = 2; /* type: cursor */
empty_anicursor3.frames[1].data.icon_info.idType = 2; /* type: cursor */ empty_anicursor3.frames[i].data.icon_info.idEntries[0].xHotspot = 3;
empty_anicursor3.frames[1].data.icon_info.idEntries[0].xHotspot = 3; empty_anicursor3.frames[i].data.icon_info.idEntries[0].yHotspot = 3;
empty_anicursor3.frames[1].data.icon_info.idEntries[0].yHotspot = 3; }
empty_anicursor3.frames[2].data.icon_info.idType = 2; /* type: cursor */
empty_anicursor3.frames[2].data.icon_info.idEntries[0].xHotspot = 3;
empty_anicursor3.frames[2].data.icon_info.idEntries[0].yHotspot = 3;
h1 = CreateIconFromResource((PBYTE) &empty_anicursor3, sizeof(empty_anicursor3), FALSE, 0x00030000); h1 = CreateIconFromResource((PBYTE) &empty_anicursor3, sizeof(empty_anicursor3), FALSE, 0x00030000);
ok(h1 != NULL, "Create cursor failed.\n"); ok(h1 != NULL, "Create cursor failed.\n");
/* Check GetCursorFrameInfo behavior on a multi-frame animated cursor */ /* Check number of steps in multi-frame animated cursor */
unk1 = unk2 = unk3 = unk4 = 0xdead; i=0;
h2 = pGetCursorFrameInfo(h1, &unk1, (VOID*)0, &unk3, &unk4); while (DrawIconEx(hdc, 0, 0, h1, 32, 32, i, NULL, DI_NORMAL))
ok(h2 != 0, "GetCursorFrameInfo() failed: (%p != 0).\n", h2); i++;
ok(unk1 == 0xdead, "GetCursorFrameInfo() unexpected param 2 value (%d != 0xdead).\n", unk1); ok(i == empty_anicursor3.header.header.num_steps,
ok(unk2 == 0xdead, "GetCursorFrameInfo() unexpected param 3 value (%d != 0xdead).\n", unk2); "Unexpected number of steps in cursor (%d != %d)\n",
ok(unk3 == 0xbeef, "GetCursorFrameInfo() unexpected param 4 value (0x%x != 0xbeef).\n", unk3); i, empty_anicursor3.header.header.num_steps);
ok(unk4 == ~0 || broken(unk4 == 1) /*win2k*/, "GetCursorFrameInfo() unexpected param 5 value (%d != 1).\n", unk4);
/* Check GetCursorFrameInfo behavior on a multi-frame animated cursor */ /* Check GetCursorFrameInfo behavior on a multi-frame animated cursor */
for (i=0; i<empty_anicursor3.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.header.header.display_rate,
"GetCursorFrameInfo() unexpected param 4 value (0x%x != 0x%x).\n",
unk3, empty_anicursor3.header.header.display_rate);
ok(unk4 == empty_anicursor3.header.header.num_steps,
"GetCursorFrameInfo() unexpected param 5 value (%d != %d).\n",
unk4, empty_anicursor3.header.header.num_steps);
}
/* Check GetCursorFrameInfo behavior on rate 3 of a multi-frame animated cursor */
unk1 = unk2 = unk3 = unk4 = 0xdead; unk1 = unk2 = unk3 = unk4 = 0xdead;
h2 = pGetCursorFrameInfo(h1, &unk1, (VOID*)1, &unk3, &unk4); h2 = pGetCursorFrameInfo(h1, &unk1, (VOID*)3, &unk3, &unk4);
ok(h2 == 0, "GetCursorFrameInfo() failed: (%p != 0).\n", h2); ok(h2 == 0, "GetCursorFrameInfo() failed for cursor %p: (%p != 0).\n", h1, h2);
ok(unk1 == 0xdead, "GetCursorFrameInfo() unexpected param 2 value (%d != 0xdead).\n", unk1); ok(unk1 == 0xdead, "GetCursorFrameInfo() unexpected param 2 value (0x%x != 0xdead).\n", unk1);
ok(unk2 == 0xdead, "GetCursorFrameInfo() unexpected param 3 value (%d != 0xdead).\n", unk2); ok(unk2 == 0xdead, "GetCursorFrameInfo() unexpected param 3 value (0x%x != 0xdead).\n", unk2);
ok(unk3 == 0xdead || broken(unk3 == 0xbeef) /*win2k*/, "GetCursorFrameInfo() unexpected param 4 value (0x%x != 0xdead).\n", unk3); ok(unk3 == 0xdead || broken(unk3 == empty_anicursor3.header.header.display_rate) /*win2k*/
ok(unk4 == 0xdead || broken(unk4 == 1) /*win2k*/, "GetCursorFrameInfo() unexpected param 5 value (%d != 0xdead).\n", unk4); || broken(unk3 == ~0) /*win2k (sporadic)*/,
"GetCursorFrameInfo() unexpected param 4 value (0x%x != 0xdead).\n", unk3);
ok(unk4 == 0xdead || broken(unk4 == empty_anicursor3.header.header.num_steps) /*win2k*/
|| broken(unk4 == 0) /*win2k (sporadic)*/,
"GetCursorFrameInfo() unexpected param 5 value (0x%x != 0xdead).\n", unk4);
/* Clean up multi-frame animated cursor. */ /* Clean up multi-frame animated cursor. */
ret = DestroyCursor(h1); ret = DestroyCursor(h1);
ok(ret, "DestroyCursor() failed.\n"); ok(ret, "DestroyCursor() failed.\n");
/* Create a multi-frame animated cursor with num_steps == 1 */
empty_anicursor3.header.header.num_steps = 1;
h1 = CreateIconFromResource((PBYTE) &empty_anicursor3, sizeof(empty_anicursor3), FALSE, 0x00030000);
ok(h1 != NULL, "Create cursor failed.\n");
/* Check number of steps in multi-frame animated cursor (mismatch between steps and frames) */
i=0;
while (DrawIconEx(hdc, 0, 0, h1, 32, 32, i, NULL, DI_NORMAL))
i++;
ok(i == empty_anicursor3.header.header.num_steps,
"Unexpected number of steps in cursor (%d != %d)\n",
i, empty_anicursor3.header.header.num_steps);
/* Check GetCursorFrameInfo behavior on rate 0 for a multi-frame animated cursor (with num_steps == 1) */
unk1 = unk2 = unk3 = unk4 = 0xdead;
h2 = pGetCursorFrameInfo(h1, &unk1, (VOID*)0, &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.header.header.display_rate,
"GetCursorFrameInfo() unexpected param 4 value (0x%x != 0x%x).\n",
unk3, empty_anicursor3.header.header.display_rate);
ok(unk4 == ~0 || broken(unk4 == empty_anicursor3.header.header.num_steps) /*win2k*/,
"GetCursorFrameInfo() unexpected param 5 value (%d != ~0).\n", unk4);
/* Check GetCursorFrameInfo behavior on rate 1 for a multi-frame animated cursor (with num_steps == 1) */
unk1 = unk2 = unk3 = unk4 = 0xdead;
h2 = pGetCursorFrameInfo(h1, &unk1, (VOID*)1, &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 == 0xdead || broken(unk3 == empty_anicursor3.header.header.display_rate) /*win2k*/
|| broken(unk3 == ~0) /*win2k (sporadic)*/,
"GetCursorFrameInfo() unexpected param 4 value (0x%x != 0xdead).\n", unk3);
ok(unk4 == 0xdead || broken(unk4 == empty_anicursor3.header.header.num_steps) /*win2k*/
|| broken(unk4 == 0) /*win2k (sporadic)*/,
"GetCursorFrameInfo() unexpected param 5 value (%d != 0xdead).\n", unk4);
/* Clean up multi-frame animated cursor. */
ret = DestroyCursor(h1);
ok(ret, "DestroyCursor() failed.\n");
cleanup:
if(bmpOld) SelectObject(hdc, bmpOld);
if(bmp) DeleteObject(bmp);
if(hdc) DeleteDC(hdc);
} }
static HICON create_test_icon(HDC hdc, int width, int height, int bpp, static HICON create_test_icon(HDC hdc, int width, int height, int bpp,