Store cubic bezier control points, instead of storing them as quadratics.
Signed-off-by: Connor McAdams conmanx360@gmail.com --- dlls/d2d1/geometry.c | 197 +++++++++++++++++++++++++++++++++---------- 1 file changed, 154 insertions(+), 43 deletions(-)
diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c index c18b648aef..6f48980eb8 100644 --- a/dlls/d2d1/geometry.c +++ b/dlls/d2d1/geometry.c @@ -44,12 +44,17 @@ enum d2d_cdt_edge_next D2D_EDGE_NEXT_TOR = 3, };
+/* Flag bit for bezier vertices. */ +#define D2D_VERTEX_TYPE_SPLIT_BEZIER 0x40 +#define D2D_VERTEX_TYPE_BEZIER 0x80 enum d2d_vertex_type { - D2D_VERTEX_TYPE_NONE, - D2D_VERTEX_TYPE_LINE, - D2D_VERTEX_TYPE_BEZIER, - D2D_VERTEX_TYPE_SPLIT_BEZIER, + D2D_VERTEX_TYPE_NONE = 0, + D2D_VERTEX_TYPE_LINE = 1, + D2D_VERTEX_TYPE_QUADRATIC_BEZIER = 2 | D2D_VERTEX_TYPE_BEZIER, + D2D_VERTEX_TYPE_CUBIC_BEZIER = 3 | D2D_VERTEX_TYPE_BEZIER, + D2D_VERTEX_TYPE_SPLIT_QUAD_BEZIER = 4 | D2D_VERTEX_TYPE_SPLIT_BEZIER, + D2D_VERTEX_TYPE_SPLIT_CUBIC_BEZIER = 5 | D2D_VERTEX_TYPE_SPLIT_BEZIER, };
struct d2d_segment_idx @@ -57,6 +62,7 @@ struct d2d_segment_idx size_t figure_idx; size_t vertex_idx; size_t control_idx; + size_t bezier_idx; };
struct d2d_figure @@ -70,6 +76,7 @@ struct d2d_figure D2D1_POINT_2F *bezier_controls; size_t bezier_controls_size; size_t bezier_control_count; + size_t bezier_control_points;
D2D1_POINT_2F *original_bezier_controls; size_t original_bezier_control_count; @@ -409,6 +416,15 @@ static void d2d_point_normalise(D2D1_POINT_2F *p) d2d_point_scale(p, 1.0f / l); }
+static void d2d_bezier_cubic_to_quad(const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, + const D2D1_POINT_2F *p2, const D2D1_POINT_2F *p3, D2D1_POINT_2F *c0) +{ + c0->x = (p1->x + p2->x) * 0.75f; + c0->y = (p1->y + p2->y) * 0.75f; + c0->x -= (p0->x + p3->x) * 0.25f; + c0->y -= (p0->y + p3->y) * 0.25f; +} + /* This implementation is based on the paper "Adaptive Precision * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and * associated (Public Domain) code by Jonathan Richard Shewchuk. */ @@ -613,33 +629,35 @@ static BOOL d2d_figure_add_vertex(struct d2d_figure *figure, D2D1_POINT_2F verte return TRUE; }
-static BOOL d2d_figure_insert_bezier_control(struct d2d_figure *figure, size_t idx, const D2D1_POINT_2F *p) +static BOOL d2d_figure_insert_quadratic_bezier_control(struct d2d_figure *figure, size_t idx, const D2D1_POINT_2F *p) { if (!d2d_array_reserve((void **)&figure->bezier_controls, &figure->bezier_controls_size, - figure->bezier_control_count + 1, sizeof(*figure->bezier_controls))) + figure->bezier_control_points + 1, sizeof(*figure->bezier_controls))) { ERR("Failed to grow bezier controls array.\n"); return FALSE; }
memmove(&figure->bezier_controls[idx + 1], &figure->bezier_controls[idx], - (figure->bezier_control_count - idx) * sizeof(*figure->bezier_controls)); + (figure->bezier_control_points - idx) * sizeof(*figure->bezier_controls)); figure->bezier_controls[idx] = *p; + ++figure->bezier_control_points; ++figure->bezier_control_count;
return TRUE; }
-static BOOL d2d_figure_add_bezier_control(struct d2d_figure *figure, const D2D1_POINT_2F *p) +static BOOL d2d_figure_add_quadratic_bezier_control(struct d2d_figure *figure, const D2D1_POINT_2F *p) { if (!d2d_array_reserve((void **)&figure->bezier_controls, &figure->bezier_controls_size, - figure->bezier_control_count + 1, sizeof(*figure->bezier_controls))) + figure->bezier_control_points + 1, sizeof(*figure->bezier_controls))) { ERR("Failed to grow bezier controls array.\n"); return FALSE; }
- figure->bezier_controls[figure->bezier_control_count++] = *p; + figure->bezier_controls[figure->bezier_control_points++] = *p; + ++figure->bezier_control_count;
return TRUE; } @@ -1875,7 +1893,7 @@ static BOOL d2d_geometry_apply_intersections(struct d2d_geometry *geometry,
figure = &geometry->u.path.figures[inter->figure_idx]; vertex_type = figure->vertex_types[inter->vertex_idx + vertex_offset]; - if (vertex_type != D2D_VERTEX_TYPE_BEZIER && vertex_type != D2D_VERTEX_TYPE_SPLIT_BEZIER) + if (!(vertex_type & D2D_VERTEX_TYPE_BEZIER) && !(vertex_type & D2D_VERTEX_TYPE_SPLIT_BEZIER)) { if (!d2d_figure_insert_vertex(&geometry->u.path.figures[inter->figure_idx], inter->vertex_idx + vertex_offset + 1, inter->p)) @@ -1908,13 +1926,13 @@ static BOOL d2d_geometry_apply_intersections(struct d2d_geometry *geometry, d2d_point_lerp(&q[1], p[1], p[2], t);
figure->bezier_controls[inter->control_idx + control_offset] = q[0]; - if (!(d2d_figure_insert_bezier_control(figure, inter->control_idx + control_offset + 1, &q[1]))) + if (!(d2d_figure_insert_quadratic_bezier_control(figure, inter->control_idx + control_offset + 1, &q[1]))) return FALSE; ++control_offset;
if (!(d2d_figure_insert_vertex(figure, inter->vertex_idx + vertex_offset + 1, inter->p))) return FALSE; - figure->vertex_types[inter->vertex_idx + vertex_offset + 1] = D2D_VERTEX_TYPE_SPLIT_BEZIER; + figure->vertex_types[inter->vertex_idx + vertex_offset + 1] = D2D_VERTEX_TYPE_SPLIT_QUAD_BEZIER; ++vertex_offset; }
@@ -1961,9 +1979,9 @@ static BOOL d2d_geometry_intersect_self(struct d2d_geometry *geometry) for (idx_q.vertex_idx = 0; idx_q.vertex_idx < max_q; ++idx_q.vertex_idx) { type_q = figure_q->vertex_types[idx_q.vertex_idx]; - if (type_q == D2D_VERTEX_TYPE_BEZIER) + if (type_q & D2D_VERTEX_TYPE_BEZIER) { - if (type_p == D2D_VERTEX_TYPE_BEZIER) + if (type_p & D2D_VERTEX_TYPE_BEZIER) { if (!d2d_geometry_intersect_bezier_bezier(geometry, &intersections, &idx_p, 0.0f, 1.0f, &idx_q, 0.0f, 1.0f)) @@ -1974,11 +1992,14 @@ static BOOL d2d_geometry_intersect_self(struct d2d_geometry *geometry) if (!d2d_geometry_intersect_bezier_line(geometry, &intersections, &idx_q, &idx_p)) goto done; } - ++idx_q.control_idx; + if (type_q == D2D_VERTEX_TYPE_QUADRATIC_BEZIER) + ++idx_q.control_idx; + else if (type_q == D2D_VERTEX_TYPE_CUBIC_BEZIER) + idx_q.control_idx += 2; } else { - if (type_p == D2D_VERTEX_TYPE_BEZIER) + if (type_p & D2D_VERTEX_TYPE_BEZIER) { if (!d2d_geometry_intersect_bezier_line(geometry, &intersections, &idx_p, &idx_q)) goto done; @@ -1991,8 +2012,10 @@ static BOOL d2d_geometry_intersect_self(struct d2d_geometry *geometry) } } } - if (type_p == D2D_VERTEX_TYPE_BEZIER) + if (type_p == D2D_VERTEX_TYPE_QUADRATIC_BEZIER) ++idx_p.control_idx; + else if (type_p == D2D_VERTEX_TYPE_CUBIC_BEZIER) + idx_p.control_idx += 2; } }
@@ -2328,27 +2351,30 @@ static BOOL d2d_geometry_add_figure_outline(struct d2d_geometry *geometry, if (!i) { prev_type = figure->vertex_types[figure->vertex_count - 1]; - if (prev_type == D2D_VERTEX_TYPE_BEZIER) - prev = &figure->bezier_controls[figure->bezier_control_count - 1]; + if (prev_type & D2D_VERTEX_TYPE_BEZIER) + prev = &figure->bezier_controls[figure->bezier_control_points - 1]; else prev = &figure->vertices[figure->vertex_count - 1]; } else { prev_type = figure->vertex_types[i - 1]; - if (prev_type == D2D_VERTEX_TYPE_BEZIER) + if (prev_type & D2D_VERTEX_TYPE_BEZIER) prev = &figure->bezier_controls[bezier_idx - 1]; else prev = &figure->vertices[i - 1]; }
- if (type == D2D_VERTEX_TYPE_BEZIER) + if (type & D2D_VERTEX_TYPE_BEZIER) next = &figure->bezier_controls[bezier_idx++]; else if (i == figure->vertex_count - 1) next = &figure->vertices[0]; else next = &figure->vertices[i + 1];
+ if (type == D2D_VERTEX_TYPE_CUBIC_BEZIER) + bezier_idx++; + if (figure_end == D2D1_FIGURE_END_CLOSED || (i && i < figure->vertex_count - 1)) { D2D1_POINT_2F q_next, q_prev; @@ -2372,15 +2398,23 @@ static BOOL d2d_geometry_add_figure_outline(struct d2d_geometry *geometry, ERR("Failed to add line segment.\n"); return FALSE; } - else if (type == D2D_VERTEX_TYPE_BEZIER) + else if (type & D2D_VERTEX_TYPE_BEZIER) { const D2D1_POINT_2F *p2; + D2D1_POINT_2F tmp;
if (i == figure->vertex_count - 1) p2 = &figure->vertices[0]; else p2 = &figure->vertices[i + 1];
+ if (type == D2D_VERTEX_TYPE_CUBIC_BEZIER) + { + d2d_bezier_cubic_to_quad(p0, &figure->bezier_controls[bezier_idx - 2], + &figure->bezier_controls[bezier_idx - 1], p2, &tmp); + next = &tmp; + } + if (!d2d_geometry_outline_add_bezier_segment(geometry, p0, next, p2)) { ERR("Failed to add bezier segment.\n"); @@ -2581,12 +2615,12 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_AddBeziers(ID2D1GeometrySink *if p.y = (beziers[i].point1.y + beziers[i].point2.y) * 0.75f; p.x -= (figure->vertices[figure->vertex_count - 1].x + beziers[i].point3.x) * 0.25f; p.y -= (figure->vertices[figure->vertex_count - 1].y + beziers[i].point3.y) * 0.25f; - figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_BEZIER; + figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_QUADRATIC_BEZIER;
d2d_rect_get_bezier_bounds(&bezier_bounds, &figure->vertices[figure->vertex_count - 1], &p, &beziers[i].point3);
- if (!d2d_figure_add_bezier_control(figure, &p)) + if (!d2d_figure_add_quadratic_bezier_control(figure, &p)) { ERR("Failed to add bezier control.\n"); geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR; @@ -2659,23 +2693,31 @@ static void d2d_path_geometry_free_figures(struct d2d_geometry *geometry)
static BOOL d2d_geometry_get_bezier_segment_idx(struct d2d_geometry *geometry, struct d2d_segment_idx *idx, BOOL next) { + struct d2d_figure *figure = &geometry->u.path.figures[idx->figure_idx]; + enum d2d_vertex_type type = figure->vertex_types[idx->vertex_idx]; + if (next) { + if (type == D2D_VERTEX_TYPE_SPLIT_CUBIC_BEZIER || type == D2D_VERTEX_TYPE_CUBIC_BEZIER) + ++idx->control_idx; + ++idx->vertex_idx; ++idx->control_idx; + ++idx->bezier_idx; }
- for (; idx->figure_idx < geometry->u.path.figure_count; ++idx->figure_idx, idx->vertex_idx = idx->control_idx = 0) + for (; idx->figure_idx < geometry->u.path.figure_count; ++idx->figure_idx, + idx->vertex_idx = idx->control_idx = idx->bezier_idx = 0) { - struct d2d_figure *figure = &geometry->u.path.figures[idx->figure_idx]; + figure = &geometry->u.path.figures[idx->figure_idx];
if (!figure->bezier_control_count || figure->flags & D2D_FIGURE_FLAG_HOLLOW) continue;
for (; idx->vertex_idx < figure->vertex_count; ++idx->vertex_idx) { - if (figure->vertex_types[idx->vertex_idx] == D2D_VERTEX_TYPE_BEZIER - || figure->vertex_types[idx->vertex_idx] == D2D_VERTEX_TYPE_SPLIT_BEZIER) + type = figure->vertex_types[idx->vertex_idx]; + if (type & D2D_VERTEX_TYPE_BEZIER || type & D2D_VERTEX_TYPE_SPLIT_BEZIER) return TRUE; } } @@ -2815,11 +2857,11 @@ static BOOL d2d_geometry_split_bezier(struct d2d_geometry *geometry, const struc d2d_point_lerp(&q[2], &q[0], &q[1], 0.5f);
figure->bezier_controls[idx->control_idx] = q[0]; - if (!(d2d_figure_insert_bezier_control(figure, idx->control_idx + 1, &q[1]))) + if (!(d2d_figure_insert_quadratic_bezier_control(figure, idx->control_idx + 1, &q[1]))) return FALSE; if (!(d2d_figure_insert_vertex(figure, idx->vertex_idx + 1, q[2]))) return FALSE; - figure->vertex_types[idx->vertex_idx + 1] = D2D_VERTEX_TYPE_SPLIT_BEZIER; + figure->vertex_types[idx->vertex_idx + 1] = D2D_VERTEX_TYPE_SPLIT_QUAD_BEZIER;
return TRUE; } @@ -2867,7 +2909,7 @@ static HRESULT d2d_geometry_resolve_beziers(struct d2d_geometry *geometry) { if (geometry->u.path.figures[i].flags & D2D_FIGURE_FLAG_HOLLOW) continue; - geometry->fill.bezier_vertex_count += 3 * geometry->u.path.figures[i].bezier_control_count; + geometry->fill.bezier_vertex_count += 3 * geometry->u.path.figures[i].bezier_control_points; }
if (!(geometry->fill.bezier_vertices = heap_calloc(geometry->fill.bezier_vertex_count, @@ -2934,7 +2976,7 @@ static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_Close(ID2D1GeometrySink *ifac for (i = 0; i < geometry->u.path.figure_count; ++i) { struct d2d_figure *figure = &geometry->u.path.figures[i]; - size_t size = figure->bezier_control_count * sizeof(*figure->original_bezier_controls); + size_t size = figure->bezier_control_points * sizeof(*figure->original_bezier_controls); if (!(figure->original_bezier_controls = heap_alloc(size))) goto done; memcpy(figure->original_bezier_controls, figure->bezier_controls, size); @@ -3002,8 +3044,8 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBeziers(ID2D1Geometr 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_control(figure, &beziers[i].point1)) + figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_QUADRATIC_BEZIER; + if (!d2d_figure_add_quadratic_bezier_control(figure, &beziers[i].point1)) { ERR("Failed to add bezier.\n"); geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR; @@ -3198,7 +3240,7 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetBounds(ID2D1PathGeometry * for (bezier_idx = 0, ++j; j < figure->vertex_count; ++j) { if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE - || figure->vertex_types[j] == D2D_VERTEX_TYPE_SPLIT_BEZIER) + || figure->vertex_types[j] & D2D_VERTEX_TYPE_SPLIT_BEZIER) continue;
switch (type) @@ -3209,7 +3251,7 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetBounds(ID2D1PathGeometry * d2d_rect_expand(bounds, &p); break;
- case D2D_VERTEX_TYPE_BEZIER: + case D2D_VERTEX_TYPE_QUADRATIC_BEZIER: p1 = figure->original_bezier_controls[bezier_idx++]; d2d_point_transform(&p1, transform, p1.x, p1.y); p2 = figure->vertices[j]; @@ -3219,6 +3261,20 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetBounds(ID2D1PathGeometry * p = p2; break;
+ case D2D_VERTEX_TYPE_CUBIC_BEZIER: + d2d_bezier_cubic_to_quad(&figure->vertices[j - 1], + &figure->original_bezier_controls[bezier_idx], + &figure->original_bezier_controls[bezier_idx + 1], + &figure->vertices[j], &p1); + bezier_idx += 2; + d2d_point_transform(&p1, transform, p1.x, p1.y); + p2 = figure->vertices[j]; + d2d_point_transform(&p2, transform, p2.x, p2.y); + d2d_rect_get_bezier_bounds(&bezier_bounds, &p, &p1, &p2); + d2d_rect_union(bounds, &bezier_bounds); + p = p2; + break; + default: FIXME("Unhandled vertex type %#x.\n", type); p = figure->vertices[j]; @@ -3230,9 +3286,20 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetBounds(ID2D1PathGeometry * type = figure->vertex_types[j]; }
- if (type == D2D_VERTEX_TYPE_BEZIER) + if (type & D2D_VERTEX_TYPE_BEZIER) { - p1 = figure->original_bezier_controls[bezier_idx++]; + if (type == D2D_VERTEX_TYPE_CUBIC_BEZIER) + { + d2d_bezier_cubic_to_quad(&figure->vertices[j - 1], + &figure->original_bezier_controls[bezier_idx], + &figure->original_bezier_controls[bezier_idx + 1], + &figure->vertices[0], &p1); + + bezier_idx += 2; + } + else + p1 = figure->original_bezier_controls[bezier_idx++]; + d2d_point_transform(&p1, transform, p1.x, p1.y); p2 = figure->vertices[0]; d2d_point_transform(&p2, transform, p2.x, p2.y); @@ -3365,6 +3432,23 @@ static void d2d_geometry_simplify_quadratic(ID2D1SimplifiedGeometrySink *sink, ID2D1SimplifiedGeometrySink_AddBeziers(sink, &b, 1); }
+static void d2d_geometry_simplify_cubic(ID2D1SimplifiedGeometrySink *sink, + D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_POINT_2F *p0, + const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2, const D2D1_POINT_2F *p3, + float tolerance) +{ + D2D1_BEZIER_SEGMENT b; + + b.point1 = *p1; + b.point2 = *p2; + b.point3 = *p3; + + if (option == D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES) + d2d_geometry_flatten_cubic(sink, p0, &b, tolerance); + else + ID2D1SimplifiedGeometrySink_AddBeziers(sink, &b, 1); +} + static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *iface, D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink) @@ -3373,7 +3457,7 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *i enum d2d_vertex_type type = D2D_VERTEX_TYPE_NONE; unsigned int i, j, bezier_idx; D2D1_FIGURE_BEGIN begin; - D2D1_POINT_2F p, p1, p2; + D2D1_POINT_2F p, p1, p2, p3; D2D1_FIGURE_END end;
TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n", @@ -3401,7 +3485,7 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *i for (bezier_idx = 0, ++j; j < figure->vertex_count; ++j) { if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE - || figure->vertex_types[j] == D2D_VERTEX_TYPE_SPLIT_BEZIER) + || figure->vertex_types[j] & D2D_VERTEX_TYPE_SPLIT_BEZIER) continue;
switch (type) @@ -3413,7 +3497,7 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *i ID2D1SimplifiedGeometrySink_AddLines(sink, &p, 1); break;
- case D2D_VERTEX_TYPE_BEZIER: + case D2D_VERTEX_TYPE_QUADRATIC_BEZIER: p1 = figure->original_bezier_controls[bezier_idx++]; if (transform) d2d_point_transform(&p1, transform, p1.x, p1.y); @@ -3424,6 +3508,20 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *i p = p2; break;
+ case D2D_VERTEX_TYPE_CUBIC_BEZIER: + p1 = figure->original_bezier_controls[bezier_idx++]; + if (transform) + d2d_point_transform(&p1, transform, p1.x, p1.y); + p2 = figure->original_bezier_controls[bezier_idx++]; + if (transform) + d2d_point_transform(&p2, transform, p2.x, p2.y); + p3 = figure->vertices[j]; + if (transform) + d2d_point_transform(&p3, transform, p3.x, p3.y); + d2d_geometry_simplify_cubic(sink, option, &p, &p1, &p2, &p3, tolerance); + p = p3; + break; + default: FIXME("Unhandled vertex type %#x.\n", type); p = figure->vertices[j]; @@ -3436,7 +3534,7 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *i type = figure->vertex_types[j]; }
- if (type == D2D_VERTEX_TYPE_BEZIER) + if (type == D2D_VERTEX_TYPE_QUADRATIC_BEZIER) { p1 = figure->original_bezier_controls[bezier_idx++]; if (transform) @@ -3446,6 +3544,19 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *i d2d_point_transform(&p2, transform, p2.x, p2.y); d2d_geometry_simplify_quadratic(sink, option, &p, &p1, &p2, tolerance); } + else if (type == D2D_VERTEX_TYPE_CUBIC_BEZIER) + { + p1 = figure->original_bezier_controls[bezier_idx++]; + if (transform) + d2d_point_transform(&p1, transform, p1.x, p1.y); + p2 = figure->original_bezier_controls[bezier_idx++]; + if (transform) + d2d_point_transform(&p2, transform, p2.x, p2.y); + p3 = figure->vertices[0]; + if (transform) + d2d_point_transform(&p3, transform, p3.x, p3.y); + d2d_geometry_simplify_cubic(sink, option, &p, &p1, &p2, &p3, tolerance); + }
end = figure->flags & D2D_FIGURE_FLAG_CLOSED ? D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN; ID2D1SimplifiedGeometrySink_EndFigure(sink, end);