wined3d: The cursor image surface is not allowed to be NULL in wined3d_device_set_cursor_properties().

Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Henri Verbeet 2015-10-16 10:35:09 +02:00 committed by Alexandre Julliard
parent 51b9aba9cc
commit 8b9e56cc9e
1 changed files with 77 additions and 75 deletions

View File

@ -4205,6 +4205,10 @@ static struct wined3d_texture *wined3d_device_create_cursor_texture(struct wined
HRESULT CDECL wined3d_device_set_cursor_properties(struct wined3d_device *device,
UINT x_hotspot, UINT y_hotspot, struct wined3d_surface *cursor_image)
{
struct wined3d_display_mode mode;
struct wined3d_map_desc map_desc;
HRESULT hr;
TRACE("device %p, x_hotspot %u, y_hotspot %u, cursor_image %p.\n",
device, x_hotspot, y_hotspot, cursor_image);
@ -4214,86 +4218,84 @@ HRESULT CDECL wined3d_device_set_cursor_properties(struct wined3d_device *device
device->cursor_texture = NULL;
}
if (cursor_image)
if (cursor_image->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
{
struct wined3d_display_mode mode;
struct wined3d_map_desc map_desc;
HRESULT hr;
/* MSDN: Cursor must be A8R8G8B8 */
if (cursor_image->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
{
WARN("surface %p has an invalid format.\n", cursor_image);
return WINED3DERR_INVALIDCALL;
}
if (FAILED(hr = wined3d_get_adapter_display_mode(device->wined3d, device->adapter->ordinal, &mode, NULL)))
{
ERR("Failed to get display mode, hr %#x.\n", hr);
return WINED3DERR_INVALIDCALL;
}
/* MSDN: Cursor must be smaller than the display mode */
if (cursor_image->resource.width > mode.width || cursor_image->resource.height > mode.height)
{
WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
cursor_image, cursor_image->resource.width, cursor_image->resource.height,
mode.width, mode.height);
return WINED3DERR_INVALIDCALL;
}
/* TODO: MSDN: Cursor sizes must be a power of 2 */
/* Do not store the surface's pointer because the application may
* release it after setting the cursor image. Windows doesn't
* addref the set surface, so we can't do this either without
* creating circular refcount dependencies. */
if (!(device->cursor_texture = wined3d_device_create_cursor_texture(device, cursor_image)))
{
ERR("Failed to create cursor texture.\n");
return WINED3DERR_INVALIDCALL;
}
device->cursorWidth = cursor_image->resource.width;
device->cursorHeight = cursor_image->resource.height;
if (cursor_image->resource.width == 32 && cursor_image->resource.height == 32)
{
UINT mask_size = cursor_image->resource.width * cursor_image->resource.height / 8;
ICONINFO cursorInfo;
DWORD *maskBits;
HCURSOR cursor;
/* 32-bit user32 cursors ignore the alpha channel if it's all
* zeroes, and use the mask instead. Fill the mask with all ones
* to ensure we still get a fully transparent cursor. */
maskBits = HeapAlloc(GetProcessHeap(), 0, mask_size);
memset(maskBits, 0xff, mask_size);
wined3d_surface_map(cursor_image, &map_desc, NULL,
WINED3D_MAP_NO_DIRTY_UPDATE | WINED3D_MAP_READONLY);
TRACE("width: %u height: %u.\n", cursor_image->resource.width, cursor_image->resource.height);
cursorInfo.fIcon = FALSE;
cursorInfo.xHotspot = x_hotspot;
cursorInfo.yHotspot = y_hotspot;
cursorInfo.hbmMask = CreateBitmap(cursor_image->resource.width, cursor_image->resource.height,
1, 1, maskBits);
cursorInfo.hbmColor = CreateBitmap(cursor_image->resource.width, cursor_image->resource.height,
1, 32, map_desc.data);
wined3d_surface_unmap(cursor_image);
/* Create our cursor and clean up. */
cursor = CreateIconIndirect(&cursorInfo);
if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
if (device->hardwareCursor) DestroyCursor(device->hardwareCursor);
device->hardwareCursor = cursor;
if (device->bCursorVisible) SetCursor( cursor );
HeapFree(GetProcessHeap(), 0, maskBits);
}
WARN("Surface %p has an invalid format %s.\n",
cursor_image, debug_d3dformat(cursor_image->resource.format->id));
return WINED3DERR_INVALIDCALL;
}
if (FAILED(hr = wined3d_get_adapter_display_mode(device->wined3d, device->adapter->ordinal, &mode, NULL)))
{
ERR("Failed to get display mode, hr %#x.\n", hr);
return WINED3DERR_INVALIDCALL;
}
if (cursor_image->resource.width > mode.width || cursor_image->resource.height > mode.height)
{
WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
cursor_image, cursor_image->resource.width, cursor_image->resource.height,
mode.width, mode.height);
return WINED3DERR_INVALIDCALL;
}
/* TODO: MSDN: Cursor sizes must be a power of 2 */
/* Do not store the surface's pointer because the application may
* release it after setting the cursor image. Windows doesn't
* addref the set surface, so we can't do this either without
* creating circular refcount dependencies. */
if (!(device->cursor_texture = wined3d_device_create_cursor_texture(device, cursor_image)))
{
ERR("Failed to create cursor texture.\n");
return WINED3DERR_INVALIDCALL;
}
if (cursor_image->resource.width == 32 && cursor_image->resource.height == 32)
{
UINT mask_size = cursor_image->resource.width * cursor_image->resource.height / 8;
ICONINFO cursor_info;
DWORD *mask_bits;
HCURSOR cursor;
/* 32-bit user32 cursors ignore the alpha channel if it's all
* zeroes, and use the mask instead. Fill the mask with all ones
* to ensure we still get a fully transparent cursor. */
if (!(mask_bits = HeapAlloc(GetProcessHeap(), 0, mask_size)))
return E_OUTOFMEMORY;
memset(mask_bits, 0xff, mask_size);
wined3d_surface_map(cursor_image, &map_desc, NULL, WINED3D_MAP_NO_DIRTY_UPDATE | WINED3D_MAP_READONLY);
cursor_info.fIcon = FALSE;
cursor_info.xHotspot = x_hotspot;
cursor_info.yHotspot = y_hotspot;
cursor_info.hbmMask = CreateBitmap(cursor_image->resource.width,
cursor_image->resource.height, 1, 1, mask_bits);
cursor_info.hbmColor = CreateBitmap(cursor_image->resource.width,
cursor_image->resource.height, 1, 32, map_desc.data);
wined3d_surface_unmap(cursor_image);
/* Create our cursor and clean up. */
cursor = CreateIconIndirect(&cursor_info);
if (cursor_info.hbmMask)
DeleteObject(cursor_info.hbmMask);
if (cursor_info.hbmColor)
DeleteObject(cursor_info.hbmColor);
if (device->hardwareCursor)
DestroyCursor(device->hardwareCursor);
device->hardwareCursor = cursor;
if (device->bCursorVisible)
SetCursor(cursor);
HeapFree(GetProcessHeap(), 0, mask_bits);
}
TRACE("New cursor dimensions are %ux%u.\n", cursor_image->resource.width, cursor_image->resource.height);
device->cursorWidth = cursor_image->resource.width;
device->cursorHeight = cursor_image->resource.height;
device->xHotSpot = x_hotspot;
device->yHotSpot = y_hotspot;
return WINED3D_OK;
}