d2d1: Implement bezier/line intersections.
Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
a5f02132d3
commit
a4f23ea148
|
@ -54,12 +54,14 @@ enum d2d_vertex_type
|
||||||
D2D_VERTEX_TYPE_NONE,
|
D2D_VERTEX_TYPE_NONE,
|
||||||
D2D_VERTEX_TYPE_LINE,
|
D2D_VERTEX_TYPE_LINE,
|
||||||
D2D_VERTEX_TYPE_BEZIER,
|
D2D_VERTEX_TYPE_BEZIER,
|
||||||
|
D2D_VERTEX_TYPE_SPLIT_BEZIER,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct d2d_segment_idx
|
struct d2d_segment_idx
|
||||||
{
|
{
|
||||||
size_t figure_idx;
|
size_t figure_idx;
|
||||||
size_t vertex_idx;
|
size_t vertex_idx;
|
||||||
|
size_t control_idx;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct d2d_figure
|
struct d2d_figure
|
||||||
|
@ -74,6 +76,9 @@ struct d2d_figure
|
||||||
size_t bezier_controls_size;
|
size_t bezier_controls_size;
|
||||||
size_t bezier_control_count;
|
size_t bezier_control_count;
|
||||||
|
|
||||||
|
D2D1_POINT_2F *original_bezier_controls;
|
||||||
|
size_t original_bezier_control_count;
|
||||||
|
|
||||||
D2D1_RECT_F bounds;
|
D2D1_RECT_F bounds;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
};
|
};
|
||||||
|
@ -105,6 +110,7 @@ struct d2d_geometry_intersection
|
||||||
{
|
{
|
||||||
size_t figure_idx;
|
size_t figure_idx;
|
||||||
size_t vertex_idx;
|
size_t vertex_idx;
|
||||||
|
size_t control_idx;
|
||||||
float t;
|
float t;
|
||||||
D2D1_POINT_2F p;
|
D2D1_POINT_2F p;
|
||||||
};
|
};
|
||||||
|
@ -391,6 +397,15 @@ static void d2d_point_lerp(D2D1_POINT_2F *out,
|
||||||
out->y = a->y * (1.0f - t) + b->y * t;
|
out->y = a->y * (1.0f - t) + b->y * t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void d2d_point_calculate_bezier(D2D1_POINT_2F *out, const D2D1_POINT_2F *p0,
|
||||||
|
const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2, float t)
|
||||||
|
{
|
||||||
|
float t_c = 1.0f - t;
|
||||||
|
|
||||||
|
out->x = t_c * (t_c * p0->x + t * p1->x) + t * (t_c * p1->x + t * p2->x);
|
||||||
|
out->y = t_c * (t_c * p0->y + t * p1->y) + t * (t_c * p1->y + t * p2->y);
|
||||||
|
}
|
||||||
|
|
||||||
static float d2d_point_dot(const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1)
|
static float d2d_point_dot(const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1)
|
||||||
{
|
{
|
||||||
return p0->x * p1->x + p0->y * p1->y;
|
return p0->x * p1->x + p0->y * p1->y;
|
||||||
|
@ -576,6 +591,23 @@ static BOOL d2d_figure_add_vertex(struct d2d_figure *figure, D2D1_POINT_2F verte
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BOOL d2d_figure_insert_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)))
|
||||||
|
{
|
||||||
|
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_controls[idx] = *p;
|
||||||
|
++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_bezier_control(struct d2d_figure *figure, const D2D1_POINT_2F *p)
|
||||||
{
|
{
|
||||||
if (!d2d_array_reserve((void **)&figure->bezier_controls, &figure->bezier_controls_size,
|
if (!d2d_array_reserve((void **)&figure->bezier_controls, &figure->bezier_controls_size,
|
||||||
|
@ -1562,6 +1594,7 @@ static BOOL d2d_geometry_intersections_add(struct d2d_geometry_intersections *i,
|
||||||
intersection = &i->intersections[i->intersection_count++];
|
intersection = &i->intersections[i->intersection_count++];
|
||||||
intersection->figure_idx = segment_idx->figure_idx;
|
intersection->figure_idx = segment_idx->figure_idx;
|
||||||
intersection->vertex_idx = segment_idx->vertex_idx;
|
intersection->vertex_idx = segment_idx->vertex_idx;
|
||||||
|
intersection->control_idx = segment_idx->control_idx;
|
||||||
intersection->t = t;
|
intersection->t = t;
|
||||||
intersection->p = p;
|
intersection->p = p;
|
||||||
|
|
||||||
|
@ -1632,6 +1665,172 @@ static BOOL d2d_geometry_intersect_line_line(struct d2d_geometry *geometry,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BOOL d2d_geometry_add_bezier_line_intersections(struct d2d_geometry *geometry,
|
||||||
|
struct d2d_geometry_intersections *intersections, const struct d2d_segment_idx *idx_p,
|
||||||
|
const D2D1_POINT_2F **p, const struct d2d_segment_idx *idx_q, const D2D1_POINT_2F **q, float s)
|
||||||
|
{
|
||||||
|
D2D1_POINT_2F intersection;
|
||||||
|
float t;
|
||||||
|
|
||||||
|
d2d_point_calculate_bezier(&intersection, p[0], p[1], p[2], s);
|
||||||
|
if (fabsf(q[1]->x - q[0]->x) > fabsf(q[1]->y - q[0]->y))
|
||||||
|
t = (intersection.x - q[0]->x) / (q[1]->x - q[0]->x);
|
||||||
|
else
|
||||||
|
t = (intersection.y - q[0]->y) / (q[1]->y - q[0]->y);
|
||||||
|
if (t < 0.0f || t > 1.0f)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
d2d_point_lerp(&intersection, q[0], q[1], t);
|
||||||
|
|
||||||
|
if (s > 0.0f && s < 1.0f && !d2d_geometry_intersections_add(intersections, idx_p, s, intersection))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (t > 0.0f && t < 1.0f && !d2d_geometry_intersections_add(intersections, idx_q, t, intersection))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL d2d_geometry_intersect_bezier_line(struct d2d_geometry *geometry,
|
||||||
|
struct d2d_geometry_intersections *intersections,
|
||||||
|
const struct d2d_segment_idx *idx_p, const struct d2d_segment_idx *idx_q)
|
||||||
|
{
|
||||||
|
const D2D1_POINT_2F *p[3], *q[2];
|
||||||
|
const struct d2d_figure *figure;
|
||||||
|
float y[3], root, theta, d, e;
|
||||||
|
size_t next;
|
||||||
|
|
||||||
|
figure = &geometry->u.path.figures[idx_p->figure_idx];
|
||||||
|
p[0] = &figure->vertices[idx_p->vertex_idx];
|
||||||
|
p[1] = &figure->bezier_controls[idx_p->control_idx];
|
||||||
|
next = idx_p->vertex_idx + 1;
|
||||||
|
if (next == figure->vertex_count)
|
||||||
|
next = 0;
|
||||||
|
p[2] = &figure->vertices[next];
|
||||||
|
|
||||||
|
figure = &geometry->u.path.figures[idx_q->figure_idx];
|
||||||
|
q[0] = &figure->vertices[idx_q->vertex_idx];
|
||||||
|
next = idx_q->vertex_idx + 1;
|
||||||
|
if (next == figure->vertex_count)
|
||||||
|
next = 0;
|
||||||
|
q[1] = &figure->vertices[next];
|
||||||
|
|
||||||
|
/* Align the line with x-axis. */
|
||||||
|
theta = -atan2f(q[1]->y - q[0]->y, q[1]->x - q[0]->x);
|
||||||
|
y[0] = (p[0]->x - q[0]->x) * sinf(theta) + (p[0]->y - q[0]->y) * cosf(theta);
|
||||||
|
y[1] = (p[1]->x - q[0]->x) * sinf(theta) + (p[1]->y - q[0]->y) * cosf(theta);
|
||||||
|
y[2] = (p[2]->x - q[0]->x) * sinf(theta) + (p[2]->y - q[0]->y) * cosf(theta);
|
||||||
|
|
||||||
|
/* Intersect the transformed curve with the x-axis.
|
||||||
|
*
|
||||||
|
* f(t) = (1 - t)²P₀ + 2(1 - t)tP₁ + t²P₂
|
||||||
|
* = (P₀ - 2P₁ + P₂)t² + 2(P₁ - P₀)t + P₀
|
||||||
|
*
|
||||||
|
* a = P₀ - 2P₁ + P₂
|
||||||
|
* b = 2(P₁ - P₀)
|
||||||
|
* c = P₀
|
||||||
|
*
|
||||||
|
* f(t) = 0
|
||||||
|
* t = (-b ± √(b² - 4ac)) / 2a
|
||||||
|
* = (-2(P₁ - P₀) ± √((2(P₁ - P₀))² - 4((P₀ - 2P₁ + P₂)P₀))) / 2(P₀ - 2P₁ + P₂)
|
||||||
|
* = (2P₀ - 2P₁ ± √(4P₀² + 4P₁² - 8P₀P₁ - 4P₀² + 8P₀P₁ - 4P₀P₂)) / (2P₀ - 4P₁ + 2P₂)
|
||||||
|
* = (P₀ - P₁ ± √(P₁² - P₀P₂)) / (P₀ - 2P₁ + P₂) */
|
||||||
|
|
||||||
|
d = y[0] - 2 * y[1] + y[2];
|
||||||
|
if (d == 0.0f)
|
||||||
|
{
|
||||||
|
/* P₀ - 2P₁ + P₂ = 0
|
||||||
|
* f(t) = (P₀ - 2P₁ + P₂)t² + 2(P₁ - P₀)t + P₀ = 0
|
||||||
|
* t = -P₀ / 2(P₁ - P₀) */
|
||||||
|
root = -y[0] / (2.0f * (y[1] - y[0]));
|
||||||
|
if (root < 0.0f || root > 1.0f)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return d2d_geometry_add_bezier_line_intersections(geometry, intersections, idx_p, p, idx_q, q, root);
|
||||||
|
}
|
||||||
|
|
||||||
|
e = y[1] * y[1] - y[0] * y[2];
|
||||||
|
if (e < 0.0f)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
root = (y[0] - y[1] + sqrtf(e)) / d;
|
||||||
|
if (root >= 0.0f && root <= 1.0f && !d2d_geometry_add_bezier_line_intersections(geometry,
|
||||||
|
intersections, idx_p, p, idx_q, q, root))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
root = (y[0] - y[1] - sqrtf(e)) / d;
|
||||||
|
if (root >= 0.0f && root <= 1.0f && !d2d_geometry_add_bezier_line_intersections(geometry,
|
||||||
|
intersections, idx_p, p, idx_q, q, root))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL d2d_geometry_apply_intersections(struct d2d_geometry *geometry,
|
||||||
|
struct d2d_geometry_intersections *intersections)
|
||||||
|
{
|
||||||
|
size_t vertex_offset, control_offset, next, i;
|
||||||
|
struct d2d_geometry_intersection *inter;
|
||||||
|
enum d2d_vertex_type vertex_type;
|
||||||
|
const D2D1_POINT_2F *p[3];
|
||||||
|
struct d2d_figure *figure;
|
||||||
|
D2D1_POINT_2F q[2];
|
||||||
|
float t, t_prev;
|
||||||
|
|
||||||
|
for (i = 0; i < intersections->intersection_count; ++i)
|
||||||
|
{
|
||||||
|
inter = &intersections->intersections[i];
|
||||||
|
if (!i || inter->figure_idx != intersections->intersections[i - 1].figure_idx)
|
||||||
|
vertex_offset = control_offset = 0;
|
||||||
|
|
||||||
|
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 (!d2d_figure_insert_vertex(&geometry->u.path.figures[inter->figure_idx],
|
||||||
|
inter->vertex_idx + vertex_offset + 1, inter->p))
|
||||||
|
return FALSE;
|
||||||
|
++vertex_offset;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
t = inter->t;
|
||||||
|
if (i && inter->figure_idx == intersections->intersections[i - 1].figure_idx
|
||||||
|
&& inter->vertex_idx == intersections->intersections[i - 1].vertex_idx)
|
||||||
|
{
|
||||||
|
t_prev = intersections->intersections[i - 1].t;
|
||||||
|
if (t - t_prev < 1e-3f)
|
||||||
|
{
|
||||||
|
inter->t = intersections->intersections[i - 1].t;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
t = (t - t_prev) / (1.0f - t_prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
p[0] = &figure->vertices[inter->vertex_idx + vertex_offset];
|
||||||
|
p[1] = &figure->bezier_controls[inter->control_idx + control_offset];
|
||||||
|
next = inter->vertex_idx + vertex_offset + 1;
|
||||||
|
if (next == figure->vertex_count)
|
||||||
|
next = 0;
|
||||||
|
p[2] = &figure->vertices[next];
|
||||||
|
|
||||||
|
d2d_point_lerp(&q[0], p[0], p[1], t);
|
||||||
|
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])))
|
||||||
|
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;
|
||||||
|
++vertex_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Intersect the geometry's segments with themselves. This uses the
|
/* Intersect the geometry's segments with themselves. This uses the
|
||||||
* straightforward approach of testing everything against everything, but
|
* straightforward approach of testing everything against everything, but
|
||||||
* there certainly exist more scalable algorithms for this. */
|
* there certainly exist more scalable algorithms for this. */
|
||||||
|
@ -1642,8 +1841,8 @@ static BOOL d2d_geometry_intersect_self(struct d2d_geometry *geometry)
|
||||||
const struct d2d_figure *figure_p, *figure_q;
|
const struct d2d_figure *figure_p, *figure_q;
|
||||||
struct d2d_segment_idx idx_p, idx_q;
|
struct d2d_segment_idx idx_p, idx_q;
|
||||||
enum d2d_vertex_type type_p, type_q;
|
enum d2d_vertex_type type_p, type_q;
|
||||||
size_t i, j, max_q;
|
|
||||||
BOOL ret = FALSE;
|
BOOL ret = FALSE;
|
||||||
|
size_t max_q;
|
||||||
|
|
||||||
if (!geometry->u.path.figure_count)
|
if (!geometry->u.path.figure_count)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -1651,6 +1850,7 @@ static BOOL d2d_geometry_intersect_self(struct d2d_geometry *geometry)
|
||||||
for (idx_p.figure_idx = 0; idx_p.figure_idx < geometry->u.path.figure_count; ++idx_p.figure_idx)
|
for (idx_p.figure_idx = 0; idx_p.figure_idx < geometry->u.path.figure_count; ++idx_p.figure_idx)
|
||||||
{
|
{
|
||||||
figure_p = &geometry->u.path.figures[idx_p.figure_idx];
|
figure_p = &geometry->u.path.figures[idx_p.figure_idx];
|
||||||
|
idx_p.control_idx = 0;
|
||||||
for (idx_p.vertex_idx = 0; idx_p.vertex_idx < figure_p->vertex_count; ++idx_p.vertex_idx)
|
for (idx_p.vertex_idx = 0; idx_p.vertex_idx < figure_p->vertex_count; ++idx_p.vertex_idx)
|
||||||
{
|
{
|
||||||
type_p = figure_p->vertex_types[idx_p.vertex_idx];
|
type_p = figure_p->vertex_types[idx_p.vertex_idx];
|
||||||
|
@ -1671,33 +1871,40 @@ static BOOL d2d_geometry_intersect_self(struct d2d_geometry *geometry)
|
||||||
max_q = idx_p.vertex_idx;
|
max_q = idx_p.vertex_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
idx_q.control_idx = 0;
|
||||||
for (idx_q.vertex_idx = 0; idx_q.vertex_idx < max_q; ++idx_q.vertex_idx)
|
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];
|
type_q = figure_q->vertex_types[idx_q.vertex_idx];
|
||||||
if (type_p != D2D_VERTEX_TYPE_BEZIER && type_q != D2D_VERTEX_TYPE_BEZIER
|
if (type_q == D2D_VERTEX_TYPE_BEZIER)
|
||||||
&& !d2d_geometry_intersect_line_line(geometry, &intersections, &idx_p, &idx_q))
|
{
|
||||||
|
if (type_p != D2D_VERTEX_TYPE_BEZIER
|
||||||
|
&& !d2d_geometry_intersect_bezier_line(geometry, &intersections, &idx_q, &idx_p))
|
||||||
|
goto done;
|
||||||
|
++idx_q.control_idx;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (type_p == D2D_VERTEX_TYPE_BEZIER)
|
||||||
|
{
|
||||||
|
if (!d2d_geometry_intersect_bezier_line(geometry, &intersections, &idx_p, &idx_q))
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!d2d_geometry_intersect_line_line(geometry, &intersections, &idx_p, &idx_q))
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (type_p == D2D_VERTEX_TYPE_BEZIER)
|
||||||
|
++idx_p.control_idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
qsort(intersections.intersections, intersections.intersection_count,
|
qsort(intersections.intersections, intersections.intersection_count,
|
||||||
sizeof(*intersections.intersections), d2d_geometry_intersections_compare);
|
sizeof(*intersections.intersections), d2d_geometry_intersections_compare);
|
||||||
for (i = 0; i < intersections.intersection_count; ++i)
|
ret = d2d_geometry_apply_intersections(geometry, &intersections);
|
||||||
{
|
|
||||||
const struct d2d_geometry_intersection *inter = &intersections.intersections[i];
|
|
||||||
|
|
||||||
if (!i || inter->figure_idx != intersections.intersections[i - 1].figure_idx)
|
|
||||||
j = 0;
|
|
||||||
|
|
||||||
if (!d2d_figure_insert_vertex(&geometry->u.path.figures[inter->figure_idx],
|
|
||||||
inter->vertex_idx + j + 1, inter->p))
|
|
||||||
goto done;
|
|
||||||
++j;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
HeapFree(GetProcessHeap(), 0, intersections.intersections);
|
HeapFree(GetProcessHeap(), 0, intersections.intersections);
|
||||||
|
@ -2263,6 +2470,7 @@ static void d2d_path_geometry_free_figures(struct d2d_geometry *geometry)
|
||||||
for (i = 0; i < geometry->u.path.figure_count; ++i)
|
for (i = 0; i < geometry->u.path.figure_count; ++i)
|
||||||
{
|
{
|
||||||
HeapFree(GetProcessHeap(), 0, geometry->u.path.figures[i].bezier_controls);
|
HeapFree(GetProcessHeap(), 0, geometry->u.path.figures[i].bezier_controls);
|
||||||
|
HeapFree(GetProcessHeap(), 0, geometry->u.path.figures[i].original_bezier_controls);
|
||||||
HeapFree(GetProcessHeap(), 0, geometry->u.path.figures[i].vertices);
|
HeapFree(GetProcessHeap(), 0, geometry->u.path.figures[i].vertices);
|
||||||
}
|
}
|
||||||
HeapFree(GetProcessHeap(), 0, geometry->u.path.figures);
|
HeapFree(GetProcessHeap(), 0, geometry->u.path.figures);
|
||||||
|
@ -2298,7 +2506,8 @@ static HRESULT d2d_geometry_resolve_beziers(struct d2d_geometry *geometry)
|
||||||
struct d2d_bezier_vertex *b;
|
struct d2d_bezier_vertex *b;
|
||||||
float sign = -1.0f;
|
float sign = -1.0f;
|
||||||
|
|
||||||
if (figure->vertex_types[j] != D2D_VERTEX_TYPE_BEZIER)
|
if (figure->vertex_types[j] != D2D_VERTEX_TYPE_BEZIER
|
||||||
|
&& figure->vertex_types[j] != D2D_VERTEX_TYPE_SPLIT_BEZIER)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
b = &geometry->fill.bezier_vertices[bezier_idx * 3];
|
b = &geometry->fill.bezier_vertices[bezier_idx * 3];
|
||||||
|
@ -2334,6 +2543,7 @@ static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_Close(ID2D1GeometrySink *ifac
|
||||||
{
|
{
|
||||||
struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
|
struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
|
||||||
HRESULT hr = E_FAIL;
|
HRESULT hr = E_FAIL;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
TRACE("iface %p.\n", iface);
|
TRACE("iface %p.\n", iface);
|
||||||
|
|
||||||
|
@ -2345,6 +2555,15 @@ static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_Close(ID2D1GeometrySink *ifac
|
||||||
}
|
}
|
||||||
geometry->u.path.state = D2D_GEOMETRY_STATE_CLOSED;
|
geometry->u.path.state = D2D_GEOMETRY_STATE_CLOSED;
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (!(figure->original_bezier_controls = HeapAlloc(GetProcessHeap(), 0, size)))
|
||||||
|
goto done;
|
||||||
|
memcpy(figure->original_bezier_controls, figure->bezier_controls, size);
|
||||||
|
}
|
||||||
|
|
||||||
if (!d2d_geometry_intersect_self(geometry))
|
if (!d2d_geometry_intersect_self(geometry))
|
||||||
goto done;
|
goto done;
|
||||||
if (FAILED(hr = d2d_geometry_resolve_beziers(geometry)))
|
if (FAILED(hr = d2d_geometry_resolve_beziers(geometry)))
|
||||||
|
@ -2678,7 +2897,8 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *i
|
||||||
|
|
||||||
for (bezier_idx = 0, ++j; j < figure->vertex_count; ++j)
|
for (bezier_idx = 0, ++j; j < figure->vertex_count; ++j)
|
||||||
{
|
{
|
||||||
if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
|
if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE
|
||||||
|
|| figure->vertex_types[j] == D2D_VERTEX_TYPE_SPLIT_BEZIER)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
|
@ -2691,7 +2911,7 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *i
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case D2D_VERTEX_TYPE_BEZIER:
|
case D2D_VERTEX_TYPE_BEZIER:
|
||||||
p1 = figure->bezier_controls[bezier_idx++];
|
p1 = figure->original_bezier_controls[bezier_idx++];
|
||||||
if (transform)
|
if (transform)
|
||||||
d2d_point_transform(&p1, transform, p1.x, p1.y);
|
d2d_point_transform(&p1, transform, p1.x, p1.y);
|
||||||
p2 = figure->vertices[j];
|
p2 = figure->vertices[j];
|
||||||
|
@ -2715,7 +2935,7 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *i
|
||||||
|
|
||||||
if (type == D2D_VERTEX_TYPE_BEZIER)
|
if (type == D2D_VERTEX_TYPE_BEZIER)
|
||||||
{
|
{
|
||||||
p1 = figure->bezier_controls[bezier_idx++];
|
p1 = figure->original_bezier_controls[bezier_idx++];
|
||||||
if (transform)
|
if (transform)
|
||||||
d2d_point_transform(&p1, transform, p1.x, p1.y);
|
d2d_point_transform(&p1, transform, p1.x, p1.y);
|
||||||
p2 = figure->vertices[0];
|
p2 = figure->vertices[0];
|
||||||
|
|
|
@ -5653,7 +5653,7 @@ static void test_bezier_intersect(void)
|
||||||
"cHAwMm5vMTNtbjI0bG0zNWtrNTdpajY4aGk3OmZnOTtlZjo8ZGQ8PmJjPT9hYj5BX2BAQl5eQkRc"
|
"cHAwMm5vMTNtbjI0bG0zNWtrNTdpajY4aGk3OmZnOTtlZjo8ZGQ8PmJjPT9hYj5BX2BAQl5eQkRc"
|
||||||
"XUNGWltFR1lZR0lXWEhLVVZKTVNUTE9RUk5RT1BQUk5OUlRMTFRWSkpWWUdIWFtFRVteQkNdYEBA"
|
"XUNGWltFR1lZR0lXWEhLVVZKTVNUTE9RUk5RT1BQUk5OUlRMTFRWSkpWWUdIWFtFRVteQkNdYEBA"
|
||||||
"YGI+PmJlOztlaDg4aGs1NWtuMjJuci4vcXUrK3V6JiZ6fiIifoMBHR2DAYsBFRWLAZUBCwuVAQAA");
|
"YGI+PmJlOztlaDg4aGs1NWtuMjJuci4vcXUrK3V6JiZ6fiIifoMBHR2DAYsBFRWLAZUBCwuVAQAA");
|
||||||
todo_wine ok(match, "Figure does not match.\n");
|
ok(match, "Figure does not match.\n");
|
||||||
|
|
||||||
hr = ID2D1Factory_CreatePathGeometry(factory, &geometry);
|
hr = ID2D1Factory_CreatePathGeometry(factory, &geometry);
|
||||||
ok(SUCCEEDED(hr), "Failed to create path geometry, hr %#x.\n", hr);
|
ok(SUCCEEDED(hr), "Failed to create path geometry, hr %#x.\n", hr);
|
||||||
|
|
Loading…
Reference in New Issue