By flipping the export_surfaces flag a developer can easily access the generated bitmaps to inspect them visually. By default the flag is disabled, so that no files are generated or overwritten and no performance penalty is paid.
Signed-off-by: Giovanni Mascellani gio@debian.org ---
Is this kind of developer-oriented patch acceptable in Wine? Or is there already an easy way to export the bitmaps generated during the test? I could not find one.
--- dlls/d2d1/tests/d2d1.c | 45 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+)
diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 5377c4ea34..801334f2ad 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -28,6 +28,7 @@ #include "wine/heap.h"
static BOOL use_mt = TRUE; +static const BOOL export_surfaces = FALSE;
static struct test_entry { @@ -613,6 +614,30 @@ static void read_figure(struct figure *figure, BYTE *data, unsigned int pitch, figure_add_span(figure, span); }
+static void export_surface_to_ppm(IDXGISurface *surface, const char *filename, + unsigned int x, unsigned int y, + unsigned int w, unsigned int h) { + unsigned int i, j, pitch; + struct resource_readback rb; + const BYTE *data; + FILE *fout; + + get_surface_readback(surface, &rb); + data = rb.map_desc.pData; + pitch = rb.map_desc.RowPitch; + + fout = fopen(filename, "w"); + fprintf(fout, "P3\n%d %d\n%d\n", w, h, 255); + for (i = 0; i < h; i++) { + const BYTE *row = &data[(y+i) * pitch + x * 4]; + for (j = 0; j < w; j++) { + fprintf(fout, "%d %d %d\n", row[j * 4 + 2], row[j * 4 + 1], row[j * 4]); + } + } + fflush(fout); + fclose(fout); +} + static BOOL compare_figure(IDXGISurface *surface, unsigned int x, unsigned int y, unsigned int w, unsigned int h, DWORD prev, unsigned int max_diff, const char *ref) { @@ -5841,6 +5866,10 @@ static void test_draw_geometry(void) hr = ID2D1RenderTarget_EndDraw(rt, NULL, NULL); ok(SUCCEEDED(hr), "Failed to end draw, hr %#x.\n", hr);
+ if (export_surfaces) { + export_surface_to_ppm(surface, "surface1.ppm", 0, 0, 640, 480); + } + match = compare_figure(surface, 0, 0, 160, 160, 0xff652e89, 0, ""); ok(match, "Figure does not match.\n"); match = compare_figure(surface, 160, 0, 160, 160, 0xff652e89, 0, "yGBQUFBQUFBQUFDoYQAA"); @@ -5983,6 +6012,10 @@ static void test_draw_geometry(void) ok(SUCCEEDED(hr), "Failed to end draw, hr %#x.\n", hr); ID2D1PathGeometry_Release(geometry);
+ if (export_surfaces) { + export_surface_to_ppm(surface, "surface2.ppm", 0, 0, 640, 480); + } + match = compare_figure(surface, 0, 0, 160, 160, 0xff652e89, 0, ""); ok(match, "Figure does not match.\n"); match = compare_figure(surface, 160, 0, 160, 160, 0xff652e89, 0, ""); @@ -6095,6 +6128,10 @@ static void test_draw_geometry(void) ID2D1RectangleGeometry_Release(rect_geometry[1]); ID2D1RectangleGeometry_Release(rect_geometry[0]);
+ if (export_surfaces) { + export_surface_to_ppm(surface, "surface3.ppm", 0, 0, 640, 480); + } + match = compare_figure(surface, 0, 0, 160, 160, 0xff652e89, 0, "vi5kPGQ8ZDxkPGQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwU" "PBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8" @@ -6266,6 +6303,10 @@ static void test_draw_geometry(void) ok(SUCCEEDED(hr), "Failed to end draw, hr %#x.\n", hr); ID2D1PathGeometry_Release(geometry);
+ if (export_surfaces) { + export_surface_to_ppm(surface, "surface4.ppm", 0, 0, 640, 480); + } + match = compare_figure(surface, 0, 0, 160, 160, 0xff652e89, 0, "vi5kPGQ8ZDxkPGQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwU" "PBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8" @@ -6446,6 +6487,10 @@ static void test_draw_geometry(void) ID2D1TransformedGeometry_Release(transformed_geometry[1]); ID2D1TransformedGeometry_Release(transformed_geometry[0]);
+ if (export_surfaces) { + export_surface_to_ppm(surface, "surface5.ppm", 0, 0, 640, 480); + } + match = compare_figure(surface, 0, 0, 160, 160, 0xff652e89, 128, "yjIJkQEHBwaIAQUSBYMBBBYEggEEFgSCAQQWBIIBBBYEggEEFgSCAQQWBIIBBBYEggEEFgSCAQQW" "BIIBBBYEggEEFgSDAQQVBIMBBBUEgwEEFQSDAQQVBIMBBBUEgwEEFQSDAQQVBIMBBBUEgwEEFQSD"
Currently rounded parts are approximated with quadratic Bézier curves.
Signed-off-by: Giovanni Mascellani gio@debian.org ---
The approximation is clearly very crude, but still a better one than the whole shape missing!
I am also writing a patch to actually display arc segments by introducing the appropriate shaders, and will submit it as soon as it is a bit more polished.
--- dlls/d2d1/d2d1_private.h | 12 ++ dlls/d2d1/factory.c | 22 ++- dlls/d2d1/geometry.c | 302 +++++++++++++++++++++++++++++++++++++++ dlls/d2d1/tests/d2d1.c | 1 - 4 files changed, 333 insertions(+), 4 deletions(-)
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index 2e42d6d550..a7b13e914a 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -483,6 +483,10 @@ struct d2d_geometry D2D1_RECT_F rect; } rectangle; struct + { + D2D1_ROUNDED_RECT rounded_rect; + } rounded_rectangle; + struct { ID2D1Geometry *src_geometry; D2D_MATRIX_3X2_F transform; @@ -499,6 +503,8 @@ struct d2d_geometry void d2d_path_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory) DECLSPEC_HIDDEN; HRESULT d2d_rectangle_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_RECT_F *rect) DECLSPEC_HIDDEN; +HRESULT d2d_rounded_rectangle_geometry_init(struct d2d_geometry *geometry, + ID2D1Factory *factory, const D2D1_ROUNDED_RECT *rounded_rect) DECLSPEC_HIDDEN; void d2d_transformed_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, ID2D1Geometry *src_geometry, const D2D_MATRIX_3X2_F *transform) DECLSPEC_HIDDEN; HRESULT d2d_geometry_group_init(struct d2d_geometry *geometry, ID2D1Factory *factory, @@ -620,4 +626,10 @@ static inline const char *debug_d2d_rect_f(const D2D1_RECT_F *rect) return wine_dbg_sprintf("(%.8e,%.8e)-(%.8e,%.8e)", rect->left, rect->top, rect->right, rect->bottom ); }
+static inline const char *debug_d2d_rounded_rect(const D2D1_ROUNDED_RECT *rounded_rect) +{ + if (!rounded_rect) return "(null)"; + return wine_dbg_sprintf("(%.8e,%.8e)-(%.8e,%.8e)[%.8e,%.8e]", rounded_rect->rect.left, rounded_rect->rect.top, rounded_rect->rect.right, rounded_rect->rect.bottom, rounded_rect->radiusX, rounded_rect->radiusY ); +} + #endif /* __WINE_D2D1_PRIVATE_H */ diff --git a/dlls/d2d1/factory.c b/dlls/d2d1/factory.c index 48a2efb96b..86284f4ae4 100644 --- a/dlls/d2d1/factory.c +++ b/dlls/d2d1/factory.c @@ -152,11 +152,27 @@ static HRESULT STDMETHODCALLTYPE d2d_factory_CreateRectangleGeometry(ID2D1Factor }
static HRESULT STDMETHODCALLTYPE d2d_factory_CreateRoundedRectangleGeometry(ID2D1Factory2 *iface, - const D2D1_ROUNDED_RECT *rect, ID2D1RoundedRectangleGeometry **geometry) + const D2D1_ROUNDED_RECT *rounded_rect, ID2D1RoundedRectangleGeometry **geometry) { - FIXME("iface %p, rect %p, geometry %p stub!\n", iface, rect, geometry); + struct d2d_geometry *object; + HRESULT hr;
- return E_NOTIMPL; + TRACE("iface %p, rounded_rect %s, geometry %p.\n", iface, debug_d2d_rounded_rect(rounded_rect), geometry); + + if (!(object = heap_alloc_zero(sizeof(*object)))) + return E_OUTOFMEMORY; + + if (FAILED(hr = d2d_rounded_rectangle_geometry_init(object, (ID2D1Factory *)iface, rounded_rect))) + { + WARN("Failed to initialize rounded rectangle geometry, hr %#x.\n", hr); + heap_free(object); + return hr; + } + + TRACE("Created rounded rectangle geometry %p.\n", object); + *geometry = (ID2D1RoundedRectangleGeometry *)&object->ID2D1Geometry_iface; + + return S_OK; }
static HRESULT STDMETHODCALLTYPE d2d_factory_CreateEllipseGeometry(ID2D1Factory2 *iface, diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c index 6697eccee4..a8ceb1cf41 100644 --- a/dlls/d2d1/geometry.c +++ b/dlls/d2d1/geometry.c @@ -3840,6 +3840,307 @@ fail: return E_OUTOFMEMORY; }
+static inline struct d2d_geometry *impl_from_ID2D1RoundedRectangleGeometry(ID2D1RoundedRectangleGeometry *iface) +{ + return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface); +} + +static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_QueryInterface(ID2D1RoundedRectangleGeometry *iface, + REFIID iid, void **out) +{ + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_ID2D1RoundedRectangleGeometry) + || IsEqualGUID(iid, &IID_ID2D1Geometry) + || IsEqualGUID(iid, &IID_ID2D1Resource) + || IsEqualGUID(iid, &IID_IUnknown)) + { + ID2D1RoundedRectangleGeometry_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_rounded_rectangle_geometry_AddRef(ID2D1RoundedRectangleGeometry *iface) +{ + struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface); + ULONG refcount = InterlockedIncrement(&geometry->refcount); + + TRACE("%p increasing refcount to %u.\n", iface, refcount); + + return refcount; +} + +static ULONG STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Release(ID2D1RoundedRectangleGeometry *iface) +{ + struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface); + ULONG refcount = InterlockedDecrement(&geometry->refcount); + + TRACE("%p decreasing refcount to %u.\n", iface, refcount); + + if (!refcount) + { + d2d_geometry_cleanup(geometry); + heap_free(geometry); + } + + return refcount; +} + +static void STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetFactory(ID2D1RoundedRectangleGeometry *iface, ID2D1Factory **factory) +{ + struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface); + + TRACE("iface %p, factory %p.\n", iface, factory); + + ID2D1Factory_AddRef(*factory = geometry->factory); +} + +static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetBounds(ID2D1RoundedRectangleGeometry *iface, + const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds) +{ + FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetWidenedBounds(ID2D1RoundedRectangleGeometry *iface, + float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, + float tolerance, D2D1_RECT_F *bounds) +{ + FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n", + iface, stroke_width, stroke_style, transform, tolerance, bounds); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_StrokeContainsPoint(ID2D1RoundedRectangleGeometry *iface, + D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, + float tolerance, BOOL *contains) +{ + FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p stub!\n", + iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_FillContainsPoint(ID2D1RoundedRectangleGeometry *iface, + D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains) +{ + FIXME("iface %p, point %s, transform %p, tolerance %.8e, contains %p stub!\n", + iface, debug_d2d_point_2f(&point), transform, tolerance, contains); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_CompareWithGeometry(ID2D1RoundedRectangleGeometry *iface, + ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation) +{ + FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n", + iface, geometry, transform, tolerance, relation); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Simplify(ID2D1RoundedRectangleGeometry *iface, + D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance, + ID2D1SimplifiedGeometrySink *sink) +{ + FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n", + iface, option, transform, tolerance, sink); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Tessellate(ID2D1RoundedRectangleGeometry *iface, + const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink) +{ + FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_CombineWithGeometry(ID2D1RoundedRectangleGeometry *iface, + ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform, + float tolerance, ID2D1SimplifiedGeometrySink *sink) +{ + FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n", + iface, geometry, combine_mode, transform, tolerance, sink); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Outline(ID2D1RoundedRectangleGeometry *iface, + const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink) +{ + FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_ComputeArea(ID2D1RoundedRectangleGeometry *iface, + const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area) +{ + FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_ComputeLength(ID2D1RoundedRectangleGeometry *iface, + const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length) +{ + FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_ComputePointAtLength(ID2D1RoundedRectangleGeometry *iface, + float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point, + D2D1_POINT_2F *tangent) +{ + FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n", + iface, length, transform, tolerance, point, tangent); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Widen(ID2D1RoundedRectangleGeometry *iface, float stroke_width, + ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance, + ID2D1SimplifiedGeometrySink *sink) +{ + FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n", + iface, stroke_width, stroke_style, transform, tolerance, sink); + + return E_NOTIMPL; +} + +static void STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetRoundedRect(ID2D1RoundedRectangleGeometry *iface, D2D1_ROUNDED_RECT *rounded_rect) +{ + struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface); + + TRACE("iface %p, rounded_rect %p.\n", iface, rounded_rect); + + *rounded_rect = geometry->u.rounded_rectangle.rounded_rect; +} + +static const struct ID2D1RoundedRectangleGeometryVtbl d2d_rounded_rectangle_geometry_vtbl = +{ + d2d_rounded_rectangle_geometry_QueryInterface, + d2d_rounded_rectangle_geometry_AddRef, + d2d_rounded_rectangle_geometry_Release, + d2d_rounded_rectangle_geometry_GetFactory, + d2d_rounded_rectangle_geometry_GetBounds, + d2d_rounded_rectangle_geometry_GetWidenedBounds, + d2d_rounded_rectangle_geometry_StrokeContainsPoint, + d2d_rounded_rectangle_geometry_FillContainsPoint, + d2d_rounded_rectangle_geometry_CompareWithGeometry, + d2d_rounded_rectangle_geometry_Simplify, + d2d_rounded_rectangle_geometry_Tessellate, + d2d_rounded_rectangle_geometry_CombineWithGeometry, + d2d_rounded_rectangle_geometry_Outline, + d2d_rounded_rectangle_geometry_ComputeArea, + d2d_rounded_rectangle_geometry_ComputeLength, + d2d_rounded_rectangle_geometry_ComputePointAtLength, + d2d_rounded_rectangle_geometry_Widen, + d2d_rounded_rectangle_geometry_GetRoundedRect, +}; + +HRESULT d2d_rounded_rectangle_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_ROUNDED_RECT *rounded_rect) +{ + struct d2d_face *f; + struct d2d_bezier_vertex *bv; + D2D1_POINT_2F *v, v1, v2, v3, v4; + float l, r, t, b; + float rX, rY; + + d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rounded_rectangle_geometry_vtbl); + geometry->u.rounded_rectangle.rounded_rect = *rounded_rect; + + if (!(geometry->fill.vertices = heap_alloc(8 * sizeof(*geometry->fill.vertices)))) + goto fail; + if (!d2d_array_reserve((void **)&geometry->fill.faces, + &geometry->fill.faces_size, 6, sizeof(*geometry->fill.faces))) + goto fail; + if (!(geometry->fill.bezier_vertices = heap_alloc(12 * sizeof(*geometry->fill.bezier_vertices)))) + goto fail; + + l = min(rounded_rect->rect.left, rounded_rect->rect.right); + r = max(rounded_rect->rect.left, rounded_rect->rect.right); + t = min(rounded_rect->rect.top, rounded_rect->rect.bottom); + b = max(rounded_rect->rect.top, rounded_rect->rect.bottom); + + rX = min(rounded_rect->radiusX, 0.5f*(r-l)); + rY = min(rounded_rect->radiusY, 0.5f*(b-t)); + + d2d_point_set(&v1, r, t); + d2d_point_set(&v2, r, b); + d2d_point_set(&v3, l, b); + d2d_point_set(&v4, l, t); + + v = geometry->fill.vertices; + d2d_point_set(&v[0], l+rX, t); + d2d_point_set(&v[1], r-rX, t); + d2d_point_set(&v[2], r, t+rY); + d2d_point_set(&v[3], r, b-rY); + d2d_point_set(&v[4], r-rX, b); + d2d_point_set(&v[5], l+rX, b); + d2d_point_set(&v[6], l, b-rY); + d2d_point_set(&v[7], l, t+rY); + geometry->fill.vertex_count = 8; + + f = geometry->fill.faces; + d2d_face_set(&f[0], 0, 7, 6); + d2d_face_set(&f[1], 0, 6, 5); + d2d_face_set(&f[2], 0, 5, 4); + d2d_face_set(&f[3], 0, 4, 1); + d2d_face_set(&f[4], 1, 4, 3); + d2d_face_set(&f[5], 1, 3, 2); + geometry->fill.face_count = 6; + + bv = geometry->fill.bezier_vertices; + d2d_bezier_vertex_set(&bv[0], &v[1], 0.0f, 0.0f, -1.0f); + d2d_bezier_vertex_set(&bv[1], &v1, 0.5f, 0.0f, -1.0f); + d2d_bezier_vertex_set(&bv[2], &v[2], 1.0f, 1.0f, -1.0f); + d2d_bezier_vertex_set(&bv[3], &v[3], 0.0f, 0.0f, -1.0f); + d2d_bezier_vertex_set(&bv[4], &v2, 0.5f, 0.0f, -1.0f); + d2d_bezier_vertex_set(&bv[5], &v[4], 1.0f, 1.0f, -1.0f); + d2d_bezier_vertex_set(&bv[6], &v[5], 0.0f, 0.0f, -1.0f); + d2d_bezier_vertex_set(&bv[7], &v3, 0.5f, 0.0f, -1.0f); + d2d_bezier_vertex_set(&bv[8], &v[6], 1.0f, 1.0f, -1.0f); + d2d_bezier_vertex_set(&bv[9], &v[7], 0.0f, 0.0f, -1.0f); + d2d_bezier_vertex_set(&bv[10], &v4, 0.5f, 0.0f, -1.0f); + d2d_bezier_vertex_set(&bv[11], &v[0], 1.0f, 1.0f, -1.0f); + geometry->fill.bezier_vertex_count = 12; + + if (!d2d_geometry_outline_add_line_segment(geometry, &v[0], &v[1])) + goto fail; + if (!d2d_geometry_outline_add_bezier_segment(geometry, &v[1], &v1, &v[2])) + goto fail; + if (!d2d_geometry_outline_add_line_segment(geometry, &v[2], &v[3])) + goto fail; + if (!d2d_geometry_outline_add_bezier_segment(geometry, &v[3], &v2, &v[4])) + goto fail; + if (!d2d_geometry_outline_add_line_segment(geometry, &v[4], &v[5])) + goto fail; + if (!d2d_geometry_outline_add_bezier_segment(geometry, &v[5], &v3, &v[6])) + goto fail; + if (!d2d_geometry_outline_add_line_segment(geometry, &v[6], &v[7])) + goto fail; + if (!d2d_geometry_outline_add_bezier_segment(geometry, &v[7], &v4, &v[0])) + goto fail; + + return S_OK; + +fail: + d2d_geometry_cleanup(geometry); + return E_OUTOFMEMORY; +} + static inline struct d2d_geometry *impl_from_ID2D1TransformedGeometry(ID2D1TransformedGeometry *iface) { return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface); @@ -4385,6 +4686,7 @@ struct d2d_geometry *unsafe_impl_from_ID2D1Geometry(ID2D1Geometry *iface) return NULL; assert(iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl + || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_rounded_rectangle_geometry_vtbl || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_geometry_group_vtbl); return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface); diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 801334f2ad..42cf524deb 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -3815,7 +3815,6 @@ static void test_rounded_rectangle_geometry(void)
set_rounded_rect(&rect, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); hr = ID2D1Factory_CreateRoundedRectangleGeometry(factory, &rect, &geometry); -todo_wine ok(SUCCEEDED(hr), "Failed to create geometry, hr %#x.\n", hr); if (FAILED(hr)) {
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=63474
Your paranoid android.
=== debian10 (32 bit French report) ===
Report errors: d2d1:d2d1 has no test summary line (early exit of the main process?) d2d1:d2d1 has unaccounted for todo messages
=== debian10 (build log) ===
X Error of failed request: GLXBadFBConfig Major opcode of failed request: 150 (GLX) Minor opcode of failed request: 34 ()
On Tue, 21 Jan 2020 at 15:40, Giovanni Mascellani gio@debian.org wrote:
+static inline const char *debug_d2d_rounded_rect(const D2D1_ROUNDED_RECT *rounded_rect) +{
- if (!rounded_rect) return "(null)";
- return wine_dbg_sprintf("(%.8e,%.8e)-(%.8e,%.8e)[%.8e,%.8e]", rounded_rect->rect.left, rounded_rect->rect.top, rounded_rect->rect.right, rounded_rect->rect.bottom, rounded_rect->radiusX, rounded_rect->radiusY );
This line seems a bit on the long side. For reference, we try to stick to 100-120 columns.
+HRESULT d2d_rounded_rectangle_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_ROUNDED_RECT *rounded_rect) +{
- struct d2d_face *f;
- struct d2d_bezier_vertex *bv;
- D2D1_POINT_2F *v, v1, v2, v3, v4;
- float l, r, t, b;
- float rX, rY;
- d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rounded_rectangle_geometry_vtbl);
- geometry->u.rounded_rectangle.rounded_rect = *rounded_rect;
- if (!(geometry->fill.vertices = heap_alloc(8 * sizeof(*geometry->fill.vertices))))
goto fail;
- if (!d2d_array_reserve((void **)&geometry->fill.faces,
&geometry->fill.faces_size, 6, sizeof(*geometry->fill.faces)))
goto fail;
- if (!(geometry->fill.bezier_vertices = heap_alloc(12 * sizeof(*geometry->fill.bezier_vertices))))
goto fail;
- l = min(rounded_rect->rect.left, rounded_rect->rect.right);
- r = max(rounded_rect->rect.left, rounded_rect->rect.right);
- t = min(rounded_rect->rect.top, rounded_rect->rect.bottom);
- b = max(rounded_rect->rect.top, rounded_rect->rect.bottom);
- rX = min(rounded_rect->radiusX, 0.5f*(r-l));
- rY = min(rounded_rect->radiusY, 0.5f*(b-t));
- d2d_point_set(&v1, r, t);
- d2d_point_set(&v2, r, b);
- d2d_point_set(&v3, l, b);
- d2d_point_set(&v4, l, t);
- v = geometry->fill.vertices;
- d2d_point_set(&v[0], l+rX, t);
- d2d_point_set(&v[1], r-rX, t);
- d2d_point_set(&v[2], r, t+rY);
- d2d_point_set(&v[3], r, b-rY);
- d2d_point_set(&v[4], r-rX, b);
- d2d_point_set(&v[5], l+rX, b);
- d2d_point_set(&v[6], l, b-rY);
- d2d_point_set(&v[7], l, t+rY);
- geometry->fill.vertex_count = 8;
- f = geometry->fill.faces;
- d2d_face_set(&f[0], 0, 7, 6);
- d2d_face_set(&f[1], 0, 6, 5);
- d2d_face_set(&f[2], 0, 5, 4);
- d2d_face_set(&f[3], 0, 4, 1);
- d2d_face_set(&f[4], 1, 4, 3);
- d2d_face_set(&f[5], 1, 3, 2);
- geometry->fill.face_count = 6;
- bv = geometry->fill.bezier_vertices;
- d2d_bezier_vertex_set(&bv[0], &v[1], 0.0f, 0.0f, -1.0f);
- d2d_bezier_vertex_set(&bv[1], &v1, 0.5f, 0.0f, -1.0f);
- d2d_bezier_vertex_set(&bv[2], &v[2], 1.0f, 1.0f, -1.0f);
- d2d_bezier_vertex_set(&bv[3], &v[3], 0.0f, 0.0f, -1.0f);
- d2d_bezier_vertex_set(&bv[4], &v2, 0.5f, 0.0f, -1.0f);
- d2d_bezier_vertex_set(&bv[5], &v[4], 1.0f, 1.0f, -1.0f);
- d2d_bezier_vertex_set(&bv[6], &v[5], 0.0f, 0.0f, -1.0f);
- d2d_bezier_vertex_set(&bv[7], &v3, 0.5f, 0.0f, -1.0f);
- d2d_bezier_vertex_set(&bv[8], &v[6], 1.0f, 1.0f, -1.0f);
- d2d_bezier_vertex_set(&bv[9], &v[7], 0.0f, 0.0f, -1.0f);
- d2d_bezier_vertex_set(&bv[10], &v4, 0.5f, 0.0f, -1.0f);
- d2d_bezier_vertex_set(&bv[11], &v[0], 1.0f, 1.0f, -1.0f);
- geometry->fill.bezier_vertex_count = 12;
- if (!d2d_geometry_outline_add_line_segment(geometry, &v[0], &v[1]))
goto fail;
- if (!d2d_geometry_outline_add_bezier_segment(geometry, &v[1], &v1, &v[2]))
goto fail;
- if (!d2d_geometry_outline_add_line_segment(geometry, &v[2], &v[3]))
goto fail;
- if (!d2d_geometry_outline_add_bezier_segment(geometry, &v[3], &v2, &v[4]))
goto fail;
- if (!d2d_geometry_outline_add_line_segment(geometry, &v[4], &v[5]))
goto fail;
- if (!d2d_geometry_outline_add_bezier_segment(geometry, &v[5], &v3, &v[6]))
goto fail;
- if (!d2d_geometry_outline_add_line_segment(geometry, &v[6], &v[7]))
goto fail;
- if (!d2d_geometry_outline_add_bezier_segment(geometry, &v[7], &v4, &v[0]))
goto fail;
- return S_OK;
+fail:
- d2d_geometry_cleanup(geometry);
- return E_OUTOFMEMORY;
+}
It seems tempting to first approximate arc primitives on top of beziers, and to then use those primitives here, instead of directly using beziers here. Any reason not to?
Currently the ellipse is approximated with quadratic Bézier curves.
Signed-off-by: Giovanni Mascellani gio@debian.org ---
Same comments as the rounded rectangle patch.
--- dlls/d2d1/d2d1_private.h | 12 ++ dlls/d2d1/factory.c | 20 ++- dlls/d2d1/geometry.c | 282 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 312 insertions(+), 2 deletions(-)
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index a7b13e914a..d0ce357a31 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -487,6 +487,10 @@ struct d2d_geometry D2D1_ROUNDED_RECT rounded_rect; } rounded_rectangle; struct + { + D2D1_ELLIPSE ellipse; + } ellipse; + struct { ID2D1Geometry *src_geometry; D2D_MATRIX_3X2_F transform; @@ -505,6 +509,8 @@ HRESULT d2d_rectangle_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_RECT_F *rect) DECLSPEC_HIDDEN; HRESULT d2d_rounded_rectangle_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_ROUNDED_RECT *rounded_rect) DECLSPEC_HIDDEN; +HRESULT d2d_ellipse_geometry_init(struct d2d_geometry *geometry, + ID2D1Factory *factory, const D2D1_ELLIPSE *ellipse) DECLSPEC_HIDDEN; void d2d_transformed_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, ID2D1Geometry *src_geometry, const D2D_MATRIX_3X2_F *transform) DECLSPEC_HIDDEN; HRESULT d2d_geometry_group_init(struct d2d_geometry *geometry, ID2D1Factory *factory, @@ -632,4 +638,10 @@ static inline const char *debug_d2d_rounded_rect(const D2D1_ROUNDED_RECT *rounde return wine_dbg_sprintf("(%.8e,%.8e)-(%.8e,%.8e)[%.8e,%.8e]", rounded_rect->rect.left, rounded_rect->rect.top, rounded_rect->rect.right, rounded_rect->rect.bottom, rounded_rect->radiusX, rounded_rect->radiusY ); }
+static inline const char *debug_d2d_ellipse(const D2D1_ELLIPSE *ellipse) +{ + if (!ellipse) return "(null)"; + return wine_dbg_sprintf("(%.8e,%.8e)[%.8e,%.8e]", ellipse->point.x, ellipse->point.y, ellipse->radiusX, ellipse->radiusY ); +} + #endif /* __WINE_D2D1_PRIVATE_H */ diff --git a/dlls/d2d1/factory.c b/dlls/d2d1/factory.c index 86284f4ae4..9fb7d05cca 100644 --- a/dlls/d2d1/factory.c +++ b/dlls/d2d1/factory.c @@ -178,9 +178,25 @@ static HRESULT STDMETHODCALLTYPE d2d_factory_CreateRoundedRectangleGeometry(ID2D static HRESULT STDMETHODCALLTYPE d2d_factory_CreateEllipseGeometry(ID2D1Factory2 *iface, const D2D1_ELLIPSE *ellipse, ID2D1EllipseGeometry **geometry) { - FIXME("iface %p, ellipse %p, geometry %p stub!\n", iface, ellipse, geometry); + struct d2d_geometry *object; + HRESULT hr;
- return E_NOTIMPL; + TRACE("iface %p, ellipse %s, geometry %p.\n", iface, debug_d2d_ellipse(ellipse), geometry); + + if (!(object = heap_alloc_zero(sizeof(*object)))) + return E_OUTOFMEMORY; + + if (FAILED(hr = d2d_ellipse_geometry_init(object, (ID2D1Factory *)iface, ellipse))) + { + WARN("Failed to initialize ellipse geometry, hr %#x.\n", hr); + heap_free(object); + return hr; + } + + TRACE("Created rounded ellipse %p.\n", object); + *geometry = (ID2D1EllipseGeometry *)&object->ID2D1Geometry_iface; + + return S_OK; }
static HRESULT STDMETHODCALLTYPE d2d_factory_CreateGeometryGroup(ID2D1Factory2 *iface, diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c index a8ceb1cf41..2ea244dabd 100644 --- a/dlls/d2d1/geometry.c +++ b/dlls/d2d1/geometry.c @@ -4141,6 +4141,287 @@ fail: return E_OUTOFMEMORY; }
+static inline struct d2d_geometry *impl_from_ID2D1EllipseGeometry(ID2D1EllipseGeometry *iface) +{ + return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface); +} + +static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_QueryInterface(ID2D1EllipseGeometry *iface, + REFIID iid, void **out) +{ + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_ID2D1EllipseGeometry) + || IsEqualGUID(iid, &IID_ID2D1Geometry) + || IsEqualGUID(iid, &IID_ID2D1Resource) + || IsEqualGUID(iid, &IID_IUnknown)) + { + ID2D1EllipseGeometry_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_ellipse_geometry_AddRef(ID2D1EllipseGeometry *iface) +{ + struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface); + ULONG refcount = InterlockedIncrement(&geometry->refcount); + + TRACE("%p increasing refcount to %u.\n", iface, refcount); + + return refcount; +} + +static ULONG STDMETHODCALLTYPE d2d_ellipse_geometry_Release(ID2D1EllipseGeometry *iface) +{ + struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface); + ULONG refcount = InterlockedDecrement(&geometry->refcount); + + TRACE("%p decreasing refcount to %u.\n", iface, refcount); + + if (!refcount) + { + d2d_geometry_cleanup(geometry); + heap_free(geometry); + } + + return refcount; +} + +static void STDMETHODCALLTYPE d2d_ellipse_geometry_GetFactory(ID2D1EllipseGeometry *iface, ID2D1Factory **factory) +{ + struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface); + + TRACE("iface %p, factory %p.\n", iface, factory); + + ID2D1Factory_AddRef(*factory = geometry->factory); +} + +static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_GetBounds(ID2D1EllipseGeometry *iface, + const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds) +{ + FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_GetWidenedBounds(ID2D1EllipseGeometry *iface, + float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, + float tolerance, D2D1_RECT_F *bounds) +{ + FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n", + iface, stroke_width, stroke_style, transform, tolerance, bounds); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_StrokeContainsPoint(ID2D1EllipseGeometry *iface, + D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, + float tolerance, BOOL *contains) +{ + FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p stub!\n", + iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_FillContainsPoint(ID2D1EllipseGeometry *iface, + D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains) +{ + FIXME("iface %p, point %s, transform %p, tolerance %.8e, contains %p stub!\n", + iface, debug_d2d_point_2f(&point), transform, tolerance, contains); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_CompareWithGeometry(ID2D1EllipseGeometry *iface, + ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation) +{ + FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n", + iface, geometry, transform, tolerance, relation); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Simplify(ID2D1EllipseGeometry *iface, + D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance, + ID2D1SimplifiedGeometrySink *sink) +{ + FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n", + iface, option, transform, tolerance, sink); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Tessellate(ID2D1EllipseGeometry *iface, + const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink) +{ + FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_CombineWithGeometry(ID2D1EllipseGeometry *iface, + ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform, + float tolerance, ID2D1SimplifiedGeometrySink *sink) +{ + FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n", + iface, geometry, combine_mode, transform, tolerance, sink); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Outline(ID2D1EllipseGeometry *iface, + const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink) +{ + FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_ComputeArea(ID2D1EllipseGeometry *iface, + const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area) +{ + FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_ComputeLength(ID2D1EllipseGeometry *iface, + const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length) +{ + FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_ComputePointAtLength(ID2D1EllipseGeometry *iface, + float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point, + D2D1_POINT_2F *tangent) +{ + FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n", + iface, length, transform, tolerance, point, tangent); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Widen(ID2D1EllipseGeometry *iface, float stroke_width, + ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance, + ID2D1SimplifiedGeometrySink *sink) +{ + FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n", + iface, stroke_width, stroke_style, transform, tolerance, sink); + + return E_NOTIMPL; +} + +static void STDMETHODCALLTYPE d2d_ellipse_geometry_GetRoundedRect(ID2D1EllipseGeometry *iface, D2D1_ELLIPSE *ellipse) +{ + struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface); + + TRACE("iface %p, ellipse %p.\n", iface, ellipse); + + *ellipse = geometry->u.ellipse.ellipse; +} + +static const struct ID2D1EllipseGeometryVtbl d2d_ellipse_geometry_vtbl = +{ + d2d_ellipse_geometry_QueryInterface, + d2d_ellipse_geometry_AddRef, + d2d_ellipse_geometry_Release, + d2d_ellipse_geometry_GetFactory, + d2d_ellipse_geometry_GetBounds, + d2d_ellipse_geometry_GetWidenedBounds, + d2d_ellipse_geometry_StrokeContainsPoint, + d2d_ellipse_geometry_FillContainsPoint, + d2d_ellipse_geometry_CompareWithGeometry, + d2d_ellipse_geometry_Simplify, + d2d_ellipse_geometry_Tessellate, + d2d_ellipse_geometry_CombineWithGeometry, + d2d_ellipse_geometry_Outline, + d2d_ellipse_geometry_ComputeArea, + d2d_ellipse_geometry_ComputeLength, + d2d_ellipse_geometry_ComputePointAtLength, + d2d_ellipse_geometry_Widen, + d2d_ellipse_geometry_GetRoundedRect, +}; + +HRESULT d2d_ellipse_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_ELLIPSE *ellipse) +{ + struct d2d_face *f; + struct d2d_bezier_vertex *bv; + D2D1_POINT_2F *v, v1, v2, v3, v4; + float l, r, t, b; + + d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_ellipse_geometry_vtbl); + geometry->u.ellipse.ellipse = *ellipse; + + if (!(geometry->fill.vertices = heap_alloc(4 * sizeof(*geometry->fill.vertices)))) + goto fail; + if (!d2d_array_reserve((void **)&geometry->fill.faces, + &geometry->fill.faces_size, 2, sizeof(*geometry->fill.faces))) + goto fail; + if (!(geometry->fill.bezier_vertices = heap_alloc(12 * sizeof(*geometry->fill.bezier_vertices)))) + goto fail; + + l = ellipse->point.x - ellipse->radiusX; + r = ellipse->point.x + ellipse->radiusX; + t = ellipse->point.y - ellipse->radiusY; + b = ellipse->point.y + ellipse->radiusY; + + d2d_point_set(&v1, r, t); + d2d_point_set(&v2, r, b); + d2d_point_set(&v3, l, b); + d2d_point_set(&v4, l, t); + + v = geometry->fill.vertices; + d2d_point_set(&v[0], ellipse->point.x, t); + d2d_point_set(&v[1], r, ellipse->point.y); + d2d_point_set(&v[2], ellipse->point.x, b); + d2d_point_set(&v[3], l, ellipse->point.y); + geometry->fill.vertex_count = 4; + + f = geometry->fill.faces; + d2d_face_set(&f[0], 0, 3, 2); + d2d_face_set(&f[1], 0, 2, 1); + geometry->fill.face_count = 2; + + bv = geometry->fill.bezier_vertices; + d2d_bezier_vertex_set(&bv[0], &v[0], 0.0f, 0.0f, -1.0f); + d2d_bezier_vertex_set(&bv[1], &v1, 0.5f, 0.0f, -1.0f); + d2d_bezier_vertex_set(&bv[2], &v[1], 1.0f, 1.0f, -1.0f); + d2d_bezier_vertex_set(&bv[3], &v[1], 0.0f, 0.0f, -1.0f); + d2d_bezier_vertex_set(&bv[4], &v2, 0.5f, 0.0f, -1.0f); + d2d_bezier_vertex_set(&bv[5], &v[2], 1.0f, 1.0f, -1.0f); + d2d_bezier_vertex_set(&bv[6], &v[2], 0.0f, 0.0f, -1.0f); + d2d_bezier_vertex_set(&bv[7], &v3, 0.5f, 0.0f, -1.0f); + d2d_bezier_vertex_set(&bv[8], &v[3], 1.0f, 1.0f, -1.0f); + d2d_bezier_vertex_set(&bv[9], &v[3], 0.0f, 0.0f, -1.0f); + d2d_bezier_vertex_set(&bv[10], &v4, 0.5f, 0.0f, -1.0f); + d2d_bezier_vertex_set(&bv[11], &v[0], 1.0f, 1.0f, -1.0f); + geometry->fill.bezier_vertex_count = 12; + + if (!d2d_geometry_outline_add_bezier_segment(geometry, &v[0], &v1, &v[1])) + goto fail; + if (!d2d_geometry_outline_add_bezier_segment(geometry, &v[1], &v2, &v[2])) + goto fail; + if (!d2d_geometry_outline_add_bezier_segment(geometry, &v[2], &v3, &v[3])) + goto fail; + if (!d2d_geometry_outline_add_bezier_segment(geometry, &v[3], &v4, &v[0])) + goto fail; + + return S_OK; + +fail: + d2d_geometry_cleanup(geometry); + return E_OUTOFMEMORY; +} + static inline struct d2d_geometry *impl_from_ID2D1TransformedGeometry(ID2D1TransformedGeometry *iface) { return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface); @@ -4687,6 +4968,7 @@ struct d2d_geometry *unsafe_impl_from_ID2D1Geometry(ID2D1Geometry *iface) assert(iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_rounded_rectangle_geometry_vtbl + || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_ellipse_geometry_vtbl || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_geometry_group_vtbl); return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
On Tue, 21 Jan 2020 at 15:32, Giovanni Mascellani gio@debian.org wrote:
Is this kind of developer-oriented patch acceptable in Wine? Or is there already an easy way to export the bitmaps generated during the test? I could not find one.
I've been using something like the attached patch, mostly for getting data out of the testbot. For local debugging, in many cases it's enough to simply add a IDXGISwapchain_Present() call followed by a Sleep() in the appropriated place.
I think the general sentiment is that these kinds of debugging patches are trivial enough for individual developers to write on their own when needed, but personally I'm not necessarily opposed to having something like this in the upstream tree.
Hi,
Il 21/01/20 16:11, Henri Verbeet ha scritto:
I think the general sentiment is that these kinds of debugging patches are trivial enough for individual developers to write on their own when needed, but personally I'm not necessarily opposed to having something like this in the upstream tree.
Just in case you are waiting for my input, no problem to drop that patch. The other two are the interesting ones. :-)
Thanks, Giovanni.