From 2f6f8f1242233bc365d4e94c4d326e65bc94011f Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Fri, 10 Jul 2015 15:03:42 +0200 Subject: [PATCH] d2d1: Only allow path geometries to be opened once. --- dlls/d2d1/d2d1_private.h | 9 +++++ dlls/d2d1/geometry.c | 15 +++++++-- dlls/d2d1/tests/d2d1.c | 73 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 2 deletions(-) diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index 7d82b90c7bd..b018a24b940 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -189,11 +189,20 @@ void d2d_state_block_init(struct d2d_state_block *state_block, const D2D1_DRAWIN IDWriteRenderingParams *text_rendering_params) DECLSPEC_HIDDEN; struct d2d_state_block *unsafe_impl_from_ID2D1DrawingStateBlock(ID2D1DrawingStateBlock *iface) DECLSPEC_HIDDEN; +enum d2d_geometry_state +{ + D2D_GEOMETRY_STATE_INITIAL = 0, + D2D_GEOMETRY_STATE_OPEN, + D2D_GEOMETRY_STATE_CLOSED, +}; + struct d2d_geometry { ID2D1Geometry ID2D1Geometry_iface; ID2D1GeometrySink ID2D1GeometrySink_iface; LONG refcount; + + enum d2d_geometry_state state; }; void d2d_path_geometry_init(struct d2d_geometry *geometry) DECLSPEC_HIDDEN; diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c index 2f3a6cc3041..8e049763e9f 100644 --- a/dlls/d2d1/geometry.c +++ b/dlls/d2d1/geometry.c @@ -101,9 +101,15 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_EndFigure(ID2D1GeometrySink *ifa static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_Close(ID2D1GeometrySink *iface) { - FIXME("iface %p stub!\n", iface); + struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface); - return E_NOTIMPL; + TRACE("iface %p.\n", iface); + + if (geometry->state != D2D_GEOMETRY_STATE_OPEN) + return D2DERR_WRONG_STATE; + geometry->state = D2D_GEOMETRY_STATE_CLOSED; + + return S_OK; } static void STDMETHODCALLTYPE d2d_geometry_sink_AddLine(ID2D1GeometrySink *iface, D2D1_POINT_2F point) @@ -336,9 +342,14 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Open(ID2D1PathGeometry *iface TRACE("iface %p, sink %p.\n", iface, sink); + if (geometry->state != D2D_GEOMETRY_STATE_INITIAL) + return D2DERR_WRONG_STATE; + *sink = &geometry->ID2D1GeometrySink_iface; ID2D1GeometrySink_AddRef(*sink); + geometry->state = D2D_GEOMETRY_STATE_OPEN; + return S_OK; } diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 29e1bc62a01..b80f28e190c 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -873,10 +873,83 @@ static void test_bitmap_brush(void) DestroyWindow(window); } +static void test_path_geometry(void) +{ + ID2D1GeometrySink *sink, *tmp_sink; + ID2D1PathGeometry *geometry; + IDXGISwapChain *swapchain; + ID2D1RenderTarget *rt; + ID3D10Device1 *device; + IDXGISurface *surface; + ID2D1Factory *factory; + ULONG refcount; + HWND window; + HRESULT hr; + + if (!(device = create_device())) + { + skip("Failed to create device, skipping tests.\n"); + return; + } + window = CreateWindowA("static", "d2d1_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 0, 0, 640, 480, NULL, NULL, NULL, NULL); + swapchain = create_swapchain(device, window, TRUE); + hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGISurface, (void **)&surface); + ok(SUCCEEDED(hr), "Failed to get buffer, hr %#x.\n", hr); + rt = create_render_target(surface); + ok(!!rt, "Failed to create render target.\n"); + ID2D1RenderTarget_GetFactory(rt, &factory); + + /* Close() when closed. */ + hr = ID2D1Factory_CreatePathGeometry(factory, &geometry); + ok(SUCCEEDED(hr), "Failed to create path geometry, hr %#x.\n", hr); + hr = ID2D1PathGeometry_Open(geometry, &sink); + ok(SUCCEEDED(hr), "Failed to open geometry sink, hr %#x.\n", hr); + hr = ID2D1GeometrySink_Close(sink); + ok(SUCCEEDED(hr), "Failed to close geometry sink, hr %#x.\n", hr); + hr = ID2D1GeometrySink_Close(sink); + ok(hr == D2DERR_WRONG_STATE, "Got unexpected hr %#x.\n", hr); + ID2D1GeometrySink_Release(sink); + ID2D1PathGeometry_Release(geometry); + + /* Open() when closed. */ + hr = ID2D1Factory_CreatePathGeometry(factory, &geometry); + ok(SUCCEEDED(hr), "Failed to create path geometry, hr %#x.\n", hr); + hr = ID2D1PathGeometry_Open(geometry, &sink); + ok(SUCCEEDED(hr), "Failed to open geometry sink, hr %#x.\n", hr); + hr = ID2D1GeometrySink_Close(sink); + ok(SUCCEEDED(hr), "Failed to close geometry sink, hr %#x.\n", hr); + ID2D1GeometrySink_Release(sink); + hr = ID2D1PathGeometry_Open(geometry, &sink); + ok(hr == D2DERR_WRONG_STATE, "Got unexpected hr %#x.\n", hr); + ID2D1PathGeometry_Release(geometry); + + /* Open() when open. */ + hr = ID2D1Factory_CreatePathGeometry(factory, &geometry); + ok(SUCCEEDED(hr), "Failed to create path geometry, hr %#x.\n", hr); + hr = ID2D1PathGeometry_Open(geometry, &sink); + ok(SUCCEEDED(hr), "Failed to open geometry sink, hr %#x.\n", hr); + hr = ID2D1PathGeometry_Open(geometry, &tmp_sink); + ok(hr == D2DERR_WRONG_STATE, "Got unexpected hr %#x.\n", hr); + hr = ID2D1GeometrySink_Close(sink); + ok(SUCCEEDED(hr), "Failed to close geometry sink, hr %#x.\n", hr); + ID2D1GeometrySink_Release(sink); + ID2D1PathGeometry_Release(geometry); + + ID2D1RenderTarget_Release(rt); + refcount = ID2D1Factory_Release(factory); + ok(!refcount, "Factory has %u references left.\n", refcount); + IDXGISurface_Release(surface); + IDXGISwapChain_Release(swapchain); + ID3D10Device1_Release(device); + DestroyWindow(window); +} + START_TEST(d2d1) { test_clip(); test_state_block(); test_color_brush(); test_bitmap_brush(); + test_path_geometry(); }