From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/d2d1/d2d1_private.h | 17 ++++++++ dlls/d2d1/device.c | 66 +++++++++++++++++++++++++--- dlls/d2d1/geometry.c | 92 ++++++++++++++++++++++++++++++++++++++++ dlls/d2d1/tests/d2d1.c | 56 ++++++++++++++++++++++++ 4 files changed, 226 insertions(+), 5 deletions(-)
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index e910b19db28..e99dc165bac 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -620,6 +620,23 @@ HRESULT d2d_geometry_group_init(struct d2d_geometry *geometry, ID2D1Factory *fac D2D1_FILL_MODE fill_mode, ID2D1Geometry **src_geometries, unsigned int geometry_count); struct d2d_geometry *unsafe_impl_from_ID2D1Geometry(ID2D1Geometry *iface);
+struct d2d_geometry_realization +{ + ID2D1GeometryRealization ID2D1GeometryRealization_iface; + LONG refcount; + + ID2D1Factory *factory; + ID2D1Geometry *geometry; + bool filled; + + ID2D1StrokeStyle *stroke_style; + float stroke_width; +}; + +HRESULT d2d_geometry_realization_init(struct d2d_geometry_realization *realization, + ID2D1Factory *factory, ID2D1Geometry *geometry); +struct d2d_geometry_realization *unsafe_impl_from_ID2D1GeometryRealization(ID2D1GeometryRealization *iface); + struct d2d_device { ID2D1Device6 ID2D1Device6_iface; diff --git a/dlls/d2d1/device.c b/dlls/d2d1/device.c index 59e93bfac38..3969046d5b3 100644 --- a/dlls/d2d1/device.c +++ b/dlls/d2d1/device.c @@ -2749,26 +2749,82 @@ static void STDMETHODCALLTYPE d2d_device_context_ID2D1DeviceContext_FillOpacityM static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateFilledGeometryRealization(ID2D1DeviceContext6 *iface, ID2D1Geometry *geometry, float tolerance, ID2D1GeometryRealization **realization) { - FIXME("iface %p, geometry %p, tolerance %.8e, realization %p stub!\n", iface, geometry, tolerance, + struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface); + struct d2d_geometry_realization *object; + HRESULT hr; + + TRACE("iface %p, geometry %p, tolerance %.8e, realization %p.\n", iface, geometry, tolerance, realization);
- return E_NOTIMPL; + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + if (FAILED(hr = d2d_geometry_realization_init(object, context->factory, geometry))) + { + WARN("Failed to initialise geometry realization, hr %#lx.\n", hr); + free(object); + return hr; + } + object->filled = true; + + TRACE("Created geometry realization %p.\n", object); + *realization = &object->ID2D1GeometryRealization_iface; + + return S_OK; }
static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateStrokedGeometryRealization( ID2D1DeviceContext6 *iface, ID2D1Geometry *geometry, float tolerance, float stroke_width, ID2D1StrokeStyle *stroke_style, ID2D1GeometryRealization **realization) { - FIXME("iface %p, geometry %p, tolerance %.8e, stroke_width %.8e, stroke_style %p, realization %p stub!\n", + struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface); + struct d2d_geometry_realization *object; + HRESULT hr; + + TRACE("iface %p, geometry %p, tolerance %.8e, stroke_width %.8e, stroke_style %p, realization %p.\n", iface, geometry, tolerance, stroke_width, stroke_style, realization);
- return E_NOTIMPL; + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + if (FAILED(hr = d2d_geometry_realization_init(object, context->factory, geometry))) + { + WARN("Failed to initialise geometry realization, hr %#lx.\n", hr); + free(object); + return hr; + } + object->stroke_width = stroke_width; + object->stroke_style = stroke_style; + if (object->stroke_style) + ID2D1StrokeStyle_AddRef(object->stroke_style); + + TRACE("Created geometry realization %p.\n", object); + *realization = &object->ID2D1GeometryRealization_iface; + + return S_OK; }
static void STDMETHODCALLTYPE d2d_device_context_DrawGeometryRealization(ID2D1DeviceContext6 *iface, ID2D1GeometryRealization *realization, ID2D1Brush *brush) { - FIXME("iface %p, realization %p, brush %p stub!\n", iface, realization, brush); + struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface); + struct d2d_geometry_realization *r = unsafe_impl_from_ID2D1GeometryRealization(realization); + + FIXME("iface %p, realization %p, brush %p semi-stub!\n", iface, realization, brush); + + if (context->target.type == D2D_TARGET_COMMAND_LIST) + { + if (r->filled) + { + d2d_command_list_fill_geometry(context->target.command_list, context, r->geometry, brush, NULL); + } + else + { + d2d_command_list_draw_geometry(context->target.command_list, context, r->geometry, brush, + r->stroke_width, r->stroke_style); + } + return; + } }
static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateInk(ID2D1DeviceContext6 *iface, diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c index 97592ba6dd9..e9ed1e43ff5 100644 --- a/dlls/d2d1/geometry.c +++ b/dlls/d2d1/geometry.c @@ -5507,3 +5507,95 @@ struct d2d_geometry *unsafe_impl_from_ID2D1Geometry(ID2D1Geometry *iface) || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_geometry_group_vtbl); return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface); } + +static inline struct d2d_geometry_realization *impl_from_ID2D1GeometryRealization( + ID2D1GeometryRealization *iface) +{ + return CONTAINING_RECORD(iface, struct d2d_geometry_realization, ID2D1GeometryRealization_iface); +} + +static HRESULT STDMETHODCALLTYPE d2d_geometry_realization_QueryInterface( + ID2D1GeometryRealization *iface, REFIID iid, void **out) +{ + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_ID2D1GeometryRealization) + || IsEqualGUID(iid, &IID_ID2D1Resource) + || IsEqualGUID(iid, &IID_IUnknown)) + { + ID2D1GeometryRealization_AddRef(iface); + *out = iface; + return S_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE d2d_geometry_realization_AddRef(ID2D1GeometryRealization *iface) +{ + struct d2d_geometry_realization *realization = impl_from_ID2D1GeometryRealization(iface); + ULONG refcount = InterlockedIncrement(&realization->refcount); + + TRACE("%p increasing refcount to %lu.\n", iface, refcount); + + return refcount; +} + +static ULONG STDMETHODCALLTYPE d2d_geometry_realization_Release(ID2D1GeometryRealization *iface) +{ + struct d2d_geometry_realization *realization = impl_from_ID2D1GeometryRealization(iface); + ULONG refcount = InterlockedDecrement(&realization->refcount); + + TRACE("%p decreasing refcount to %lu.\n", iface, refcount); + + if (!refcount) + { + if (realization->stroke_style) + ID2D1StrokeStyle_Release(realization->stroke_style); + ID2D1Geometry_Release(realization->geometry); + ID2D1Factory_Release(realization->factory); + free(realization); + } + + return refcount; +} + +static void STDMETHODCALLTYPE d2d_geometry_realization_GetFactory(ID2D1GeometryRealization *iface, + ID2D1Factory **factory) +{ + struct d2d_geometry_realization *realization = impl_from_ID2D1GeometryRealization(iface); + + TRACE("iface %p, factory %p.\n", iface, factory); + + ID2D1Factory_AddRef(*factory = realization->factory); +} + +static const ID2D1GeometryRealizationVtbl d2d_geometry_realization_vtbl = +{ + d2d_geometry_realization_QueryInterface, + d2d_geometry_realization_AddRef, + d2d_geometry_realization_Release, + d2d_geometry_realization_GetFactory, +}; + +HRESULT d2d_geometry_realization_init(struct d2d_geometry_realization *realization, + ID2D1Factory *factory, ID2D1Geometry *geometry) +{ + realization->ID2D1GeometryRealization_iface.lpVtbl = &d2d_geometry_realization_vtbl; + realization->refcount = 1; + ID2D1Factory_AddRef(realization->factory = factory); + ID2D1Geometry_AddRef(realization->geometry = geometry); + + return S_OK; +} + +struct d2d_geometry_realization *unsafe_impl_from_ID2D1GeometryRealization(ID2D1GeometryRealization *iface) +{ + if (!iface) + return NULL; + assert(iface->lpVtbl == &d2d_geometry_realization_vtbl); + return CONTAINING_RECORD(iface, struct d2d_geometry_realization, ID2D1GeometryRealization_iface); +} diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 5e8cbed748e..24829994e16 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -15989,6 +15989,61 @@ static void test_mesh(BOOL d3d11) release_test_context(&ctx); }
+static void test_geometry_realization(BOOL d3d11) +{ + ID2D1GeometryRealization *realization, *realization2; + ID2D1RectangleGeometry *rectangle_geometry; + ID2D1DeviceContext1 *device_context; + struct d2d1_test_context ctx; + ID2D1SolidColorBrush *brush; + D2D1_COLOR_F color; + D2D1_RECT_F rect; + HRESULT hr; + + if (!init_test_context(&ctx, d3d11)) + return; + + if (!ctx.factory2) + { + skip("Geometry realizations are not supported.\n"); + release_test_context(&ctx); + return; + } + + hr = ID2D1DeviceContext_QueryInterface(ctx.context, &IID_ID2D1DeviceContext1, (void **)&device_context); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + set_rect(&rect, -1.0f, -1.0f, 1.0f, 1.0f); + hr = ID2D1Factory_CreateRectangleGeometry(ctx.factory, &rect, &rectangle_geometry); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID2D1DeviceContext1_CreateFilledGeometryRealization(device_context, + (ID2D1Geometry *)rectangle_geometry, 10.0f, &realization); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID2D1DeviceContext1_CreateStrokedGeometryRealization(device_context, + (ID2D1Geometry *)rectangle_geometry, 0.0f, 2.0f, NULL, &realization2); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ID2D1RectangleGeometry_Release(rectangle_geometry); + + set_color(&color, 0.0f, 0.0f, 0.0f, 0.0f); + hr = ID2D1DeviceContext1_CreateSolidColorBrush(device_context, &color, NULL, &brush); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + ID2D1DeviceContext1_BeginDraw(device_context); + ID2D1DeviceContext1_DrawGeometryRealization(device_context, realization, (ID2D1Brush *)brush); + ID2D1DeviceContext1_DrawGeometryRealization(device_context, realization2, (ID2D1Brush *)brush); + hr = ID2D1DeviceContext1_EndDraw(device_context, NULL, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + ID2D1SolidColorBrush_Release(brush); + + ID2D1GeometryRealization_Release(realization); + ID2D1GeometryRealization_Release(realization2); + ID2D1DeviceContext1_Release(device_context); + release_test_context(&ctx); +} + START_TEST(d2d1) { HMODULE d2d1_dll = GetModuleHandleA("d2d1.dll"); @@ -16089,6 +16144,7 @@ START_TEST(d2d1) queue_test(test_get_dxgi_device); queue_test(test_no_target); queue_test(test_mesh); + queue_test(test_geometry_realization);
run_queued_tests(); }