[PATCH v2 0/2] MR10723: ddraw: Ignore hwnd clipper in exclusive fullscreen mode.
-- v2: ddraw: Ignore hwnd clipper in exclusive fullscreen mode. ddraw/tests: Add tests for clipper in exclusive fullscreen mode. https://gitlab.winehq.org/wine/wine/-/merge_requests/10723
From: Paul Gofman <pgofman@codeweavers.com> --- dlls/ddraw/tests/ddraw1.c | 184 ++++++++++++++++++++++++++++++++++++++ dlls/ddraw/tests/ddraw2.c | 184 ++++++++++++++++++++++++++++++++++++++ dlls/ddraw/tests/ddraw4.c | 184 ++++++++++++++++++++++++++++++++++++++ dlls/ddraw/tests/ddraw7.c | 184 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 736 insertions(+) diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c index 2e2f7e62483..594baee6ff9 100644 --- a/dlls/ddraw/tests/ddraw1.c +++ b/dlls/ddraw/tests/ddraw1.c @@ -114,6 +114,14 @@ static void flush_events(void) } } +static void pump_messages(void) +{ + MSG msg; + + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) + DispatchMessageA(&msg); +} + static HWND create_foreground_window(void) { for (UINT retries = 5; retries; retries--) @@ -16382,6 +16390,181 @@ out: DestroyWindow(window); } +static void check_surface_clipper(IDirectDrawSurface *surface, IDirectDrawClipper *clipper_hwnd, + IDirectDrawClipper *clipper_region, RECT *window_rect, DWORD style) +{ + unsigned int c; + DDBLTFX fx; + HRESULT hr; + + memset(&fx, 0, sizeof(fx)); + fx.dwSize = sizeof(fx); + fx.dwFillColor = 0xff00ff00; + + fill_surface(surface, 0xffff0000); + + /* Clipper with region works. */ + hr = IDirectDrawSurface_SetClipper(surface, clipper_region); + ok(hr == DD_OK, "got %#lx.\n", hr); + c = get_surface_color(surface, 101, 101); + ok(c == 0x00ff0000, "got %#x.\n", c); + hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx); + ok(hr == DD_OK, "got %#lx.\n", hr); + c = get_surface_color(surface, 0, 0); + ok(c == 0x00ff0000, "got %#x.\n", c); + c = get_surface_color(surface, 101, 101); + ok(c == 0x0000ff00, "got %#x.\n", c); + + /* Clipper with window has no effect. */ + hr = IDirectDrawSurface_SetClipper(surface, clipper_hwnd); + ok(hr == DD_OK, "got %#lx.\n", hr); + fill_surface(surface, 0xff0000ff); + c = get_surface_color(surface, window_rect->left + 1, window_rect->top + 1); + ok(c == 0x000000ff, "got %#x.\n", c); + + hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx); + ok(hr == DD_OK, "got %#lx.\n", hr); + + c = get_surface_color(surface, window_rect->left + 1, window_rect->top + 1); + todo_wine_if(!(style & WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + c = get_surface_color(surface, 0, 0); + todo_wine_if((style & (WS_CHILD | WS_VISIBLE)) != (WS_CHILD | WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + + hr = IDirectDrawSurface_SetClipper(surface, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + fill_surface(surface, 0); +} + +static void test_clipper_in_exclusive_fullscreen(void) +{ + static const struct + { + DWORD style; + BOOL parent; + } + tests[] = + { + { WS_POPUP }, + { WS_POPUP, TRUE }, + { WS_CHILD, TRUE }, + { WS_OVERLAPPED }, + { WS_CHILD | WS_VISIBLE, TRUE }, + { WS_POPUP | WS_VISIBLE }, + }; + IDirectDrawSurface *primary, *offscreen; + IDirectDrawClipper *clipper, *clipper2; + DDSURFACEDESC surface_desc; + HWND window, clip_window; + IDirectDraw *ddraw; + RGNDATA *rgn_data; + DWORD ret, style; + RECT window_rect; + ULONG refcount; + unsigned int i; + HRESULT hr; + HRGN rgn; + + if (!(ddraw = create_ddraw())) + { + skip("Failed to create ddraw, skipping test.\n"); + return; + } + hr = IDirectDraw_CreateClipper(ddraw, 0, &clipper, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + hr = IDirectDraw_CreateClipper(ddraw, 0, &clipper2, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + window = CreateWindowA("static", "ddraw_fullscreen", WS_POPUP | WS_VISIBLE, 0, 0, 640, 480, NULL, NULL, NULL, NULL); + pump_messages(); + hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + ok(hr == DD_OK, "got %#lx.\n", hr); + pump_messages(); + + rgn = CreateRectRgn(100, 100, 200, 200); + ok(!!rgn, "Failed to create region.\n"); + ret = GetRegionData(rgn, 0, NULL); + rgn_data = malloc(ret); + ret = GetRegionData(rgn, ret, rgn_data); + ok(!!ret, "Failed to get region data.\n"); + DeleteObject(rgn); + hr = IDirectDrawClipper_SetClipList(clipper2, rgn_data, 0); + ok(hr == DD_OK, "got %#lx.\n", hr); + free(rgn_data); + + memset(&surface_desc, 0, sizeof(surface_desc)); + surface_desc.dwSize = sizeof(surface_desc); + surface_desc.dwFlags = DDSD_CAPS; + surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &primary, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + surface_desc.dwWidth = 640; + surface_desc.dwHeight = 480; + hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &offscreen, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("test %u", i); + style = tests[i].style; + clip_window = CreateWindowA("static", "ddraw_clip", style, 100, 100, 100, 100, + tests[i].parent ? window : NULL, NULL, NULL, NULL); + ok(!!clip_window, "got error %ld.\n", GetLastError()); + pump_messages(); + + GetWindowRect(clip_window, &window_rect); + hr = IDirectDrawClipper_SetHWnd(clipper, 0, clip_window); + ok(hr == DD_OK, "got %#lx.\n", hr); + + hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret); + ok(hr == DD_OK, "got %#lx.\n", hr); + rgn_data = malloc(ret); + hr = IDirectDrawClipper_GetClipList(clipper, NULL, rgn_data, &ret); + ok(hr == DD_OK, "got %#lx.\n", hr); + ok(rgn_data->rdh.dwSize == sizeof(rgn_data->rdh), "Got unexpected structure size %#lx.\n", rgn_data->rdh.dwSize); + ok(rgn_data->rdh.iType == RDH_RECTANGLES, "Got unexpected type %#lx.\n", rgn_data->rdh.iType); + if (style & WS_VISIBLE) + { + ok(rgn_data->rdh.nCount >= 1, "got %lu.\n", rgn_data->rdh.nCount); + if (!(style & WS_CHILD)) + ok(EqualRect(&rgn_data->rdh.rcBound, &window_rect), "got %s, expected %s.\n", + wine_dbgstr_rect(&rgn_data->rdh.rcBound), wine_dbgstr_rect(&window_rect)); + } + else + { + ok(!rgn_data->rdh.nCount, "got %lu.\n", rgn_data->rdh.nCount); + } + free(rgn_data); + + winetest_push_context("primary"); + check_surface_clipper(primary, clipper, clipper2, &window_rect, style); + winetest_pop_context(); + + winetest_push_context("offscreen"); + check_surface_clipper(offscreen, clipper, clipper2, &window_rect, style); + winetest_pop_context(); + + hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + DestroyWindow(clip_window); + pump_messages(); + winetest_pop_context(); + } + + IDirectDrawClipper_Release(clipper); + refcount = IDirectDrawSurface_Release(offscreen); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + refcount = IDirectDrawSurface_Release(primary); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + + IDirectDraw_Release(ddraw); + DestroyWindow(window); + pump_messages(); +} + START_TEST(ddraw1) { DDDEVICEIDENTIFIER identifier; @@ -16508,4 +16691,5 @@ START_TEST(ddraw1) test_sysmem_x_channel(); test_yuv_blit(); test_blit_to_self(); + test_clipper_in_exclusive_fullscreen(); } diff --git a/dlls/ddraw/tests/ddraw2.c b/dlls/ddraw/tests/ddraw2.c index 114b297d239..fdf22191743 100644 --- a/dlls/ddraw/tests/ddraw2.c +++ b/dlls/ddraw/tests/ddraw2.c @@ -115,6 +115,14 @@ static void flush_events(void) } } +static void pump_messages(void) +{ + MSG msg; + + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) + DispatchMessageA(&msg); +} + static HWND create_foreground_window(void) { for (UINT retries = 5; retries; retries--) @@ -17453,6 +17461,181 @@ out: DestroyWindow(window); } +static void check_surface_clipper(IDirectDrawSurface *surface, IDirectDrawClipper *clipper_hwnd, + IDirectDrawClipper *clipper_region, RECT *window_rect, DWORD style) +{ + unsigned int c; + DDBLTFX fx; + HRESULT hr; + + memset(&fx, 0, sizeof(fx)); + fx.dwSize = sizeof(fx); + fx.dwFillColor = 0xff00ff00; + + fill_surface(surface, 0xffff0000); + + /* Clipper with region works. */ + hr = IDirectDrawSurface_SetClipper(surface, clipper_region); + ok(hr == DD_OK, "got %#lx.\n", hr); + c = get_surface_color(surface, 101, 101); + ok(c == 0x00ff0000, "got %#x.\n", c); + hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx); + ok(hr == DD_OK, "got %#lx.\n", hr); + c = get_surface_color(surface, 0, 0); + ok(c == 0x00ff0000, "got %#x.\n", c); + c = get_surface_color(surface, 101, 101); + ok(c == 0x0000ff00, "got %#x.\n", c); + + /* Clipper with window has no effect. */ + hr = IDirectDrawSurface_SetClipper(surface, clipper_hwnd); + ok(hr == DD_OK, "got %#lx.\n", hr); + fill_surface(surface, 0xff0000ff); + c = get_surface_color(surface, window_rect->left + 1, window_rect->top + 1); + ok(c == 0x000000ff, "got %#x.\n", c); + + hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx); + ok(hr == DD_OK, "got %#lx.\n", hr); + + c = get_surface_color(surface, window_rect->left + 1, window_rect->top + 1); + todo_wine_if(!(style & WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + c = get_surface_color(surface, 0, 0); + todo_wine_if((style & (WS_CHILD | WS_VISIBLE)) != (WS_CHILD | WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + + hr = IDirectDrawSurface_SetClipper(surface, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + fill_surface(surface, 0); +} + +static void test_clipper_in_exclusive_fullscreen(void) +{ + static const struct + { + DWORD style; + BOOL parent; + } + tests[] = + { + { WS_POPUP }, + { WS_POPUP, TRUE }, + { WS_CHILD, TRUE }, + { WS_OVERLAPPED }, + { WS_CHILD | WS_VISIBLE, TRUE }, + { WS_POPUP | WS_VISIBLE }, + }; + IDirectDrawSurface *primary, *offscreen; + IDirectDrawClipper *clipper, *clipper2; + DDSURFACEDESC surface_desc; + HWND window, clip_window; + IDirectDraw2 *ddraw; + RGNDATA *rgn_data; + DWORD ret, style; + RECT window_rect; + ULONG refcount; + unsigned int i; + HRESULT hr; + HRGN rgn; + + if (!(ddraw = create_ddraw())) + { + skip("Failed to create ddraw, skipping test.\n"); + return; + } + hr = IDirectDraw2_CreateClipper(ddraw, 0, &clipper, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + hr = IDirectDraw2_CreateClipper(ddraw, 0, &clipper2, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + window = CreateWindowA("static", "ddraw_fullscreen", WS_POPUP | WS_VISIBLE, 0, 0, 640, 480, NULL, NULL, NULL, NULL); + pump_messages(); + hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + ok(hr == DD_OK, "got %#lx.\n", hr); + pump_messages(); + + rgn = CreateRectRgn(100, 100, 200, 200); + ok(!!rgn, "Failed to create region.\n"); + ret = GetRegionData(rgn, 0, NULL); + rgn_data = malloc(ret); + ret = GetRegionData(rgn, ret, rgn_data); + ok(!!ret, "Failed to get region data.\n"); + DeleteObject(rgn); + hr = IDirectDrawClipper_SetClipList(clipper2, rgn_data, 0); + ok(hr == DD_OK, "got %#lx.\n", hr); + free(rgn_data); + + memset(&surface_desc, 0, sizeof(surface_desc)); + surface_desc.dwSize = sizeof(surface_desc); + surface_desc.dwFlags = DDSD_CAPS; + surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &primary, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + surface_desc.dwWidth = 640; + surface_desc.dwHeight = 480; + hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &offscreen, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("test %u", i); + style = tests[i].style; + clip_window = CreateWindowA("static", "ddraw_clip", style, 100, 100, 100, 100, + tests[i].parent ? window : NULL, NULL, NULL, NULL); + ok(!!clip_window, "got error %ld.\n", GetLastError()); + pump_messages(); + + GetWindowRect(clip_window, &window_rect); + hr = IDirectDrawClipper_SetHWnd(clipper, 0, clip_window); + ok(hr == DD_OK, "got %#lx.\n", hr); + + hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret); + ok(hr == DD_OK, "got %#lx.\n", hr); + rgn_data = malloc(ret); + hr = IDirectDrawClipper_GetClipList(clipper, NULL, rgn_data, &ret); + ok(hr == DD_OK, "got %#lx.\n", hr); + ok(rgn_data->rdh.dwSize == sizeof(rgn_data->rdh), "Got unexpected structure size %#lx.\n", rgn_data->rdh.dwSize); + ok(rgn_data->rdh.iType == RDH_RECTANGLES, "Got unexpected type %#lx.\n", rgn_data->rdh.iType); + if (style & WS_VISIBLE) + { + ok(rgn_data->rdh.nCount >= 1, "got %lu.\n", rgn_data->rdh.nCount); + if (!(style & WS_CHILD)) + ok(EqualRect(&rgn_data->rdh.rcBound, &window_rect), "got %s, expected %s.\n", + wine_dbgstr_rect(&rgn_data->rdh.rcBound), wine_dbgstr_rect(&window_rect)); + } + else + { + ok(!rgn_data->rdh.nCount, "got %lu.\n", rgn_data->rdh.nCount); + } + free(rgn_data); + + winetest_push_context("primary"); + check_surface_clipper(primary, clipper, clipper2, &window_rect, style); + winetest_pop_context(); + + winetest_push_context("offscreen"); + check_surface_clipper(offscreen, clipper, clipper2, &window_rect, style); + winetest_pop_context(); + + hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + DestroyWindow(clip_window); + pump_messages(); + winetest_pop_context(); + } + + IDirectDrawClipper_Release(clipper); + refcount = IDirectDrawSurface_Release(offscreen); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + refcount = IDirectDrawSurface_Release(primary); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + + IDirectDraw2_Release(ddraw); + DestroyWindow(window); + pump_messages(); +} + START_TEST(ddraw2) { DDDEVICEIDENTIFIER identifier; @@ -17585,4 +17768,5 @@ START_TEST(ddraw2) test_sysmem_x_channel(); test_yuv_blit(); test_blit_to_self(); + test_clipper_in_exclusive_fullscreen(); } diff --git a/dlls/ddraw/tests/ddraw4.c b/dlls/ddraw/tests/ddraw4.c index 285b36f54c6..e2fa4738cbc 100644 --- a/dlls/ddraw/tests/ddraw4.c +++ b/dlls/ddraw/tests/ddraw4.c @@ -121,6 +121,14 @@ static void flush_events(void) } } +static void pump_messages(void) +{ + MSG msg; + + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) + DispatchMessageA(&msg); +} + static HWND create_foreground_window(void) { for (UINT retries = 5; retries; retries--) @@ -20552,6 +20560,181 @@ out: DestroyWindow(window); } +static void check_surface_clipper(IDirectDrawSurface4 *surface, IDirectDrawClipper *clipper_hwnd, + IDirectDrawClipper *clipper_region, RECT *window_rect, DWORD style) +{ + unsigned int c; + DDBLTFX fx; + HRESULT hr; + + memset(&fx, 0, sizeof(fx)); + fx.dwSize = sizeof(fx); + fx.dwFillColor = 0xff00ff00; + + fill_surface(surface, 0xffff0000); + + /* Clipper with region works. */ + hr = IDirectDrawSurface4_SetClipper(surface, clipper_region); + ok(hr == DD_OK, "got %#lx.\n", hr); + c = get_surface_color(surface, 101, 101); + ok(c == 0x00ff0000, "got %#x.\n", c); + hr = IDirectDrawSurface4_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx); + ok(hr == DD_OK, "got %#lx.\n", hr); + c = get_surface_color(surface, 0, 0); + ok(c == 0x00ff0000, "got %#x.\n", c); + c = get_surface_color(surface, 101, 101); + ok(c == 0x0000ff00, "got %#x.\n", c); + + /* Clipper with window has no effect. */ + hr = IDirectDrawSurface4_SetClipper(surface, clipper_hwnd); + ok(hr == DD_OK, "got %#lx.\n", hr); + fill_surface(surface, 0xff0000ff); + c = get_surface_color(surface, window_rect->left + 1, window_rect->top + 1); + ok(c == 0x000000ff, "got %#x.\n", c); + + hr = IDirectDrawSurface4_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx); + ok(hr == DD_OK, "got %#lx.\n", hr); + + c = get_surface_color(surface, window_rect->left + 1, window_rect->top + 1); + todo_wine_if(!(style & WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + c = get_surface_color(surface, 0, 0); + todo_wine_if((style & (WS_CHILD | WS_VISIBLE)) != (WS_CHILD | WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + + hr = IDirectDrawSurface4_SetClipper(surface, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + fill_surface(surface, 0); +} + +static void test_clipper_in_exclusive_fullscreen(void) +{ + static const struct + { + DWORD style; + BOOL parent; + } + tests[] = + { + { WS_POPUP }, + { WS_POPUP, TRUE }, + { WS_CHILD, TRUE }, + { WS_OVERLAPPED }, + { WS_CHILD | WS_VISIBLE, TRUE }, + { WS_POPUP | WS_VISIBLE }, + }; + IDirectDrawSurface4 *primary, *offscreen; + IDirectDrawClipper *clipper, *clipper2; + DDSURFACEDESC2 surface_desc; + HWND window, clip_window; + IDirectDraw4 *ddraw; + RGNDATA *rgn_data; + DWORD ret, style; + RECT window_rect; + ULONG refcount; + unsigned int i; + HRESULT hr; + HRGN rgn; + + if (!(ddraw = create_ddraw())) + { + skip("Failed to create ddraw, skipping test.\n"); + return; + } + hr = IDirectDraw4_CreateClipper(ddraw, 0, &clipper, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + hr = IDirectDraw4_CreateClipper(ddraw, 0, &clipper2, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + window = CreateWindowA("static", "ddraw_fullscreen", WS_POPUP | WS_VISIBLE, 0, 0, 640, 480, NULL, NULL, NULL, NULL); + pump_messages(); + hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + ok(hr == DD_OK, "got %#lx.\n", hr); + pump_messages(); + + rgn = CreateRectRgn(100, 100, 200, 200); + ok(!!rgn, "Failed to create region.\n"); + ret = GetRegionData(rgn, 0, NULL); + rgn_data = malloc(ret); + ret = GetRegionData(rgn, ret, rgn_data); + ok(!!ret, "Failed to get region data.\n"); + DeleteObject(rgn); + hr = IDirectDrawClipper_SetClipList(clipper2, rgn_data, 0); + ok(hr == DD_OK, "got %#lx.\n", hr); + free(rgn_data); + + memset(&surface_desc, 0, sizeof(surface_desc)); + surface_desc.dwSize = sizeof(surface_desc); + surface_desc.dwFlags = DDSD_CAPS; + surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &primary, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + surface_desc.dwWidth = 640; + surface_desc.dwHeight = 480; + hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &offscreen, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("test %u", i); + style = tests[i].style; + clip_window = CreateWindowA("static", "ddraw_clip", style, 100, 100, 100, 100, + tests[i].parent ? window : NULL, NULL, NULL, NULL); + ok(!!clip_window, "got error %ld.\n", GetLastError()); + pump_messages(); + + GetWindowRect(clip_window, &window_rect); + hr = IDirectDrawClipper_SetHWnd(clipper, 0, clip_window); + ok(hr == DD_OK, "got %#lx.\n", hr); + + hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret); + ok(hr == DD_OK, "got %#lx.\n", hr); + rgn_data = malloc(ret); + hr = IDirectDrawClipper_GetClipList(clipper, NULL, rgn_data, &ret); + ok(hr == DD_OK, "got %#lx.\n", hr); + ok(rgn_data->rdh.dwSize == sizeof(rgn_data->rdh), "Got unexpected structure size %#lx.\n", rgn_data->rdh.dwSize); + ok(rgn_data->rdh.iType == RDH_RECTANGLES, "Got unexpected type %#lx.\n", rgn_data->rdh.iType); + if (style & WS_VISIBLE) + { + ok(rgn_data->rdh.nCount >= 1, "got %lu.\n", rgn_data->rdh.nCount); + if (!(style & WS_CHILD)) + ok(EqualRect(&rgn_data->rdh.rcBound, &window_rect), "got %s, expected %s.\n", + wine_dbgstr_rect(&rgn_data->rdh.rcBound), wine_dbgstr_rect(&window_rect)); + } + else + { + ok(!rgn_data->rdh.nCount, "got %lu.\n", rgn_data->rdh.nCount); + } + free(rgn_data); + + winetest_push_context("primary"); + check_surface_clipper(primary, clipper, clipper2, &window_rect, style); + winetest_pop_context(); + + winetest_push_context("offscreen"); + check_surface_clipper(offscreen, clipper, clipper2, &window_rect, style); + winetest_pop_context(); + + hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + DestroyWindow(clip_window); + pump_messages(); + winetest_pop_context(); + } + + IDirectDrawClipper_Release(clipper); + refcount = IDirectDrawSurface4_Release(offscreen); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + refcount = IDirectDrawSurface4_Release(primary); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + + IDirectDraw4_Release(ddraw); + DestroyWindow(window); + pump_messages(); +} + START_TEST(ddraw4) { DDDEVICEIDENTIFIER identifier; @@ -20701,4 +20884,5 @@ START_TEST(ddraw4) test_sysmem_x_channel(); test_yuv_blit(); test_blit_to_self(); + test_clipper_in_exclusive_fullscreen(); } diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c index e8487283ead..eb35cfa6792 100644 --- a/dlls/ddraw/tests/ddraw7.c +++ b/dlls/ddraw/tests/ddraw7.c @@ -162,6 +162,14 @@ static void flush_events(void) } } +static void pump_messages(void) +{ + MSG msg; + + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) + DispatchMessageA(&msg); +} + static HWND create_foreground_window(void) { for (UINT retries = 5; retries; retries--) @@ -20950,6 +20958,181 @@ out: DestroyWindow(window); } +static void check_surface_clipper(IDirectDrawSurface7 *surface, IDirectDrawClipper *clipper_hwnd, + IDirectDrawClipper *clipper_region, RECT *window_rect, DWORD style) +{ + unsigned int c; + DDBLTFX fx; + HRESULT hr; + + memset(&fx, 0, sizeof(fx)); + fx.dwSize = sizeof(fx); + fx.dwFillColor = 0xff00ff00; + + fill_surface(surface, 0xffff0000); + + /* Clipper with region works. */ + hr = IDirectDrawSurface7_SetClipper(surface, clipper_region); + ok(hr == DD_OK, "got %#lx.\n", hr); + c = get_surface_color(surface, 101, 101); + ok(c == 0x00ff0000, "got %#x.\n", c); + hr = IDirectDrawSurface7_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx); + ok(hr == DD_OK, "got %#lx.\n", hr); + c = get_surface_color(surface, 0, 0); + ok(c == 0x00ff0000, "got %#x.\n", c); + c = get_surface_color(surface, 101, 101); + ok(c == 0x0000ff00, "got %#x.\n", c); + + /* Clipper with window has no effect. */ + hr = IDirectDrawSurface7_SetClipper(surface, clipper_hwnd); + ok(hr == DD_OK, "got %#lx.\n", hr); + fill_surface(surface, 0xff0000ff); + c = get_surface_color(surface, window_rect->left + 1, window_rect->top + 1); + ok(c == 0x000000ff, "got %#x.\n", c); + + hr = IDirectDrawSurface7_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx); + ok(hr == DD_OK, "got %#lx.\n", hr); + + c = get_surface_color(surface, window_rect->left + 1, window_rect->top + 1); + todo_wine_if(!(style & WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + c = get_surface_color(surface, 0, 0); + todo_wine_if((style & (WS_CHILD | WS_VISIBLE)) != (WS_CHILD | WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + + hr = IDirectDrawSurface7_SetClipper(surface, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + clear_surface(surface, 0); +} + +static void test_clipper_in_exclusive_fullscreen(void) +{ + static const struct + { + DWORD style; + BOOL parent; + } + tests[] = + { + { WS_POPUP }, + { WS_POPUP, TRUE }, + { WS_CHILD, TRUE }, + { WS_OVERLAPPED }, + { WS_CHILD | WS_VISIBLE, TRUE }, + { WS_POPUP | WS_VISIBLE }, + }; + IDirectDrawSurface7 *primary, *offscreen; + IDirectDrawClipper *clipper, *clipper2; + DDSURFACEDESC2 surface_desc; + HWND window, clip_window; + IDirectDraw7 *ddraw; + RGNDATA *rgn_data; + DWORD ret, style; + RECT window_rect; + ULONG refcount; + unsigned int i; + HRESULT hr; + HRGN rgn; + + if (!(ddraw = create_ddraw())) + { + skip("Failed to create ddraw, skipping test.\n"); + return; + } + hr = IDirectDraw7_CreateClipper(ddraw, 0, &clipper, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + hr = IDirectDraw7_CreateClipper(ddraw, 0, &clipper2, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + window = CreateWindowA("static", "ddraw_fullscreen", WS_POPUP | WS_VISIBLE, 0, 0, 640, 480, NULL, NULL, NULL, NULL); + pump_messages(); + hr = IDirectDraw7_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + ok(hr == DD_OK, "got %#lx.\n", hr); + pump_messages(); + + rgn = CreateRectRgn(100, 100, 200, 200); + ok(!!rgn, "Failed to create region.\n"); + ret = GetRegionData(rgn, 0, NULL); + rgn_data = malloc(ret); + ret = GetRegionData(rgn, ret, rgn_data); + ok(!!ret, "Failed to get region data.\n"); + DeleteObject(rgn); + hr = IDirectDrawClipper_SetClipList(clipper2, rgn_data, 0); + ok(hr == DD_OK, "got %#lx.\n", hr); + free(rgn_data); + + memset(&surface_desc, 0, sizeof(surface_desc)); + surface_desc.dwSize = sizeof(surface_desc); + surface_desc.dwFlags = DDSD_CAPS; + surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &primary, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + surface_desc.dwWidth = 640; + surface_desc.dwHeight = 480; + hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &offscreen, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("test %u", i); + style = tests[i].style; + clip_window = CreateWindowA("static", "ddraw_clip", style, 100, 100, 100, 100, + tests[i].parent ? window : NULL, NULL, NULL, NULL); + ok(!!clip_window, "got error %ld.\n", GetLastError()); + pump_messages(); + + GetWindowRect(clip_window, &window_rect); + hr = IDirectDrawClipper_SetHWnd(clipper, 0, clip_window); + ok(hr == DD_OK, "got %#lx.\n", hr); + + hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret); + ok(hr == DD_OK, "got %#lx.\n", hr); + rgn_data = malloc(ret); + hr = IDirectDrawClipper_GetClipList(clipper, NULL, rgn_data, &ret); + ok(hr == DD_OK, "got %#lx.\n", hr); + ok(rgn_data->rdh.dwSize == sizeof(rgn_data->rdh), "Got unexpected structure size %#lx.\n", rgn_data->rdh.dwSize); + ok(rgn_data->rdh.iType == RDH_RECTANGLES, "Got unexpected type %#lx.\n", rgn_data->rdh.iType); + if (style & WS_VISIBLE) + { + ok(rgn_data->rdh.nCount >= 1, "got %lu.\n", rgn_data->rdh.nCount); + if (!(style & WS_CHILD)) + ok(EqualRect(&rgn_data->rdh.rcBound, &window_rect), "got %s, expected %s.\n", + wine_dbgstr_rect(&rgn_data->rdh.rcBound), wine_dbgstr_rect(&window_rect)); + } + else + { + ok(!rgn_data->rdh.nCount, "got %lu.\n", rgn_data->rdh.nCount); + } + free(rgn_data); + + winetest_push_context("primary"); + check_surface_clipper(primary, clipper, clipper2, &window_rect, style); + winetest_pop_context(); + + winetest_push_context("offscreen"); + check_surface_clipper(offscreen, clipper, clipper2, &window_rect, style); + winetest_pop_context(); + + hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + DestroyWindow(clip_window); + pump_messages(); + winetest_pop_context(); + } + + IDirectDrawClipper_Release(clipper); + refcount = IDirectDrawSurface7_Release(offscreen); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + refcount = IDirectDrawSurface7_Release(primary); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + + IDirectDraw7_Release(ddraw); + DestroyWindow(window); + pump_messages(); +} + START_TEST(ddraw7) { DDDEVICEIDENTIFIER2 identifier; @@ -21133,4 +21316,5 @@ START_TEST(ddraw7) test_sysmem_x_channel(); test_yuv_blit(); test_blit_to_self(); + test_clipper_in_exclusive_fullscreen(); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10723
From: Paul Gofman <pgofman@codeweavers.com> --- dlls/ddraw/surface.c | 18 +++++++++--------- dlls/ddraw/tests/ddraw1.c | 4 ++-- dlls/ddraw/tests/ddraw2.c | 4 ++-- dlls/ddraw/tests/ddraw4.c | 4 ++-- dlls/ddraw/tests/ddraw7.c | 4 ++-- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c index e6ed79afccf..139bf45921d 100644 --- a/dlls/ddraw/surface.c +++ b/dlls/ddraw/surface.c @@ -1647,7 +1647,14 @@ static HRESULT ddraw_surface_blt_clipped(struct ddraw_surface *dst_surface, cons SetRectEmpty(&src_rect); } - if (!dst_surface->clipper) + if (dst_surface->clipper && !ddraw_clipper_is_valid(dst_surface->clipper)) + { + FIXME("Attempting to blit with an invalid clipper.\n"); + return DDERR_INVALIDPARAMS; + } + + if (!dst_surface->clipper || (dst_surface->ddraw->cooperative_level & DDSCL_EXCLUSIVE + && dst_surface->clipper->window)) { if (src_surface && src_surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) hr = ddraw_surface_update_frontbuffer(src_surface, &src_rect, TRUE, 0); @@ -1659,12 +1666,6 @@ static HRESULT ddraw_surface_blt_clipped(struct ddraw_surface *dst_surface, cons return hr; } - if (!ddraw_clipper_is_valid(dst_surface->clipper)) - { - FIXME("Attempting to blit with an invalid clipper.\n"); - return DDERR_INVALIDPARAMS; - } - scale_x = (float)(src_rect.right - src_rect.left) / (float)(dst_rect.right - dst_rect.left); scale_y = (float)(src_rect.bottom - src_rect.top) / (float)(dst_rect.bottom - dst_rect.top); @@ -4644,9 +4645,8 @@ static HRESULT WINAPI ddraw_surface7_SetClipper(IDirectDrawSurface7 *iface, if ((This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) && This->ddraw->wined3d_swapchain) { clipWindow = NULL; - if(clipper) { + if (clipper && !(This->ddraw->cooperative_level & DDSCL_EXCLUSIVE)) IDirectDrawClipper_GetHWnd(iclipper, &clipWindow); - } if (clipWindow) { diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c index 594baee6ff9..1d9fd3842a7 100644 --- a/dlls/ddraw/tests/ddraw1.c +++ b/dlls/ddraw/tests/ddraw1.c @@ -16426,9 +16426,9 @@ static void check_surface_clipper(IDirectDrawSurface *surface, IDirectDrawClippe ok(hr == DD_OK, "got %#lx.\n", hr); c = get_surface_color(surface, window_rect->left + 1, window_rect->top + 1); - todo_wine_if(!(style & WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + ok(c == 0x0000ff00, "got %#x.\n", c); c = get_surface_color(surface, 0, 0); - todo_wine_if((style & (WS_CHILD | WS_VISIBLE)) != (WS_CHILD | WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + ok(c == 0x0000ff00, "got %#x.\n", c); hr = IDirectDrawSurface_SetClipper(surface, NULL); ok(hr == DD_OK, "got %#lx.\n", hr); diff --git a/dlls/ddraw/tests/ddraw2.c b/dlls/ddraw/tests/ddraw2.c index fdf22191743..0e475c21e13 100644 --- a/dlls/ddraw/tests/ddraw2.c +++ b/dlls/ddraw/tests/ddraw2.c @@ -17497,9 +17497,9 @@ static void check_surface_clipper(IDirectDrawSurface *surface, IDirectDrawClippe ok(hr == DD_OK, "got %#lx.\n", hr); c = get_surface_color(surface, window_rect->left + 1, window_rect->top + 1); - todo_wine_if(!(style & WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + ok(c == 0x0000ff00, "got %#x.\n", c); c = get_surface_color(surface, 0, 0); - todo_wine_if((style & (WS_CHILD | WS_VISIBLE)) != (WS_CHILD | WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + ok(c == 0x0000ff00, "got %#x.\n", c); hr = IDirectDrawSurface_SetClipper(surface, NULL); ok(hr == DD_OK, "got %#lx.\n", hr); diff --git a/dlls/ddraw/tests/ddraw4.c b/dlls/ddraw/tests/ddraw4.c index e2fa4738cbc..702a170c2a6 100644 --- a/dlls/ddraw/tests/ddraw4.c +++ b/dlls/ddraw/tests/ddraw4.c @@ -20596,9 +20596,9 @@ static void check_surface_clipper(IDirectDrawSurface4 *surface, IDirectDrawClipp ok(hr == DD_OK, "got %#lx.\n", hr); c = get_surface_color(surface, window_rect->left + 1, window_rect->top + 1); - todo_wine_if(!(style & WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + ok(c == 0x0000ff00, "got %#x.\n", c); c = get_surface_color(surface, 0, 0); - todo_wine_if((style & (WS_CHILD | WS_VISIBLE)) != (WS_CHILD | WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + ok(c == 0x0000ff00, "got %#x.\n", c); hr = IDirectDrawSurface4_SetClipper(surface, NULL); ok(hr == DD_OK, "got %#lx.\n", hr); diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c index eb35cfa6792..7062e419ca4 100644 --- a/dlls/ddraw/tests/ddraw7.c +++ b/dlls/ddraw/tests/ddraw7.c @@ -20994,9 +20994,9 @@ static void check_surface_clipper(IDirectDrawSurface7 *surface, IDirectDrawClipp ok(hr == DD_OK, "got %#lx.\n", hr); c = get_surface_color(surface, window_rect->left + 1, window_rect->top + 1); - todo_wine_if(!(style & WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + ok(c == 0x0000ff00, "got %#x.\n", c); c = get_surface_color(surface, 0, 0); - todo_wine_if((style & (WS_CHILD | WS_VISIBLE)) != (WS_CHILD | WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + ok(c == 0x0000ff00, "got %#x.\n", c); hr = IDirectDrawSurface7_SetClipper(surface, NULL); ok(hr == DD_OK, "got %#lx.\n", hr); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10723
participants (2)
-
Paul Gofman -
Paul Gofman (@gofman)