[PATCH 0/5] MR10043: d2d1/tests: Add some more tests for geometry groups.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10043
From: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> --- dlls/d2d1/tests/d2d1.c | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 6ae1f65a24b..331821fe2b2 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -11432,6 +11432,9 @@ static void test_geometry_group(BOOL d3d11) ID2D1Geometry *geometries[2]; ID2D1GeometryGroup *group; D2D1_MATRIX_3X2_F matrix; + ID2D1PathGeometry *path; + ID2D1GeometrySink *sink; + D2D1_POINT_2F point; D2D1_RECT_F rect; HRESULT hr; BOOL match; @@ -11471,6 +11474,51 @@ static void test_geometry_group(BOOL d3d11) ID2D1Geometry_Release(geometries[0]); ID2D1Geometry_Release(geometries[1]); + /* Empty path. */ + hr = ID2D1Factory_CreatePathGeometry(ctx.factory, &path); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID2D1Factory_CreateGeometryGroup(ctx.factory, D2D1_FILL_MODE_ALTERNATE, (ID2D1Geometry **)&path, 1, &group); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID2D1GeometryGroup_GetBounds(group, NULL, &rect); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + match = compare_rect(&rect, INFINITY, INFINITY, FLT_MAX, FLT_MAX, 0); + todo_wine + ok(match, "Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n", + rect.left, rect.top, rect.right, rect.bottom); + + hr = ID2D1PathGeometry_Open(path, &sink); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + set_point(&point, 160.0f, 240.0f); + ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED); + line_to(sink, 240.0f, 240.0f); + line_to(sink, 240.0f, 720.0f); + line_to(sink, 160.0f, 720.0f); + ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_OPEN); + ID2D1GeometrySink_Close(sink); + ID2D1GeometrySink_Release(sink); + + hr = ID2D1GeometryGroup_GetBounds(group, NULL, &rect); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + match = compare_rect(&rect, INFINITY, INFINITY, FLT_MAX, FLT_MAX, 0); + todo_wine + ok(match, "Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n", + rect.left, rect.top, rect.right, rect.bottom); + + ID2D1GeometryGroup_Release(group); + + hr = ID2D1Factory_CreateGeometryGroup(ctx.factory, D2D1_FILL_MODE_ALTERNATE, (ID2D1Geometry **)&path, 1, &group); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID2D1GeometryGroup_GetBounds(group, NULL, &rect); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + match = compare_rect(&rect, 160.0f, 240.0f, 240.0f, 720.0f, 0); + ok(match, "Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n", + rect.left, rect.top, rect.right, rect.bottom); + + ID2D1GeometryGroup_Release(group); + ID2D1PathGeometry_Release(path); + release_test_context(&ctx); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10043
From: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> --- dlls/d2d1/d2d1_private.h | 1 + dlls/d2d1/geometry.c | 337 ++++++++++++++++++++++++++++++++------- 2 files changed, 276 insertions(+), 62 deletions(-) diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index 51bf830fc0a..9ec099fcff3 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -582,6 +582,7 @@ struct d2d_geometry enum d2d_geometry_state state; HRESULT code; D2D1_FILL_MODE fill_mode; + UINT32 segment_flags; UINT32 segment_count; D2D1_RECT_F bounds; diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c index 633919afa4f..878e8892295 100644 --- a/dlls/d2d1/geometry.c +++ b/dlls/d2d1/geometry.c @@ -60,6 +60,53 @@ struct d2d_segment_idx size_t control_idx; }; +enum d2d_segment_type +{ + D2D_SEGMENT_TYPE_BEZIERS = 0, + D2D_SEGMENT_TYPE_QUADRATIC_BEZIERS, + D2D_SEGMENT_TYPE_LINES, + D2D_SEGMENT_TYPE_ARCS, +}; + +struct d2d_segment +{ + uint32_t type; + uint32_t flags; + uint32_t count; +}; + +struct d2d_segment_beziers +{ + uint32_t type; + uint32_t flags; + uint32_t count; + D2D1_BEZIER_SEGMENT segments[1]; +}; + +struct d2d_segment_quadratic_beziers +{ + uint32_t type; + uint32_t flags; + uint32_t count; + D2D1_QUADRATIC_BEZIER_SEGMENT segments[1]; +}; + +struct d2d_segment_lines +{ + uint32_t type; + uint32_t flags; + uint32_t count; + D2D1_POINT_2F points[1]; +}; + +struct d2d_segment_arcs +{ + uint32_t type; + uint32_t flags; + uint32_t count; + D2D1_ARC_SEGMENT segments[1]; +}; + struct d2d_figure { D2D1_POINT_2F *vertices; @@ -78,8 +125,118 @@ struct d2d_figure D2D1_RECT_F bounds; unsigned int flags; + + struct + { + uint8_t *data; + size_t size; + size_t capacity; + + size_t current; + size_t count; + } segments; }; +static struct d2d_segment *d2d_figure_get_current_segment(struct d2d_figure *figure) +{ + if (!figure->segments.data) + return NULL; + + return (struct d2d_segment *)(figure->segments.data + figure->segments.current); +} + +static size_t d2d_figure_get_segment_data_size(enum d2d_segment_type type) +{ + if (type == D2D_SEGMENT_TYPE_BEZIERS) return sizeof(D2D1_BEZIER_SEGMENT); + if (type == D2D_SEGMENT_TYPE_QUADRATIC_BEZIERS) return sizeof(D2D1_QUADRATIC_BEZIER_SEGMENT); + if (type == D2D_SEGMENT_TYPE_LINES) return sizeof(D2D1_POINT_2F); + return sizeof(D2D1_ARC_SEGMENT); +} + +static bool d2d_figure_new_segment(struct d2d_geometry *geometry, enum d2d_segment_type type, + const void *data, unsigned int count) +{ + struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1]; + size_t segment_size = d2d_figure_get_segment_data_size(type) * count; + unsigned int segment_flags = geometry->u.path.segment_flags; + size_t size = segment_size + sizeof(struct d2d_segment); + struct d2d_segment *segment; + + if (!d2d_array_reserve((void **)&figure->segments.data, &figure->segments.capacity, + figure->segments.size + size, 1)) + { + return false; + } + figure->segments.current = figure->segments.size; + figure->segments.size += size; + ++figure->segments.count; + + segment = d2d_figure_get_current_segment(figure); + segment->type = type; + segment->flags = segment_flags; + segment->count = count; + memcpy(segment + 1, data, segment_size); + + return true; +} + +static bool d2d_figure_append_segment_data(struct d2d_geometry *geometry, + enum d2d_segment_type type, const void *data, unsigned int count) +{ + struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1]; + size_t size = d2d_figure_get_segment_data_size(type) * count; + struct d2d_segment *segment; + + if (!d2d_array_reserve((void **)&figure->segments.data, &figure->segments.capacity, + figure->segments.size + size, 1)) + { + return false; + } + segment = d2d_figure_get_current_segment(figure); + + memcpy(figure->segments.data + figure->segments.size, data, size); + figure->segments.size += size; + segment->count += count; + + return true; +} + +static bool d2d_figure_add_segment_data(struct d2d_geometry *geometry, + enum d2d_segment_type type, const void *data, unsigned int count) +{ + struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1]; + struct d2d_segment *current = d2d_figure_get_current_segment(figure); + unsigned int segment_flags = geometry->u.path.segment_flags; + + if (!current || current->flags != segment_flags || current->type != type) + return d2d_figure_new_segment(geometry, type, data, count); + + return d2d_figure_append_segment_data(geometry, type, data, count); +} + +static bool d2d_figure_add_bezier_segments(struct d2d_geometry *geometry, + const D2D1_BEZIER_SEGMENT *segments, UINT32 count) +{ + return d2d_figure_add_segment_data(geometry, D2D_SEGMENT_TYPE_BEZIERS, segments, count); +} + +static bool d2d_figure_add_quadratic_bezier_segments(struct d2d_geometry *geometry, + const D2D1_QUADRATIC_BEZIER_SEGMENT *segments, UINT32 count) +{ + return d2d_figure_add_segment_data(geometry, D2D_SEGMENT_TYPE_QUADRATIC_BEZIERS, segments, count); +} + +static bool d2d_figure_add_line_segments(struct d2d_geometry *geometry, + const D2D1_POINT_2F *points, UINT32 count) +{ + return d2d_figure_add_segment_data(geometry, D2D_SEGMENT_TYPE_LINES, points, count); +} + +static bool d2d_figure_add_arc_segment(struct d2d_geometry *geometry, const D2D1_ARC_SEGMENT *arc) +{ + return d2d_figure_add_segment_data(geometry, D2D_SEGMENT_TYPE_ARCS, arc, 1); +} + struct d2d_cdt_edge_ref { size_t idx; @@ -900,25 +1057,6 @@ static BOOL d2d_figure_add_original_bezier_controls(struct d2d_figure *figure, s return TRUE; } -static bool d2d_figure_begin(struct d2d_figure *figure, D2D1_POINT_2F start_point, - D2D1_FIGURE_BEGIN figure_begin) -{ - if (figure_begin == D2D1_FIGURE_BEGIN_HOLLOW) - figure->flags |= D2D_FIGURE_FLAG_HOLLOW; - - return d2d_figure_add_vertex(figure, start_point); -} - -static void d2d_figure_end(struct d2d_figure *figure, D2D1_FIGURE_END figure_end) -{ - if (memcmp(&figure->vertices[0], &figure->vertices[figure->vertex_count - 1], sizeof(*figure->vertices))) - figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_LINE; - else - figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_END; - if (figure_end == D2D1_FIGURE_END_CLOSED) - figure->flags |= D2D_FIGURE_FLAG_CLOSED; -} - static bool d2d_figure_add_beziers(struct d2d_figure *figure, const D2D1_BEZIER_SEGMENT *beziers, UINT32 count) { @@ -957,6 +1095,38 @@ static bool d2d_figure_add_beziers(struct d2d_figure *figure, const D2D1_BEZIER_ return true; } +static bool d2d_figure_add_quadratic_beziers(struct d2d_figure *figure, + const D2D1_QUADRATIC_BEZIER_SEGMENT *beziers, UINT32 bezier_count) +{ + unsigned int i; + + for (i = 0; i < bezier_count; ++i) + { + D2D1_RECT_F bezier_bounds; + D2D1_POINT_2F p[2]; + + /* Construct a cubic curve. */ + d2d_point_lerp(&p[0], &figure->vertices[figure->vertex_count - 1], &beziers[i].point1, 2.0f / 3.0f); + d2d_point_lerp(&p[1], &beziers[i].point2, &beziers[i].point1, 2.0f / 3.0f); + if (!d2d_figure_add_original_bezier_controls(figure, 2, p)) + return false; + + d2d_rect_get_bezier_bounds(&bezier_bounds, &figure->vertices[figure->vertex_count - 1], + &beziers[i].point1, &beziers[i].point2); + + figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_BEZIER; + if (!d2d_figure_add_bezier_controls(figure, 1, &beziers[i].point1)) + return false; + + if (!d2d_figure_add_vertex(figure, beziers[i].point2)) + return false; + + d2d_rect_union(&figure->bounds, &bezier_bounds); + } + + return true; +} + static bool d2d_figure_add_lines(struct d2d_figure *figure, const D2D1_POINT_2F *points, UINT32 count) { @@ -972,11 +1142,88 @@ static bool d2d_figure_add_lines(struct d2d_figure *figure, const D2D1_POINT_2F return true; } +static bool d2d_figure_produce_vertices(struct d2d_figure *figure) +{ + union + { + const struct d2d_segment *segment; + const struct d2d_segment_beziers *beziers; + const struct d2d_segment_quadratic_beziers *quad_beziers; + const struct d2d_segment_lines *lines; + const struct d2d_segment_arcs *arcs; + } s = { (struct d2d_segment *)figure->segments.data }; + unsigned int i, j; + size_t size = 0; + + for (i = 0; i < figure->segments.count; ++i) + { + switch (s.segment->type) + { + case D2D_SEGMENT_TYPE_BEZIERS: + if (!d2d_figure_add_beziers(figure, s.beziers->segments, s.beziers->count)) + return false; + + size = FIELD_OFFSET(struct d2d_segment_beziers, segments[s.beziers->count]); + break; + case D2D_SEGMENT_TYPE_QUADRATIC_BEZIERS: + if (!d2d_figure_add_quadratic_beziers(figure, s.quad_beziers->segments, s.quad_beziers->count)) + return false; + + size = FIELD_OFFSET(struct d2d_segment_quadratic_beziers, segments[s.quad_beziers->count]); + break; + case D2D_SEGMENT_TYPE_LINES: + if (!d2d_figure_add_lines(figure, s.lines->points, s.lines->count)) + return false; + + size = FIELD_OFFSET(struct d2d_segment_lines, points[s.lines->count]); + break; + case D2D_SEGMENT_TYPE_ARCS: + /* FIXME: use a sequence of bezier curves */ + for (j = 0; j < s.arcs->count; ++j) + { + if (!d2d_figure_add_vertex(figure, s.arcs->segments[j].point)) + return false; + } + + size = FIELD_OFFSET(struct d2d_segment_arcs, segments[s.arcs->count]); + break; + default: + ; + } + + s.segment = (struct d2d_segment *)((uint8_t *)s.segment + size); + } + + return true; +} + +static bool d2d_figure_begin(struct d2d_figure *figure, D2D1_POINT_2F start_point, + D2D1_FIGURE_BEGIN figure_begin) +{ + if (figure_begin == D2D1_FIGURE_BEGIN_HOLLOW) + figure->flags |= D2D_FIGURE_FLAG_HOLLOW; + + return d2d_figure_add_vertex(figure, start_point); +} + +static void d2d_figure_end(struct d2d_figure *figure, D2D1_FIGURE_END figure_end) +{ + d2d_figure_produce_vertices(figure); + + if (memcmp(&figure->vertices[0], &figure->vertices[figure->vertex_count - 1], sizeof(*figure->vertices))) + figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_LINE; + else + figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_END; + if (figure_end == D2D1_FIGURE_END_CLOSED) + figure->flags |= D2D_FIGURE_FLAG_CLOSED; +} + static void d2d_figure_cleanup(struct d2d_figure *figure) { free(figure->original_bezier_controls); free(figure->bezier_controls); free(figure->vertices); + free(figure->segments.data); memset(figure, 0, sizeof(*figure)); } @@ -2874,6 +3121,8 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_SetSegmentFlags(ID2D1GeometrySin if (flags != D2D1_PATH_SEGMENT_NONE) FIXME("Ignoring flags %#x.\n", flags); + + geometry->u.path.segment_flags = flags; } static void STDMETHODCALLTYPE d2d_geometry_sink_BeginFigure(ID2D1GeometrySink *iface, @@ -2912,7 +3161,6 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_AddLines(ID2D1GeometrySink *ifac const D2D1_POINT_2F *points, UINT32 count) { struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface); - struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1]; TRACE("iface %p, points %p, count %u.\n", iface, points, count); @@ -2922,9 +3170,8 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_AddLines(ID2D1GeometrySink *ifac return; } - if (!d2d_figure_add_lines(figure, points, count)) + if (!d2d_figure_add_line_segments(geometry, points, count)) { - ERR("Failed to add vertex.\n"); d2d_geometry_set_error(geometry, E_OUTOFMEMORY); return; } @@ -2936,7 +3183,6 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_AddBeziers(ID2D1GeometrySink *if const D2D1_BEZIER_SEGMENT *beziers, UINT32 count) { struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface); - struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1]; TRACE("iface %p, beziers %p, count %u.\n", iface, beziers, count); @@ -2946,9 +3192,8 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_AddBeziers(ID2D1GeometrySink *if return; } - if (!d2d_figure_add_beziers(figure, beziers, count)) + if (!d2d_figure_add_bezier_segments(geometry, beziers, count)) { - ERR("Failed to add Bézier curves.\n"); d2d_geometry_set_error(geometry, E_OUTOFMEMORY); return; } @@ -3309,8 +3554,6 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBeziers(ID2D1Geometr const D2D1_QUADRATIC_BEZIER_SEGMENT *beziers, UINT32 bezier_count) { struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface); - struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1]; - unsigned int i; TRACE("iface %p, beziers %p, bezier_count %u.\n", iface, beziers, bezier_count); @@ -3320,40 +3563,10 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBeziers(ID2D1Geometr return; } - for (i = 0; i < bezier_count; ++i) + if (!d2d_figure_add_quadratic_bezier_segments(geometry, beziers, bezier_count)) { - D2D1_RECT_F bezier_bounds; - D2D1_POINT_2F p[2]; - - /* Construct a cubic curve. */ - d2d_point_lerp(&p[0], &figure->vertices[figure->vertex_count - 1], &beziers[i].point1, 2.0f / 3.0f); - d2d_point_lerp(&p[1], &beziers[i].point2, &beziers[i].point1, 2.0f / 3.0f); - if (!d2d_figure_add_original_bezier_controls(figure, 2, p)) - { - ERR("Failed to add cubic Bézier controls.\n"); - d2d_geometry_set_error(geometry, E_OUTOFMEMORY); - return; - } - - d2d_rect_get_bezier_bounds(&bezier_bounds, &figure->vertices[figure->vertex_count - 1], - &beziers[i].point1, &beziers[i].point2); - - figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_BEZIER; - if (!d2d_figure_add_bezier_controls(figure, 1, &beziers[i].point1)) - { - ERR("Failed to add bezier.\n"); - d2d_geometry_set_error(geometry, E_OUTOFMEMORY); - return; - } - - if (!d2d_figure_add_vertex(figure, beziers[i].point2)) - { - ERR("Failed to add bezier vertex.\n"); - d2d_geometry_set_error(geometry, E_OUTOFMEMORY); - return; - } - - d2d_rect_union(&figure->bounds, &bezier_bounds); + d2d_geometry_set_error(geometry, E_OUTOFMEMORY); + return; } geometry->u.path.segment_count += bezier_count; @@ -3371,9 +3584,9 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_AddArc(ID2D1GeometrySink *iface, return; } - if (!d2d_figure_add_vertex(&geometry->u.path.figures[geometry->u.path.figure_count - 1], arc->point)) + if (!d2d_figure_add_arc_segment(geometry, arc)) { - ERR("Failed to add vertex.\n"); + d2d_geometry_set_error(geometry, E_OUTOFMEMORY); return; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10043
From: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> --- dlls/d2d1/geometry.c | 64 ++++++++++++++++++++++++++++++++++++++++-- dlls/d2d1/tests/d2d1.c | 5 +--- 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c index 878e8892295..b2de24ae5dc 100644 --- a/dlls/d2d1/geometry.c +++ b/dlls/d2d1/geometry.c @@ -4255,9 +4255,69 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Open(ID2D1PathGeometry1 *ifac static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Stream(ID2D1PathGeometry1 *iface, ID2D1GeometrySink *sink) { - FIXME("iface %p, sink %p stub!\n", iface, sink); + struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface); + unsigned int flags = 0; - return E_NOTIMPL; + TRACE("iface %p, sink %p.\n", iface, sink); + + if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED) + return D2DERR_WRONG_STATE; + + for (size_t i = 0; i < geometry->u.path.figure_count; ++i) + { + const struct d2d_figure *figure = &geometry->u.path.figures[i]; + union + { + const struct d2d_segment *segment; + const struct d2d_segment_beziers *beziers; + const struct d2d_segment_quadratic_beziers *quad_beziers; + const struct d2d_segment_lines *lines; + const struct d2d_segment_arcs *arcs; + } s = { (struct d2d_segment *)figure->segments.data }; + size_t size = 0; + + ID2D1GeometrySink_BeginFigure(sink, figure->vertices[0], figure->flags & D2D_FIGURE_FLAG_HOLLOW ? + D2D1_FIGURE_BEGIN_HOLLOW : D2D1_FIGURE_BEGIN_FILLED); + + for (size_t j = 0; j < figure->segments.count; ++j) + { + if (flags != s.segment->flags) + { + ID2D1GeometrySink_SetSegmentFlags(sink, s.segment->flags); + flags = s.segment->flags; + } + + switch (s.segment->type) + { + case D2D_SEGMENT_TYPE_BEZIERS: + ID2D1GeometrySink_AddBeziers(sink, s.beziers->segments, s.beziers->count); + size = FIELD_OFFSET(struct d2d_segment_beziers, segments[s.beziers->count]); + break; + case D2D_SEGMENT_TYPE_QUADRATIC_BEZIERS: + ID2D1GeometrySink_AddQuadraticBeziers(sink, s.quad_beziers->segments, s.quad_beziers->count); + size = FIELD_OFFSET(struct d2d_segment_quadratic_beziers, segments[s.quad_beziers->count]); + break; + case D2D_SEGMENT_TYPE_LINES: + ID2D1GeometrySink_AddLines(sink, s.lines->points, s.lines->count); + size = FIELD_OFFSET(struct d2d_segment_lines, points[s.lines->count]); + break; + case D2D_SEGMENT_TYPE_ARCS: + for (unsigned int k = 0; k < s.arcs->count; ++k) + ID2D1GeometrySink_AddArc(sink, &s.arcs->segments[k]); + size = FIELD_OFFSET(struct d2d_segment_arcs, segments[s.arcs->count]); + break; + default: + ; + } + + s.segment = (struct d2d_segment *)((uint8_t *)s.segment + size); + } + + ID2D1GeometrySink_EndFigure(sink, figure->flags & D2D_FIGURE_FLAG_CLOSED ? + D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN); + } + + return S_OK; } static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetSegmentCount(ID2D1PathGeometry1 *iface, UINT32 *count) diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 331821fe2b2..dc0cae71f2d 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -17596,7 +17596,6 @@ static void test_path_geometry_stream(BOOL d3d11) ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); hr = ID2D1PathGeometry_Stream(geometry, &stream_sink.ID2D1GeometrySink_iface); - todo_wine ok(hr == D2DERR_WRONG_STATE, "Got unexpected hr %#lx.\n", hr); hr = ID2D1PathGeometry_Open(geometry, &sink); @@ -17612,10 +17611,8 @@ static void test_path_geometry_stream(BOOL d3d11) ID2D1GeometrySink_Release(sink); hr = ID2D1PathGeometry_Stream(geometry, &stream_sink.ID2D1GeometrySink_iface); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - if (SUCCEEDED(hr)) - geometry_sink_check(&stream_sink, D2D1_FILL_MODE_ALTERNATE, 1, &expected_figures[0], 1); + geometry_sink_check(&stream_sink, D2D1_FILL_MODE_ALTERNATE, 1, &expected_figures[0], 1); geometry_sink_cleanup(&stream_sink); ID2D1PathGeometry_Release(geometry); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10043
From: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> --- dlls/d2d1/d2d1_private.h | 10 +++ dlls/d2d1/geometry.c | 185 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 183 insertions(+), 12 deletions(-) diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index 9ec099fcff3..6faf58f9d27 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -511,11 +511,21 @@ struct d2d_curve_outline_vertex D2D1_POINT_2F prev, next; }; +struct d2d_geometry; + +struct d2d_geometry_ops +{ + void (*stream)(struct d2d_geometry *geometry, const D2D_MATRIX_3X2_F *transform, + ID2D1GeometrySink *sink); +}; + struct d2d_geometry { ID2D1Geometry ID2D1Geometry_iface; LONG refcount; + const struct d2d_geometry_ops *ops; + ID2D1Factory *factory; D2D_MATRIX_3X2_F transform; diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c index b2de24ae5dc..9566113183c 100644 --- a/dlls/d2d1/geometry.c +++ b/dlls/d2d1/geometry.c @@ -3037,12 +3037,14 @@ static void d2d_geometry_cleanup(struct d2d_geometry *geometry) } static void d2d_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, - const D2D1_MATRIX_3X2_F *transform, const struct ID2D1GeometryVtbl *vtbl) + const D2D1_MATRIX_3X2_F *transform, const struct ID2D1GeometryVtbl *vtbl, + const struct d2d_geometry_ops *ops) { geometry->ID2D1Geometry_iface.lpVtbl = vtbl; geometry->refcount = 1; ID2D1Factory_AddRef(geometry->factory = factory); geometry->transform = *transform; + geometry->ops = ops; } static inline struct d2d_geometry *impl_from_ID2D1GeometrySink(ID2D1GeometrySink *iface) @@ -4253,15 +4255,101 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Open(ID2D1PathGeometry1 *ifac return S_OK; } -static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Stream(ID2D1PathGeometry1 *iface, ID2D1GeometrySink *sink) +static void d2d_path_geometry_transformed_stream(struct d2d_geometry *geometry, + const D2D_MATRIX_3X2_F *transform, ID2D1GeometrySink *sink) { - struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface); unsigned int flags = 0; + D2D1_POINT_2F point; - TRACE("iface %p, sink %p.\n", iface, sink); + for (size_t i = 0; i < geometry->u.path.figure_count; ++i) + { + const struct d2d_figure *figure = &geometry->u.path.figures[i]; + union + { + const struct d2d_segment *segment; + const struct d2d_segment_beziers *beziers; + const struct d2d_segment_quadratic_beziers *quad_beziers; + const struct d2d_segment_lines *lines; + const struct d2d_segment_arcs *arcs; + } s = { (struct d2d_segment *)figure->segments.data }; + size_t size = 0; - if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED) - return D2DERR_WRONG_STATE; + d2d_point_transform(&point, transform, figure->vertices[0].x, figure->vertices[0].y); + ID2D1GeometrySink_BeginFigure(sink, point, figure->flags & D2D_FIGURE_FLAG_HOLLOW ? + D2D1_FIGURE_BEGIN_HOLLOW : D2D1_FIGURE_BEGIN_FILLED); + + for (size_t j = 0; j < figure->segments.count; ++j) + { + if (flags != s.segment->flags) + { + ID2D1GeometrySink_SetSegmentFlags(sink, s.segment->flags); + flags = s.segment->flags; + } + + switch (s.segment->type) + { + case D2D_SEGMENT_TYPE_BEZIERS: + for (unsigned int k = 0; k < s.beziers->count; ++k) + { + D2D1_BEZIER_SEGMENT bezier_segment; + d2d_point_transform(&bezier_segment.point1, transform, s.beziers->segments[k].point1.x, s.beziers->segments[k].point1.y); + d2d_point_transform(&bezier_segment.point2, transform, s.beziers->segments[k].point2.x, s.beziers->segments[k].point2.y); + d2d_point_transform(&bezier_segment.point3, transform, s.beziers->segments[k].point3.x, s.beziers->segments[k].point3.y); + ID2D1GeometrySink_AddBeziers(sink, &bezier_segment, 1); + } + size = FIELD_OFFSET(struct d2d_segment_beziers, segments[s.beziers->count]); + break; + case D2D_SEGMENT_TYPE_QUADRATIC_BEZIERS: + for (unsigned int k = 0; k < s.quad_beziers->count; ++k) + { + D2D1_QUADRATIC_BEZIER_SEGMENT bezier_segment; + d2d_point_transform(&bezier_segment.point1, transform, s.quad_beziers->segments[k].point1.x, s.quad_beziers->segments[k].point1.y); + d2d_point_transform(&bezier_segment.point2, transform, s.quad_beziers->segments[k].point2.x, s.quad_beziers->segments[k].point2.y); + ID2D1GeometrySink_AddQuadraticBeziers(sink, &bezier_segment, 1); + } + size = FIELD_OFFSET(struct d2d_segment_quadratic_beziers, segments[s.quad_beziers->count]); + break; + case D2D_SEGMENT_TYPE_LINES: + for (unsigned int k = 0; k < s.lines->count; ++k) + { + d2d_point_transform(&point, transform, s.lines->points[k].x, s.lines->points[k].y); + ID2D1GeometrySink_AddLines(sink, &point, 1); + } + size = FIELD_OFFSET(struct d2d_segment_lines, points[s.lines->count]); + break; + case D2D_SEGMENT_TYPE_ARCS: + for (unsigned int k = 0; k < s.arcs->count; ++k) + { + D2D1_ARC_SEGMENT arc = s.arcs->segments[k]; + + d2d_point_transform(&arc.point, transform, arc.point.x, arc.point.y); + d2d_point_transform(&point, transform, arc.size.width, 0.0f); + arc.size.width = d2d_point_length(&point); + d2d_point_transform(&point, transform, 0.0f, arc.size.height); + arc.size.height = d2d_point_length(&point); + ID2D1GeometrySink_AddArc(sink, &arc); + } + size = FIELD_OFFSET(struct d2d_segment_arcs, segments[s.arcs->count]); + break; + default: + ; + } + + s.segment = (struct d2d_segment *)((uint8_t *)s.segment + size); + } + + ID2D1GeometrySink_EndFigure(sink, figure->flags & D2D_FIGURE_FLAG_CLOSED ? + D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN); + } +} + +static void d2d_path_geometry_stream(struct d2d_geometry *geometry, const D2D_MATRIX_3X2_F *transform, + ID2D1GeometrySink *sink) +{ + unsigned int flags = 0; + + if (transform) + return d2d_path_geometry_transformed_stream(geometry, transform, sink); for (size_t i = 0; i < geometry->u.path.figure_count; ++i) { @@ -4316,6 +4404,18 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Stream(ID2D1PathGeometry1 *if ID2D1GeometrySink_EndFigure(sink, figure->flags & D2D_FIGURE_FLAG_CLOSED ? D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN); } +} + +static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Stream(ID2D1PathGeometry1 *iface, ID2D1GeometrySink *sink) +{ + struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface); + + TRACE("iface %p, sink %p.\n", iface, sink); + + if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED) + return D2DERR_WRONG_STATE; + + d2d_path_geometry_stream(geometry, NULL, sink); return S_OK; } @@ -4384,9 +4484,15 @@ static const struct ID2D1PathGeometry1Vtbl d2d_path_geometry_vtbl = d2d_path_geometry1_ComputePointAndSegmentAtLength, }; +static const struct d2d_geometry_ops d2d_path_geometry_ops = +{ + .stream = d2d_path_geometry_stream, +}; + void d2d_path_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory) { - d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl); + d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl, + &d2d_path_geometry_ops); geometry->u.path.ID2D1GeometrySink_iface.lpVtbl = &d2d_geometry_sink_vtbl; geometry->u.path.bounds.left = FLT_MAX; geometry->u.path.bounds.right = -FLT_MAX; @@ -4672,13 +4778,24 @@ static const struct ID2D1EllipseGeometryVtbl d2d_ellipse_geometry_vtbl = d2d_ellipse_geometry_GetEllipse, }; +static void d2d_ellipse_geometry_stream(struct d2d_geometry *geometry, const D2D_MATRIX_3X2_F *transform, + ID2D1GeometrySink *sink) +{ +} + +static const struct d2d_geometry_ops d2d_ellipse_geometry_ops = +{ + .stream = d2d_ellipse_geometry_stream, +}; + HRESULT d2d_ellipse_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_ELLIPSE *ellipse) { D2D1_POINT_2F *v, v1, v2, v3, v4; struct d2d_face *f; float l, r, t, b; - d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_ellipse_geometry_vtbl); + d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_ellipse_geometry_vtbl, + &d2d_ellipse_geometry_ops); geometry->u.ellipse.ellipse = *ellipse; if (!(geometry->fill.vertices = malloc(4 * sizeof(*geometry->fill.vertices)))) @@ -5101,6 +5218,16 @@ static const struct ID2D1RectangleGeometryVtbl d2d_rectangle_geometry_vtbl = d2d_rectangle_geometry_GetRect, }; +static void d2d_rectangle_geometry_stream(struct d2d_geometry *geometry, + const D2D_MATRIX_3X2_F *transform, ID2D1GeometrySink *sink) +{ +} + +static const struct d2d_geometry_ops d2d_rectangle_geometry_ops = +{ + .stream = d2d_rectangle_geometry_stream, +}; + HRESULT d2d_rectangle_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_RECT_F *rect) { struct d2d_face *f; @@ -5122,7 +5249,8 @@ HRESULT d2d_rectangle_geometry_init(struct d2d_geometry *geometry, ID2D1Factory {-1.0f, 0.0f}, }; - d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl); + d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl, + &d2d_rectangle_geometry_ops); geometry->u.rectangle.rect = *rect; if (!(geometry->fill.vertices = malloc(4 * sizeof(*geometry->fill.vertices)))) @@ -5449,6 +5577,16 @@ static const struct ID2D1RoundedRectangleGeometryVtbl d2d_rounded_rectangle_geom d2d_rounded_rectangle_geometry_GetRoundedRect, }; +static void d2d_rounded_rectangle_geometry_stream(struct d2d_geometry *geometry, + const D2D_MATRIX_3X2_F *transform, ID2D1GeometrySink *sink) +{ +} + +static const struct d2d_geometry_ops d2d_rounded_rectangle_geometry_ops = +{ + .stream = d2d_rounded_rectangle_geometry_stream, +}; + HRESULT d2d_rounded_rectangle_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_ROUNDED_RECT *rounded_rect) { @@ -5457,7 +5595,8 @@ HRESULT d2d_rounded_rectangle_geometry_init(struct d2d_geometry *geometry, float l, r, t, b; float rx, ry; - d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rounded_rectangle_geometry_vtbl); + d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rounded_rectangle_geometry_vtbl, + &d2d_rounded_rectangle_geometry_ops); geometry->u.rounded_rectangle.rounded_rect = *rounded_rect; if (!(geometry->fill.vertices = malloc(8 * sizeof(*geometry->fill.vertices)))) @@ -5813,6 +5952,16 @@ static const struct ID2D1TransformedGeometryVtbl d2d_transformed_geometry_vtbl = d2d_transformed_geometry_GetTransform, }; +static void d2d_transformed_geometry_stream(struct d2d_geometry *geometry, + const D2D_MATRIX_3X2_F *transform, ID2D1GeometrySink *sink) +{ +} + +static const struct d2d_geometry_ops d2d_transformed_geometry_ops = +{ + .stream = d2d_transformed_geometry_stream, +}; + void d2d_transformed_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, ID2D1Geometry *src_geometry, const D2D_MATRIX_3X2_F *transform) { @@ -5823,7 +5972,8 @@ void d2d_transformed_geometry_init(struct d2d_geometry *geometry, ID2D1Factory * g = src_impl->transform; d2d_matrix_multiply(&g, transform); - d2d_geometry_init(geometry, factory, &g, (ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl); + d2d_geometry_init(geometry, factory, &g, (ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl, + &d2d_transformed_geometry_ops); ID2D1Geometry_AddRef(geometry->u.transformed.src_geometry = src_geometry); geometry->u.transformed.transform = *transform; geometry->fill = src_impl->fill; @@ -6084,12 +6234,23 @@ static const struct ID2D1GeometryGroupVtbl d2d_geometry_group_vtbl = d2d_geometry_group_GetSourceGeometries, }; +static void d2d_geometry_group_stream(struct d2d_geometry *geometry, + const D2D_MATRIX_3X2_F *transform, ID2D1GeometrySink *sink) +{ +} + +static const struct d2d_geometry_ops d2d_geometry_group_ops = +{ + .stream = d2d_geometry_group_stream, +}; + HRESULT d2d_geometry_group_init(struct d2d_geometry *geometry, ID2D1Factory *factory, D2D1_FILL_MODE fill_mode, ID2D1Geometry **geometries, unsigned int geometry_count) { unsigned int i; - d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_geometry_group_vtbl); + d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_geometry_group_vtbl, + &d2d_geometry_group_ops); if (!(geometry->u.group.src_geometries = calloc(geometry_count, sizeof(*geometries)))) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10043
From: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> --- dlls/d2d1/d2d1_private.h | 1 + dlls/d2d1/geometry.c | 166 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 161 insertions(+), 6 deletions(-) diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index 6faf58f9d27..ff411385bd2 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -615,6 +615,7 @@ struct d2d_geometry ID2D1Geometry **src_geometries; UINT32 geometry_count; D2D1_FILL_MODE fill_mode; + ID2D1PathGeometry *path; } group; } u; }; diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c index 9566113183c..07442260502 100644 --- a/dlls/d2d1/geometry.c +++ b/dlls/d2d1/geometry.c @@ -4255,6 +4255,17 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Open(ID2D1PathGeometry1 *ifac return S_OK; } +static inline void d2d_arc_transform(D2D1_ARC_SEGMENT *arc, const D2D1_MATRIX_3X2_F *transform) +{ + D2D_POINT_2F point; + + d2d_point_transform(&arc->point, transform, arc->point.x, arc->point.y); + d2d_point_transform(&point, transform, arc->size.width, 0.0f); + arc->size.width = d2d_point_length(&point); + d2d_point_transform(&point, transform, 0.0f, arc->size.height); + arc->size.height = d2d_point_length(&point); +} + static void d2d_path_geometry_transformed_stream(struct d2d_geometry *geometry, const D2D_MATRIX_3X2_F *transform, ID2D1GeometrySink *sink) { @@ -4322,11 +4333,7 @@ static void d2d_path_geometry_transformed_stream(struct d2d_geometry *geometry, { D2D1_ARC_SEGMENT arc = s.arcs->segments[k]; - d2d_point_transform(&arc.point, transform, arc.point.x, arc.point.y); - d2d_point_transform(&point, transform, arc.size.width, 0.0f); - arc.size.width = d2d_point_length(&point); - d2d_point_transform(&point, transform, 0.0f, arc.size.height); - arc.size.height = d2d_point_length(&point); + d2d_arc_transform(&arc, transform); ID2D1GeometrySink_AddArc(sink, &arc); } size = FIELD_OFFSET(struct d2d_segment_arcs, segments[s.arcs->count]); @@ -4781,6 +4788,36 @@ static const struct ID2D1EllipseGeometryVtbl d2d_ellipse_geometry_vtbl = static void d2d_ellipse_geometry_stream(struct d2d_geometry *geometry, const D2D_MATRIX_3X2_F *transform, ID2D1GeometrySink *sink) { + const D2D1_ELLIPSE *e = &geometry->u.ellipse.ellipse; + D2D1_POINT_2F start_point; + D2D1_ARC_SEGMENT arcs[4]; + + arcs[0].size.width = e->radiusX; + arcs[0].size.height = e->radiusY; + arcs[0].rotationAngle = 90.0f; + arcs[0].sweepDirection = D2D1_SWEEP_DIRECTION_CLOCKWISE; + arcs[0].arcSize = D2D1_ARC_SIZE_SMALL; + arcs[1] = arcs[2] = arcs[3] = arcs[0]; + + d2d_point_set(&start_point, e->point.x - e->radiusX, e->point.y); + d2d_point_set(&arcs[0].point, e->point.x, e->point.y - e->radiusY); + d2d_point_set(&arcs[1].point, e->point.x + e->radiusX, e->point.y); + d2d_point_set(&arcs[2].point, e->point.x, e->point.y + e->radiusY); + d2d_point_set(&arcs[3].point, start_point.x, start_point.y); + + if (transform) + { + d2d_point_transform(&start_point, transform, start_point.x, start_point.y); + for (int i = 0; i < ARRAYSIZE(arcs); ++i) + d2d_arc_transform(&arcs[i], transform); + } + + ID2D1GeometrySink_BeginFigure(sink, start_point, D2D1_FIGURE_BEGIN_FILLED); + + for (int i = 0; i < ARRAYSIZE(arcs); ++i) + ID2D1GeometrySink_AddArc(sink, &arcs[i]); + + ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED); } static const struct d2d_geometry_ops d2d_ellipse_geometry_ops = @@ -5218,9 +5255,34 @@ static const struct ID2D1RectangleGeometryVtbl d2d_rectangle_geometry_vtbl = d2d_rectangle_geometry_GetRect, }; +static void d2d_rectangle_stream(const D2D1_RECT_F *rect, const D2D1_MATRIX_3X2_F *transform, + ID2D1GeometrySink *sink) +{ + D2D1_POINT_2F p[4]; + unsigned int i; + + d2d_point_set(&p[0], rect->left, rect->top); + d2d_point_set(&p[1], rect->right, rect->top); + d2d_point_set(&p[2], rect->right, rect->bottom); + d2d_point_set(&p[3], rect->left, rect->bottom); + + if (transform) + { + for (i = 0; i < ARRAY_SIZE(p); ++i) + { + d2d_point_transform(&p[i], transform, p[i].x, p[i].y); + } + } + + ID2D1GeometrySink_BeginFigure(sink, p[0], D2D1_FIGURE_BEGIN_FILLED); + ID2D1GeometrySink_AddLines(sink, &p[1], 3); + ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED); +} + static void d2d_rectangle_geometry_stream(struct d2d_geometry *geometry, const D2D_MATRIX_3X2_F *transform, ID2D1GeometrySink *sink) { + d2d_rectangle_stream(&geometry->u.rectangle.rect, transform, sink); } static const struct d2d_geometry_ops d2d_rectangle_geometry_ops = @@ -5580,6 +5642,49 @@ static const struct ID2D1RoundedRectangleGeometryVtbl d2d_rounded_rectangle_geom static void d2d_rounded_rectangle_geometry_stream(struct d2d_geometry *geometry, const D2D_MATRIX_3X2_F *transform, ID2D1GeometrySink *sink) { + const D2D1_ROUNDED_RECT *r = &geometry->u.rounded_rectangle.rounded_rect; + D2D1_ARC_SEGMENT arcs[4]; + D2D1_POINT_2F points[4]; + + if (r->radiusX == 0.0f || r->radiusY == 0.0f) + return d2d_rectangle_stream(&r->rect, transform, sink); + + arcs[0].size.width = r->radiusX; + arcs[0].size.height = r->radiusY; + arcs[0].rotationAngle = 90.0f; + arcs[0].sweepDirection = D2D1_SWEEP_DIRECTION_CLOCKWISE; + arcs[0].arcSize = D2D1_ARC_SIZE_SMALL; + arcs[1] = arcs[2] = arcs[3] = arcs[0]; + + d2d_point_set(&points[0], r->rect.left, r->rect.top - r->radiusY); + d2d_point_set(&points[1], r->rect.right - r->radiusX, r->rect.top); + d2d_point_set(&points[2], r->rect.right, r->rect.bottom - r->radiusY); + d2d_point_set(&points[3], r->rect.left - r->radiusX, r->rect.bottom); + + d2d_point_set(&arcs[0].point, r->rect.left - r->radiusX, r->rect.top); + d2d_point_set(&arcs[1].point, r->rect.right, r->rect.top - r->radiusY); + d2d_point_set(&arcs[2].point, r->rect.right - r->radiusX, r->rect.bottom); + d2d_point_set(&arcs[3].point, r->rect.left, r->rect.bottom - r->radiusY); + + if (transform) + { + for (int i = 0; i < ARRAYSIZE(points); ++i) + d2d_point_transform(&points[i], transform, points[i].x, points[i].y); + for (int i = 0; i < ARRAYSIZE(arcs); ++i) + d2d_arc_transform(&arcs[i], transform); + } + + ID2D1GeometrySink_BeginFigure(sink, points[0], D2D1_FIGURE_BEGIN_FILLED); + + ID2D1GeometrySink_AddArc(sink, &arcs[0]); + ID2D1GeometrySink_AddLine(sink, points[1]); + ID2D1GeometrySink_AddArc(sink, &arcs[1]); + ID2D1GeometrySink_AddLine(sink, points[2]); + ID2D1GeometrySink_AddArc(sink, &arcs[2]); + ID2D1GeometrySink_AddLine(sink, points[3]); + ID2D1GeometrySink_AddArc(sink, &arcs[3]); + + ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED); } static const struct d2d_geometry_ops d2d_rounded_rectangle_geometry_ops = @@ -5952,9 +6057,20 @@ static const struct ID2D1TransformedGeometryVtbl d2d_transformed_geometry_vtbl = d2d_transformed_geometry_GetTransform, }; +static void d2d_geometry_stream(ID2D1Geometry *iface, const D2D_MATRIX_3X2_F *transform, + ID2D1GeometrySink *sink) +{ + struct d2d_geometry *geometry = unsafe_impl_from_ID2D1Geometry(iface); + geometry->ops->stream(geometry, transform, sink); +} + static void d2d_transformed_geometry_stream(struct d2d_geometry *geometry, const D2D_MATRIX_3X2_F *transform, ID2D1GeometrySink *sink) { + D2D_MATRIX_3X2_F m = geometry->transform; + + d2d_matrix_multiply(&m, transform); + d2d_geometry_stream(geometry->u.transformed.src_geometry, &m, sink); } static const struct d2d_geometry_ops d2d_transformed_geometry_ops = @@ -6028,7 +6144,10 @@ static ULONG STDMETHODCALLTYPE d2d_geometry_group_Release(ID2D1GeometryGroup *if { for (i = 0; i < geometry->u.group.geometry_count; ++i) ID2D1Geometry_Release(geometry->u.group.src_geometries[i]); + ID2D1PathGeometry_Release(geometry->u.group.path); free(geometry->u.group.src_geometries); + memset(&geometry->outline, 0, sizeof(geometry->outline)); + memset(&geometry->fill, 0, sizeof(geometry->fill)); d2d_geometry_cleanup(geometry); free(geometry); } @@ -6237,6 +6356,7 @@ static const struct ID2D1GeometryGroupVtbl d2d_geometry_group_vtbl = static void d2d_geometry_group_stream(struct d2d_geometry *geometry, const D2D_MATRIX_3X2_F *transform, ID2D1GeometrySink *sink) { + d2d_geometry_stream((ID2D1Geometry *)geometry->u.group.path, NULL, sink); } static const struct d2d_geometry_ops d2d_geometry_group_ops = @@ -6247,7 +6367,9 @@ static const struct d2d_geometry_ops d2d_geometry_group_ops = HRESULT d2d_geometry_group_init(struct d2d_geometry *geometry, ID2D1Factory *factory, D2D1_FILL_MODE fill_mode, ID2D1Geometry **geometries, unsigned int geometry_count) { + ID2D1GeometrySink *sink; unsigned int i; + HRESULT hr; d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_geometry_group_vtbl, &d2d_geometry_group_ops); @@ -6265,7 +6387,39 @@ HRESULT d2d_geometry_group_init(struct d2d_geometry *geometry, ID2D1Factory *fac geometry->u.group.geometry_count = geometry_count; geometry->u.group.fill_mode = fill_mode; - return S_OK; + if (FAILED(hr = ID2D1Factory_CreatePathGeometry(factory, &geometry->u.group.path))) + { + d2d_geometry_cleanup(geometry); + return hr; + } + + if (SUCCEEDED(hr = ID2D1PathGeometry_Open(geometry->u.group.path, &sink))) + { + ID2D1GeometrySink_SetFillMode(sink, fill_mode); + for (i = 0; i < geometry_count; ++i) + { + ID2D1GeometrySink_SetSegmentFlags(sink, 0); + d2d_geometry_stream(geometries[i], NULL, sink); + } + hr = ID2D1GeometrySink_Close(sink); + ID2D1GeometrySink_Release(sink); + } + + if (SUCCEEDED(hr)) + { + struct d2d_geometry *path_impl = unsafe_impl_from_ID2D1Geometry((ID2D1Geometry *)geometry->u.group.path); + + geometry->fill = path_impl->fill; + geometry->outline = path_impl->outline; + } + + if (FAILED(hr)) + { + d2d_geometry_cleanup(geometry); + ID2D1PathGeometry_Release(geometry->u.group.path); + } + + return hr; } struct d2d_geometry *unsafe_impl_from_ID2D1Geometry(ID2D1Geometry *iface) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10043
participants (2)
-
Nikolay Sivov -
Nikolay Sivov (@nsivov)