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