reg/tests: Test import with non-standard registry file headers.
[wine.git] / dlls / d2d1 / geometry.c
blob5ef62cbc67de6a43793b0a7dbceb3d4e270576f0
1 /*
2 * Copyright 2015 Henri Verbeet for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "config.h"
20 #include "wine/port.h"
22 #include "d2d1_private.h"
23 #ifdef HAVE_FLOAT_H
24 #include <float.h>
25 #endif
27 WINE_DEFAULT_DEBUG_CHANNEL(d2d);
29 #define D2D_CDT_EDGE_FLAG_FREED 0x80000000u
30 #define D2D_CDT_EDGE_FLAG_VISITED(r) (1u << (r))
32 #define D2D_FP_EPS (1.0f / (1 << FLT_MANT_DIG))
34 static const D2D1_MATRIX_3X2_F identity =
36 1.0f, 0.0f,
37 0.0f, 1.0f,
38 0.0f, 0.0f,
41 enum d2d_cdt_edge_next
43 D2D_EDGE_NEXT_ORIGIN = 0,
44 D2D_EDGE_NEXT_ROT = 1,
45 D2D_EDGE_NEXT_SYM = 2,
46 D2D_EDGE_NEXT_TOR = 3,
49 enum d2d_vertex_type
51 D2D_VERTEX_TYPE_NONE,
52 D2D_VERTEX_TYPE_LINE,
53 D2D_VERTEX_TYPE_BEZIER,
56 struct d2d_figure
58 D2D1_POINT_2F *vertices;
59 size_t vertices_size;
60 enum d2d_vertex_type *vertex_types;
61 size_t vertex_types_size;
62 size_t vertex_count;
64 D2D1_POINT_2F *bezier_controls;
65 size_t bezier_controls_size;
66 size_t bezier_control_count;
68 D2D1_RECT_F bounds;
71 struct d2d_cdt_edge_ref
73 size_t idx;
74 enum d2d_cdt_edge_next r;
77 struct d2d_cdt_edge
79 struct d2d_cdt_edge_ref next[4];
80 size_t vertex[2];
81 unsigned int flags;
84 struct d2d_cdt
86 struct d2d_cdt_edge *edges;
87 size_t edges_size;
88 size_t edge_count;
89 size_t free_edge;
91 const D2D1_POINT_2F *vertices;
94 struct d2d_geometry_intersection
96 size_t figure_idx;
97 size_t segment_idx;
98 float t;
99 D2D1_POINT_2F p;
102 struct d2d_geometry_intersections
104 struct d2d_geometry_intersection *intersections;
105 size_t intersections_size;
106 size_t intersection_count;
109 struct d2d_fp_two_vec2
111 float x[2];
112 float y[2];
115 struct d2d_fp_fin
117 float *now, *other;
118 size_t length;
121 static void d2d_bezier_vertex_set(struct d2d_bezier_vertex *b,
122 const D2D1_POINT_2F *p, float u, float v, float sign)
124 b->position = *p;
125 b->texcoord.u = u;
126 b->texcoord.v = v;
127 b->texcoord.sign = sign;
130 static void d2d_face_set(struct d2d_face *f, UINT16 v0, UINT16 v1, UINT16 v2)
132 f->v[0] = v0;
133 f->v[1] = v1;
134 f->v[2] = v2;
137 static void d2d_outline_vertex_set(struct d2d_outline_vertex *v, float x, float y,
138 float prev_x, float prev_y, float next_x, float next_y)
140 d2d_point_set(&v->position, x, y);
141 d2d_point_set(&v->prev, prev_x, prev_y);
142 d2d_point_set(&v->next, next_x, next_y);
145 static void d2d_fp_two_sum(float *out, float a, float b)
147 float a_virt, a_round, b_virt, b_round;
149 out[1] = a + b;
150 b_virt = out[1] - a;
151 a_virt = out[1] - b_virt;
152 b_round = b - b_virt;
153 a_round = a - a_virt;
154 out[0] = a_round + b_round;
157 static void d2d_fp_fast_two_sum(float *out, float a, float b)
159 float b_virt;
161 out[1] = a + b;
162 b_virt = out[1] - a;
163 out[0] = b - b_virt;
166 static void d2d_fp_two_two_sum(float *out, const float *a, const float *b)
168 float sum[2];
170 d2d_fp_two_sum(out, a[0], b[0]);
171 d2d_fp_two_sum(sum, a[1], out[1]);
172 d2d_fp_two_sum(&out[1], sum[0], b[1]);
173 d2d_fp_two_sum(&out[2], sum[1], out[2]);
176 static void d2d_fp_two_diff_tail(float *out, float a, float b, float x)
178 float a_virt, a_round, b_virt, b_round;
180 b_virt = a - x;
181 a_virt = x + b_virt;
182 b_round = b_virt - b;
183 a_round = a - a_virt;
184 *out = a_round + b_round;
187 static void d2d_fp_two_two_diff(float *out, const float *a, const float *b)
189 float sum[2], diff;
191 diff = a[0] - b[0];
192 d2d_fp_two_diff_tail(out, a[0], b[0], diff);
193 d2d_fp_two_sum(sum, a[1], diff);
194 diff = sum[0] - b[1];
195 d2d_fp_two_diff_tail(&out[1], sum[0], b[1], diff);
196 d2d_fp_two_sum(&out[2], sum[1], diff);
199 static void d2d_fp_split(float *out, float a)
201 float a_big, c;
203 c = a * ((1 << (FLT_MANT_DIG / 2)) + 1.0f);
204 a_big = c - a;
205 out[1] = c - a_big;
206 out[0] = a - out[1];
209 static void d2d_fp_two_product_presplit(float *out, float a, float b, const float *b_split)
211 float a_split[2], err1, err2, err3;
213 out[1] = a * b;
214 d2d_fp_split(a_split, a);
215 err1 = out[1] - (a_split[1] * b_split[1]);
216 err2 = err1 - (a_split[0] * b_split[1]);
217 err3 = err2 - (a_split[1] * b_split[0]);
218 out[0] = (a_split[0] * b_split[0]) - err3;
221 static void d2d_fp_two_product(float *out, float a, float b)
223 float b_split[2];
225 d2d_fp_split(b_split, b);
226 d2d_fp_two_product_presplit(out, a, b, b_split);
229 static void d2d_fp_square(float *out, float a)
231 float a_split[2], err1, err2;
233 out[1] = a * a;
234 d2d_fp_split(a_split, a);
235 err1 = out[1] - (a_split[1] * a_split[1]);
236 err2 = err1 - ((a_split[1] + a_split[1]) * a_split[0]);
237 out[0] = (a_split[0] * a_split[0]) - err2;
240 static float d2d_fp_estimate(float *a, size_t len)
242 float out = a[0];
243 size_t idx = 1;
245 while (idx < len)
246 out += a[idx++];
248 return out;
251 static void d2d_fp_fast_expansion_sum_zeroelim(float *out, size_t *out_len,
252 const float *a, size_t a_len, const float *b, size_t b_len)
254 float sum[2], q, a_curr, b_curr;
255 size_t a_idx, b_idx, out_idx;
257 a_curr = a[0];
258 b_curr = b[0];
259 a_idx = b_idx = 0;
260 if ((b_curr > a_curr) == (b_curr > -a_curr))
262 q = a_curr;
263 a_curr = a[++a_idx];
265 else
267 q = b_curr;
268 b_curr = b[++b_idx];
270 out_idx = 0;
271 if (a_idx < a_len && b_idx < b_len)
273 if ((b_curr > a_curr) == (b_curr > -a_curr))
275 d2d_fp_fast_two_sum(sum, a_curr, q);
276 a_curr = a[++a_idx];
278 else
280 d2d_fp_fast_two_sum(sum, b_curr, q);
281 b_curr = b[++b_idx];
283 if (sum[0] != 0.0f)
284 out[out_idx++] = sum[0];
285 q = sum[1];
286 while (a_idx < a_len && b_idx < b_len)
288 if ((b_curr > a_curr) == (b_curr > -a_curr))
290 d2d_fp_two_sum(sum, q, a_curr);
291 a_curr = a[++a_idx];
293 else
295 d2d_fp_two_sum(sum, q, b_curr);
296 b_curr = b[++b_idx];
298 if (sum[0] != 0.0f)
299 out[out_idx++] = sum[0];
300 q = sum[1];
303 while (a_idx < a_len)
305 d2d_fp_two_sum(sum, q, a_curr);
306 a_curr = a[++a_idx];
307 if (sum[0] != 0.0f)
308 out[out_idx++] = sum[0];
309 q = sum[1];
311 while (b_idx < b_len)
313 d2d_fp_two_sum(sum, q, b_curr);
314 b_curr = b[++b_idx];
315 if (sum[0] != 0.0f)
316 out[out_idx++] = sum[0];
317 q = sum[1];
319 if (q != 0.0f || !out_idx)
320 out[out_idx++] = q;
322 *out_len = out_idx;
325 static void d2d_fp_scale_expansion_zeroelim(float *out, size_t *out_len, const float *a, size_t a_len, float b)
327 float product[2], sum[2], b_split[2], q[2], a_curr;
328 size_t a_idx, out_idx;
330 d2d_fp_split(b_split, b);
331 d2d_fp_two_product_presplit(q, a[0], b, b_split);
332 out_idx = 0;
333 if (q[0] != 0.0f)
334 out[out_idx++] = q[0];
335 for (a_idx = 1; a_idx < a_len; ++a_idx)
337 a_curr = a[a_idx];
338 d2d_fp_two_product_presplit(product, a_curr, b, b_split);
339 d2d_fp_two_sum(sum, q[1], product[0]);
340 if (sum[0] != 0.0f)
341 out[out_idx++] = sum[0];
342 d2d_fp_fast_two_sum(q, product[1], sum[1]);
343 if (q[0] != 0.0f)
344 out[out_idx++] = q[0];
346 if (q[1] != 0.0f || !out_idx)
347 out[out_idx++] = q[1];
349 *out_len = out_idx;
352 static void d2d_point_subtract(D2D1_POINT_2F *out,
353 const D2D1_POINT_2F *a, const D2D1_POINT_2F *b)
355 out->x = a->x - b->x;
356 out->y = a->y - b->y;
359 static void d2d_point_scale(D2D1_POINT_2F *p, float scale)
361 p->x *= scale;
362 p->y *= scale;
365 static float d2d_point_dot(const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1)
367 return p0->x * p1->x + p0->y * p1->y;
370 static void d2d_point_normalise(D2D1_POINT_2F *p)
372 float l;
374 if ((l = sqrtf(d2d_point_dot(p, p))) != 0.0f)
375 d2d_point_scale(p, 1.0f / l);
378 /* This implementation is based on the paper "Adaptive Precision
379 * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
380 * associated (Public Domain) code by Jonathan Richard Shewchuk. */
381 static float d2d_point_ccw(const D2D1_POINT_2F *a, const D2D1_POINT_2F *b, const D2D1_POINT_2F *c)
383 static const float err_bound_result = (3.0f + 8.0f * D2D_FP_EPS) * D2D_FP_EPS;
384 static const float err_bound_a = (3.0f + 16.0f * D2D_FP_EPS) * D2D_FP_EPS;
385 static const float err_bound_b = (2.0f + 12.0f * D2D_FP_EPS) * D2D_FP_EPS;
386 static const float err_bound_c = (9.0f + 64.0f * D2D_FP_EPS) * D2D_FP_EPS * D2D_FP_EPS;
387 float det_d[16], det_c2[12], det_c1[8], det_b[4], temp4[4], temp2a[2], temp2b[2], abxacy[2], abyacx[2];
388 size_t det_d_len, det_c2_len, det_c1_len;
389 float det, det_sum, err_bound;
390 struct d2d_fp_two_vec2 ab, ac;
392 ab.x[1] = b->x - a->x;
393 ab.y[1] = b->y - a->y;
394 ac.x[1] = c->x - a->x;
395 ac.y[1] = c->y - a->y;
397 abxacy[1] = ab.x[1] * ac.y[1];
398 abyacx[1] = ab.y[1] * ac.x[1];
399 det = abxacy[1] - abyacx[1];
401 if (abxacy[1] > 0.0f)
403 if (abyacx[1] <= 0.0f)
404 return det;
405 det_sum = abxacy[1] + abyacx[1];
407 else if (abxacy[1] < 0.0f)
409 if (abyacx[1] >= 0.0f)
410 return det;
411 det_sum = -abxacy[1] - abyacx[1];
413 else
415 return det;
418 err_bound = err_bound_a * det_sum;
419 if (det >= err_bound || -det >= err_bound)
420 return det;
422 d2d_fp_two_product(abxacy, ab.x[1], ac.y[1]);
423 d2d_fp_two_product(abyacx, ab.y[1], ac.x[1]);
424 d2d_fp_two_two_diff(det_b, abxacy, abyacx);
426 det = d2d_fp_estimate(det_b, 4);
427 err_bound = err_bound_b * det_sum;
428 if (det >= err_bound || -det >= err_bound)
429 return det;
431 d2d_fp_two_diff_tail(&ab.x[0], b->x, a->x, ab.x[1]);
432 d2d_fp_two_diff_tail(&ab.y[0], b->y, a->y, ab.y[1]);
433 d2d_fp_two_diff_tail(&ac.x[0], c->x, a->x, ac.x[1]);
434 d2d_fp_two_diff_tail(&ac.y[0], c->y, a->y, ac.y[1]);
436 if (ab.x[0] == 0.0f && ab.y[0] == 0.0f && ac.x[0] == 0.0f && ac.y[0] == 0.0f)
437 return det;
439 err_bound = err_bound_c * det_sum + err_bound_result * fabsf(det);
440 det += (ab.x[1] * ac.y[0] + ac.y[1] * ab.x[0]) - (ab.y[1] * ac.x[0] + ac.x[1] * ab.y[0]);
441 if (det >= err_bound || -det >= err_bound)
442 return det;
444 d2d_fp_two_product(temp2a, ab.x[0], ac.y[1]);
445 d2d_fp_two_product(temp2b, ab.y[0], ac.x[1]);
446 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
447 d2d_fp_fast_expansion_sum_zeroelim(det_c1, &det_c1_len, det_b, 4, temp4, 4);
449 d2d_fp_two_product(temp2a, ab.x[1], ac.y[0]);
450 d2d_fp_two_product(temp2b, ab.y[1], ac.x[0]);
451 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
452 d2d_fp_fast_expansion_sum_zeroelim(det_c2, &det_c2_len, det_c1, det_c1_len, temp4, 4);
454 d2d_fp_two_product(temp2a, ab.x[0], ac.y[0]);
455 d2d_fp_two_product(temp2b, ab.y[0], ac.x[0]);
456 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
457 d2d_fp_fast_expansion_sum_zeroelim(det_d, &det_d_len, det_c2, det_c2_len, temp4, 4);
459 return det_d[det_d_len - 1];
462 static BOOL d2d_array_reserve(void **elements, size_t *capacity, size_t element_count, size_t element_size)
464 size_t new_capacity, max_capacity;
465 void *new_elements;
467 if (element_count <= *capacity)
468 return TRUE;
470 max_capacity = ~(size_t)0 / element_size;
471 if (max_capacity < element_count)
472 return FALSE;
474 new_capacity = max(*capacity, 4);
475 while (new_capacity < element_count && new_capacity <= max_capacity / 2)
476 new_capacity *= 2;
478 if (new_capacity < element_count)
479 new_capacity = max_capacity;
481 if (*elements)
482 new_elements = HeapReAlloc(GetProcessHeap(), 0, *elements, new_capacity * element_size);
483 else
484 new_elements = HeapAlloc(GetProcessHeap(), 0, new_capacity * element_size);
486 if (!new_elements)
487 return FALSE;
489 *elements = new_elements;
490 *capacity = new_capacity;
491 return TRUE;
494 static void d2d_figure_update_bounds(struct d2d_figure *figure, D2D1_POINT_2F vertex)
496 if (vertex.x < figure->bounds.left)
497 figure->bounds.left = vertex.x;
498 if (vertex.x > figure->bounds.right)
499 figure->bounds.right = vertex.x;
500 if (vertex.y < figure->bounds.top)
501 figure->bounds.top = vertex.y;
502 if (vertex.y > figure->bounds.bottom)
503 figure->bounds.bottom = vertex.y;
506 static BOOL d2d_figure_insert_vertex(struct d2d_figure *figure, size_t idx, D2D1_POINT_2F vertex)
508 if (!d2d_array_reserve((void **)&figure->vertices, &figure->vertices_size,
509 figure->vertex_count + 1, sizeof(*figure->vertices)))
511 ERR("Failed to grow vertices array.\n");
512 return FALSE;
515 if (!d2d_array_reserve((void **)&figure->vertex_types, &figure->vertex_types_size,
516 figure->vertex_count + 1, sizeof(*figure->vertex_types)))
518 ERR("Failed to grow vertex types array.\n");
519 return FALSE;
522 memmove(&figure->vertices[idx + 1], &figure->vertices[idx],
523 (figure->vertex_count - idx) * sizeof(*figure->vertices));
524 memmove(&figure->vertex_types[idx + 1], &figure->vertex_types[idx],
525 (figure->vertex_count - idx) * sizeof(*figure->vertex_types));
526 figure->vertices[idx] = vertex;
527 figure->vertex_types[idx] = D2D_VERTEX_TYPE_NONE;
528 d2d_figure_update_bounds(figure, vertex);
529 ++figure->vertex_count;
530 return TRUE;
533 static BOOL d2d_figure_add_vertex(struct d2d_figure *figure, D2D1_POINT_2F vertex)
535 size_t last = figure->vertex_count - 1;
537 if (figure->vertex_count && figure->vertex_types[last] == D2D_VERTEX_TYPE_LINE
538 && !memcmp(&figure->vertices[last], &vertex, sizeof(vertex)))
539 return TRUE;
541 if (!d2d_array_reserve((void **)&figure->vertices, &figure->vertices_size,
542 figure->vertex_count + 1, sizeof(*figure->vertices)))
544 ERR("Failed to grow vertices array.\n");
545 return FALSE;
548 if (!d2d_array_reserve((void **)&figure->vertex_types, &figure->vertex_types_size,
549 figure->vertex_count + 1, sizeof(*figure->vertex_types)))
551 ERR("Failed to grow vertex types array.\n");
552 return FALSE;
555 figure->vertices[figure->vertex_count] = vertex;
556 figure->vertex_types[figure->vertex_count] = D2D_VERTEX_TYPE_NONE;
557 d2d_figure_update_bounds(figure, vertex);
558 ++figure->vertex_count;
559 return TRUE;
562 static BOOL d2d_figure_add_bezier_control(struct d2d_figure *figure, const D2D1_POINT_2F *p)
564 if (!d2d_array_reserve((void **)&figure->bezier_controls, &figure->bezier_controls_size,
565 figure->bezier_control_count + 1, sizeof(*figure->bezier_controls)))
567 ERR("Failed to grow bezier controls array.\n");
568 return FALSE;
571 figure->bezier_controls[figure->bezier_control_count++] = *p;
573 return TRUE;
576 static void d2d_cdt_edge_rot(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
578 dst->idx = src->idx;
579 dst->r = (src->r + D2D_EDGE_NEXT_ROT) & 3;
582 static void d2d_cdt_edge_sym(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
584 dst->idx = src->idx;
585 dst->r = (src->r + D2D_EDGE_NEXT_SYM) & 3;
588 static void d2d_cdt_edge_tor(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
590 dst->idx = src->idx;
591 dst->r = (src->r + D2D_EDGE_NEXT_TOR) & 3;
594 static void d2d_cdt_edge_next_left(const struct d2d_cdt *cdt,
595 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
597 d2d_cdt_edge_rot(dst, &cdt->edges[src->idx].next[(src->r + D2D_EDGE_NEXT_TOR) & 3]);
600 static void d2d_cdt_edge_next_origin(const struct d2d_cdt *cdt,
601 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
603 *dst = cdt->edges[src->idx].next[src->r];
606 static void d2d_cdt_edge_prev_origin(const struct d2d_cdt *cdt,
607 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
609 d2d_cdt_edge_rot(dst, &cdt->edges[src->idx].next[(src->r + D2D_EDGE_NEXT_ROT) & 3]);
612 static size_t d2d_cdt_edge_origin(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
614 return cdt->edges[e->idx].vertex[e->r >> 1];
617 static size_t d2d_cdt_edge_destination(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
619 return cdt->edges[e->idx].vertex[!(e->r >> 1)];
622 static void d2d_cdt_edge_set_origin(const struct d2d_cdt *cdt,
623 const struct d2d_cdt_edge_ref *e, size_t vertex)
625 cdt->edges[e->idx].vertex[e->r >> 1] = vertex;
628 static void d2d_cdt_edge_set_destination(const struct d2d_cdt *cdt,
629 const struct d2d_cdt_edge_ref *e, size_t vertex)
631 cdt->edges[e->idx].vertex[!(e->r >> 1)] = vertex;
634 static float d2d_cdt_ccw(const struct d2d_cdt *cdt, size_t a, size_t b, size_t c)
636 return d2d_point_ccw(&cdt->vertices[a], &cdt->vertices[b], &cdt->vertices[c]);
639 static BOOL d2d_cdt_rightof(const struct d2d_cdt *cdt, size_t p, const struct d2d_cdt_edge_ref *e)
641 return d2d_cdt_ccw(cdt, p, d2d_cdt_edge_destination(cdt, e), d2d_cdt_edge_origin(cdt, e)) > 0.0f;
644 static BOOL d2d_cdt_leftof(const struct d2d_cdt *cdt, size_t p, const struct d2d_cdt_edge_ref *e)
646 return d2d_cdt_ccw(cdt, p, d2d_cdt_edge_origin(cdt, e), d2d_cdt_edge_destination(cdt, e)) > 0.0f;
649 /* |ax ay|
650 * |bx by| */
651 static void d2d_fp_four_det2x2(float *out, float ax, float ay, float bx, float by)
653 float axby[2], aybx[2];
655 d2d_fp_two_product(axby, ax, by);
656 d2d_fp_two_product(aybx, ay, bx);
657 d2d_fp_two_two_diff(out, axby, aybx);
660 /* (a->x² + a->y²) * det2x2 */
661 static void d2d_fp_sub_det3x3(float *out, size_t *out_len, const struct d2d_fp_two_vec2 *a, const float *det2x2)
663 size_t axd_len, ayd_len, axxd_len, ayyd_len;
664 float axd[8], ayd[8], axxd[16], ayyd[16];
666 d2d_fp_scale_expansion_zeroelim(axd, &axd_len, det2x2, 4, a->x[1]);
667 d2d_fp_scale_expansion_zeroelim(axxd, &axxd_len, axd, axd_len, a->x[1]);
668 d2d_fp_scale_expansion_zeroelim(ayd, &ayd_len, det2x2, 4, a->y[1]);
669 d2d_fp_scale_expansion_zeroelim(ayyd, &ayyd_len, ayd, ayd_len, a->y[1]);
670 d2d_fp_fast_expansion_sum_zeroelim(out, out_len, axxd, axxd_len, ayyd, ayyd_len);
673 /* det_abt = det_ab * c[0]
674 * fin += c[0] * (az * b - bz * a + c[1] * det_ab * 2.0f) */
675 static void d2d_cdt_incircle_refine1(struct d2d_fp_fin *fin, float *det_abt, size_t *det_abt_len,
676 const float *det_ab, float a, const float *az, float b, const float *bz, const float *c)
678 size_t temp48_len, temp32_len, temp16a_len, temp16b_len, temp16c_len, temp8_len;
679 float temp48[48], temp32[32], temp16a[16], temp16b[16], temp16c[16], temp8[8];
680 float *swap;
682 d2d_fp_scale_expansion_zeroelim(det_abt, det_abt_len, det_ab, 4, c[0]);
683 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, det_abt, *det_abt_len, 2.0f * c[1]);
684 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, az, 4, c[0]);
685 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, temp8, temp8_len, b);
686 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, bz, 4, c[0]);
687 d2d_fp_scale_expansion_zeroelim(temp16c, &temp16c_len, temp8, temp8_len, -a);
688 d2d_fp_fast_expansion_sum_zeroelim(temp32, &temp32_len, temp16a, temp16a_len, temp16b, temp16b_len);
689 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16c, temp16c_len, temp32, temp32_len);
690 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
691 swap = fin->now; fin->now = fin->other; fin->other = swap;
694 static void d2d_cdt_incircle_refine2(struct d2d_fp_fin *fin, const struct d2d_fp_two_vec2 *a,
695 const struct d2d_fp_two_vec2 *b, const float *bz, const struct d2d_fp_two_vec2 *c, const float *cz,
696 const float *axt_det_bc, size_t axt_det_bc_len, const float *ayt_det_bc, size_t ayt_det_bc_len)
698 size_t temp64_len, temp48_len, temp32a_len, temp32b_len, temp16a_len, temp16b_len, temp8_len;
699 float temp64[64], temp48[48], temp32a[32], temp32b[32], temp16a[16], temp16b[16], temp8[8];
700 float bct[8], bctt[4], temp4a[4], temp4b[4], temp2a[2], temp2b[2];
701 size_t bct_len, bctt_len;
702 float *swap;
704 /* bct = (b->x[0] * c->y[1] + b->x[1] * c->y[0]) - (c->x[0] * b->y[1] + c->x[1] * b->y[0]) */
705 /* bctt = b->x[0] * c->y[0] + c->x[0] * b->y[0] */
706 if (b->x[0] != 0.0f || b->y[0] != 0.0f || c->x[0] != 0.0f || c->y[0] != 0.0f)
708 d2d_fp_two_product(temp2a, b->x[0], c->y[1]);
709 d2d_fp_two_product(temp2b, b->x[1], c->y[0]);
710 d2d_fp_two_two_sum(temp4a, temp2a, temp2b);
711 d2d_fp_two_product(temp2a, c->x[0], -b->y[1]);
712 d2d_fp_two_product(temp2b, c->x[1], -b->y[0]);
713 d2d_fp_two_two_sum(temp4b, temp2a, temp2b);
714 d2d_fp_fast_expansion_sum_zeroelim(bct, &bct_len, temp4a, 4, temp4b, 4);
716 d2d_fp_two_product(temp2a, b->x[0], c->y[0]);
717 d2d_fp_two_product(temp2b, c->x[0], b->y[0]);
718 d2d_fp_two_two_diff(bctt, temp2a, temp2b);
719 bctt_len = 4;
721 else
723 bct[0] = 0.0f;
724 bct_len = 1;
725 bctt[0] = 0.0f;
726 bctt_len = 1;
729 if (a->x[0] != 0.0f)
731 size_t axt_bct_len, axt_bctt_len;
732 float axt_bct[16], axt_bctt[8];
734 /* fin += a->x[0] * (axt_det_bc + bct * 2.0f * a->x[1]) */
735 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, axt_det_bc, axt_det_bc_len, a->x[0]);
736 d2d_fp_scale_expansion_zeroelim(axt_bct, &axt_bct_len, bct, bct_len, a->x[0]);
737 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, axt_bct, axt_bct_len, 2.0f * a->x[1]);
738 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16a, temp16a_len, temp32a, temp32a_len);
739 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
740 swap = fin->now; fin->now = fin->other; fin->other = swap;
742 if (b->y[0] != 0.0f)
744 /* fin += a->x[0] * cz * b->y[0] */
745 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, cz, 4, a->x[0]);
746 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, temp8, temp8_len, b->y[0]);
747 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp16a, temp16a_len);
748 swap = fin->now; fin->now = fin->other; fin->other = swap;
751 if (c->y[0] != 0.0f)
753 /* fin -= a->x[0] * bz * c->y[0] */
754 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, bz, 4, -a->x[0]);
755 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, temp8, temp8_len, c->y[0]);
756 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp16a, temp16a_len);
757 swap = fin->now; fin->now = fin->other; fin->other = swap;
760 /* fin += a->x[0] * (bct * a->x[0] + bctt * (2.0f * a->x[1] + a->x[0])) */
761 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, axt_bct, axt_bct_len, a->x[0]);
762 d2d_fp_scale_expansion_zeroelim(axt_bctt, &axt_bctt_len, bctt, bctt_len, a->x[0]);
763 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, axt_bctt, axt_bctt_len, 2.0f * a->x[1]);
764 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, axt_bctt, axt_bctt_len, a->x[0]);
765 d2d_fp_fast_expansion_sum_zeroelim(temp32b, &temp32b_len, temp16a, temp16a_len, temp16b, temp16b_len);
766 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, temp32a, temp32a_len, temp32b, temp32b_len);
767 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp64, temp64_len);
768 swap = fin->now; fin->now = fin->other; fin->other = swap;
771 if (a->y[0] != 0.0f)
773 size_t ayt_bct_len, ayt_bctt_len;
774 float ayt_bct[16], ayt_bctt[8];
776 /* fin += a->y[0] * (ayt_det_bc + bct * 2.0f * a->y[1]) */
777 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, ayt_det_bc, ayt_det_bc_len, a->y[0]);
778 d2d_fp_scale_expansion_zeroelim(ayt_bct, &ayt_bct_len, bct, bct_len, a->y[0]);
779 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, ayt_bct, ayt_bct_len, 2.0f * a->y[1]);
780 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16a, temp16a_len, temp32a, temp32a_len);
781 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
782 swap = fin->now; fin->now = fin->other; fin->other = swap;
784 /* fin += a->y[0] * (bct * a->y[0] + bctt * (2.0f * a->y[1] + a->y[0])) */
785 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, ayt_bct, ayt_bct_len, a->y[0]);
786 d2d_fp_scale_expansion_zeroelim(ayt_bctt, &ayt_bctt_len, bctt, bctt_len, a->y[0]);
787 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, ayt_bctt, ayt_bctt_len, 2.0f * a->y[1]);
788 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, ayt_bctt, ayt_bctt_len, a->y[0]);
789 d2d_fp_fast_expansion_sum_zeroelim(temp32b, &temp32b_len, temp16a, temp16a_len, temp16b, temp16b_len);
790 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, temp32a, temp32a_len, temp32b, temp32b_len);
791 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp64, temp64_len);
792 swap = fin->now; fin->now = fin->other; fin->other = swap;
796 /* Determine if point D is inside or outside the circle defined by points A,
797 * B, C. As explained in the paper by Guibas and Stolfi, this is equivalent to
798 * calculating the signed volume of the tetrahedron defined by projecting the
799 * points onto the paraboloid of revolution x = x² + y²,
800 * λ:(x, y) → (x, y, x² + y²). I.e., D is inside the cirlce if
802 * |λ(A) 1|
803 * |λ(B) 1| > 0
804 * |λ(C) 1|
805 * |λ(D) 1|
807 * After translating D to the origin, that becomes:
809 * |λ(A-D)|
810 * |λ(B-D)| > 0
811 * |λ(C-D)|
813 * This implementation is based on the paper "Adaptive Precision
814 * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
815 * associated (Public Domain) code by Jonathan Richard Shewchuk. */
816 static BOOL d2d_cdt_incircle(const struct d2d_cdt *cdt, size_t a, size_t b, size_t c, size_t d)
818 static const float err_bound_result = (3.0f + 8.0f * D2D_FP_EPS) * D2D_FP_EPS;
819 static const float err_bound_a = (10.0f + 96.0f * D2D_FP_EPS) * D2D_FP_EPS;
820 static const float err_bound_b = (4.0f + 48.0f * D2D_FP_EPS) * D2D_FP_EPS;
821 static const float err_bound_c = (44.0f + 576.0f * D2D_FP_EPS) * D2D_FP_EPS * D2D_FP_EPS;
823 size_t axt_det_bc_len, ayt_det_bc_len, bxt_det_ca_len, byt_det_ca_len, cxt_det_ab_len, cyt_det_ab_len;
824 float axt_det_bc[8], ayt_det_bc[8], bxt_det_ca[8], byt_det_ca[8], cxt_det_ab[8], cyt_det_ab[8];
825 float fin1[1152], fin2[1152], temp64[64], sub_det_a[32], sub_det_b[32], sub_det_c[32];
826 float det_bc[4], det_ca[4], det_ab[4], daz[4], dbz[4], dcz[4], temp2a[2], temp2b[2];
827 size_t temp64_len, sub_det_a_len, sub_det_b_len, sub_det_c_len;
828 float dbxdcy, dbydcx, dcxday, dcydax, daxdby, daydbx;
829 const D2D1_POINT_2F *p = cdt->vertices;
830 struct d2d_fp_two_vec2 da, db, dc;
831 float permanent, err_bound, det;
832 struct d2d_fp_fin fin;
834 da.x[1] = p[a].x - p[d].x;
835 da.y[1] = p[a].y - p[d].y;
836 db.x[1] = p[b].x - p[d].x;
837 db.y[1] = p[b].y - p[d].y;
838 dc.x[1] = p[c].x - p[d].x;
839 dc.y[1] = p[c].y - p[d].y;
841 daz[3] = da.x[1] * da.x[1] + da.y[1] * da.y[1];
842 dbxdcy = db.x[1] * dc.y[1];
843 dbydcx = db.y[1] * dc.x[1];
845 dbz[3] = db.x[1] * db.x[1] + db.y[1] * db.y[1];
846 dcxday = dc.x[1] * da.y[1];
847 dcydax = dc.y[1] * da.x[1];
849 dcz[3] = dc.x[1] * dc.x[1] + dc.y[1] * dc.y[1];
850 daxdby = da.x[1] * db.y[1];
851 daydbx = da.y[1] * db.x[1];
853 det = daz[3] * (dbxdcy - dbydcx) + dbz[3] * (dcxday - dcydax) + dcz[3] * (daxdby - daydbx);
854 permanent = daz[3] * (fabsf(dbxdcy) + fabsf(dbydcx))
855 + dbz[3] * (fabsf(dcxday) + fabsf(dcydax))
856 + dcz[3] * (fabsf(daxdby) + fabsf(daydbx));
857 err_bound = err_bound_a * permanent;
858 if (det > err_bound || -det > err_bound)
859 return det > 0.0f;
861 fin.now = fin1;
862 fin.other = fin2;
864 d2d_fp_four_det2x2(det_bc, db.x[1], db.y[1], dc.x[1], dc.y[1]);
865 d2d_fp_sub_det3x3(sub_det_a, &sub_det_a_len, &da, det_bc);
867 d2d_fp_four_det2x2(det_ca, dc.x[1], dc.y[1], da.x[1], da.y[1]);
868 d2d_fp_sub_det3x3(sub_det_b, &sub_det_b_len, &db, det_ca);
870 d2d_fp_four_det2x2(det_ab, da.x[1], da.y[1], db.x[1], db.y[1]);
871 d2d_fp_sub_det3x3(sub_det_c, &sub_det_c_len, &dc, det_ab);
873 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, sub_det_a, sub_det_a_len, sub_det_b, sub_det_b_len);
874 d2d_fp_fast_expansion_sum_zeroelim(fin.now, &fin.length, temp64, temp64_len, sub_det_c, sub_det_c_len);
875 det = d2d_fp_estimate(fin.now, fin.length);
876 err_bound = err_bound_b * permanent;
877 if (det >= err_bound || -det >= err_bound)
878 return det > 0.0f;
880 d2d_fp_two_diff_tail(&da.x[0], p[a].x, p[d].x, da.x[1]);
881 d2d_fp_two_diff_tail(&da.y[0], p[a].y, p[d].y, da.y[1]);
882 d2d_fp_two_diff_tail(&db.x[0], p[b].x, p[d].x, db.x[1]);
883 d2d_fp_two_diff_tail(&db.y[0], p[b].y, p[d].y, db.y[1]);
884 d2d_fp_two_diff_tail(&dc.x[0], p[c].x, p[d].x, dc.x[1]);
885 d2d_fp_two_diff_tail(&dc.y[0], p[c].y, p[d].y, dc.y[1]);
886 if (da.x[0] == 0.0f && db.x[0] == 0.0f && dc.x[0] == 0.0f
887 && da.y[0] == 0.0f && db.y[0] == 0.0f && dc.y[0] == 0.0f)
888 return det > 0.0f;
890 err_bound = err_bound_c * permanent + err_bound_result * fabsf(det);
891 det += (daz[3] * ((db.x[1] * dc.y[0] + dc.y[1] * db.x[0]) - (db.y[1] * dc.x[0] + dc.x[1] * db.y[0]))
892 + 2.0f * (da.x[1] * da.x[0] + da.y[1] * da.y[0]) * (db.x[1] * dc.y[1] - db.y[1] * dc.x[1]))
893 + (dbz[3] * ((dc.x[1] * da.y[0] + da.y[1] * dc.x[0]) - (dc.y[1] * da.x[0] + da.x[1] * dc.y[0]))
894 + 2.0f * (db.x[1] * db.x[0] + db.y[1] * db.y[0]) * (dc.x[1] * da.y[1] - dc.y[1] * da.x[1]))
895 + (dcz[3] * ((da.x[1] * db.y[0] + db.y[1] * da.x[0]) - (da.y[1] * db.x[0] + db.x[1] * da.y[0]))
896 + 2.0f * (dc.x[1] * dc.x[0] + dc.y[1] * dc.y[0]) * (da.x[1] * db.y[1] - da.y[1] * db.x[1]));
897 if (det >= err_bound || -det >= err_bound)
898 return det > 0.0f;
900 if (db.x[0] != 0.0f || db.y[0] != 0.0f || dc.x[0] != 0.0f || dc.y[0] != 0.0f)
902 d2d_fp_square(temp2a, da.x[1]);
903 d2d_fp_square(temp2b, da.y[1]);
904 d2d_fp_two_two_sum(daz, temp2a, temp2b);
906 if (dc.x[0] != 0.0f || dc.y[0] != 0.0f || da.x[0] != 0.0f || da.y[0] != 0.0f)
908 d2d_fp_square(temp2a, db.x[1]);
909 d2d_fp_square(temp2b, db.y[1]);
910 d2d_fp_two_two_sum(dbz, temp2a, temp2b);
912 if (da.x[0] != 0.0f || da.y[0] != 0.0f || db.x[0] != 0.0f || db.y[0] != 0.0f)
914 d2d_fp_square(temp2a, dc.x[1]);
915 d2d_fp_square(temp2b, dc.y[1]);
916 d2d_fp_two_two_sum(dcz, temp2a, temp2b);
919 if (da.x[0] != 0.0f)
920 d2d_cdt_incircle_refine1(&fin, axt_det_bc, &axt_det_bc_len, det_bc, dc.y[1], dcz, db.y[1], dbz, da.x);
921 if (da.y[0] != 0.0f)
922 d2d_cdt_incircle_refine1(&fin, ayt_det_bc, &ayt_det_bc_len, det_bc, db.x[1], dbz, dc.x[1], dcz, da.y);
923 if (db.x[0] != 0.0f)
924 d2d_cdt_incircle_refine1(&fin, bxt_det_ca, &bxt_det_ca_len, det_ca, da.y[1], daz, dc.y[1], dcz, db.x);
925 if (db.y[0] != 0.0f)
926 d2d_cdt_incircle_refine1(&fin, byt_det_ca, &byt_det_ca_len, det_ca, dc.x[1], dcz, da.x[1], daz, db.y);
927 if (dc.x[0] != 0.0f)
928 d2d_cdt_incircle_refine1(&fin, cxt_det_ab, &cxt_det_ab_len, det_ab, db.y[1], dbz, da.y[1], daz, dc.x);
929 if (dc.y[0] != 0.0f)
930 d2d_cdt_incircle_refine1(&fin, cyt_det_ab, &cyt_det_ab_len, det_ab, da.x[1], daz, db.x[1], dbz, dc.y);
932 if (da.x[0] != 0.0f || da.y[0] != 0.0f)
933 d2d_cdt_incircle_refine2(&fin, &da, &db, dbz, &dc, dcz,
934 axt_det_bc, axt_det_bc_len, ayt_det_bc, ayt_det_bc_len);
935 if (db.x[0] != 0.0f || db.y[0] != 0.0f)
936 d2d_cdt_incircle_refine2(&fin, &db, &dc, dcz, &da, daz,
937 bxt_det_ca, bxt_det_ca_len, byt_det_ca, byt_det_ca_len);
938 if (dc.x[0] != 0.0f || dc.y[0] != 0.0f)
939 d2d_cdt_incircle_refine2(&fin, &dc, &da, daz, &db, dbz,
940 cxt_det_ab, cxt_det_ab_len, cyt_det_ab, cyt_det_ab_len);
942 return fin.now[fin.length - 1] > 0.0f;
945 static void d2d_cdt_splice(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *a,
946 const struct d2d_cdt_edge_ref *b)
948 struct d2d_cdt_edge_ref ta, tb, alpha, beta;
950 ta = cdt->edges[a->idx].next[a->r];
951 tb = cdt->edges[b->idx].next[b->r];
952 cdt->edges[a->idx].next[a->r] = tb;
953 cdt->edges[b->idx].next[b->r] = ta;
955 d2d_cdt_edge_rot(&alpha, &ta);
956 d2d_cdt_edge_rot(&beta, &tb);
958 ta = cdt->edges[alpha.idx].next[alpha.r];
959 tb = cdt->edges[beta.idx].next[beta.r];
960 cdt->edges[alpha.idx].next[alpha.r] = tb;
961 cdt->edges[beta.idx].next[beta.r] = ta;
964 static BOOL d2d_cdt_create_edge(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *e)
966 struct d2d_cdt_edge *edge;
968 if (cdt->free_edge != ~0u)
970 e->idx = cdt->free_edge;
971 cdt->free_edge = cdt->edges[e->idx].next[D2D_EDGE_NEXT_ORIGIN].idx;
973 else
975 if (!d2d_array_reserve((void **)&cdt->edges, &cdt->edges_size, cdt->edge_count + 1, sizeof(*cdt->edges)))
977 ERR("Failed to grow edges array.\n");
978 return FALSE;
980 e->idx = cdt->edge_count++;
982 e->r = 0;
984 edge = &cdt->edges[e->idx];
985 edge->next[D2D_EDGE_NEXT_ORIGIN] = *e;
986 d2d_cdt_edge_tor(&edge->next[D2D_EDGE_NEXT_ROT], e);
987 d2d_cdt_edge_sym(&edge->next[D2D_EDGE_NEXT_SYM], e);
988 d2d_cdt_edge_rot(&edge->next[D2D_EDGE_NEXT_TOR], e);
989 edge->flags = 0;
991 return TRUE;
994 static void d2d_cdt_destroy_edge(struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
996 struct d2d_cdt_edge_ref next, sym, prev;
998 d2d_cdt_edge_next_origin(cdt, &next, e);
999 if (next.idx != e->idx || next.r != e->r)
1001 d2d_cdt_edge_prev_origin(cdt, &prev, e);
1002 d2d_cdt_splice(cdt, e, &prev);
1005 d2d_cdt_edge_sym(&sym, e);
1007 d2d_cdt_edge_next_origin(cdt, &next, &sym);
1008 if (next.idx != sym.idx || next.r != sym.r)
1010 d2d_cdt_edge_prev_origin(cdt, &prev, &sym);
1011 d2d_cdt_splice(cdt, &sym, &prev);
1014 cdt->edges[e->idx].flags |= D2D_CDT_EDGE_FLAG_FREED;
1015 cdt->edges[e->idx].next[D2D_EDGE_NEXT_ORIGIN].idx = cdt->free_edge;
1016 cdt->free_edge = e->idx;
1019 static BOOL d2d_cdt_connect(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *e,
1020 const struct d2d_cdt_edge_ref *a, const struct d2d_cdt_edge_ref *b)
1022 struct d2d_cdt_edge_ref tmp;
1024 if (!d2d_cdt_create_edge(cdt, e))
1025 return FALSE;
1026 d2d_cdt_edge_set_origin(cdt, e, d2d_cdt_edge_destination(cdt, a));
1027 d2d_cdt_edge_set_destination(cdt, e, d2d_cdt_edge_origin(cdt, b));
1028 d2d_cdt_edge_next_left(cdt, &tmp, a);
1029 d2d_cdt_splice(cdt, e, &tmp);
1030 d2d_cdt_edge_sym(&tmp, e);
1031 d2d_cdt_splice(cdt, &tmp, b);
1033 return TRUE;
1036 static BOOL d2d_cdt_merge(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *left_outer,
1037 struct d2d_cdt_edge_ref *left_inner, struct d2d_cdt_edge_ref *right_inner,
1038 struct d2d_cdt_edge_ref *right_outer)
1040 struct d2d_cdt_edge_ref base_edge, tmp;
1042 /* Create the base edge between both parts. */
1043 for (;;)
1045 if (d2d_cdt_leftof(cdt, d2d_cdt_edge_origin(cdt, right_inner), left_inner))
1047 d2d_cdt_edge_next_left(cdt, left_inner, left_inner);
1049 else if (d2d_cdt_rightof(cdt, d2d_cdt_edge_origin(cdt, left_inner), right_inner))
1051 d2d_cdt_edge_sym(&tmp, right_inner);
1052 d2d_cdt_edge_next_origin(cdt, right_inner, &tmp);
1054 else
1056 break;
1060 d2d_cdt_edge_sym(&tmp, right_inner);
1061 if (!d2d_cdt_connect(cdt, &base_edge, &tmp, left_inner))
1062 return FALSE;
1063 if (d2d_cdt_edge_origin(cdt, left_inner) == d2d_cdt_edge_origin(cdt, left_outer))
1064 d2d_cdt_edge_sym(left_outer, &base_edge);
1065 if (d2d_cdt_edge_origin(cdt, right_inner) == d2d_cdt_edge_origin(cdt, right_outer))
1066 *right_outer = base_edge;
1068 for (;;)
1070 struct d2d_cdt_edge_ref left_candidate, right_candidate, sym_base_edge;
1071 BOOL left_valid, right_valid;
1073 /* Find the left candidate. */
1074 d2d_cdt_edge_sym(&sym_base_edge, &base_edge);
1075 d2d_cdt_edge_next_origin(cdt, &left_candidate, &sym_base_edge);
1076 if ((left_valid = d2d_cdt_leftof(cdt, d2d_cdt_edge_destination(cdt, &left_candidate), &sym_base_edge)))
1078 d2d_cdt_edge_next_origin(cdt, &tmp, &left_candidate);
1079 while (d2d_cdt_edge_destination(cdt, &tmp) != d2d_cdt_edge_destination(cdt, &sym_base_edge)
1080 && d2d_cdt_incircle(cdt,
1081 d2d_cdt_edge_origin(cdt, &sym_base_edge), d2d_cdt_edge_destination(cdt, &sym_base_edge),
1082 d2d_cdt_edge_destination(cdt, &left_candidate), d2d_cdt_edge_destination(cdt, &tmp)))
1084 d2d_cdt_destroy_edge(cdt, &left_candidate);
1085 left_candidate = tmp;
1086 d2d_cdt_edge_next_origin(cdt, &tmp, &left_candidate);
1089 d2d_cdt_edge_sym(&left_candidate, &left_candidate);
1091 /* Find the right candidate. */
1092 d2d_cdt_edge_prev_origin(cdt, &right_candidate, &base_edge);
1093 if ((right_valid = d2d_cdt_rightof(cdt, d2d_cdt_edge_destination(cdt, &right_candidate), &base_edge)))
1095 d2d_cdt_edge_prev_origin(cdt, &tmp, &right_candidate);
1096 while (d2d_cdt_edge_destination(cdt, &tmp) != d2d_cdt_edge_destination(cdt, &base_edge)
1097 && d2d_cdt_incircle(cdt,
1098 d2d_cdt_edge_origin(cdt, &sym_base_edge), d2d_cdt_edge_destination(cdt, &sym_base_edge),
1099 d2d_cdt_edge_destination(cdt, &right_candidate), d2d_cdt_edge_destination(cdt, &tmp)))
1101 d2d_cdt_destroy_edge(cdt, &right_candidate);
1102 right_candidate = tmp;
1103 d2d_cdt_edge_prev_origin(cdt, &tmp, &right_candidate);
1107 if (!left_valid && !right_valid)
1108 break;
1110 /* Connect the appropriate candidate with the base edge. */
1111 if (!left_valid || (right_valid && d2d_cdt_incircle(cdt,
1112 d2d_cdt_edge_origin(cdt, &left_candidate), d2d_cdt_edge_destination(cdt, &left_candidate),
1113 d2d_cdt_edge_origin(cdt, &right_candidate), d2d_cdt_edge_destination(cdt, &right_candidate))))
1115 if (!d2d_cdt_connect(cdt, &base_edge, &right_candidate, &sym_base_edge))
1116 return FALSE;
1118 else
1120 if (!d2d_cdt_connect(cdt, &base_edge, &sym_base_edge, &left_candidate))
1121 return FALSE;
1125 return TRUE;
1128 /* Create a Delaunay triangulation from a set of vertices. This is an
1129 * implementation of the divide-and-conquer algorithm described by Guibas and
1130 * Stolfi. Should be called with at least two vertices. */
1131 static BOOL d2d_cdt_triangulate(struct d2d_cdt *cdt, size_t start_vertex, size_t vertex_count,
1132 struct d2d_cdt_edge_ref *left_edge, struct d2d_cdt_edge_ref *right_edge)
1134 struct d2d_cdt_edge_ref left_inner, left_outer, right_inner, right_outer, tmp;
1135 size_t cut;
1137 /* Only two vertices, create a single edge. */
1138 if (vertex_count == 2)
1140 struct d2d_cdt_edge_ref a;
1142 if (!d2d_cdt_create_edge(cdt, &a))
1143 return FALSE;
1144 d2d_cdt_edge_set_origin(cdt, &a, start_vertex);
1145 d2d_cdt_edge_set_destination(cdt, &a, start_vertex + 1);
1147 *left_edge = a;
1148 d2d_cdt_edge_sym(right_edge, &a);
1150 return TRUE;
1153 /* Three vertices, create a triangle. */
1154 if (vertex_count == 3)
1156 struct d2d_cdt_edge_ref a, b, c;
1157 float det;
1159 if (!d2d_cdt_create_edge(cdt, &a))
1160 return FALSE;
1161 if (!d2d_cdt_create_edge(cdt, &b))
1162 return FALSE;
1163 d2d_cdt_edge_sym(&tmp, &a);
1164 d2d_cdt_splice(cdt, &tmp, &b);
1166 d2d_cdt_edge_set_origin(cdt, &a, start_vertex);
1167 d2d_cdt_edge_set_destination(cdt, &a, start_vertex + 1);
1168 d2d_cdt_edge_set_origin(cdt, &b, start_vertex + 1);
1169 d2d_cdt_edge_set_destination(cdt, &b, start_vertex + 2);
1171 det = d2d_cdt_ccw(cdt, start_vertex, start_vertex + 1, start_vertex + 2);
1172 if (det != 0.0f && !d2d_cdt_connect(cdt, &c, &b, &a))
1173 return FALSE;
1175 if (det < 0.0f)
1177 d2d_cdt_edge_sym(left_edge, &c);
1178 *right_edge = c;
1180 else
1182 *left_edge = a;
1183 d2d_cdt_edge_sym(right_edge, &b);
1186 return TRUE;
1189 /* More than tree vertices, divide. */
1190 cut = vertex_count / 2;
1191 if (!d2d_cdt_triangulate(cdt, start_vertex, cut, &left_outer, &left_inner))
1192 return FALSE;
1193 if (!d2d_cdt_triangulate(cdt, start_vertex + cut, vertex_count - cut, &right_inner, &right_outer))
1194 return FALSE;
1195 /* Merge the left and right parts. */
1196 if (!d2d_cdt_merge(cdt, &left_outer, &left_inner, &right_inner, &right_outer))
1197 return FALSE;
1199 *left_edge = left_outer;
1200 *right_edge = right_outer;
1201 return TRUE;
1204 static int d2d_cdt_compare_vertices(const void *a, const void *b)
1206 const D2D1_POINT_2F *p0 = a;
1207 const D2D1_POINT_2F *p1 = b;
1208 float diff = p0->x - p1->x;
1210 if (diff == 0.0f)
1211 diff = p0->y - p1->y;
1213 return diff == 0.0f ? 0 : (diff > 0.0f ? 1 : -1);
1216 /* Determine whether a given point is inside the geometry, using the current
1217 * fill mode rule. */
1218 static BOOL d2d_path_geometry_point_inside(const struct d2d_geometry *geometry,
1219 const D2D1_POINT_2F *probe, BOOL triangles_only)
1221 const D2D1_POINT_2F *p0, *p1;
1222 D2D1_POINT_2F v_p, v_probe;
1223 unsigned int score;
1224 size_t i, j, last;
1226 for (i = 0, score = 0; i < geometry->u.path.figure_count; ++i)
1228 const struct d2d_figure *figure = &geometry->u.path.figures[i];
1230 if (probe->x < figure->bounds.left || probe->x > figure->bounds.right
1231 || probe->y < figure->bounds.top || probe->y > figure->bounds.bottom)
1232 continue;
1234 last = figure->vertex_count - 1;
1235 if (!triangles_only)
1237 while (last && figure->vertex_types[last] == D2D_VERTEX_TYPE_NONE)
1238 --last;
1240 p0 = &figure->vertices[last];
1241 for (j = 0; j <= last; ++j)
1243 if (!triangles_only && figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
1244 continue;
1246 p1 = &figure->vertices[j];
1247 d2d_point_subtract(&v_p, p1, p0);
1248 d2d_point_subtract(&v_probe, probe, p0);
1250 if ((probe->y < p0->y) != (probe->y < p1->y) && v_probe.x < v_p.x * (v_probe.y / v_p.y))
1252 if (geometry->u.path.fill_mode == D2D1_FILL_MODE_ALTERNATE || (probe->y < p0->y))
1253 ++score;
1254 else
1255 --score;
1258 p0 = p1;
1262 return geometry->u.path.fill_mode == D2D1_FILL_MODE_ALTERNATE ? score & 1 : score;
1265 static BOOL d2d_path_geometry_add_fill_face(struct d2d_geometry *geometry, const struct d2d_cdt *cdt,
1266 const struct d2d_cdt_edge_ref *base_edge)
1268 struct d2d_cdt_edge_ref tmp;
1269 struct d2d_face *face;
1270 D2D1_POINT_2F probe;
1272 if (cdt->edges[base_edge->idx].flags & D2D_CDT_EDGE_FLAG_VISITED(base_edge->r))
1273 return TRUE;
1275 if (!d2d_array_reserve((void **)&geometry->fill.faces, &geometry->fill.faces_size,
1276 geometry->fill.face_count + 1, sizeof(*geometry->fill.faces)))
1278 ERR("Failed to grow faces array.\n");
1279 return FALSE;
1282 face = &geometry->fill.faces[geometry->fill.face_count];
1284 /* It may seem tempting to use the center of the face as probe origin, but
1285 * multiplying by powers of two works much better for preserving accuracy. */
1287 tmp = *base_edge;
1288 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1289 face->v[0] = d2d_cdt_edge_origin(cdt, &tmp);
1290 probe.x = cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.25f;
1291 probe.y = cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.25f;
1293 d2d_cdt_edge_next_left(cdt, &tmp, &tmp);
1294 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1295 face->v[1] = d2d_cdt_edge_origin(cdt, &tmp);
1296 probe.x += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.25f;
1297 probe.y += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.25f;
1299 d2d_cdt_edge_next_left(cdt, &tmp, &tmp);
1300 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1301 face->v[2] = d2d_cdt_edge_origin(cdt, &tmp);
1302 probe.x += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.50f;
1303 probe.y += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.50f;
1305 if (d2d_cdt_leftof(cdt, face->v[2], base_edge) && d2d_path_geometry_point_inside(geometry, &probe, TRUE))
1306 ++geometry->fill.face_count;
1308 return TRUE;
1311 static BOOL d2d_cdt_generate_faces(const struct d2d_cdt *cdt, struct d2d_geometry *geometry)
1313 struct d2d_cdt_edge_ref base_edge;
1314 size_t i;
1316 for (i = 0; i < cdt->edge_count; ++i)
1318 if (cdt->edges[i].flags & D2D_CDT_EDGE_FLAG_FREED)
1319 continue;
1321 base_edge.idx = i;
1322 base_edge.r = 0;
1323 if (!d2d_path_geometry_add_fill_face(geometry, cdt, &base_edge))
1324 goto fail;
1325 d2d_cdt_edge_sym(&base_edge, &base_edge);
1326 if (!d2d_path_geometry_add_fill_face(geometry, cdt, &base_edge))
1327 goto fail;
1330 return TRUE;
1332 fail:
1333 HeapFree(GetProcessHeap(), 0, geometry->fill.faces);
1334 geometry->fill.faces = NULL;
1335 geometry->fill.faces_size = 0;
1336 geometry->fill.face_count = 0;
1337 return FALSE;
1340 static BOOL d2d_cdt_fixup(struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *base_edge)
1342 struct d2d_cdt_edge_ref candidate, next, new_base;
1343 unsigned int count = 0;
1345 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1346 if (next.idx == base_edge->idx)
1348 ERR("Degenerate face.\n");
1349 return FALSE;
1352 candidate = next;
1353 while (d2d_cdt_edge_destination(cdt, &next) != d2d_cdt_edge_origin(cdt, base_edge))
1355 if (d2d_cdt_incircle(cdt, d2d_cdt_edge_origin(cdt, base_edge), d2d_cdt_edge_destination(cdt, base_edge),
1356 d2d_cdt_edge_destination(cdt, &candidate), d2d_cdt_edge_destination(cdt, &next)))
1357 candidate = next;
1358 d2d_cdt_edge_next_left(cdt, &next, &next);
1359 ++count;
1362 if (count > 1)
1364 d2d_cdt_edge_next_left(cdt, &next, &candidate);
1365 if (d2d_cdt_edge_destination(cdt, &next) == d2d_cdt_edge_origin(cdt, base_edge))
1366 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1367 else
1368 next = *base_edge;
1369 if (!d2d_cdt_connect(cdt, &new_base, &candidate, &next))
1370 return FALSE;
1371 if (!d2d_cdt_fixup(cdt, &new_base))
1372 return FALSE;
1373 d2d_cdt_edge_sym(&new_base, &new_base);
1374 if (!d2d_cdt_fixup(cdt, &new_base))
1375 return FALSE;
1378 return TRUE;
1381 static void d2d_cdt_cut_edges(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *end_edge,
1382 const struct d2d_cdt_edge_ref *base_edge, size_t start_vertex, size_t end_vertex)
1384 struct d2d_cdt_edge_ref next;
1385 float ccw;
1387 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1388 if (d2d_cdt_edge_destination(cdt, &next) == end_vertex)
1390 *end_edge = next;
1391 return;
1394 ccw = d2d_cdt_ccw(cdt, d2d_cdt_edge_destination(cdt, &next), end_vertex, start_vertex);
1395 if (ccw == 0.0f)
1397 *end_edge = next;
1398 return;
1401 if (ccw > 0.0f)
1402 d2d_cdt_edge_next_left(cdt, &next, &next);
1404 d2d_cdt_edge_sym(&next, &next);
1405 d2d_cdt_cut_edges(cdt, end_edge, &next, start_vertex, end_vertex);
1406 d2d_cdt_destroy_edge(cdt, &next);
1409 static BOOL d2d_cdt_insert_segment(struct d2d_cdt *cdt, struct d2d_geometry *geometry,
1410 const struct d2d_cdt_edge_ref *origin, struct d2d_cdt_edge_ref *edge, size_t end_vertex)
1412 struct d2d_cdt_edge_ref base_edge, current, new_origin, next, target;
1413 size_t current_destination, current_origin;
1415 for (current = *origin;; current = next)
1417 d2d_cdt_edge_next_origin(cdt, &next, &current);
1419 current_destination = d2d_cdt_edge_destination(cdt, &current);
1420 if (current_destination == end_vertex)
1422 d2d_cdt_edge_sym(edge, &current);
1423 return TRUE;
1426 current_origin = d2d_cdt_edge_origin(cdt, &current);
1427 if (d2d_cdt_ccw(cdt, end_vertex, current_origin, current_destination) == 0.0f
1428 && (cdt->vertices[current_destination].x > cdt->vertices[current_origin].x)
1429 == (cdt->vertices[end_vertex].x > cdt->vertices[current_origin].x)
1430 && (cdt->vertices[current_destination].y > cdt->vertices[current_origin].y)
1431 == (cdt->vertices[end_vertex].y > cdt->vertices[current_origin].y))
1433 d2d_cdt_edge_sym(&new_origin, &current);
1434 return d2d_cdt_insert_segment(cdt, geometry, &new_origin, edge, end_vertex);
1437 if (d2d_cdt_rightof(cdt, end_vertex, &next) && d2d_cdt_leftof(cdt, end_vertex, &current))
1439 d2d_cdt_edge_next_left(cdt, &base_edge, &current);
1441 d2d_cdt_edge_sym(&base_edge, &base_edge);
1442 d2d_cdt_cut_edges(cdt, &target, &base_edge, d2d_cdt_edge_origin(cdt, origin), end_vertex);
1443 d2d_cdt_destroy_edge(cdt, &base_edge);
1445 if (!d2d_cdt_connect(cdt, &base_edge, &target, &current))
1446 return FALSE;
1447 *edge = base_edge;
1448 if (!d2d_cdt_fixup(cdt, &base_edge))
1449 return FALSE;
1450 d2d_cdt_edge_sym(&base_edge, &base_edge);
1451 if (!d2d_cdt_fixup(cdt, &base_edge))
1452 return FALSE;
1454 if (d2d_cdt_edge_origin(cdt, edge) == end_vertex)
1455 return TRUE;
1456 new_origin = *edge;
1457 return d2d_cdt_insert_segment(cdt, geometry, &new_origin, edge, end_vertex);
1460 if (next.idx == origin->idx)
1462 ERR("Triangle not found.\n");
1463 return FALSE;
1468 static BOOL d2d_cdt_insert_segments(struct d2d_cdt *cdt, struct d2d_geometry *geometry)
1470 size_t start_vertex, end_vertex, i, j, k;
1471 struct d2d_cdt_edge_ref edge, new_edge;
1472 const struct d2d_figure *figure;
1473 const D2D1_POINT_2F *p;
1474 BOOL found;
1476 for (i = 0; i < geometry->u.path.figure_count; ++i)
1478 figure = &geometry->u.path.figures[i];
1480 /* Degenerate figure. */
1481 if (figure->vertex_count < 2)
1482 continue;
1484 p = bsearch(&figure->vertices[figure->vertex_count - 1], cdt->vertices,
1485 geometry->fill.vertex_count, sizeof(*p), d2d_cdt_compare_vertices);
1486 start_vertex = p - cdt->vertices;
1488 for (k = 0, found = FALSE; k < cdt->edge_count; ++k)
1490 if (cdt->edges[k].flags & D2D_CDT_EDGE_FLAG_FREED)
1491 continue;
1493 edge.idx = k;
1494 edge.r = 0;
1496 if (d2d_cdt_edge_origin(cdt, &edge) == start_vertex)
1498 found = TRUE;
1499 break;
1501 d2d_cdt_edge_sym(&edge, &edge);
1502 if (d2d_cdt_edge_origin(cdt, &edge) == start_vertex)
1504 found = TRUE;
1505 break;
1509 if (!found)
1511 ERR("Edge not found.\n");
1512 return FALSE;
1515 for (j = 0; j < figure->vertex_count; start_vertex = end_vertex, ++j)
1517 p = bsearch(&figure->vertices[j], cdt->vertices,
1518 geometry->fill.vertex_count, sizeof(*p), d2d_cdt_compare_vertices);
1519 end_vertex = p - cdt->vertices;
1521 if (start_vertex == end_vertex)
1522 continue;
1524 if (!d2d_cdt_insert_segment(cdt, geometry, &edge, &new_edge, end_vertex))
1525 return FALSE;
1526 edge = new_edge;
1530 return TRUE;
1533 static BOOL d2d_geometry_intersections_add(struct d2d_geometry_intersections *i,
1534 size_t figure_idx, size_t segment_idx, float t, D2D1_POINT_2F p)
1536 struct d2d_geometry_intersection *intersection;
1538 if (!d2d_array_reserve((void **)&i->intersections, &i->intersections_size,
1539 i->intersection_count + 1, sizeof(*i->intersections)))
1541 ERR("Failed to grow intersections array.\n");
1542 return FALSE;
1545 intersection = &i->intersections[i->intersection_count++];
1546 intersection->figure_idx = figure_idx;
1547 intersection->segment_idx = segment_idx;
1548 intersection->t = t;
1549 intersection->p = p;
1551 return TRUE;
1554 static int d2d_geometry_intersections_compare(const void *a, const void *b)
1556 const struct d2d_geometry_intersection *i0 = a;
1557 const struct d2d_geometry_intersection *i1 = b;
1559 if (i0->figure_idx != i1->figure_idx)
1560 return i0->figure_idx - i1->figure_idx;
1561 if (i0->segment_idx != i1->segment_idx)
1562 return i0->segment_idx - i1->segment_idx;
1563 if (i0->t != i1->t)
1564 return i0->t > i1->t ? 1 : -1;
1565 return 0;
1568 /* Intersect the geometry's segments with themselves. This uses the
1569 * straightforward approach of testing everything against everything, but
1570 * there certainly exist more scalable algorithms for this. */
1571 /* FIXME: Beziers can't currently self-intersect. */
1572 static BOOL d2d_geometry_intersect_self(struct d2d_geometry *geometry)
1574 D2D1_POINT_2F p0, p1, q0, q1, v_p, v_q, v_qp, intersection;
1575 struct d2d_geometry_intersections intersections = {0};
1576 struct d2d_figure *figure_p, *figure_q;
1577 size_t i, j, k, l, max_l;
1578 BOOL ret = FALSE;
1579 float s, t, det;
1581 for (i = 0; i < geometry->u.path.figure_count; ++i)
1583 figure_p = &geometry->u.path.figures[i];
1584 p0 = figure_p->vertices[figure_p->vertex_count - 1];
1585 for (k = 0; k < figure_p->vertex_count; p0 = p1, ++k)
1587 p1 = figure_p->vertices[k];
1588 d2d_point_subtract(&v_p, &p1, &p0);
1589 for (j = 0; j < i || (j == i && k); ++j)
1591 figure_q = &geometry->u.path.figures[j];
1593 if (figure_p->bounds.left > figure_q->bounds.right
1594 || figure_q->bounds.left > figure_p->bounds.right
1595 || figure_p->bounds.top > figure_q->bounds.bottom
1596 || figure_q->bounds.top > figure_p->bounds.bottom)
1597 continue;
1599 max_l = j == i ? k - 1 : figure_q->vertex_count;
1600 q0 = figure_q->vertices[figure_q->vertex_count - 1];
1601 for (l = 0; l < max_l; q0 = q1, ++l)
1603 q1 = figure_q->vertices[l];
1604 d2d_point_subtract(&v_q, &q1, &q0);
1605 d2d_point_subtract(&v_qp, &p0, &q0);
1607 det = v_p.x * v_q.y - v_p.y * v_q.x;
1608 if (det == 0.0f)
1609 continue;
1611 s = (v_q.x * v_qp.y - v_q.y * v_qp.x) / det;
1612 t = (v_p.x * v_qp.y - v_p.y * v_qp.x) / det;
1614 if (s < 0.0f || s > 1.0f || t < 0.0f || t > 1.0f)
1615 continue;
1617 intersection.x = p0.x + v_p.x * s;
1618 intersection.y = p0.y + v_p.y * s;
1620 if (t > 0.0f && t < 1.0f
1621 && !d2d_geometry_intersections_add(&intersections, j, l, t, intersection))
1622 goto done;
1624 if (s > 0.0f && s < 1.0f
1625 && !d2d_geometry_intersections_add(&intersections, i, k, s, intersection))
1626 goto done;
1632 qsort(intersections.intersections, intersections.intersection_count,
1633 sizeof(*intersections.intersections), d2d_geometry_intersections_compare);
1634 for (i = 0; i < intersections.intersection_count; ++i)
1636 const struct d2d_geometry_intersection *inter = &intersections.intersections[i];
1638 if (!i || inter->figure_idx != intersections.intersections[i - 1].figure_idx)
1639 j = 0;
1641 if (!d2d_figure_insert_vertex(&geometry->u.path.figures[inter->figure_idx],
1642 inter->segment_idx + j, inter->p))
1643 goto done;
1644 ++j;
1647 ret = TRUE;
1649 done:
1650 HeapFree(GetProcessHeap(), 0, intersections.intersections);
1651 return ret;
1654 static HRESULT d2d_path_geometry_triangulate(struct d2d_geometry *geometry)
1656 struct d2d_cdt_edge_ref left_edge, right_edge;
1657 size_t vertex_count, i, j;
1658 struct d2d_cdt cdt = {0};
1659 D2D1_POINT_2F *vertices;
1661 for (i = 0, vertex_count = 0; i < geometry->u.path.figure_count; ++i)
1663 vertex_count += geometry->u.path.figures[i].vertex_count;
1666 if (vertex_count < 3)
1668 WARN("Geometry has %lu vertices.\n", (long)vertex_count);
1669 return S_OK;
1672 if (!(vertices = HeapAlloc(GetProcessHeap(), 0, vertex_count * sizeof(*vertices))))
1673 return E_OUTOFMEMORY;
1675 for (i = 0, j = 0; i < geometry->u.path.figure_count; ++i)
1677 memcpy(&vertices[j], geometry->u.path.figures[i].vertices,
1678 geometry->u.path.figures[i].vertex_count * sizeof(*vertices));
1679 j += geometry->u.path.figures[i].vertex_count;
1682 /* Sort vertices, eliminate duplicates. */
1683 qsort(vertices, vertex_count, sizeof(*vertices), d2d_cdt_compare_vertices);
1684 for (i = 1; i < vertex_count; ++i)
1686 if (!memcmp(&vertices[i - 1], &vertices[i], sizeof(*vertices)))
1688 --vertex_count;
1689 memmove(&vertices[i], &vertices[i + 1], (vertex_count - i) * sizeof(*vertices));
1690 --i;
1694 geometry->fill.vertices = vertices;
1695 geometry->fill.vertex_count = vertex_count;
1697 cdt.free_edge = ~0u;
1698 cdt.vertices = vertices;
1699 if (!d2d_cdt_triangulate(&cdt, 0, vertex_count, &left_edge, &right_edge))
1700 goto fail;
1701 if (!d2d_cdt_insert_segments(&cdt, geometry))
1702 goto fail;
1703 if (!d2d_cdt_generate_faces(&cdt, geometry))
1704 goto fail;
1706 HeapFree(GetProcessHeap(), 0, cdt.edges);
1707 return S_OK;
1709 fail:
1710 geometry->fill.vertices = NULL;
1711 geometry->fill.vertex_count = 0;
1712 HeapFree(GetProcessHeap(), 0, vertices);
1713 HeapFree(GetProcessHeap(), 0, cdt.edges);
1714 return E_FAIL;
1717 static BOOL d2d_path_geometry_add_figure(struct d2d_geometry *geometry)
1719 struct d2d_figure *figure;
1721 if (!d2d_array_reserve((void **)&geometry->u.path.figures, &geometry->u.path.figures_size,
1722 geometry->u.path.figure_count + 1, sizeof(*geometry->u.path.figures)))
1724 ERR("Failed to grow figures array.\n");
1725 return FALSE;
1728 figure = &geometry->u.path.figures[geometry->u.path.figure_count];
1729 memset(figure, 0, sizeof(*figure));
1730 figure->bounds.left = FLT_MAX;
1731 figure->bounds.top = FLT_MAX;
1732 figure->bounds.right = -FLT_MAX;
1733 figure->bounds.bottom = -FLT_MAX;
1735 ++geometry->u.path.figure_count;
1736 return TRUE;
1739 static BOOL d2d_geometry_outline_add_join(struct d2d_geometry *geometry,
1740 const D2D1_POINT_2F *prev, const D2D1_POINT_2F *p0, const D2D1_POINT_2F *next)
1742 D2D1_POINT_2F q_prev, q_next;
1743 struct d2d_outline_vertex *v;
1744 struct d2d_face *f;
1745 size_t base_idx;
1746 float ccw;
1748 if (!d2d_array_reserve((void **)&geometry->outline.vertices, &geometry->outline.vertices_size,
1749 geometry->outline.vertex_count + 4, sizeof(*geometry->outline.vertices)))
1751 ERR("Failed to grow outline vertices array.\n");
1752 return FALSE;
1754 base_idx = geometry->outline.vertex_count;
1755 v = &geometry->outline.vertices[base_idx];
1757 if (!d2d_array_reserve((void **)&geometry->outline.faces, &geometry->outline.faces_size,
1758 geometry->outline.face_count + 2, sizeof(*geometry->outline.faces)))
1760 ERR("Failed to grow outline faces array.\n");
1761 return FALSE;
1763 f = &geometry->outline.faces[geometry->outline.face_count];
1765 d2d_point_subtract(&q_prev, p0, prev);
1766 d2d_point_subtract(&q_next, next, p0);
1768 d2d_point_normalise(&q_prev);
1769 d2d_point_normalise(&q_next);
1771 ccw = d2d_point_ccw(p0, prev, next);
1772 if (ccw == 0.0f)
1774 d2d_outline_vertex_set(&v[0], p0->x, p0->y, q_prev.x, q_prev.y, q_prev.x, q_prev.y);
1775 d2d_outline_vertex_set(&v[1], p0->x, p0->y, -q_prev.x, -q_prev.y, -q_prev.x, -q_prev.y);
1776 d2d_outline_vertex_set(&v[2], p0->x + 25.0f * q_prev.x, p0->y + 25.0f * q_prev.y,
1777 -q_prev.x, -q_prev.y, -q_prev.x, -q_prev.y);
1778 d2d_outline_vertex_set(&v[3], p0->x + 25.0f * q_prev.x, p0->y + 25.0f * q_prev.y,
1779 q_prev.x, q_prev.y, q_prev.x, q_prev.y);
1781 else if (ccw < 0.0f)
1783 d2d_outline_vertex_set(&v[0], p0->x, p0->y, 0.0f, 0.0f, 0.0f, 0.0f);
1784 d2d_outline_vertex_set(&v[1], p0->x, p0->y, -q_next.x, -q_next.y, -q_next.x, -q_next.y);
1785 d2d_outline_vertex_set(&v[2], p0->x, p0->y, -q_next.x, -q_next.y, -q_prev.x, -q_prev.y);
1786 d2d_outline_vertex_set(&v[3], p0->x, p0->y, -q_prev.x, -q_prev.y, -q_prev.x, -q_prev.y);
1788 else
1790 d2d_outline_vertex_set(&v[0], p0->x, p0->y, 0.0f, 0.0f, 0.0f, 0.0f);
1791 d2d_outline_vertex_set(&v[1], p0->x, p0->y, q_prev.x, q_prev.y, q_prev.x, q_prev.y);
1792 d2d_outline_vertex_set(&v[2], p0->x, p0->y, q_prev.x, q_prev.y, q_next.x, q_next.y);
1793 d2d_outline_vertex_set(&v[3], p0->x, p0->y, q_next.x, q_next.y, q_next.x, q_next.y);
1795 geometry->outline.vertex_count += 4;
1797 d2d_face_set(&f[0], base_idx + 1, base_idx + 0, base_idx + 2);
1798 d2d_face_set(&f[1], base_idx + 2, base_idx + 0, base_idx + 3);
1799 geometry->outline.face_count += 2;
1801 return TRUE;
1804 static BOOL d2d_geometry_outline_add_line_segment(struct d2d_geometry *geometry,
1805 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *next)
1807 struct d2d_outline_vertex *v;
1808 D2D1_POINT_2F q_next;
1809 struct d2d_face *f;
1810 size_t base_idx;
1812 if (!d2d_array_reserve((void **)&geometry->outline.vertices, &geometry->outline.vertices_size,
1813 geometry->outline.vertex_count + 4, sizeof(*geometry->outline.vertices)))
1815 ERR("Failed to grow outline vertices array.\n");
1816 return FALSE;
1818 base_idx = geometry->outline.vertex_count;
1819 v = &geometry->outline.vertices[base_idx];
1821 if (!d2d_array_reserve((void **)&geometry->outline.faces, &geometry->outline.faces_size,
1822 geometry->outline.face_count + 2, sizeof(*geometry->outline.faces)))
1824 ERR("Failed to grow outline faces array.\n");
1825 return FALSE;
1827 f = &geometry->outline.faces[geometry->outline.face_count];
1829 d2d_point_subtract(&q_next, next, p0);
1830 d2d_point_normalise(&q_next);
1832 d2d_outline_vertex_set(&v[0], p0->x, p0->y, q_next.x, q_next.y, q_next.x, q_next.y);
1833 d2d_outline_vertex_set(&v[1], p0->x, p0->y, -q_next.x, -q_next.y, -q_next.x, -q_next.y);
1834 d2d_outline_vertex_set(&v[2], next->x, next->y, q_next.x, q_next.y, q_next.x, q_next.y);
1835 d2d_outline_vertex_set(&v[3], next->x, next->y, -q_next.x, -q_next.y, -q_next.x, -q_next.y);
1836 geometry->outline.vertex_count += 4;
1838 d2d_face_set(&f[0], base_idx + 0, base_idx + 1, base_idx + 2);
1839 d2d_face_set(&f[1], base_idx + 2, base_idx + 1, base_idx + 3);
1840 geometry->outline.face_count += 2;
1842 return TRUE;
1845 static BOOL d2d_geometry_add_figure_outline(struct d2d_geometry *geometry,
1846 struct d2d_figure *figure, D2D1_FIGURE_END figure_end)
1848 const D2D1_POINT_2F *prev, *p0, *next;
1849 enum d2d_vertex_type prev_type, type;
1850 size_t bezier_idx, i;
1852 for (i = 0, bezier_idx = 0; i < figure->vertex_count; ++i)
1854 type = figure->vertex_types[i];
1855 if (type == D2D_VERTEX_TYPE_NONE)
1856 continue;
1858 p0 = &figure->vertices[i];
1860 if (!i)
1862 prev_type = figure->vertex_types[figure->vertex_count - 1];
1863 if (prev_type == D2D_VERTEX_TYPE_BEZIER)
1864 prev = &figure->bezier_controls[figure->bezier_control_count - 1];
1865 else
1866 prev = &figure->vertices[figure->vertex_count - 1];
1868 else
1870 prev_type = figure->vertex_types[i - 1];
1871 if (prev_type == D2D_VERTEX_TYPE_BEZIER)
1872 prev = &figure->bezier_controls[bezier_idx - 1];
1873 else
1874 prev = &figure->vertices[i - 1];
1877 if (type == D2D_VERTEX_TYPE_BEZIER)
1878 next = &figure->bezier_controls[bezier_idx++];
1879 else if (i == figure->vertex_count - 1)
1880 next = &figure->vertices[0];
1881 else
1882 next = &figure->vertices[i + 1];
1884 if ((figure_end == D2D1_FIGURE_END_CLOSED || (i && i < figure->vertex_count - 1))
1885 && !d2d_geometry_outline_add_join(geometry, prev, p0, next))
1887 ERR("Failed to add join.\n");
1888 return FALSE;
1891 if (type == D2D_VERTEX_TYPE_LINE && (figure_end == D2D1_FIGURE_END_CLOSED || i < figure->vertex_count - 1)
1892 && !d2d_geometry_outline_add_line_segment(geometry, p0, next))
1894 ERR("Failed to add line segment.\n");
1895 return FALSE;
1899 return TRUE;
1902 static void d2d_geometry_cleanup(struct d2d_geometry *geometry)
1904 HeapFree(GetProcessHeap(), 0, geometry->outline.faces);
1905 HeapFree(GetProcessHeap(), 0, geometry->outline.vertices);
1906 HeapFree(GetProcessHeap(), 0, geometry->fill.bezier_vertices);
1907 HeapFree(GetProcessHeap(), 0, geometry->fill.faces);
1908 HeapFree(GetProcessHeap(), 0, geometry->fill.vertices);
1909 ID2D1Factory_Release(geometry->factory);
1912 static void d2d_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
1913 const D2D1_MATRIX_3X2_F *transform, const struct ID2D1GeometryVtbl *vtbl)
1915 geometry->ID2D1Geometry_iface.lpVtbl = vtbl;
1916 geometry->refcount = 1;
1917 ID2D1Factory_AddRef(geometry->factory = factory);
1918 geometry->transform = *transform;
1921 static inline struct d2d_geometry *impl_from_ID2D1GeometrySink(ID2D1GeometrySink *iface)
1923 return CONTAINING_RECORD(iface, struct d2d_geometry, u.path.ID2D1GeometrySink_iface);
1926 static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_QueryInterface(ID2D1GeometrySink *iface, REFIID iid, void **out)
1928 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
1930 if (IsEqualGUID(iid, &IID_ID2D1GeometrySink)
1931 || IsEqualGUID(iid, &IID_ID2D1SimplifiedGeometrySink)
1932 || IsEqualGUID(iid, &IID_IUnknown))
1934 ID2D1GeometrySink_AddRef(iface);
1935 *out = iface;
1936 return S_OK;
1939 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
1941 *out = NULL;
1942 return E_NOINTERFACE;
1945 static ULONG STDMETHODCALLTYPE d2d_geometry_sink_AddRef(ID2D1GeometrySink *iface)
1947 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1949 TRACE("iface %p.\n", iface);
1951 return ID2D1Geometry_AddRef(&geometry->ID2D1Geometry_iface);
1954 static ULONG STDMETHODCALLTYPE d2d_geometry_sink_Release(ID2D1GeometrySink *iface)
1956 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1958 TRACE("iface %p.\n", iface);
1960 return ID2D1Geometry_Release(&geometry->ID2D1Geometry_iface);
1963 static void STDMETHODCALLTYPE d2d_geometry_sink_SetFillMode(ID2D1GeometrySink *iface, D2D1_FILL_MODE mode)
1965 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1967 TRACE("iface %p, mode %#x.\n", iface, mode);
1969 geometry->u.path.fill_mode = mode;
1972 static void STDMETHODCALLTYPE d2d_geometry_sink_SetSegmentFlags(ID2D1GeometrySink *iface, D2D1_PATH_SEGMENT flags)
1974 FIXME("iface %p, flags %#x stub!\n", iface, flags);
1977 static void STDMETHODCALLTYPE d2d_geometry_sink_BeginFigure(ID2D1GeometrySink *iface,
1978 D2D1_POINT_2F start_point, D2D1_FIGURE_BEGIN figure_begin)
1980 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1982 TRACE("iface %p, start_point {%.8e, %.8e}, figure_begin %#x.\n",
1983 iface, start_point.x, start_point.y, figure_begin);
1985 if (geometry->u.path.state != D2D_GEOMETRY_STATE_OPEN)
1987 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1988 return;
1991 if (figure_begin != D2D1_FIGURE_BEGIN_FILLED)
1992 FIXME("Ignoring figure_begin %#x.\n", figure_begin);
1994 if (!d2d_path_geometry_add_figure(geometry))
1996 ERR("Failed to add figure.\n");
1997 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1998 return;
2001 if (!d2d_figure_add_vertex(&geometry->u.path.figures[geometry->u.path.figure_count - 1], start_point))
2003 ERR("Failed to add vertex.\n");
2004 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2005 return;
2008 geometry->u.path.state = D2D_GEOMETRY_STATE_FIGURE;
2009 ++geometry->u.path.segment_count;
2012 static void STDMETHODCALLTYPE d2d_geometry_sink_AddLines(ID2D1GeometrySink *iface,
2013 const D2D1_POINT_2F *points, UINT32 count)
2015 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2016 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2017 unsigned int i;
2019 TRACE("iface %p, points %p, count %u.\n", iface, points, count);
2021 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2023 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2024 return;
2027 for (i = 0; i < count; ++i)
2029 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_LINE;
2030 if (!d2d_figure_add_vertex(figure, points[i]))
2032 ERR("Failed to add vertex.\n");
2033 return;
2037 geometry->u.path.segment_count += count;
2040 static void STDMETHODCALLTYPE d2d_geometry_sink_AddBeziers(ID2D1GeometrySink *iface,
2041 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
2043 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2044 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2045 D2D1_POINT_2F p;
2046 unsigned int i;
2048 TRACE("iface %p, beziers %p, count %u.\n", iface, beziers, count);
2050 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2052 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2053 return;
2056 for (i = 0; i < count; ++i)
2058 /* FIXME: This tries to approximate a cubic bezier with a quadratic one. */
2059 p.x = (beziers[i].point1.x + beziers[i].point2.x) * 0.75f;
2060 p.y = (beziers[i].point1.y + beziers[i].point2.y) * 0.75f;
2061 p.x -= (figure->vertices[figure->vertex_count - 1].x + beziers[i].point3.x) * 0.25f;
2062 p.y -= (figure->vertices[figure->vertex_count - 1].y + beziers[i].point3.y) * 0.25f;
2063 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_BEZIER;
2065 if (!d2d_figure_add_bezier_control(figure, &p))
2067 ERR("Failed to add bezier control.\n");
2068 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2069 return;
2072 if (!d2d_figure_add_vertex(figure, beziers[i].point3))
2074 ERR("Failed to add bezier vertex.\n");
2075 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2076 return;
2080 geometry->u.path.segment_count += count;
2083 static void STDMETHODCALLTYPE d2d_geometry_sink_EndFigure(ID2D1GeometrySink *iface, D2D1_FIGURE_END figure_end)
2085 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2086 struct d2d_figure *figure;
2088 TRACE("iface %p, figure_end %#x.\n", iface, figure_end);
2090 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2092 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2093 return;
2096 figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2097 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_LINE;
2098 if (figure_end == D2D1_FIGURE_END_CLOSED && !memcmp(&figure->vertices[0],
2099 &figure->vertices[figure->vertex_count - 1], sizeof(*figure->vertices)))
2100 --figure->vertex_count;
2102 if (!d2d_geometry_add_figure_outline(geometry, figure, figure_end))
2104 ERR("Failed to add figure outline.\n");
2105 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2106 return;
2109 geometry->u.path.state = D2D_GEOMETRY_STATE_OPEN;
2112 static void d2d_path_geometry_free_figures(struct d2d_geometry *geometry)
2114 size_t i;
2116 if (!geometry->u.path.figures)
2117 return;
2119 for (i = 0; i < geometry->u.path.figure_count; ++i)
2121 HeapFree(GetProcessHeap(), 0, geometry->u.path.figures[i].bezier_controls);
2122 HeapFree(GetProcessHeap(), 0, geometry->u.path.figures[i].vertices);
2124 HeapFree(GetProcessHeap(), 0, geometry->u.path.figures);
2125 geometry->u.path.figures = NULL;
2126 geometry->u.path.figures_size = 0;
2129 static HRESULT d2d_geometry_resolve_beziers(struct d2d_geometry *geometry)
2131 size_t bezier_idx, control_idx, i, j;
2133 for (i = 0; i < geometry->u.path.figure_count; ++i)
2135 geometry->fill.bezier_vertex_count += 3 * geometry->u.path.figures[i].bezier_control_count;
2138 if (!(geometry->fill.bezier_vertices = HeapAlloc(GetProcessHeap(), 0,
2139 geometry->fill.bezier_vertex_count * sizeof(*geometry->fill.bezier_vertices))))
2141 ERR("Failed to allocate bezier vertices array.\n");
2142 geometry->fill.bezier_vertex_count = 0;
2143 return E_OUTOFMEMORY;
2146 for (i = 0, bezier_idx = 0; i < geometry->u.path.figure_count; ++i)
2148 struct d2d_figure *figure = &geometry->u.path.figures[i];
2149 if (figure->bezier_control_count)
2151 for (j = 0, control_idx = 0; j < figure->vertex_count; ++j)
2153 const D2D1_POINT_2F *p0, *p1, *p2;
2154 struct d2d_bezier_vertex *b;
2155 float sign = -1.0f;
2157 if (figure->vertex_types[j] != D2D_VERTEX_TYPE_BEZIER)
2158 continue;
2160 b = &geometry->fill.bezier_vertices[bezier_idx * 3];
2161 p0 = &figure->vertices[j];
2162 p1 = &figure->bezier_controls[control_idx++];
2164 if (d2d_path_geometry_point_inside(geometry, p1, FALSE))
2166 sign = 1.0f;
2167 d2d_figure_insert_vertex(figure, j + 1, *p1);
2168 /* Inserting a vertex potentially invalidates p0. */
2169 p0 = &figure->vertices[j];
2170 ++j;
2173 if (j == figure->vertex_count - 1)
2174 p2 = &figure->vertices[0];
2175 else
2176 p2 = &figure->vertices[j + 1];
2178 d2d_bezier_vertex_set(&b[0], p0, 0.0f, 0.0f, sign);
2179 d2d_bezier_vertex_set(&b[1], p1, 0.5f, 0.0f, sign);
2180 d2d_bezier_vertex_set(&b[2], p2, 1.0f, 1.0f, sign);
2181 ++bezier_idx;
2186 return TRUE;
2189 static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_Close(ID2D1GeometrySink *iface)
2191 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2192 HRESULT hr = E_FAIL;
2194 TRACE("iface %p.\n", iface);
2196 if (geometry->u.path.state != D2D_GEOMETRY_STATE_OPEN)
2198 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
2199 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2200 return D2DERR_WRONG_STATE;
2202 geometry->u.path.state = D2D_GEOMETRY_STATE_CLOSED;
2204 if (!d2d_geometry_intersect_self(geometry))
2205 goto done;
2206 if (FAILED(hr = d2d_geometry_resolve_beziers(geometry)))
2207 goto done;
2208 if (FAILED(hr = d2d_path_geometry_triangulate(geometry)))
2209 goto done;
2211 done:
2212 if (FAILED(hr))
2214 HeapFree(GetProcessHeap(), 0, geometry->fill.bezier_vertices);
2215 geometry->fill.bezier_vertex_count = 0;
2216 d2d_path_geometry_free_figures(geometry);
2217 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2219 return hr;
2222 static void STDMETHODCALLTYPE d2d_geometry_sink_AddLine(ID2D1GeometrySink *iface, D2D1_POINT_2F point)
2224 TRACE("iface %p, point {%.8e, %.8e}.\n", iface, point.x, point.y);
2226 d2d_geometry_sink_AddLines(iface, &point, 1);
2229 static void STDMETHODCALLTYPE d2d_geometry_sink_AddBezier(ID2D1GeometrySink *iface, const D2D1_BEZIER_SEGMENT *bezier)
2231 TRACE("iface %p, bezier %p.\n", iface, bezier);
2233 d2d_geometry_sink_AddBeziers(iface, bezier, 1);
2236 static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBezier(ID2D1GeometrySink *iface,
2237 const D2D1_QUADRATIC_BEZIER_SEGMENT *bezier)
2239 TRACE("iface %p, bezier %p.\n", iface, bezier);
2241 ID2D1GeometrySink_AddQuadraticBeziers(iface, bezier, 1);
2244 static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBeziers(ID2D1GeometrySink *iface,
2245 const D2D1_QUADRATIC_BEZIER_SEGMENT *beziers, UINT32 bezier_count)
2247 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2248 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2249 unsigned int i;
2251 TRACE("iface %p, beziers %p, bezier_count %u.\n", iface, beziers, bezier_count);
2253 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2255 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2256 return;
2259 for (i = 0; i < bezier_count; ++i)
2261 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_BEZIER;
2262 if (!d2d_figure_add_bezier_control(figure, &beziers[i].point1))
2264 ERR("Failed to add bezier.\n");
2265 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2266 return;
2269 if (!d2d_figure_add_vertex(figure, beziers[i].point2))
2271 ERR("Failed to add bezier vertex.\n");
2272 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2273 return;
2277 geometry->u.path.segment_count += bezier_count;
2280 static void STDMETHODCALLTYPE d2d_geometry_sink_AddArc(ID2D1GeometrySink *iface, const D2D1_ARC_SEGMENT *arc)
2282 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2284 FIXME("iface %p, arc %p stub!\n", iface, arc);
2286 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2288 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2289 return;
2292 if (!d2d_figure_add_vertex(&geometry->u.path.figures[geometry->u.path.figure_count - 1], arc->point))
2294 ERR("Failed to add vertex.\n");
2295 return;
2298 ++geometry->u.path.segment_count;
2301 static const struct ID2D1GeometrySinkVtbl d2d_geometry_sink_vtbl =
2303 d2d_geometry_sink_QueryInterface,
2304 d2d_geometry_sink_AddRef,
2305 d2d_geometry_sink_Release,
2306 d2d_geometry_sink_SetFillMode,
2307 d2d_geometry_sink_SetSegmentFlags,
2308 d2d_geometry_sink_BeginFigure,
2309 d2d_geometry_sink_AddLines,
2310 d2d_geometry_sink_AddBeziers,
2311 d2d_geometry_sink_EndFigure,
2312 d2d_geometry_sink_Close,
2313 d2d_geometry_sink_AddLine,
2314 d2d_geometry_sink_AddBezier,
2315 d2d_geometry_sink_AddQuadraticBezier,
2316 d2d_geometry_sink_AddQuadraticBeziers,
2317 d2d_geometry_sink_AddArc,
2320 static inline struct d2d_geometry *impl_from_ID2D1PathGeometry(ID2D1PathGeometry *iface)
2322 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
2325 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_QueryInterface(ID2D1PathGeometry *iface, REFIID iid, void **out)
2327 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
2329 if (IsEqualGUID(iid, &IID_ID2D1PathGeometry)
2330 || IsEqualGUID(iid, &IID_ID2D1Geometry)
2331 || IsEqualGUID(iid, &IID_ID2D1Resource)
2332 || IsEqualGUID(iid, &IID_IUnknown))
2334 ID2D1PathGeometry_AddRef(iface);
2335 *out = iface;
2336 return S_OK;
2339 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
2341 *out = NULL;
2342 return E_NOINTERFACE;
2345 static ULONG STDMETHODCALLTYPE d2d_path_geometry_AddRef(ID2D1PathGeometry *iface)
2347 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2348 ULONG refcount = InterlockedIncrement(&geometry->refcount);
2350 TRACE("%p increasing refcount to %u.\n", iface, refcount);
2352 return refcount;
2355 static ULONG STDMETHODCALLTYPE d2d_path_geometry_Release(ID2D1PathGeometry *iface)
2357 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2358 ULONG refcount = InterlockedDecrement(&geometry->refcount);
2360 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
2362 if (!refcount)
2364 d2d_path_geometry_free_figures(geometry);
2365 d2d_geometry_cleanup(geometry);
2366 HeapFree(GetProcessHeap(), 0, geometry);
2369 return refcount;
2372 static void STDMETHODCALLTYPE d2d_path_geometry_GetFactory(ID2D1PathGeometry *iface, ID2D1Factory **factory)
2374 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2376 TRACE("iface %p, factory %p.\n", iface, factory);
2378 ID2D1Factory_AddRef(*factory = geometry->factory);
2381 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetBounds(ID2D1PathGeometry *iface,
2382 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
2384 FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
2386 return E_NOTIMPL;
2389 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetWidenedBounds(ID2D1PathGeometry *iface, float stroke_width,
2390 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_RECT_F *bounds)
2392 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
2393 iface, stroke_width, stroke_style, transform, tolerance, bounds);
2395 return E_NOTIMPL;
2398 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_StrokeContainsPoint(ID2D1PathGeometry *iface,
2399 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
2400 float tolerance, BOOL *contains)
2402 FIXME("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
2403 "transform %p, tolerance %.8e, contains %p stub!\n",
2404 iface, point.x, point.y, stroke_width, stroke_style, transform, tolerance, contains);
2406 return E_NOTIMPL;
2409 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_FillContainsPoint(ID2D1PathGeometry *iface,
2410 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
2412 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2413 D2D1_MATRIX_3X2_F g_i;
2415 TRACE("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p.\n",
2416 iface, point.x, point.y, transform, tolerance, contains);
2418 if (transform)
2420 if (!d2d_matrix_invert(&g_i, transform))
2421 return D2DERR_UNSUPPORTED_OPERATION;
2422 d2d_point_transform(&point, &g_i, point.x, point.y);
2425 *contains = !!d2d_path_geometry_point_inside(geometry, &point, FALSE);
2427 TRACE("-> %#x.\n", *contains);
2429 return S_OK;
2432 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_CompareWithGeometry(ID2D1PathGeometry *iface,
2433 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
2435 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
2436 iface, geometry, transform, tolerance, relation);
2438 return E_NOTIMPL;
2441 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *iface,
2442 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
2443 ID2D1SimplifiedGeometrySink *sink)
2445 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2446 iface, option, transform, tolerance, sink);
2448 return E_NOTIMPL;
2451 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Tessellate(ID2D1PathGeometry *iface,
2452 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
2454 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
2456 return E_NOTIMPL;
2459 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_CombineWithGeometry(ID2D1PathGeometry *iface,
2460 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
2461 float tolerance, ID2D1SimplifiedGeometrySink *sink)
2463 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2464 iface, geometry, combine_mode, transform, tolerance, sink);
2466 return E_NOTIMPL;
2469 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Outline(ID2D1PathGeometry *iface,
2470 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
2472 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
2474 return E_NOTIMPL;
2477 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeArea(ID2D1PathGeometry *iface,
2478 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
2480 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
2482 return E_NOTIMPL;
2485 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeLength(ID2D1PathGeometry *iface,
2486 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
2488 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
2490 return E_NOTIMPL;
2493 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputePointAtLength(ID2D1PathGeometry *iface, float length,
2494 const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point, D2D1_POINT_2F *tangent)
2496 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
2497 iface, length, transform, tolerance, point, tangent);
2499 return E_NOTIMPL;
2502 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Widen(ID2D1PathGeometry *iface, float stroke_width,
2503 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
2504 ID2D1SimplifiedGeometrySink *sink)
2506 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
2507 iface, stroke_width, stroke_style, transform, tolerance, sink);
2509 return E_NOTIMPL;
2512 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Open(ID2D1PathGeometry *iface, ID2D1GeometrySink **sink)
2514 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2516 TRACE("iface %p, sink %p.\n", iface, sink);
2518 if (geometry->u.path.state != D2D_GEOMETRY_STATE_INITIAL)
2519 return D2DERR_WRONG_STATE;
2521 *sink = &geometry->u.path.ID2D1GeometrySink_iface;
2522 ID2D1GeometrySink_AddRef(*sink);
2524 geometry->u.path.state = D2D_GEOMETRY_STATE_OPEN;
2526 return S_OK;
2529 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Stream(ID2D1PathGeometry *iface, ID2D1GeometrySink *sink)
2531 FIXME("iface %p, sink %p stub!\n", iface, sink);
2533 return E_NOTIMPL;
2536 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetSegmentCount(ID2D1PathGeometry *iface, UINT32 *count)
2538 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2540 TRACE("iface %p, count %p.\n", iface, count);
2542 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
2543 return D2DERR_WRONG_STATE;
2545 *count = geometry->u.path.segment_count;
2547 return S_OK;
2550 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetFigureCount(ID2D1PathGeometry *iface, UINT32 *count)
2552 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2554 TRACE("iface %p, count %p.\n", iface, count);
2556 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
2557 return D2DERR_WRONG_STATE;
2559 *count = geometry->u.path.figure_count;
2561 return S_OK;
2564 static const struct ID2D1PathGeometryVtbl d2d_path_geometry_vtbl =
2566 d2d_path_geometry_QueryInterface,
2567 d2d_path_geometry_AddRef,
2568 d2d_path_geometry_Release,
2569 d2d_path_geometry_GetFactory,
2570 d2d_path_geometry_GetBounds,
2571 d2d_path_geometry_GetWidenedBounds,
2572 d2d_path_geometry_StrokeContainsPoint,
2573 d2d_path_geometry_FillContainsPoint,
2574 d2d_path_geometry_CompareWithGeometry,
2575 d2d_path_geometry_Simplify,
2576 d2d_path_geometry_Tessellate,
2577 d2d_path_geometry_CombineWithGeometry,
2578 d2d_path_geometry_Outline,
2579 d2d_path_geometry_ComputeArea,
2580 d2d_path_geometry_ComputeLength,
2581 d2d_path_geometry_ComputePointAtLength,
2582 d2d_path_geometry_Widen,
2583 d2d_path_geometry_Open,
2584 d2d_path_geometry_Stream,
2585 d2d_path_geometry_GetSegmentCount,
2586 d2d_path_geometry_GetFigureCount,
2589 void d2d_path_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory)
2591 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl);
2592 geometry->u.path.ID2D1GeometrySink_iface.lpVtbl = &d2d_geometry_sink_vtbl;
2595 static inline struct d2d_geometry *impl_from_ID2D1RectangleGeometry(ID2D1RectangleGeometry *iface)
2597 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
2600 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_QueryInterface(ID2D1RectangleGeometry *iface,
2601 REFIID iid, void **out)
2603 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
2605 if (IsEqualGUID(iid, &IID_ID2D1RectangleGeometry)
2606 || IsEqualGUID(iid, &IID_ID2D1Geometry)
2607 || IsEqualGUID(iid, &IID_ID2D1Resource)
2608 || IsEqualGUID(iid, &IID_IUnknown))
2610 ID2D1RectangleGeometry_AddRef(iface);
2611 *out = iface;
2612 return S_OK;
2615 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
2617 *out = NULL;
2618 return E_NOINTERFACE;
2621 static ULONG STDMETHODCALLTYPE d2d_rectangle_geometry_AddRef(ID2D1RectangleGeometry *iface)
2623 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
2624 ULONG refcount = InterlockedIncrement(&geometry->refcount);
2626 TRACE("%p increasing refcount to %u.\n", iface, refcount);
2628 return refcount;
2631 static ULONG STDMETHODCALLTYPE d2d_rectangle_geometry_Release(ID2D1RectangleGeometry *iface)
2633 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
2634 ULONG refcount = InterlockedDecrement(&geometry->refcount);
2636 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
2638 if (!refcount)
2640 d2d_geometry_cleanup(geometry);
2641 HeapFree(GetProcessHeap(), 0, geometry);
2644 return refcount;
2647 static void STDMETHODCALLTYPE d2d_rectangle_geometry_GetFactory(ID2D1RectangleGeometry *iface, ID2D1Factory **factory)
2649 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
2651 TRACE("iface %p, factory %p.\n", iface, factory);
2653 ID2D1Factory_AddRef(*factory = geometry->factory);
2656 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_GetBounds(ID2D1RectangleGeometry *iface,
2657 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
2659 FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
2661 return E_NOTIMPL;
2664 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_GetWidenedBounds(ID2D1RectangleGeometry *iface,
2665 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
2666 float tolerance, D2D1_RECT_F *bounds)
2668 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
2669 iface, stroke_width, stroke_style, transform, tolerance, bounds);
2671 return E_NOTIMPL;
2674 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_StrokeContainsPoint(ID2D1RectangleGeometry *iface,
2675 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
2676 float tolerance, BOOL *contains)
2678 FIXME("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
2679 "transform %p, tolerance %.8e, contains %p stub!\n",
2680 iface, point.x, point.y, stroke_width, stroke_style, transform, tolerance, contains);
2682 return E_NOTIMPL;
2685 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_FillContainsPoint(ID2D1RectangleGeometry *iface,
2686 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
2688 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
2689 D2D1_RECT_F *rect = &geometry->u.rectangle.rect;
2690 float dx, dy;
2692 TRACE("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p.\n",
2693 iface, point.x, point.y, transform, tolerance, contains);
2695 if (transform)
2697 D2D1_MATRIX_3X2_F g_i;
2699 if (!d2d_matrix_invert(&g_i, transform))
2700 return D2DERR_UNSUPPORTED_OPERATION;
2701 d2d_point_transform(&point, &g_i, point.x, point.y);
2704 if (tolerance == 0.0f)
2705 tolerance = D2D1_DEFAULT_FLATTENING_TOLERANCE;
2707 dx = max(fabsf((rect->right + rect->left) / 2.0f - point.x) - (rect->right - rect->left) / 2.0f, 0.0f);
2708 dy = max(fabsf((rect->bottom + rect->top) / 2.0f - point.y) - (rect->bottom - rect->top) / 2.0f, 0.0f);
2710 *contains = tolerance * tolerance > (dx * dx + dy * dy);
2711 return S_OK;
2714 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_CompareWithGeometry(ID2D1RectangleGeometry *iface,
2715 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
2717 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
2718 iface, geometry, transform, tolerance, relation);
2720 return E_NOTIMPL;
2723 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Simplify(ID2D1RectangleGeometry *iface,
2724 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
2725 ID2D1SimplifiedGeometrySink *sink)
2727 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2728 iface, option, transform, tolerance, sink);
2730 return E_NOTIMPL;
2733 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Tessellate(ID2D1RectangleGeometry *iface,
2734 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
2736 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
2738 return E_NOTIMPL;
2741 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_CombineWithGeometry(ID2D1RectangleGeometry *iface,
2742 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
2743 float tolerance, ID2D1SimplifiedGeometrySink *sink)
2745 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2746 iface, geometry, combine_mode, transform, tolerance, sink);
2748 return E_NOTIMPL;
2751 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Outline(ID2D1RectangleGeometry *iface,
2752 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
2754 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
2756 return E_NOTIMPL;
2759 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputeArea(ID2D1RectangleGeometry *iface,
2760 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
2762 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
2764 return E_NOTIMPL;
2767 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputeLength(ID2D1RectangleGeometry *iface,
2768 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
2770 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
2772 return E_NOTIMPL;
2775 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputePointAtLength(ID2D1RectangleGeometry *iface,
2776 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
2777 D2D1_POINT_2F *tangent)
2779 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
2780 iface, length, transform, tolerance, point, tangent);
2782 return E_NOTIMPL;
2785 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Widen(ID2D1RectangleGeometry *iface, float stroke_width,
2786 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
2787 ID2D1SimplifiedGeometrySink *sink)
2789 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
2790 iface, stroke_width, stroke_style, transform, tolerance, sink);
2792 return E_NOTIMPL;
2795 static void STDMETHODCALLTYPE d2d_rectangle_geometry_GetRect(ID2D1RectangleGeometry *iface, D2D1_RECT_F *rect)
2797 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
2799 TRACE("iface %p, rect %p.\n", iface, rect);
2801 *rect = geometry->u.rectangle.rect;
2804 static const struct ID2D1RectangleGeometryVtbl d2d_rectangle_geometry_vtbl =
2806 d2d_rectangle_geometry_QueryInterface,
2807 d2d_rectangle_geometry_AddRef,
2808 d2d_rectangle_geometry_Release,
2809 d2d_rectangle_geometry_GetFactory,
2810 d2d_rectangle_geometry_GetBounds,
2811 d2d_rectangle_geometry_GetWidenedBounds,
2812 d2d_rectangle_geometry_StrokeContainsPoint,
2813 d2d_rectangle_geometry_FillContainsPoint,
2814 d2d_rectangle_geometry_CompareWithGeometry,
2815 d2d_rectangle_geometry_Simplify,
2816 d2d_rectangle_geometry_Tessellate,
2817 d2d_rectangle_geometry_CombineWithGeometry,
2818 d2d_rectangle_geometry_Outline,
2819 d2d_rectangle_geometry_ComputeArea,
2820 d2d_rectangle_geometry_ComputeLength,
2821 d2d_rectangle_geometry_ComputePointAtLength,
2822 d2d_rectangle_geometry_Widen,
2823 d2d_rectangle_geometry_GetRect,
2826 HRESULT d2d_rectangle_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_RECT_F *rect)
2828 struct d2d_face *f;
2829 D2D1_POINT_2F *v;
2830 float l, r, t, b;
2832 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl);
2833 geometry->u.rectangle.rect = *rect;
2835 if (!(geometry->fill.vertices = HeapAlloc(GetProcessHeap(), 0, 4 * sizeof(*geometry->fill.vertices))))
2836 goto fail;
2837 if (!d2d_array_reserve((void **)&geometry->fill.faces,
2838 &geometry->fill.faces_size, 2, sizeof(*geometry->fill.faces)))
2839 goto fail;
2841 l = min(rect->left, rect->right);
2842 r = max(rect->left, rect->right);
2843 t = min(rect->top, rect->bottom);
2844 b = max(rect->top, rect->bottom);
2846 v = geometry->fill.vertices;
2847 d2d_point_set(&v[0], l, t);
2848 d2d_point_set(&v[1], l, b);
2849 d2d_point_set(&v[2], r, b);
2850 d2d_point_set(&v[3], r, t);
2851 geometry->fill.vertex_count = 4;
2853 f = geometry->fill.faces;
2854 d2d_face_set(&f[0], 1, 2, 0);
2855 d2d_face_set(&f[1], 0, 2, 3);
2856 geometry->fill.face_count = 2;
2858 if (!d2d_geometry_outline_add_line_segment(geometry, &v[0], &v[1]))
2859 goto fail;
2860 if (!d2d_geometry_outline_add_line_segment(geometry, &v[1], &v[2]))
2861 goto fail;
2862 if (!d2d_geometry_outline_add_line_segment(geometry, &v[2], &v[3]))
2863 goto fail;
2864 if (!d2d_geometry_outline_add_line_segment(geometry, &v[3], &v[0]))
2865 goto fail;
2867 if (!d2d_geometry_outline_add_join(geometry, &v[3], &v[0], &v[1]))
2868 goto fail;
2869 if (!d2d_geometry_outline_add_join(geometry, &v[0], &v[1], &v[2]))
2870 goto fail;
2871 if (!d2d_geometry_outline_add_join(geometry, &v[1], &v[2], &v[3]))
2872 goto fail;
2873 if (!d2d_geometry_outline_add_join(geometry, &v[2], &v[3], &v[0]))
2874 goto fail;
2876 return S_OK;
2878 fail:
2879 d2d_geometry_cleanup(geometry);
2880 return E_OUTOFMEMORY;
2883 static inline struct d2d_geometry *impl_from_ID2D1TransformedGeometry(ID2D1TransformedGeometry *iface)
2885 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
2888 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_QueryInterface(ID2D1TransformedGeometry *iface,
2889 REFIID iid, void **out)
2891 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
2893 if (IsEqualGUID(iid, &IID_ID2D1TransformedGeometry)
2894 || IsEqualGUID(iid, &IID_ID2D1Geometry)
2895 || IsEqualGUID(iid, &IID_ID2D1Resource)
2896 || IsEqualGUID(iid, &IID_IUnknown))
2898 ID2D1TransformedGeometry_AddRef(iface);
2899 *out = iface;
2900 return S_OK;
2903 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
2905 *out = NULL;
2906 return E_NOINTERFACE;
2909 static ULONG STDMETHODCALLTYPE d2d_transformed_geometry_AddRef(ID2D1TransformedGeometry *iface)
2911 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
2912 ULONG refcount = InterlockedIncrement(&geometry->refcount);
2914 TRACE("%p increasing refcount to %u.\n", iface, refcount);
2916 return refcount;
2919 static ULONG STDMETHODCALLTYPE d2d_transformed_geometry_Release(ID2D1TransformedGeometry *iface)
2921 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
2922 ULONG refcount = InterlockedDecrement(&geometry->refcount);
2924 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
2926 if (!refcount)
2928 geometry->outline.faces = NULL;
2929 geometry->outline.vertices = NULL;
2930 geometry->fill.bezier_vertices = NULL;
2931 geometry->fill.faces = NULL;
2932 geometry->fill.vertices = NULL;
2933 ID2D1Geometry_Release(geometry->u.transformed.src_geometry);
2934 d2d_geometry_cleanup(geometry);
2935 HeapFree(GetProcessHeap(), 0, geometry);
2938 return refcount;
2941 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetFactory(ID2D1TransformedGeometry *iface,
2942 ID2D1Factory **factory)
2944 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
2946 TRACE("iface %p, factory %p.\n", iface, factory);
2948 ID2D1Factory_AddRef(*factory = geometry->factory);
2951 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_GetBounds(ID2D1TransformedGeometry *iface,
2952 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
2954 FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
2956 return E_NOTIMPL;
2959 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_GetWidenedBounds(ID2D1TransformedGeometry *iface,
2960 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
2961 float tolerance, D2D1_RECT_F *bounds)
2963 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
2964 iface, stroke_width, stroke_style, transform, tolerance, bounds);
2966 return E_NOTIMPL;
2969 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_StrokeContainsPoint(ID2D1TransformedGeometry *iface,
2970 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
2971 float tolerance, BOOL *contains)
2973 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
2974 D2D1_MATRIX_3X2_F g;
2976 TRACE("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
2977 "transform %p, tolerance %.8e, contains %p.\n",
2978 iface, point.x, point.y, stroke_width, stroke_style, transform, tolerance, contains);
2980 g = geometry->transform;
2981 if (transform)
2982 d2d_matrix_multiply(&g, transform);
2984 return ID2D1Geometry_StrokeContainsPoint(geometry->u.transformed.src_geometry, point, stroke_width, stroke_style,
2985 &g, tolerance, contains);
2988 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_FillContainsPoint(ID2D1TransformedGeometry *iface,
2989 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
2991 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
2992 D2D1_MATRIX_3X2_F g;
2994 TRACE("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p.\n",
2995 iface, point.x, point.y, transform, tolerance, contains);
2997 g = geometry->transform;
2998 if (transform)
2999 d2d_matrix_multiply(&g, transform);
3001 return ID2D1Geometry_FillContainsPoint(geometry->u.transformed.src_geometry, point, &g, tolerance, contains);
3004 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_CompareWithGeometry(ID2D1TransformedGeometry *iface,
3005 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
3007 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
3008 iface, geometry, transform, tolerance, relation);
3010 return E_NOTIMPL;
3013 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Simplify(ID2D1TransformedGeometry *iface,
3014 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
3015 ID2D1SimplifiedGeometrySink *sink)
3017 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
3018 iface, option, transform, tolerance, sink);
3020 return E_NOTIMPL;
3023 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Tessellate(ID2D1TransformedGeometry *iface,
3024 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
3026 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
3028 return E_NOTIMPL;
3031 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_CombineWithGeometry(ID2D1TransformedGeometry *iface,
3032 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
3033 float tolerance, ID2D1SimplifiedGeometrySink *sink)
3035 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
3036 iface, geometry, combine_mode, transform, tolerance, sink);
3038 return E_NOTIMPL;
3041 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Outline(ID2D1TransformedGeometry *iface,
3042 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
3044 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
3046 return E_NOTIMPL;
3049 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputeArea(ID2D1TransformedGeometry *iface,
3050 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
3052 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
3054 return E_NOTIMPL;
3057 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputeLength(ID2D1TransformedGeometry *iface,
3058 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
3060 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
3062 return E_NOTIMPL;
3065 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputePointAtLength(ID2D1TransformedGeometry *iface,
3066 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
3067 D2D1_POINT_2F *tangent)
3069 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
3070 iface, length, transform, tolerance, point, tangent);
3072 return E_NOTIMPL;
3075 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Widen(ID2D1TransformedGeometry *iface, float stroke_width,
3076 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
3077 ID2D1SimplifiedGeometrySink *sink)
3079 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
3080 iface, stroke_width, stroke_style, transform, tolerance, sink);
3082 return E_NOTIMPL;
3085 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetSourceGeometry(ID2D1TransformedGeometry *iface,
3086 ID2D1Geometry **src_geometry)
3088 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
3090 TRACE("iface %p, src_geometry %p.\n", iface, src_geometry);
3092 ID2D1Geometry_AddRef(*src_geometry = geometry->u.transformed.src_geometry);
3095 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetTransform(ID2D1TransformedGeometry *iface,
3096 D2D1_MATRIX_3X2_F *transform)
3098 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
3100 TRACE("iface %p, transform %p.\n", iface, transform);
3102 *transform = geometry->u.transformed.transform;
3105 static const struct ID2D1TransformedGeometryVtbl d2d_transformed_geometry_vtbl =
3107 d2d_transformed_geometry_QueryInterface,
3108 d2d_transformed_geometry_AddRef,
3109 d2d_transformed_geometry_Release,
3110 d2d_transformed_geometry_GetFactory,
3111 d2d_transformed_geometry_GetBounds,
3112 d2d_transformed_geometry_GetWidenedBounds,
3113 d2d_transformed_geometry_StrokeContainsPoint,
3114 d2d_transformed_geometry_FillContainsPoint,
3115 d2d_transformed_geometry_CompareWithGeometry,
3116 d2d_transformed_geometry_Simplify,
3117 d2d_transformed_geometry_Tessellate,
3118 d2d_transformed_geometry_CombineWithGeometry,
3119 d2d_transformed_geometry_Outline,
3120 d2d_transformed_geometry_ComputeArea,
3121 d2d_transformed_geometry_ComputeLength,
3122 d2d_transformed_geometry_ComputePointAtLength,
3123 d2d_transformed_geometry_Widen,
3124 d2d_transformed_geometry_GetSourceGeometry,
3125 d2d_transformed_geometry_GetTransform,
3128 void d2d_transformed_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
3129 ID2D1Geometry *src_geometry, const D2D_MATRIX_3X2_F *transform)
3131 struct d2d_geometry *src_impl;
3132 D2D_MATRIX_3X2_F g;
3134 src_impl = unsafe_impl_from_ID2D1Geometry(src_geometry);
3136 g = src_impl->transform;
3137 d2d_matrix_multiply(&g, transform);
3138 d2d_geometry_init(geometry, factory, &g, (ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl);
3139 ID2D1Geometry_AddRef(geometry->u.transformed.src_geometry = src_geometry);
3140 geometry->u.transformed.transform = *transform;
3141 geometry->fill = src_impl->fill;
3142 geometry->outline = src_impl->outline;
3145 struct d2d_geometry *unsafe_impl_from_ID2D1Geometry(ID2D1Geometry *iface)
3147 if (!iface)
3148 return NULL;
3149 assert(iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl
3150 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl
3151 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl);
3152 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);