d2d1: Only test overlapping figures in d2d_geometry_intersect_self().
[wine/multimedia.git] / dlls / d2d1 / geometry.c
blob4c6623940e6083d2069cf4afde145d9674fa1c7d
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 struct d2d_figure
51 D2D1_POINT_2F *vertices;
52 size_t vertices_size;
53 size_t vertex_count;
55 struct d2d_bezier *beziers;
56 size_t beziers_size;
57 size_t bezier_count;
59 D2D1_RECT_F bounds;
62 struct d2d_cdt_edge_ref
64 size_t idx;
65 enum d2d_cdt_edge_next r;
68 struct d2d_cdt_edge
70 struct d2d_cdt_edge_ref next[4];
71 size_t vertex[2];
72 unsigned int flags;
75 struct d2d_cdt
77 struct d2d_cdt_edge *edges;
78 size_t edges_size;
79 size_t edge_count;
80 size_t free_edge;
82 const D2D1_POINT_2F *vertices;
85 struct d2d_fp_two_vec2
87 float x[2];
88 float y[2];
91 struct d2d_fp_fin
93 float *now, *other;
94 size_t length;
97 static void d2d_fp_two_sum(float *out, float a, float b)
99 float a_virt, a_round, b_virt, b_round;
101 out[1] = a + b;
102 b_virt = out[1] - a;
103 a_virt = out[1] - b_virt;
104 b_round = b - b_virt;
105 a_round = a - a_virt;
106 out[0] = a_round + b_round;
109 static void d2d_fp_fast_two_sum(float *out, float a, float b)
111 float b_virt;
113 out[1] = a + b;
114 b_virt = out[1] - a;
115 out[0] = b - b_virt;
118 static void d2d_fp_two_two_sum(float *out, const float *a, const float *b)
120 float sum[2];
122 d2d_fp_two_sum(out, a[0], b[0]);
123 d2d_fp_two_sum(sum, a[1], out[1]);
124 d2d_fp_two_sum(&out[1], sum[0], b[1]);
125 d2d_fp_two_sum(&out[2], sum[1], out[2]);
128 static void d2d_fp_two_diff_tail(float *out, float a, float b, float x)
130 float a_virt, a_round, b_virt, b_round;
132 b_virt = a - x;
133 a_virt = x + b_virt;
134 b_round = b_virt - b;
135 a_round = a - a_virt;
136 *out = a_round + b_round;
139 static void d2d_fp_two_two_diff(float *out, const float *a, const float *b)
141 float sum[2], diff;
143 diff = a[0] - b[0];
144 d2d_fp_two_diff_tail(out, a[0], b[0], diff);
145 d2d_fp_two_sum(sum, a[1], diff);
146 diff = sum[0] - b[1];
147 d2d_fp_two_diff_tail(&out[1], sum[0], b[1], diff);
148 d2d_fp_two_sum(&out[2], sum[1], diff);
151 static void d2d_fp_split(float *out, float a)
153 float a_big, c;
155 c = a * ((1 << (FLT_MANT_DIG / 2)) + 1.0f);
156 a_big = c - a;
157 out[1] = c - a_big;
158 out[0] = a - out[1];
161 static void d2d_fp_two_product_presplit(float *out, float a, float b, const float *b_split)
163 float a_split[2], err1, err2, err3;
165 out[1] = a * b;
166 d2d_fp_split(a_split, a);
167 err1 = out[1] - (a_split[1] * b_split[1]);
168 err2 = err1 - (a_split[0] * b_split[1]);
169 err3 = err2 - (a_split[1] * b_split[0]);
170 out[0] = (a_split[0] * b_split[0]) - err3;
173 static void d2d_fp_two_product(float *out, float a, float b)
175 float b_split[2];
177 d2d_fp_split(b_split, b);
178 d2d_fp_two_product_presplit(out, a, b, b_split);
181 static void d2d_fp_square(float *out, float a)
183 float a_split[2], err1, err2;
185 out[1] = a * a;
186 d2d_fp_split(a_split, a);
187 err1 = out[1] - (a_split[1] * a_split[1]);
188 err2 = err1 - ((a_split[1] + a_split[1]) * a_split[0]);
189 out[0] = (a_split[0] * a_split[0]) - err2;
192 static float d2d_fp_estimate(float *a, size_t len)
194 float out = a[0];
195 size_t idx = 1;
197 while (idx < len)
198 out += a[idx++];
200 return out;
203 static void d2d_fp_fast_expansion_sum_zeroelim(float *out, size_t *out_len,
204 const float *a, size_t a_len, const float *b, size_t b_len)
206 float sum[2], q, a_curr, b_curr;
207 size_t a_idx, b_idx, out_idx;
209 a_curr = a[0];
210 b_curr = b[0];
211 a_idx = b_idx = 0;
212 if ((b_curr > a_curr) == (b_curr > -a_curr))
214 q = a_curr;
215 a_curr = a[++a_idx];
217 else
219 q = b_curr;
220 b_curr = b[++b_idx];
222 out_idx = 0;
223 if (a_idx < a_len && b_idx < b_len)
225 if ((b_curr > a_curr) == (b_curr > -a_curr))
227 d2d_fp_fast_two_sum(sum, a_curr, q);
228 a_curr = a[++a_idx];
230 else
232 d2d_fp_fast_two_sum(sum, b_curr, q);
233 b_curr = b[++b_idx];
235 if (sum[0] != 0.0f)
236 out[out_idx++] = sum[0];
237 q = sum[1];
238 while (a_idx < a_len && b_idx < b_len)
240 if ((b_curr > a_curr) == (b_curr > -a_curr))
242 d2d_fp_two_sum(sum, q, a_curr);
243 a_curr = a[++a_idx];
245 else
247 d2d_fp_two_sum(sum, q, b_curr);
248 b_curr = b[++b_idx];
250 if (sum[0] != 0.0f)
251 out[out_idx++] = sum[0];
252 q = sum[1];
255 while (a_idx < a_len)
257 d2d_fp_two_sum(sum, q, a_curr);
258 a_curr = a[++a_idx];
259 if (sum[0] != 0.0f)
260 out[out_idx++] = sum[0];
261 q = sum[1];
263 while (b_idx < b_len)
265 d2d_fp_two_sum(sum, q, b_curr);
266 b_curr = b[++b_idx];
267 if (sum[0] != 0.0f)
268 out[out_idx++] = sum[0];
269 q = sum[1];
271 if (q != 0.0f || !out_idx)
272 out[out_idx++] = q;
274 *out_len = out_idx;
277 static void d2d_fp_scale_expansion_zeroelim(float *out, size_t *out_len, const float *a, size_t a_len, float b)
279 float product[2], sum[2], b_split[2], q[2], a_curr;
280 size_t a_idx, out_idx;
282 d2d_fp_split(b_split, b);
283 d2d_fp_two_product_presplit(q, a[0], b, b_split);
284 out_idx = 0;
285 if (q[0] != 0.0f)
286 out[out_idx++] = q[0];
287 for (a_idx = 1; a_idx < a_len; ++a_idx)
289 a_curr = a[a_idx];
290 d2d_fp_two_product_presplit(product, a_curr, b, b_split);
291 d2d_fp_two_sum(sum, q[1], product[0]);
292 if (sum[0] != 0.0f)
293 out[out_idx++] = sum[0];
294 d2d_fp_fast_two_sum(q, product[1], sum[1]);
295 if (q[0] != 0.0f)
296 out[out_idx++] = q[0];
298 if (q[1] != 0.0f || !out_idx)
299 out[out_idx++] = q[1];
301 *out_len = out_idx;
304 static void d2d_point_subtract(D2D1_POINT_2F *out,
305 const D2D1_POINT_2F *a, const D2D1_POINT_2F *b)
307 out->x = a->x - b->x;
308 out->y = a->y - b->y;
311 /* This implementation is based on the paper "Adaptive Precision
312 * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
313 * associated (Public Domain) code by Jonathan Richard Shewchuk. */
314 static float d2d_point_ccw(const D2D1_POINT_2F *a, const D2D1_POINT_2F *b, const D2D1_POINT_2F *c)
316 static const float err_bound_result = (3.0f + 8.0f * D2D_FP_EPS) * D2D_FP_EPS;
317 static const float err_bound_a = (3.0f + 16.0f * D2D_FP_EPS) * D2D_FP_EPS;
318 static const float err_bound_b = (2.0f + 12.0f * D2D_FP_EPS) * D2D_FP_EPS;
319 static const float err_bound_c = (9.0f + 64.0f * D2D_FP_EPS) * D2D_FP_EPS * D2D_FP_EPS;
320 float det_d[16], det_c2[12], det_c1[8], det_b[4], temp4[4], temp2a[2], temp2b[2], abxacy[2], abyacx[2];
321 size_t det_d_len, det_c2_len, det_c1_len;
322 float det, det_sum, err_bound;
323 struct d2d_fp_two_vec2 ab, ac;
325 ab.x[1] = b->x - a->x;
326 ab.y[1] = b->y - a->y;
327 ac.x[1] = c->x - a->x;
328 ac.y[1] = c->y - a->y;
330 abxacy[1] = ab.x[1] * ac.y[1];
331 abyacx[1] = ab.y[1] * ac.x[1];
332 det = abxacy[1] - abyacx[1];
334 if (abxacy[1] > 0.0f)
336 if (abyacx[1] <= 0.0f)
337 return det;
338 det_sum = abxacy[1] + abyacx[1];
340 else if (abxacy[1] < 0.0f)
342 if (abyacx[1] >= 0.0f)
343 return det;
344 det_sum = -abxacy[1] - abyacx[1];
346 else
348 return det;
351 err_bound = err_bound_a * det_sum;
352 if (det >= err_bound || -det >= err_bound)
353 return det;
355 d2d_fp_two_product(abxacy, ab.x[1], ac.y[1]);
356 d2d_fp_two_product(abyacx, ab.y[1], ac.x[1]);
357 d2d_fp_two_two_diff(det_b, abxacy, abyacx);
359 det = d2d_fp_estimate(det_b, 4);
360 err_bound = err_bound_b * det_sum;
361 if (det >= err_bound || -det >= err_bound)
362 return det;
364 d2d_fp_two_diff_tail(&ab.x[0], b->x, a->x, ab.x[1]);
365 d2d_fp_two_diff_tail(&ab.y[0], b->y, a->y, ab.y[1]);
366 d2d_fp_two_diff_tail(&ac.x[0], c->x, a->x, ac.x[1]);
367 d2d_fp_two_diff_tail(&ac.y[0], c->y, a->y, ac.y[1]);
369 if (ab.x[0] == 0.0f && ab.y[0] == 0.0f && ac.x[0] == 0.0f && ac.y[0] == 0.0f)
370 return det;
372 err_bound = err_bound_c * det_sum + err_bound_result * fabsf(det);
373 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]);
374 if (det >= err_bound || -det >= err_bound)
375 return det;
377 d2d_fp_two_product(temp2a, ab.x[0], ac.y[1]);
378 d2d_fp_two_product(temp2b, ab.y[0], ac.x[1]);
379 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
380 d2d_fp_fast_expansion_sum_zeroelim(det_c1, &det_c1_len, det_b, 4, temp4, 4);
382 d2d_fp_two_product(temp2a, ab.x[1], ac.y[0]);
383 d2d_fp_two_product(temp2b, ab.y[1], ac.x[0]);
384 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
385 d2d_fp_fast_expansion_sum_zeroelim(det_c2, &det_c2_len, det_c1, det_c1_len, temp4, 4);
387 d2d_fp_two_product(temp2a, ab.x[0], ac.y[0]);
388 d2d_fp_two_product(temp2b, ab.y[0], ac.x[0]);
389 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
390 d2d_fp_fast_expansion_sum_zeroelim(det_d, &det_d_len, det_c2, det_c2_len, temp4, 4);
392 return det_d[det_d_len - 1];
395 static BOOL d2d_array_reserve(void **elements, size_t *capacity, size_t element_count, size_t element_size)
397 size_t new_capacity, max_capacity;
398 void *new_elements;
400 if (element_count <= *capacity)
401 return TRUE;
403 max_capacity = ~(size_t)0 / element_size;
404 if (max_capacity < element_count)
405 return FALSE;
407 new_capacity = max(*capacity, 4);
408 while (new_capacity < element_count && new_capacity <= max_capacity / 2)
409 new_capacity *= 2;
411 if (new_capacity < element_count)
412 new_capacity = max_capacity;
414 if (*elements)
415 new_elements = HeapReAlloc(GetProcessHeap(), 0, *elements, new_capacity * element_size);
416 else
417 new_elements = HeapAlloc(GetProcessHeap(), 0, new_capacity * element_size);
419 if (!new_elements)
420 return FALSE;
422 *elements = new_elements;
423 *capacity = new_capacity;
424 return TRUE;
427 static void d2d_figure_update_bounds(struct d2d_figure *figure, D2D1_POINT_2F vertex)
429 if (vertex.x < figure->bounds.left)
430 figure->bounds.left = vertex.x;
431 if (vertex.x > figure->bounds.right)
432 figure->bounds.right = vertex.x;
433 if (vertex.y < figure->bounds.top)
434 figure->bounds.top = vertex.y;
435 if (vertex.y > figure->bounds.bottom)
436 figure->bounds.bottom = vertex.y;
439 static BOOL d2d_figure_insert_vertex(struct d2d_figure *figure, size_t idx, D2D1_POINT_2F vertex)
441 if (!d2d_array_reserve((void **)&figure->vertices, &figure->vertices_size,
442 figure->vertex_count + 1, sizeof(*figure->vertices)))
444 ERR("Failed to grow vertices array.\n");
445 return FALSE;
448 memmove(&figure->vertices[idx + 1], &figure->vertices[idx],
449 (figure->vertex_count - idx) * sizeof(*figure->vertices));
450 figure->vertices[idx] = vertex;
451 d2d_figure_update_bounds(figure, vertex);
452 ++figure->vertex_count;
453 return TRUE;
456 static BOOL d2d_figure_add_vertex(struct d2d_figure *figure, D2D1_POINT_2F vertex)
458 if (!d2d_array_reserve((void **)&figure->vertices, &figure->vertices_size,
459 figure->vertex_count + 1, sizeof(*figure->vertices)))
461 ERR("Failed to grow vertices array.\n");
462 return FALSE;
465 figure->vertices[figure->vertex_count] = vertex;
466 d2d_figure_update_bounds(figure, vertex);
467 ++figure->vertex_count;
468 return TRUE;
471 /* FIXME: No inside/outside testing is done for beziers. */
472 static BOOL d2d_figure_add_bezier(struct d2d_figure *figure, D2D1_POINT_2F p0, D2D1_POINT_2F p1, D2D1_POINT_2F p2)
474 struct d2d_bezier *b;
475 unsigned int idx1, idx2;
476 float sign;
478 if (!d2d_array_reserve((void **)&figure->beziers, &figure->beziers_size,
479 figure->bezier_count + 1, sizeof(*figure->beziers)))
481 ERR("Failed to grow beziers array.\n");
482 return FALSE;
485 if (d2d_point_ccw(&p0, &p1, &p2) > 0.0f)
487 sign = -1.0f;
488 idx1 = 1;
489 idx2 = 2;
491 else
493 sign = 1.0f;
494 idx1 = 2;
495 idx2 = 1;
498 b = &figure->beziers[figure->bezier_count];
499 b->v[0].position = p0;
500 b->v[0].texcoord.u = 0.0f;
501 b->v[0].texcoord.v = 0.0f;
502 b->v[0].texcoord.sign = sign;
503 b->v[idx1].position = p1;
504 b->v[idx1].texcoord.u = 0.5f;
505 b->v[idx1].texcoord.v = 0.0f;
506 b->v[idx1].texcoord.sign = sign;
507 b->v[idx2].position = p2;
508 b->v[idx2].texcoord.u = 1.0f;
509 b->v[idx2].texcoord.v = 1.0f;
510 b->v[idx2].texcoord.sign = sign;
511 ++figure->bezier_count;
513 if (sign > 0.0f && !d2d_figure_add_vertex(figure, p1))
514 return FALSE;
515 if (!d2d_figure_add_vertex(figure, p2))
516 return FALSE;
517 return TRUE;
520 static void d2d_cdt_edge_rot(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
522 dst->idx = src->idx;
523 dst->r = (src->r + D2D_EDGE_NEXT_ROT) & 3;
526 static void d2d_cdt_edge_sym(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
528 dst->idx = src->idx;
529 dst->r = (src->r + D2D_EDGE_NEXT_SYM) & 3;
532 static void d2d_cdt_edge_tor(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
534 dst->idx = src->idx;
535 dst->r = (src->r + D2D_EDGE_NEXT_TOR) & 3;
538 static void d2d_cdt_edge_next_left(const struct d2d_cdt *cdt,
539 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
541 d2d_cdt_edge_rot(dst, &cdt->edges[src->idx].next[(src->r + D2D_EDGE_NEXT_TOR) & 3]);
544 static void d2d_cdt_edge_next_origin(const struct d2d_cdt *cdt,
545 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
547 *dst = cdt->edges[src->idx].next[src->r];
550 static void d2d_cdt_edge_prev_origin(const struct d2d_cdt *cdt,
551 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
553 d2d_cdt_edge_rot(dst, &cdt->edges[src->idx].next[(src->r + D2D_EDGE_NEXT_ROT) & 3]);
556 static size_t d2d_cdt_edge_origin(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
558 return cdt->edges[e->idx].vertex[e->r >> 1];
561 static size_t d2d_cdt_edge_destination(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
563 return cdt->edges[e->idx].vertex[!(e->r >> 1)];
566 static void d2d_cdt_edge_set_origin(const struct d2d_cdt *cdt,
567 const struct d2d_cdt_edge_ref *e, size_t vertex)
569 cdt->edges[e->idx].vertex[e->r >> 1] = vertex;
572 static void d2d_cdt_edge_set_destination(const struct d2d_cdt *cdt,
573 const struct d2d_cdt_edge_ref *e, size_t vertex)
575 cdt->edges[e->idx].vertex[!(e->r >> 1)] = vertex;
578 static float d2d_cdt_ccw(const struct d2d_cdt *cdt, size_t a, size_t b, size_t c)
580 return d2d_point_ccw(&cdt->vertices[a], &cdt->vertices[b], &cdt->vertices[c]);
583 static BOOL d2d_cdt_rightof(const struct d2d_cdt *cdt, size_t p, const struct d2d_cdt_edge_ref *e)
585 return d2d_cdt_ccw(cdt, p, d2d_cdt_edge_destination(cdt, e), d2d_cdt_edge_origin(cdt, e)) > 0.0f;
588 static BOOL d2d_cdt_leftof(const struct d2d_cdt *cdt, size_t p, const struct d2d_cdt_edge_ref *e)
590 return d2d_cdt_ccw(cdt, p, d2d_cdt_edge_origin(cdt, e), d2d_cdt_edge_destination(cdt, e)) > 0.0f;
593 /* |ax ay|
594 * |bx by| */
595 static void d2d_fp_four_det2x2(float *out, float ax, float ay, float bx, float by)
597 float axby[2], aybx[2];
599 d2d_fp_two_product(axby, ax, by);
600 d2d_fp_two_product(aybx, ay, bx);
601 d2d_fp_two_two_diff(out, axby, aybx);
604 /* (a->x² + a->y²) * det2x2 */
605 static void d2d_fp_sub_det3x3(float *out, size_t *out_len, const struct d2d_fp_two_vec2 *a, const float *det2x2)
607 size_t axd_len, ayd_len, axxd_len, ayyd_len;
608 float axd[8], ayd[8], axxd[16], ayyd[16];
610 d2d_fp_scale_expansion_zeroelim(axd, &axd_len, det2x2, 4, a->x[1]);
611 d2d_fp_scale_expansion_zeroelim(axxd, &axxd_len, axd, axd_len, a->x[1]);
612 d2d_fp_scale_expansion_zeroelim(ayd, &ayd_len, det2x2, 4, a->y[1]);
613 d2d_fp_scale_expansion_zeroelim(ayyd, &ayyd_len, ayd, ayd_len, a->y[1]);
614 d2d_fp_fast_expansion_sum_zeroelim(out, out_len, axxd, axxd_len, ayyd, ayyd_len);
617 /* det_abt = det_ab * c[0]
618 * fin += c[0] * (az * b - bz * a + c[1] * det_ab * 2.0f) */
619 static void d2d_cdt_incircle_refine1(struct d2d_fp_fin *fin, float *det_abt, size_t *det_abt_len,
620 const float *det_ab, float a, const float *az, float b, const float *bz, const float *c)
622 size_t temp48_len, temp32_len, temp16a_len, temp16b_len, temp16c_len, temp8_len;
623 float temp48[48], temp32[32], temp16a[16], temp16b[16], temp16c[16], temp8[8];
624 float *swap;
626 d2d_fp_scale_expansion_zeroelim(det_abt, det_abt_len, det_ab, 4, c[0]);
627 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, det_abt, *det_abt_len, 2.0f * c[1]);
628 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, az, 4, c[0]);
629 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, temp8, temp8_len, b);
630 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, bz, 4, c[0]);
631 d2d_fp_scale_expansion_zeroelim(temp16c, &temp16c_len, temp8, temp8_len, -a);
632 d2d_fp_fast_expansion_sum_zeroelim(temp32, &temp32_len, temp16a, temp16a_len, temp16b, temp16b_len);
633 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16c, temp16c_len, temp32, temp32_len);
634 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
635 swap = fin->now; fin->now = fin->other; fin->other = swap;
638 static void d2d_cdt_incircle_refine2(struct d2d_fp_fin *fin, const struct d2d_fp_two_vec2 *a,
639 const struct d2d_fp_two_vec2 *b, const float *bz, const struct d2d_fp_two_vec2 *c, const float *cz,
640 const float *axt_det_bc, size_t axt_det_bc_len, const float *ayt_det_bc, size_t ayt_det_bc_len)
642 size_t temp64_len, temp48_len, temp32a_len, temp32b_len, temp16a_len, temp16b_len, temp8_len;
643 float temp64[64], temp48[48], temp32a[32], temp32b[32], temp16a[16], temp16b[16], temp8[8];
644 float bct[8], bctt[4], temp4a[4], temp4b[4], temp2a[2], temp2b[2];
645 size_t bct_len, bctt_len;
646 float *swap;
648 /* 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]) */
649 /* bctt = b->x[0] * c->y[0] + c->x[0] * b->y[0] */
650 if (b->x[0] != 0.0f || b->y[0] != 0.0f || c->x[0] != 0.0f || c->y[0] != 0.0f)
652 d2d_fp_two_product(temp2a, b->x[0], c->y[1]);
653 d2d_fp_two_product(temp2b, b->x[1], c->y[0]);
654 d2d_fp_two_two_sum(temp4a, temp2a, temp2b);
655 d2d_fp_two_product(temp2a, c->x[0], -b->y[1]);
656 d2d_fp_two_product(temp2b, c->x[1], -b->y[0]);
657 d2d_fp_two_two_sum(temp4b, temp2a, temp2b);
658 d2d_fp_fast_expansion_sum_zeroelim(bct, &bct_len, temp4a, 4, temp4b, 4);
660 d2d_fp_two_product(temp2a, b->x[0], c->y[0]);
661 d2d_fp_two_product(temp2b, c->x[0], b->y[0]);
662 d2d_fp_two_two_diff(bctt, temp2a, temp2b);
663 bctt_len = 4;
665 else
667 bct[0] = 0.0f;
668 bct_len = 1;
669 bctt[0] = 0.0f;
670 bctt_len = 1;
673 if (a->x[0] != 0.0f)
675 size_t axt_bct_len, axt_bctt_len;
676 float axt_bct[16], axt_bctt[8];
678 /* fin += a->x[0] * (axt_det_bc + bct * 2.0f * a->x[1]) */
679 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, axt_det_bc, axt_det_bc_len, a->x[0]);
680 d2d_fp_scale_expansion_zeroelim(axt_bct, &axt_bct_len, bct, bct_len, a->x[0]);
681 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, axt_bct, axt_bct_len, 2.0f * a->x[1]);
682 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16a, temp16a_len, temp32a, temp32a_len);
683 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
684 swap = fin->now; fin->now = fin->other; fin->other = swap;
686 if (b->y[0] != 0.0f)
688 /* fin += a->x[0] * cz * b->y[0] */
689 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, cz, 4, a->x[0]);
690 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, temp8, temp8_len, b->y[0]);
691 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp16a, temp16a_len);
692 swap = fin->now; fin->now = fin->other; fin->other = swap;
695 if (c->y[0] != 0.0f)
697 /* fin -= a->x[0] * bz * c->y[0] */
698 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, bz, 4, -a->x[0]);
699 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, temp8, temp8_len, c->y[0]);
700 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp16a, temp16a_len);
701 swap = fin->now; fin->now = fin->other; fin->other = swap;
704 /* fin += a->x[0] * (bct * a->x[0] + bctt * (2.0f * a->x[1] + a->x[0])) */
705 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, axt_bct, axt_bct_len, a->x[0]);
706 d2d_fp_scale_expansion_zeroelim(axt_bctt, &axt_bctt_len, bctt, bctt_len, a->x[0]);
707 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, axt_bctt, axt_bctt_len, 2.0f * a->x[1]);
708 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, axt_bctt, axt_bctt_len, a->x[0]);
709 d2d_fp_fast_expansion_sum_zeroelim(temp32b, &temp32b_len, temp16a, temp16a_len, temp16b, temp16b_len);
710 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, temp32a, temp32a_len, temp32b, temp32b_len);
711 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp64, temp64_len);
712 swap = fin->now; fin->now = fin->other; fin->other = swap;
715 if (a->y[0] != 0.0f)
717 size_t ayt_bct_len, ayt_bctt_len;
718 float ayt_bct[16], ayt_bctt[8];
720 /* fin += a->y[0] * (ayt_det_bc + bct * 2.0f * a->y[1]) */
721 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, ayt_det_bc, ayt_det_bc_len, a->y[0]);
722 d2d_fp_scale_expansion_zeroelim(ayt_bct, &ayt_bct_len, bct, bct_len, a->y[0]);
723 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, ayt_bct, ayt_bct_len, 2.0f * a->y[1]);
724 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16a, temp16a_len, temp32a, temp32a_len);
725 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
726 swap = fin->now; fin->now = fin->other; fin->other = swap;
728 /* fin += a->y[0] * (bct * a->y[0] + bctt * (2.0f * a->y[1] + a->y[0])) */
729 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, ayt_bct, ayt_bct_len, a->y[0]);
730 d2d_fp_scale_expansion_zeroelim(ayt_bctt, &ayt_bctt_len, bctt, bctt_len, a->y[0]);
731 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, ayt_bctt, ayt_bctt_len, 2.0f * a->y[1]);
732 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, ayt_bctt, ayt_bctt_len, a->y[0]);
733 d2d_fp_fast_expansion_sum_zeroelim(temp32b, &temp32b_len, temp16a, temp16a_len, temp16b, temp16b_len);
734 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, temp32a, temp32a_len, temp32b, temp32b_len);
735 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp64, temp64_len);
736 swap = fin->now; fin->now = fin->other; fin->other = swap;
740 /* Determine if point D is inside or outside the circle defined by points A,
741 * B, C. As explained in the paper by Guibas and Stolfi, this is equivalent to
742 * calculating the signed volume of the tetrahedron defined by projecting the
743 * points onto the paraboloid of revolution x = x² + y²,
744 * λ:(x, y) → (x, y, x² + y²). I.e., D is inside the cirlce if
746 * |λ(A) 1|
747 * |λ(B) 1| > 0
748 * |λ(C) 1|
749 * |λ(D) 1|
751 * After translating D to the origin, that becomes:
753 * |λ(A-D)|
754 * |λ(B-D)| > 0
755 * |λ(C-D)|
757 * This implementation is based on the paper "Adaptive Precision
758 * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
759 * associated (Public Domain) code by Jonathan Richard Shewchuk. */
760 static BOOL d2d_cdt_incircle(const struct d2d_cdt *cdt, size_t a, size_t b, size_t c, size_t d)
762 static const float err_bound_result = (3.0f + 8.0f * D2D_FP_EPS) * D2D_FP_EPS;
763 static const float err_bound_a = (10.0f + 96.0f * D2D_FP_EPS) * D2D_FP_EPS;
764 static const float err_bound_b = (4.0f + 48.0f * D2D_FP_EPS) * D2D_FP_EPS;
765 static const float err_bound_c = (44.0f + 576.0f * D2D_FP_EPS) * D2D_FP_EPS * D2D_FP_EPS;
767 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;
768 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];
769 float fin1[1152], fin2[1152], temp64[64], sub_det_a[32], sub_det_b[32], sub_det_c[32];
770 float det_bc[4], det_ca[4], det_ab[4], daz[4], dbz[4], dcz[4], temp2a[2], temp2b[2];
771 size_t temp64_len, sub_det_a_len, sub_det_b_len, sub_det_c_len;
772 float dbxdcy, dbydcx, dcxday, dcydax, daxdby, daydbx;
773 const D2D1_POINT_2F *p = cdt->vertices;
774 struct d2d_fp_two_vec2 da, db, dc;
775 float permanent, err_bound, det;
776 struct d2d_fp_fin fin;
778 da.x[1] = p[a].x - p[d].x;
779 da.y[1] = p[a].y - p[d].y;
780 db.x[1] = p[b].x - p[d].x;
781 db.y[1] = p[b].y - p[d].y;
782 dc.x[1] = p[c].x - p[d].x;
783 dc.y[1] = p[c].y - p[d].y;
785 daz[3] = da.x[1] * da.x[1] + da.y[1] * da.y[1];
786 dbxdcy = db.x[1] * dc.y[1];
787 dbydcx = db.y[1] * dc.x[1];
789 dbz[3] = db.x[1] * db.x[1] + db.y[1] * db.y[1];
790 dcxday = dc.x[1] * da.y[1];
791 dcydax = dc.y[1] * da.x[1];
793 dcz[3] = dc.x[1] * dc.x[1] + dc.y[1] * dc.y[1];
794 daxdby = da.x[1] * db.y[1];
795 daydbx = da.y[1] * db.x[1];
797 det = daz[3] * (dbxdcy - dbydcx) + dbz[3] * (dcxday - dcydax) + dcz[3] * (daxdby - daydbx);
798 permanent = daz[3] * (fabsf(dbxdcy) + fabsf(dbydcx))
799 + dbz[3] * (fabsf(dcxday) + fabsf(dcydax))
800 + dcz[3] * (fabsf(daxdby) + fabsf(daydbx));
801 err_bound = err_bound_a * permanent;
802 if (det > err_bound || -det > err_bound)
803 return det > 0.0f;
805 fin.now = fin1;
806 fin.other = fin2;
808 d2d_fp_four_det2x2(det_bc, db.x[1], db.y[1], dc.x[1], dc.y[1]);
809 d2d_fp_sub_det3x3(sub_det_a, &sub_det_a_len, &da, det_bc);
811 d2d_fp_four_det2x2(det_ca, dc.x[1], dc.y[1], da.x[1], da.y[1]);
812 d2d_fp_sub_det3x3(sub_det_b, &sub_det_b_len, &db, det_ca);
814 d2d_fp_four_det2x2(det_ab, da.x[1], da.y[1], db.x[1], db.y[1]);
815 d2d_fp_sub_det3x3(sub_det_c, &sub_det_c_len, &dc, det_ab);
817 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, sub_det_a, sub_det_a_len, sub_det_b, sub_det_b_len);
818 d2d_fp_fast_expansion_sum_zeroelim(fin.now, &fin.length, temp64, temp64_len, sub_det_c, sub_det_c_len);
819 det = d2d_fp_estimate(fin.now, fin.length);
820 err_bound = err_bound_b * permanent;
821 if (det >= err_bound || -det >= err_bound)
822 return det > 0.0f;
824 d2d_fp_two_diff_tail(&da.x[0], p[a].x, p[d].x, da.x[1]);
825 d2d_fp_two_diff_tail(&da.y[0], p[a].y, p[d].y, da.y[1]);
826 d2d_fp_two_diff_tail(&db.x[0], p[b].x, p[d].x, db.x[1]);
827 d2d_fp_two_diff_tail(&db.y[0], p[b].y, p[d].y, db.y[1]);
828 d2d_fp_two_diff_tail(&dc.x[0], p[c].x, p[d].x, dc.x[1]);
829 d2d_fp_two_diff_tail(&dc.y[0], p[c].y, p[d].y, dc.y[1]);
830 if (da.x[0] == 0.0f && db.x[0] == 0.0f && dc.x[0] == 0.0f
831 && da.y[0] == 0.0f && db.y[0] == 0.0f && dc.y[0] == 0.0f)
832 return det > 0.0f;
834 err_bound = err_bound_c * permanent + err_bound_result * fabsf(det);
835 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]))
836 + 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]))
837 + (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]))
838 + 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]))
839 + (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]))
840 + 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]));
841 if (det >= err_bound || -det >= err_bound)
842 return det > 0.0f;
844 if (db.x[0] != 0.0f || db.y[0] != 0.0f || dc.x[0] != 0.0f || dc.y[0] != 0.0f)
846 d2d_fp_square(temp2a, da.x[1]);
847 d2d_fp_square(temp2b, da.y[1]);
848 d2d_fp_two_two_sum(daz, temp2a, temp2b);
850 if (dc.x[0] != 0.0f || dc.y[0] != 0.0f || da.x[0] != 0.0f || da.y[0] != 0.0f)
852 d2d_fp_square(temp2a, db.x[1]);
853 d2d_fp_square(temp2b, db.y[1]);
854 d2d_fp_two_two_sum(dbz, temp2a, temp2b);
856 if (da.x[0] != 0.0f || da.y[0] != 0.0f || db.x[0] != 0.0f || db.y[0] != 0.0f)
858 d2d_fp_square(temp2a, dc.x[1]);
859 d2d_fp_square(temp2b, dc.y[1]);
860 d2d_fp_two_two_sum(dcz, temp2a, temp2b);
863 if (da.x[0] != 0.0f)
864 d2d_cdt_incircle_refine1(&fin, axt_det_bc, &axt_det_bc_len, det_bc, dc.y[1], dcz, db.y[1], dbz, da.x);
865 if (da.y[0] != 0.0f)
866 d2d_cdt_incircle_refine1(&fin, ayt_det_bc, &ayt_det_bc_len, det_bc, db.x[1], dbz, dc.x[1], dcz, da.y);
867 if (db.x[0] != 0.0f)
868 d2d_cdt_incircle_refine1(&fin, bxt_det_ca, &bxt_det_ca_len, det_ca, da.y[1], daz, dc.y[1], dcz, db.x);
869 if (db.y[0] != 0.0f)
870 d2d_cdt_incircle_refine1(&fin, byt_det_ca, &byt_det_ca_len, det_ca, dc.x[1], dcz, da.x[1], daz, db.y);
871 if (dc.x[0] != 0.0f)
872 d2d_cdt_incircle_refine1(&fin, cxt_det_ab, &cxt_det_ab_len, det_ab, db.y[1], dbz, da.y[1], daz, dc.x);
873 if (dc.y[0] != 0.0f)
874 d2d_cdt_incircle_refine1(&fin, cyt_det_ab, &cyt_det_ab_len, det_ab, da.x[1], daz, db.x[1], dbz, dc.y);
876 if (da.x[0] != 0.0f || da.y[0] != 0.0f)
877 d2d_cdt_incircle_refine2(&fin, &da, &db, dbz, &dc, dcz,
878 axt_det_bc, axt_det_bc_len, ayt_det_bc, ayt_det_bc_len);
879 if (db.x[0] != 0.0f || db.y[0] != 0.0f)
880 d2d_cdt_incircle_refine2(&fin, &db, &dc, dcz, &da, daz,
881 bxt_det_ca, bxt_det_ca_len, byt_det_ca, byt_det_ca_len);
882 if (dc.x[0] != 0.0f || dc.y[0] != 0.0f)
883 d2d_cdt_incircle_refine2(&fin, &dc, &da, daz, &db, dbz,
884 cxt_det_ab, cxt_det_ab_len, cyt_det_ab, cyt_det_ab_len);
886 return fin.now[fin.length - 1] > 0.0f;
889 static void d2d_cdt_splice(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *a,
890 const struct d2d_cdt_edge_ref *b)
892 struct d2d_cdt_edge_ref ta, tb, alpha, beta;
894 ta = cdt->edges[a->idx].next[a->r];
895 tb = cdt->edges[b->idx].next[b->r];
896 cdt->edges[a->idx].next[a->r] = tb;
897 cdt->edges[b->idx].next[b->r] = ta;
899 d2d_cdt_edge_rot(&alpha, &ta);
900 d2d_cdt_edge_rot(&beta, &tb);
902 ta = cdt->edges[alpha.idx].next[alpha.r];
903 tb = cdt->edges[beta.idx].next[beta.r];
904 cdt->edges[alpha.idx].next[alpha.r] = tb;
905 cdt->edges[beta.idx].next[beta.r] = ta;
908 static BOOL d2d_cdt_create_edge(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *e)
910 struct d2d_cdt_edge *edge;
912 if (cdt->free_edge != ~0u)
914 e->idx = cdt->free_edge;
915 cdt->free_edge = cdt->edges[e->idx].next[D2D_EDGE_NEXT_ORIGIN].idx;
917 else
919 if (!d2d_array_reserve((void **)&cdt->edges, &cdt->edges_size, cdt->edge_count + 1, sizeof(*cdt->edges)))
921 ERR("Failed to grow edges array.\n");
922 return FALSE;
924 e->idx = cdt->edge_count++;
926 e->r = 0;
928 edge = &cdt->edges[e->idx];
929 edge->next[D2D_EDGE_NEXT_ORIGIN] = *e;
930 d2d_cdt_edge_tor(&edge->next[D2D_EDGE_NEXT_ROT], e);
931 d2d_cdt_edge_sym(&edge->next[D2D_EDGE_NEXT_SYM], e);
932 d2d_cdt_edge_rot(&edge->next[D2D_EDGE_NEXT_TOR], e);
933 edge->flags = 0;
935 return TRUE;
938 static void d2d_cdt_destroy_edge(struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
940 struct d2d_cdt_edge_ref next, sym, prev;
942 d2d_cdt_edge_next_origin(cdt, &next, e);
943 if (next.idx != e->idx || next.r != e->r)
945 d2d_cdt_edge_prev_origin(cdt, &prev, e);
946 d2d_cdt_splice(cdt, e, &prev);
949 d2d_cdt_edge_sym(&sym, e);
951 d2d_cdt_edge_next_origin(cdt, &next, &sym);
952 if (next.idx != sym.idx || next.r != sym.r)
954 d2d_cdt_edge_prev_origin(cdt, &prev, &sym);
955 d2d_cdt_splice(cdt, &sym, &prev);
958 cdt->edges[e->idx].flags |= D2D_CDT_EDGE_FLAG_FREED;
959 cdt->edges[e->idx].next[D2D_EDGE_NEXT_ORIGIN].idx = cdt->free_edge;
960 cdt->free_edge = e->idx;
963 static BOOL d2d_cdt_connect(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *e,
964 const struct d2d_cdt_edge_ref *a, const struct d2d_cdt_edge_ref *b)
966 struct d2d_cdt_edge_ref tmp;
968 if (!d2d_cdt_create_edge(cdt, e))
969 return FALSE;
970 d2d_cdt_edge_set_origin(cdt, e, d2d_cdt_edge_destination(cdt, a));
971 d2d_cdt_edge_set_destination(cdt, e, d2d_cdt_edge_origin(cdt, b));
972 d2d_cdt_edge_next_left(cdt, &tmp, a);
973 d2d_cdt_splice(cdt, e, &tmp);
974 d2d_cdt_edge_sym(&tmp, e);
975 d2d_cdt_splice(cdt, &tmp, b);
977 return TRUE;
980 static BOOL d2d_cdt_merge(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *left_outer,
981 struct d2d_cdt_edge_ref *left_inner, struct d2d_cdt_edge_ref *right_inner,
982 struct d2d_cdt_edge_ref *right_outer)
984 struct d2d_cdt_edge_ref base_edge, tmp;
986 /* Create the base edge between both parts. */
987 for (;;)
989 if (d2d_cdt_leftof(cdt, d2d_cdt_edge_origin(cdt, right_inner), left_inner))
991 d2d_cdt_edge_next_left(cdt, left_inner, left_inner);
993 else if (d2d_cdt_rightof(cdt, d2d_cdt_edge_origin(cdt, left_inner), right_inner))
995 d2d_cdt_edge_sym(&tmp, right_inner);
996 d2d_cdt_edge_next_origin(cdt, right_inner, &tmp);
998 else
1000 break;
1004 d2d_cdt_edge_sym(&tmp, right_inner);
1005 if (!d2d_cdt_connect(cdt, &base_edge, &tmp, left_inner))
1006 return FALSE;
1007 if (d2d_cdt_edge_origin(cdt, left_inner) == d2d_cdt_edge_origin(cdt, left_outer))
1008 d2d_cdt_edge_sym(left_outer, &base_edge);
1009 if (d2d_cdt_edge_origin(cdt, right_inner) == d2d_cdt_edge_origin(cdt, right_outer))
1010 *right_outer = base_edge;
1012 for (;;)
1014 struct d2d_cdt_edge_ref left_candidate, right_candidate, sym_base_edge;
1015 BOOL left_valid, right_valid;
1017 /* Find the left candidate. */
1018 d2d_cdt_edge_sym(&sym_base_edge, &base_edge);
1019 d2d_cdt_edge_next_origin(cdt, &left_candidate, &sym_base_edge);
1020 if ((left_valid = d2d_cdt_leftof(cdt, d2d_cdt_edge_destination(cdt, &left_candidate), &sym_base_edge)))
1022 d2d_cdt_edge_next_origin(cdt, &tmp, &left_candidate);
1023 while (d2d_cdt_edge_destination(cdt, &tmp) != d2d_cdt_edge_destination(cdt, &sym_base_edge)
1024 && d2d_cdt_incircle(cdt,
1025 d2d_cdt_edge_origin(cdt, &sym_base_edge), d2d_cdt_edge_destination(cdt, &sym_base_edge),
1026 d2d_cdt_edge_destination(cdt, &left_candidate), d2d_cdt_edge_destination(cdt, &tmp)))
1028 d2d_cdt_destroy_edge(cdt, &left_candidate);
1029 left_candidate = tmp;
1030 d2d_cdt_edge_next_origin(cdt, &tmp, &left_candidate);
1033 d2d_cdt_edge_sym(&left_candidate, &left_candidate);
1035 /* Find the right candidate. */
1036 d2d_cdt_edge_prev_origin(cdt, &right_candidate, &base_edge);
1037 if ((right_valid = d2d_cdt_rightof(cdt, d2d_cdt_edge_destination(cdt, &right_candidate), &base_edge)))
1039 d2d_cdt_edge_prev_origin(cdt, &tmp, &right_candidate);
1040 while (d2d_cdt_edge_destination(cdt, &tmp) != d2d_cdt_edge_destination(cdt, &base_edge)
1041 && d2d_cdt_incircle(cdt,
1042 d2d_cdt_edge_origin(cdt, &sym_base_edge), d2d_cdt_edge_destination(cdt, &sym_base_edge),
1043 d2d_cdt_edge_destination(cdt, &right_candidate), d2d_cdt_edge_destination(cdt, &tmp)))
1045 d2d_cdt_destroy_edge(cdt, &right_candidate);
1046 right_candidate = tmp;
1047 d2d_cdt_edge_prev_origin(cdt, &tmp, &right_candidate);
1051 if (!left_valid && !right_valid)
1052 break;
1054 /* Connect the appropriate candidate with the base edge. */
1055 if (!left_valid || (right_valid && d2d_cdt_incircle(cdt,
1056 d2d_cdt_edge_origin(cdt, &left_candidate), d2d_cdt_edge_destination(cdt, &left_candidate),
1057 d2d_cdt_edge_origin(cdt, &right_candidate), d2d_cdt_edge_destination(cdt, &right_candidate))))
1059 if (!d2d_cdt_connect(cdt, &base_edge, &right_candidate, &sym_base_edge))
1060 return FALSE;
1062 else
1064 if (!d2d_cdt_connect(cdt, &base_edge, &sym_base_edge, &left_candidate))
1065 return FALSE;
1069 return TRUE;
1072 /* Create a Delaunay triangulation from a set of vertices. This is an
1073 * implementation of the divide-and-conquer algorithm described by Guibas and
1074 * Stolfi. Should be called with at least two vertices. */
1075 static BOOL d2d_cdt_triangulate(struct d2d_cdt *cdt, size_t start_vertex, size_t vertex_count,
1076 struct d2d_cdt_edge_ref *left_edge, struct d2d_cdt_edge_ref *right_edge)
1078 struct d2d_cdt_edge_ref left_inner, left_outer, right_inner, right_outer, tmp;
1079 size_t cut;
1081 /* Only two vertices, create a single edge. */
1082 if (vertex_count == 2)
1084 struct d2d_cdt_edge_ref a;
1086 if (!d2d_cdt_create_edge(cdt, &a))
1087 return FALSE;
1088 d2d_cdt_edge_set_origin(cdt, &a, start_vertex);
1089 d2d_cdt_edge_set_destination(cdt, &a, start_vertex + 1);
1091 *left_edge = a;
1092 d2d_cdt_edge_sym(right_edge, &a);
1094 return TRUE;
1097 /* Three vertices, create a triangle. */
1098 if (vertex_count == 3)
1100 struct d2d_cdt_edge_ref a, b, c;
1101 float det;
1103 if (!d2d_cdt_create_edge(cdt, &a))
1104 return FALSE;
1105 if (!d2d_cdt_create_edge(cdt, &b))
1106 return FALSE;
1107 d2d_cdt_edge_sym(&tmp, &a);
1108 d2d_cdt_splice(cdt, &tmp, &b);
1110 d2d_cdt_edge_set_origin(cdt, &a, start_vertex);
1111 d2d_cdt_edge_set_destination(cdt, &a, start_vertex + 1);
1112 d2d_cdt_edge_set_origin(cdt, &b, start_vertex + 1);
1113 d2d_cdt_edge_set_destination(cdt, &b, start_vertex + 2);
1115 det = d2d_cdt_ccw(cdt, start_vertex, start_vertex + 1, start_vertex + 2);
1116 if (det != 0.0f && !d2d_cdt_connect(cdt, &c, &b, &a))
1117 return FALSE;
1119 if (det < 0.0f)
1121 d2d_cdt_edge_sym(left_edge, &c);
1122 *right_edge = c;
1124 else
1126 *left_edge = a;
1127 d2d_cdt_edge_sym(right_edge, &b);
1130 return TRUE;
1133 /* More than tree vertices, divide. */
1134 cut = vertex_count / 2;
1135 if (!d2d_cdt_triangulate(cdt, start_vertex, cut, &left_outer, &left_inner))
1136 return FALSE;
1137 if (!d2d_cdt_triangulate(cdt, start_vertex + cut, vertex_count - cut, &right_inner, &right_outer))
1138 return FALSE;
1139 /* Merge the left and right parts. */
1140 if (!d2d_cdt_merge(cdt, &left_outer, &left_inner, &right_inner, &right_outer))
1141 return FALSE;
1143 *left_edge = left_outer;
1144 *right_edge = right_outer;
1145 return TRUE;
1148 static int d2d_cdt_compare_vertices(const void *a, const void *b)
1150 const D2D1_POINT_2F *p0 = a;
1151 const D2D1_POINT_2F *p1 = b;
1152 float diff = p0->x - p1->x;
1154 if (diff == 0.0f)
1155 diff = p0->y - p1->y;
1157 return diff == 0.0f ? 0 : (diff > 0.0f ? 1 : -1);
1160 /* Determine whether a given point is inside the geometry, using the current
1161 * fill mode rule. */
1162 static BOOL d2d_path_geometry_point_inside(const struct d2d_geometry *geometry, const D2D1_POINT_2F *probe)
1164 const D2D1_POINT_2F *p0, *p1;
1165 D2D1_POINT_2F v_p, v_probe;
1166 unsigned int score;
1167 size_t i, j;
1169 for (i = 0, score = 0; i < geometry->u.path.figure_count; ++i)
1171 const struct d2d_figure *figure = &geometry->u.path.figures[i];
1173 p0 = &figure->vertices[figure->vertex_count - 1];
1174 for (j = 0; j < figure->vertex_count; p0 = p1, ++j)
1176 p1 = &figure->vertices[j];
1177 d2d_point_subtract(&v_p, p1, p0);
1178 d2d_point_subtract(&v_probe, probe, p0);
1180 if ((probe->y < p0->y) != (probe->y < p1->y) && v_probe.x < v_p.x * (v_probe.y / v_p.y))
1182 if (geometry->u.path.fill_mode == D2D1_FILL_MODE_ALTERNATE || (probe->y < p0->y))
1183 ++score;
1184 else
1185 --score;
1190 return geometry->u.path.fill_mode == D2D1_FILL_MODE_ALTERNATE ? score & 1 : score;
1193 static BOOL d2d_path_geometry_add_face(struct d2d_geometry *geometry, const struct d2d_cdt *cdt,
1194 const struct d2d_cdt_edge_ref *base_edge)
1196 struct d2d_cdt_edge_ref tmp;
1197 struct d2d_face *face;
1198 D2D1_POINT_2F probe;
1200 if (cdt->edges[base_edge->idx].flags & D2D_CDT_EDGE_FLAG_VISITED(base_edge->r))
1201 return TRUE;
1203 if (!d2d_array_reserve((void **)&geometry->faces, &geometry->faces_size,
1204 geometry->face_count + 1, sizeof(*geometry->faces)))
1206 ERR("Failed to grow faces array.\n");
1207 return FALSE;
1210 face = &geometry->faces[geometry->face_count];
1212 /* It may seem tempting to use the center of the face as probe origin, but
1213 * multiplying by powers of two works much better for preserving accuracy. */
1215 tmp = *base_edge;
1216 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1217 face->v[0] = d2d_cdt_edge_origin(cdt, &tmp);
1218 probe.x = cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.25f;
1219 probe.y = cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.25f;
1221 d2d_cdt_edge_next_left(cdt, &tmp, &tmp);
1222 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1223 face->v[1] = d2d_cdt_edge_origin(cdt, &tmp);
1224 probe.x += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.25f;
1225 probe.y += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.25f;
1227 d2d_cdt_edge_next_left(cdt, &tmp, &tmp);
1228 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1229 face->v[2] = d2d_cdt_edge_origin(cdt, &tmp);
1230 probe.x += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.50f;
1231 probe.y += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.50f;
1233 d2d_cdt_edge_next_left(cdt, &tmp, &tmp);
1234 if (tmp.idx == base_edge->idx && d2d_path_geometry_point_inside(geometry, &probe))
1235 ++geometry->face_count;
1237 return TRUE;
1240 static BOOL d2d_cdt_generate_faces(const struct d2d_cdt *cdt, struct d2d_geometry *geometry)
1242 struct d2d_cdt_edge_ref base_edge;
1243 size_t i;
1245 for (i = 0; i < cdt->edge_count; ++i)
1247 if (cdt->edges[i].flags & D2D_CDT_EDGE_FLAG_FREED)
1248 continue;
1250 base_edge.idx = i;
1251 base_edge.r = 0;
1252 if (!d2d_path_geometry_add_face(geometry, cdt, &base_edge))
1253 goto fail;
1254 d2d_cdt_edge_sym(&base_edge, &base_edge);
1255 if (!d2d_path_geometry_add_face(geometry, cdt, &base_edge))
1256 goto fail;
1259 return TRUE;
1261 fail:
1262 HeapFree(GetProcessHeap(), 0, geometry->faces);
1263 geometry->faces = NULL;
1264 geometry->faces_size = 0;
1265 geometry->face_count = 0;
1266 return FALSE;
1269 static BOOL d2d_cdt_fixup(struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *base_edge)
1271 struct d2d_cdt_edge_ref candidate, next, new_base;
1272 unsigned int count = 0;
1274 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1275 if (next.idx == base_edge->idx)
1277 ERR("Degenerate face.\n");
1278 return FALSE;
1281 candidate = next;
1282 while (d2d_cdt_edge_destination(cdt, &next) != d2d_cdt_edge_origin(cdt, base_edge))
1284 if (d2d_cdt_incircle(cdt, d2d_cdt_edge_origin(cdt, base_edge), d2d_cdt_edge_destination(cdt, base_edge),
1285 d2d_cdt_edge_destination(cdt, &candidate), d2d_cdt_edge_destination(cdt, &next)))
1286 candidate = next;
1287 d2d_cdt_edge_next_left(cdt, &next, &next);
1288 ++count;
1291 if (count > 1)
1293 d2d_cdt_edge_next_left(cdt, &next, &candidate);
1294 if (d2d_cdt_edge_destination(cdt, &next) == d2d_cdt_edge_origin(cdt, base_edge))
1295 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1296 else
1297 next = *base_edge;
1298 if (!d2d_cdt_connect(cdt, &new_base, &candidate, &next))
1299 return FALSE;
1300 if (!d2d_cdt_fixup(cdt, &new_base))
1301 return FALSE;
1302 d2d_cdt_edge_sym(&new_base, &new_base);
1303 if (!d2d_cdt_fixup(cdt, &new_base))
1304 return FALSE;
1307 return TRUE;
1310 static void d2d_cdt_cut_edges(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *end_edge,
1311 const struct d2d_cdt_edge_ref *base_edge, size_t start_vertex, size_t end_vertex)
1313 struct d2d_cdt_edge_ref next;
1315 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1316 if (d2d_cdt_edge_destination(cdt, &next) == end_vertex)
1318 *end_edge = next;
1319 return;
1322 if (d2d_cdt_ccw(cdt, d2d_cdt_edge_destination(cdt, &next), end_vertex, start_vertex) > 0.0f)
1323 d2d_cdt_edge_next_left(cdt, &next, &next);
1325 d2d_cdt_edge_sym(&next, &next);
1326 d2d_cdt_cut_edges(cdt, end_edge, &next, start_vertex, end_vertex);
1327 d2d_cdt_destroy_edge(cdt, &next);
1330 static BOOL d2d_cdt_insert_segment(struct d2d_cdt *cdt, struct d2d_geometry *geometry,
1331 const struct d2d_cdt_edge_ref *origin, size_t end_vertex)
1333 struct d2d_cdt_edge_ref base_edge, current, next, target;
1335 for (current = *origin;; current = next)
1337 d2d_cdt_edge_next_origin(cdt, &next, &current);
1339 if (d2d_cdt_edge_destination(cdt, &current) == end_vertex)
1340 return TRUE;
1342 if (d2d_cdt_rightof(cdt, end_vertex, &next) && d2d_cdt_leftof(cdt, end_vertex, &current))
1344 d2d_cdt_edge_next_left(cdt, &base_edge, &current);
1346 d2d_cdt_edge_sym(&base_edge, &base_edge);
1347 d2d_cdt_cut_edges(cdt, &target, &base_edge, d2d_cdt_edge_origin(cdt, origin), end_vertex);
1348 d2d_cdt_destroy_edge(cdt, &base_edge);
1350 if (!d2d_cdt_connect(cdt, &base_edge, &target, &current))
1351 return FALSE;
1352 if (!d2d_cdt_fixup(cdt, &base_edge))
1353 return FALSE;
1354 d2d_cdt_edge_sym(&base_edge, &base_edge);
1355 if (!d2d_cdt_fixup(cdt, &base_edge))
1356 return FALSE;
1358 return TRUE;
1361 if (next.idx == origin->idx)
1363 ERR("Triangle not found.\n");
1364 return FALSE;
1369 static BOOL d2d_cdt_insert_segments(struct d2d_cdt *cdt, struct d2d_geometry *geometry)
1371 size_t start_vertex, end_vertex, i, j, k;
1372 const struct d2d_figure *figure;
1373 struct d2d_cdt_edge_ref edge;
1374 const D2D1_POINT_2F *p;
1376 for (i = 0; i < geometry->u.path.figure_count; ++i)
1378 figure = &geometry->u.path.figures[i];
1380 p = bsearch(&figure->vertices[figure->vertex_count - 1], cdt->vertices,
1381 geometry->vertex_count, sizeof(*p), d2d_cdt_compare_vertices);
1382 start_vertex = p - cdt->vertices;
1384 for (j = 0; j < figure->vertex_count; start_vertex = end_vertex, ++j)
1386 p = bsearch(&figure->vertices[j], cdt->vertices,
1387 geometry->vertex_count, sizeof(*p), d2d_cdt_compare_vertices);
1388 end_vertex = p - cdt->vertices;
1390 if (start_vertex == end_vertex)
1391 continue;
1393 for (k = 0; k < cdt->edge_count; ++k)
1395 if (cdt->edges[k].flags & D2D_CDT_EDGE_FLAG_FREED)
1396 continue;
1398 edge.idx = k;
1399 edge.r = 0;
1401 if (d2d_cdt_edge_origin(cdt, &edge) == start_vertex)
1403 if (!d2d_cdt_insert_segment(cdt, geometry, &edge, end_vertex))
1404 return FALSE;
1405 break;
1407 d2d_cdt_edge_sym(&edge, &edge);
1408 if (d2d_cdt_edge_origin(cdt, &edge) == start_vertex)
1410 if (!d2d_cdt_insert_segment(cdt, geometry, &edge, end_vertex))
1411 return FALSE;
1412 break;
1418 return TRUE;
1421 /* Intersect the geometry's segments with themselves. This uses the
1422 * straightforward approach of testing everything against everything, but
1423 * there certainly exist more scalable algorithms for this. */
1424 /* FIXME: Beziers can't currently self-intersect. */
1425 static BOOL d2d_geometry_intersect_self(struct d2d_geometry *geometry)
1427 D2D1_POINT_2F p0, p1, q0, q1, v_p, v_q, v_qp, intersection;
1428 struct d2d_figure *figure_p, *figure_q;
1429 size_t i, j, k, l, min_j, min_l, max_l;
1430 float s, t, det;
1432 for (i = 0; i < geometry->u.path.figure_count; ++i)
1434 figure_p = &geometry->u.path.figures[i];
1435 p0 = figure_p->vertices[figure_p->vertex_count - 1];
1436 min_j = 0;
1437 min_l = 0;
1438 for (k = 0; k < figure_p->vertex_count; p0 = p1, ++k)
1440 p1 = figure_p->vertices[k];
1441 d2d_point_subtract(&v_p, &p1, &p0);
1442 for (j = min_j, min_j = 0, l = min_l, min_l = 0; j < i || (j == i && k); ++j, l = 0)
1444 figure_q = &geometry->u.path.figures[j];
1446 if (figure_p->bounds.left > figure_q->bounds.right
1447 || figure_q->bounds.left > figure_p->bounds.right
1448 || figure_p->bounds.top > figure_q->bounds.bottom
1449 || figure_q->bounds.top > figure_p->bounds.bottom)
1450 continue;
1452 max_l = j == i ? k - 1 : figure_q->vertex_count;
1453 q0 = figure_q->vertices[l == 0 ? figure_q->vertex_count - 1 : l - 1];
1454 for (; l < max_l; q0 = q1, ++l)
1456 q1 = figure_q->vertices[l];
1457 d2d_point_subtract(&v_q, &q1, &q0);
1458 d2d_point_subtract(&v_qp, &p0, &q0);
1460 det = v_p.x * v_q.y - v_p.y * v_q.x;
1461 if (det == 0.0f)
1462 continue;
1464 s = (v_q.x * v_qp.y - v_q.y * v_qp.x) / det;
1465 t = (v_p.x * v_qp.y - v_p.y * v_qp.x) / det;
1467 if (s < 0.0f || s > 1.0f || t < 0.0f || t > 1.0f)
1468 continue;
1470 intersection.x = p0.x + v_p.x * s;
1471 intersection.y = p0.y + v_p.y * s;
1473 if (t > 0.0f && t < 1.0f)
1475 if (!d2d_figure_insert_vertex(figure_q, l, intersection))
1476 return FALSE;
1477 if (j == i)
1478 ++k;
1479 ++max_l;
1480 ++l;
1483 if (s > 0.0f && s < 1.0f)
1485 if (!d2d_figure_insert_vertex(figure_p, k, intersection))
1486 return FALSE;
1487 min_j = j;
1488 min_l = l+1;
1489 p1 = intersection;
1490 d2d_point_subtract(&v_p, &p1, &p0);
1497 return TRUE;
1500 static HRESULT d2d_path_geometry_triangulate(struct d2d_geometry *geometry)
1502 struct d2d_cdt_edge_ref left_edge, right_edge;
1503 size_t vertex_count, i, j;
1504 struct d2d_cdt cdt = {0};
1505 D2D1_POINT_2F *vertices;
1507 for (i = 0, vertex_count = 0; i < geometry->u.path.figure_count; ++i)
1509 vertex_count += geometry->u.path.figures[i].vertex_count;
1512 if (vertex_count < 3)
1514 WARN("Geometry has %lu vertices.\n", (long)vertex_count);
1515 return S_OK;
1518 if (!(vertices = HeapAlloc(GetProcessHeap(), 0, vertex_count * sizeof(*vertices))))
1519 return E_OUTOFMEMORY;
1521 for (i = 0, j = 0; i < geometry->u.path.figure_count; ++i)
1523 memcpy(&vertices[j], geometry->u.path.figures[i].vertices,
1524 geometry->u.path.figures[i].vertex_count * sizeof(*vertices));
1525 j += geometry->u.path.figures[i].vertex_count;
1528 /* Sort vertices, eliminate duplicates. */
1529 qsort(vertices, vertex_count, sizeof(*vertices), d2d_cdt_compare_vertices);
1530 for (i = 1; i < vertex_count; ++i)
1532 if (!memcmp(&vertices[i - 1], &vertices[i], sizeof(*vertices)))
1534 --vertex_count;
1535 memmove(&vertices[i], &vertices[i + 1], (vertex_count - i) * sizeof(*vertices));
1536 --i;
1540 geometry->vertices = vertices;
1541 geometry->vertex_count = vertex_count;
1543 cdt.free_edge = ~0u;
1544 cdt.vertices = vertices;
1545 if (!d2d_cdt_triangulate(&cdt, 0, vertex_count, &left_edge, &right_edge))
1546 goto fail;
1547 if (!d2d_cdt_insert_segments(&cdt, geometry))
1548 goto fail;
1549 if (!d2d_cdt_generate_faces(&cdt, geometry))
1550 goto fail;
1552 HeapFree(GetProcessHeap(), 0, cdt.edges);
1553 return S_OK;
1555 fail:
1556 geometry->vertices = NULL;
1557 geometry->vertex_count = 0;
1558 HeapFree(GetProcessHeap(), 0, vertices);
1559 HeapFree(GetProcessHeap(), 0, cdt.edges);
1560 return E_FAIL;
1563 static BOOL d2d_path_geometry_add_figure(struct d2d_geometry *geometry)
1565 struct d2d_figure *figure;
1567 if (!d2d_array_reserve((void **)&geometry->u.path.figures, &geometry->u.path.figures_size,
1568 geometry->u.path.figure_count + 1, sizeof(*geometry->u.path.figures)))
1570 ERR("Failed to grow figures array.\n");
1571 return FALSE;
1574 figure = &geometry->u.path.figures[geometry->u.path.figure_count];
1575 memset(figure, 0, sizeof(*figure));
1576 figure->bounds.left = FLT_MAX;
1577 figure->bounds.top = FLT_MAX;
1578 figure->bounds.right = -FLT_MAX;
1579 figure->bounds.bottom = -FLT_MAX;
1581 ++geometry->u.path.figure_count;
1582 return TRUE;
1585 static void d2d_geometry_cleanup(struct d2d_geometry *geometry)
1587 HeapFree(GetProcessHeap(), 0, geometry->beziers);
1588 HeapFree(GetProcessHeap(), 0, geometry->faces);
1589 HeapFree(GetProcessHeap(), 0, geometry->vertices);
1590 ID2D1Factory_Release(geometry->factory);
1593 static void d2d_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
1594 const D2D1_MATRIX_3X2_F *transform, const struct ID2D1GeometryVtbl *vtbl)
1596 geometry->ID2D1Geometry_iface.lpVtbl = vtbl;
1597 geometry->refcount = 1;
1598 ID2D1Factory_AddRef(geometry->factory = factory);
1599 geometry->transform = *transform;
1602 static inline struct d2d_geometry *impl_from_ID2D1GeometrySink(ID2D1GeometrySink *iface)
1604 return CONTAINING_RECORD(iface, struct d2d_geometry, u.path.ID2D1GeometrySink_iface);
1607 static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_QueryInterface(ID2D1GeometrySink *iface, REFIID iid, void **out)
1609 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
1611 if (IsEqualGUID(iid, &IID_ID2D1GeometrySink)
1612 || IsEqualGUID(iid, &IID_ID2D1SimplifiedGeometrySink)
1613 || IsEqualGUID(iid, &IID_IUnknown))
1615 ID2D1GeometrySink_AddRef(iface);
1616 *out = iface;
1617 return S_OK;
1620 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
1622 *out = NULL;
1623 return E_NOINTERFACE;
1626 static ULONG STDMETHODCALLTYPE d2d_geometry_sink_AddRef(ID2D1GeometrySink *iface)
1628 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1630 TRACE("iface %p.\n", iface);
1632 return ID2D1Geometry_AddRef(&geometry->ID2D1Geometry_iface);
1635 static ULONG STDMETHODCALLTYPE d2d_geometry_sink_Release(ID2D1GeometrySink *iface)
1637 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1639 TRACE("iface %p.\n", iface);
1641 return ID2D1Geometry_Release(&geometry->ID2D1Geometry_iface);
1644 static void STDMETHODCALLTYPE d2d_geometry_sink_SetFillMode(ID2D1GeometrySink *iface, D2D1_FILL_MODE mode)
1646 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1648 TRACE("iface %p, mode %#x.\n", iface, mode);
1650 geometry->u.path.fill_mode = mode;
1653 static void STDMETHODCALLTYPE d2d_geometry_sink_SetSegmentFlags(ID2D1GeometrySink *iface, D2D1_PATH_SEGMENT flags)
1655 FIXME("iface %p, flags %#x stub!\n", iface, flags);
1658 static void STDMETHODCALLTYPE d2d_geometry_sink_BeginFigure(ID2D1GeometrySink *iface,
1659 D2D1_POINT_2F start_point, D2D1_FIGURE_BEGIN figure_begin)
1661 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1663 TRACE("iface %p, start_point {%.8e, %.8e}, figure_begin %#x.\n",
1664 iface, start_point.x, start_point.y, figure_begin);
1666 if (geometry->u.path.state != D2D_GEOMETRY_STATE_OPEN)
1668 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1669 return;
1672 if (figure_begin != D2D1_FIGURE_BEGIN_FILLED)
1673 FIXME("Ignoring figure_begin %#x.\n", figure_begin);
1675 if (!d2d_path_geometry_add_figure(geometry))
1677 ERR("Failed to add figure.\n");
1678 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1679 return;
1682 if (!d2d_figure_add_vertex(&geometry->u.path.figures[geometry->u.path.figure_count - 1], start_point))
1683 ERR("Failed to add vertex.\n");
1685 geometry->u.path.state = D2D_GEOMETRY_STATE_FIGURE;
1686 ++geometry->u.path.segment_count;
1689 static void STDMETHODCALLTYPE d2d_geometry_sink_AddLines(ID2D1GeometrySink *iface,
1690 const D2D1_POINT_2F *points, UINT32 count)
1692 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1693 unsigned int i;
1695 TRACE("iface %p, points %p, count %u.\n", iface, points, count);
1697 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
1699 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1700 return;
1703 for (i = 0; i < count; ++i)
1705 if (!d2d_figure_add_vertex(&geometry->u.path.figures[geometry->u.path.figure_count - 1], points[i]))
1707 ERR("Failed to add vertex.\n");
1708 return;
1712 geometry->u.path.segment_count += count;
1715 static void STDMETHODCALLTYPE d2d_geometry_sink_AddBeziers(ID2D1GeometrySink *iface,
1716 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
1718 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1719 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
1720 D2D1_POINT_2F p;
1721 unsigned int i;
1723 TRACE("iface %p, beziers %p, count %u.\n", iface, beziers, count);
1725 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
1727 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1728 return;
1731 for (i = 0; i < count; ++i)
1733 /* FIXME: This tries to approximate a cubic bezier with a quadratic one. */
1734 p.x = (beziers[i].point1.x + beziers[i].point2.x) * 0.75f;
1735 p.y = (beziers[i].point1.y + beziers[i].point2.y) * 0.75f;
1736 p.x -= (figure->vertices[figure->vertex_count - 1].x + beziers[i].point3.x) * 0.25f;
1737 p.y -= (figure->vertices[figure->vertex_count - 1].y + beziers[i].point3.y) * 0.25f;
1738 if (!d2d_figure_add_bezier(figure, figure->vertices[figure->vertex_count - 1], p, beziers[i].point3))
1740 ERR("Failed to add bezier.\n");
1741 return;
1745 geometry->u.path.segment_count += count;
1748 static void STDMETHODCALLTYPE d2d_geometry_sink_EndFigure(ID2D1GeometrySink *iface, D2D1_FIGURE_END figure_end)
1750 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1752 TRACE("iface %p, figure_end %#x.\n", iface, figure_end);
1754 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
1756 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1757 return;
1760 if (figure_end != D2D1_FIGURE_END_CLOSED)
1761 FIXME("Ignoring figure_end %#x.\n", figure_end);
1763 geometry->u.path.state = D2D_GEOMETRY_STATE_OPEN;
1766 static void d2d_path_geometry_free_figures(struct d2d_geometry *geometry)
1768 size_t i;
1770 if (!geometry->u.path.figures)
1771 return;
1773 for (i = 0; i < geometry->u.path.figure_count; ++i)
1775 HeapFree(GetProcessHeap(), 0, geometry->u.path.figures[i].beziers);
1776 HeapFree(GetProcessHeap(), 0, geometry->u.path.figures[i].vertices);
1778 HeapFree(GetProcessHeap(), 0, geometry->u.path.figures);
1779 geometry->u.path.figures = NULL;
1780 geometry->u.path.figures_size = 0;
1783 static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_Close(ID2D1GeometrySink *iface)
1785 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1786 HRESULT hr = E_FAIL;
1787 size_t i, start;
1789 TRACE("iface %p.\n", iface);
1791 if (geometry->u.path.state != D2D_GEOMETRY_STATE_OPEN)
1793 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
1794 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1795 return D2DERR_WRONG_STATE;
1797 geometry->u.path.state = D2D_GEOMETRY_STATE_CLOSED;
1799 if (!d2d_geometry_intersect_self(geometry))
1800 goto done;
1801 if (FAILED(hr = d2d_path_geometry_triangulate(geometry)))
1802 goto done;
1804 for (i = 0; i < geometry->u.path.figure_count; ++i)
1806 geometry->bezier_count += geometry->u.path.figures[i].bezier_count;
1809 if (!(geometry->beziers = HeapAlloc(GetProcessHeap(), 0,
1810 geometry->bezier_count * sizeof(*geometry->beziers))))
1812 ERR("Failed to allocate beziers array.\n");
1813 geometry->bezier_count = 0;
1814 hr = E_OUTOFMEMORY;
1815 goto done;
1818 for (i = 0, start = 0; i < geometry->u.path.figure_count; ++i)
1820 struct d2d_figure *figure = &geometry->u.path.figures[i];
1821 if (figure->bezier_count)
1823 memcpy(&geometry->beziers[start], figure->beziers,
1824 figure->bezier_count * sizeof(*figure->beziers));
1825 start += figure->bezier_count;
1829 done:
1830 d2d_path_geometry_free_figures(geometry);
1831 if (FAILED(hr))
1832 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1833 return hr;
1836 static void STDMETHODCALLTYPE d2d_geometry_sink_AddLine(ID2D1GeometrySink *iface, D2D1_POINT_2F point)
1838 TRACE("iface %p, point {%.8e, %.8e}.\n", iface, point.x, point.y);
1840 d2d_geometry_sink_AddLines(iface, &point, 1);
1843 static void STDMETHODCALLTYPE d2d_geometry_sink_AddBezier(ID2D1GeometrySink *iface, const D2D1_BEZIER_SEGMENT *bezier)
1845 TRACE("iface %p, bezier %p.\n", iface, bezier);
1847 d2d_geometry_sink_AddBeziers(iface, bezier, 1);
1850 static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBezier(ID2D1GeometrySink *iface,
1851 const D2D1_QUADRATIC_BEZIER_SEGMENT *bezier)
1853 TRACE("iface %p, bezier %p.\n", iface, bezier);
1855 ID2D1GeometrySink_AddQuadraticBeziers(iface, bezier, 1);
1858 static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBeziers(ID2D1GeometrySink *iface,
1859 const D2D1_QUADRATIC_BEZIER_SEGMENT *beziers, UINT32 bezier_count)
1861 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1862 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
1863 unsigned int i;
1865 TRACE("iface %p, beziers %p, bezier_count %u.\n", iface, beziers, bezier_count);
1867 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
1869 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1870 return;
1873 for (i = 0; i < bezier_count; ++i)
1875 if (!d2d_figure_add_bezier(figure, figure->vertices[figure->vertex_count - 1],
1876 beziers[i].point1, beziers[i].point2))
1878 ERR("Failed to add bezier.\n");
1879 return;
1883 geometry->u.path.segment_count += bezier_count;
1886 static void STDMETHODCALLTYPE d2d_geometry_sink_AddArc(ID2D1GeometrySink *iface, const D2D1_ARC_SEGMENT *arc)
1888 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1890 FIXME("iface %p, arc %p stub!\n", iface, arc);
1892 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
1894 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1895 return;
1898 if (!d2d_figure_add_vertex(&geometry->u.path.figures[geometry->u.path.figure_count - 1], arc->point))
1900 ERR("Failed to add vertex.\n");
1901 return;
1904 ++geometry->u.path.segment_count;
1907 static const struct ID2D1GeometrySinkVtbl d2d_geometry_sink_vtbl =
1909 d2d_geometry_sink_QueryInterface,
1910 d2d_geometry_sink_AddRef,
1911 d2d_geometry_sink_Release,
1912 d2d_geometry_sink_SetFillMode,
1913 d2d_geometry_sink_SetSegmentFlags,
1914 d2d_geometry_sink_BeginFigure,
1915 d2d_geometry_sink_AddLines,
1916 d2d_geometry_sink_AddBeziers,
1917 d2d_geometry_sink_EndFigure,
1918 d2d_geometry_sink_Close,
1919 d2d_geometry_sink_AddLine,
1920 d2d_geometry_sink_AddBezier,
1921 d2d_geometry_sink_AddQuadraticBezier,
1922 d2d_geometry_sink_AddQuadraticBeziers,
1923 d2d_geometry_sink_AddArc,
1926 static inline struct d2d_geometry *impl_from_ID2D1PathGeometry(ID2D1PathGeometry *iface)
1928 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
1931 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_QueryInterface(ID2D1PathGeometry *iface, REFIID iid, void **out)
1933 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
1935 if (IsEqualGUID(iid, &IID_ID2D1PathGeometry)
1936 || IsEqualGUID(iid, &IID_ID2D1Geometry)
1937 || IsEqualGUID(iid, &IID_ID2D1Resource)
1938 || IsEqualGUID(iid, &IID_IUnknown))
1940 ID2D1PathGeometry_AddRef(iface);
1941 *out = iface;
1942 return S_OK;
1945 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
1947 *out = NULL;
1948 return E_NOINTERFACE;
1951 static ULONG STDMETHODCALLTYPE d2d_path_geometry_AddRef(ID2D1PathGeometry *iface)
1953 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
1954 ULONG refcount = InterlockedIncrement(&geometry->refcount);
1956 TRACE("%p increasing refcount to %u.\n", iface, refcount);
1958 return refcount;
1961 static ULONG STDMETHODCALLTYPE d2d_path_geometry_Release(ID2D1PathGeometry *iface)
1963 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
1964 ULONG refcount = InterlockedDecrement(&geometry->refcount);
1966 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
1968 if (!refcount)
1970 d2d_path_geometry_free_figures(geometry);
1971 d2d_geometry_cleanup(geometry);
1972 HeapFree(GetProcessHeap(), 0, geometry);
1975 return refcount;
1978 static void STDMETHODCALLTYPE d2d_path_geometry_GetFactory(ID2D1PathGeometry *iface, ID2D1Factory **factory)
1980 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
1982 TRACE("iface %p, factory %p.\n", iface, factory);
1984 ID2D1Factory_AddRef(*factory = geometry->factory);
1987 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetBounds(ID2D1PathGeometry *iface,
1988 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
1990 FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
1992 return E_NOTIMPL;
1995 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetWidenedBounds(ID2D1PathGeometry *iface, float stroke_width,
1996 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_RECT_F *bounds)
1998 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
1999 iface, stroke_width, stroke_style, transform, tolerance, bounds);
2001 return E_NOTIMPL;
2004 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_StrokeContainsPoint(ID2D1PathGeometry *iface,
2005 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
2006 float tolerance, BOOL *contains)
2008 FIXME("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
2009 "transform %p, tolerance %.8e, contains %p stub!\n",
2010 iface, point.x, point.y, stroke_width, stroke_style, transform, tolerance, contains);
2012 return E_NOTIMPL;
2015 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_FillContainsPoint(ID2D1PathGeometry *iface,
2016 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
2018 FIXME("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p stub!\n",
2019 iface, point.x, point.y, transform, tolerance, contains);
2021 return E_NOTIMPL;
2024 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_CompareWithGeometry(ID2D1PathGeometry *iface,
2025 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
2027 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
2028 iface, geometry, transform, tolerance, relation);
2030 return E_NOTIMPL;
2033 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *iface,
2034 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
2035 ID2D1SimplifiedGeometrySink *sink)
2037 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2038 iface, option, transform, tolerance, sink);
2040 return E_NOTIMPL;
2043 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Tessellate(ID2D1PathGeometry *iface,
2044 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
2046 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
2048 return E_NOTIMPL;
2051 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_CombineWithGeometry(ID2D1PathGeometry *iface,
2052 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
2053 float tolerance, ID2D1SimplifiedGeometrySink *sink)
2055 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2056 iface, geometry, combine_mode, transform, tolerance, sink);
2058 return E_NOTIMPL;
2061 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Outline(ID2D1PathGeometry *iface,
2062 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
2064 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
2066 return E_NOTIMPL;
2069 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeArea(ID2D1PathGeometry *iface,
2070 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
2072 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
2074 return E_NOTIMPL;
2077 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeLength(ID2D1PathGeometry *iface,
2078 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
2080 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
2082 return E_NOTIMPL;
2085 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputePointAtLength(ID2D1PathGeometry *iface, float length,
2086 const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point, D2D1_POINT_2F *tangent)
2088 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
2089 iface, length, transform, tolerance, point, tangent);
2091 return E_NOTIMPL;
2094 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Widen(ID2D1PathGeometry *iface, float stroke_width,
2095 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
2096 ID2D1SimplifiedGeometrySink *sink)
2098 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
2099 iface, stroke_width, stroke_style, transform, tolerance, sink);
2101 return E_NOTIMPL;
2104 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Open(ID2D1PathGeometry *iface, ID2D1GeometrySink **sink)
2106 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2108 TRACE("iface %p, sink %p.\n", iface, sink);
2110 if (geometry->u.path.state != D2D_GEOMETRY_STATE_INITIAL)
2111 return D2DERR_WRONG_STATE;
2113 *sink = &geometry->u.path.ID2D1GeometrySink_iface;
2114 ID2D1GeometrySink_AddRef(*sink);
2116 geometry->u.path.state = D2D_GEOMETRY_STATE_OPEN;
2118 return S_OK;
2121 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Stream(ID2D1PathGeometry *iface, ID2D1GeometrySink *sink)
2123 FIXME("iface %p, sink %p stub!\n", iface, sink);
2125 return E_NOTIMPL;
2128 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetSegmentCount(ID2D1PathGeometry *iface, UINT32 *count)
2130 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2132 TRACE("iface %p, count %p.\n", iface, count);
2134 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
2135 return D2DERR_WRONG_STATE;
2137 *count = geometry->u.path.segment_count;
2139 return S_OK;
2142 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetFigureCount(ID2D1PathGeometry *iface, UINT32 *count)
2144 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2146 TRACE("iface %p, count %p.\n", iface, count);
2148 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
2149 return D2DERR_WRONG_STATE;
2151 *count = geometry->u.path.figure_count;
2153 return S_OK;
2156 static const struct ID2D1PathGeometryVtbl d2d_path_geometry_vtbl =
2158 d2d_path_geometry_QueryInterface,
2159 d2d_path_geometry_AddRef,
2160 d2d_path_geometry_Release,
2161 d2d_path_geometry_GetFactory,
2162 d2d_path_geometry_GetBounds,
2163 d2d_path_geometry_GetWidenedBounds,
2164 d2d_path_geometry_StrokeContainsPoint,
2165 d2d_path_geometry_FillContainsPoint,
2166 d2d_path_geometry_CompareWithGeometry,
2167 d2d_path_geometry_Simplify,
2168 d2d_path_geometry_Tessellate,
2169 d2d_path_geometry_CombineWithGeometry,
2170 d2d_path_geometry_Outline,
2171 d2d_path_geometry_ComputeArea,
2172 d2d_path_geometry_ComputeLength,
2173 d2d_path_geometry_ComputePointAtLength,
2174 d2d_path_geometry_Widen,
2175 d2d_path_geometry_Open,
2176 d2d_path_geometry_Stream,
2177 d2d_path_geometry_GetSegmentCount,
2178 d2d_path_geometry_GetFigureCount,
2181 void d2d_path_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory)
2183 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl);
2184 geometry->u.path.ID2D1GeometrySink_iface.lpVtbl = &d2d_geometry_sink_vtbl;
2187 static inline struct d2d_geometry *impl_from_ID2D1RectangleGeometry(ID2D1RectangleGeometry *iface)
2189 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
2192 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_QueryInterface(ID2D1RectangleGeometry *iface,
2193 REFIID iid, void **out)
2195 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
2197 if (IsEqualGUID(iid, &IID_ID2D1RectangleGeometry)
2198 || IsEqualGUID(iid, &IID_ID2D1Geometry)
2199 || IsEqualGUID(iid, &IID_ID2D1Resource)
2200 || IsEqualGUID(iid, &IID_IUnknown))
2202 ID2D1RectangleGeometry_AddRef(iface);
2203 *out = iface;
2204 return S_OK;
2207 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
2209 *out = NULL;
2210 return E_NOINTERFACE;
2213 static ULONG STDMETHODCALLTYPE d2d_rectangle_geometry_AddRef(ID2D1RectangleGeometry *iface)
2215 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
2216 ULONG refcount = InterlockedIncrement(&geometry->refcount);
2218 TRACE("%p increasing refcount to %u.\n", iface, refcount);
2220 return refcount;
2223 static ULONG STDMETHODCALLTYPE d2d_rectangle_geometry_Release(ID2D1RectangleGeometry *iface)
2225 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
2226 ULONG refcount = InterlockedDecrement(&geometry->refcount);
2228 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
2230 if (!refcount)
2232 d2d_geometry_cleanup(geometry);
2233 HeapFree(GetProcessHeap(), 0, geometry);
2236 return refcount;
2239 static void STDMETHODCALLTYPE d2d_rectangle_geometry_GetFactory(ID2D1RectangleGeometry *iface, ID2D1Factory **factory)
2241 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
2243 TRACE("iface %p, factory %p.\n", iface, factory);
2245 ID2D1Factory_AddRef(*factory = geometry->factory);
2248 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_GetBounds(ID2D1RectangleGeometry *iface,
2249 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
2251 FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
2253 return E_NOTIMPL;
2256 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_GetWidenedBounds(ID2D1RectangleGeometry *iface,
2257 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
2258 float tolerance, D2D1_RECT_F *bounds)
2260 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
2261 iface, stroke_width, stroke_style, transform, tolerance, bounds);
2263 return E_NOTIMPL;
2266 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_StrokeContainsPoint(ID2D1RectangleGeometry *iface,
2267 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
2268 float tolerance, BOOL *contains)
2270 FIXME("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
2271 "transform %p, tolerance %.8e, contains %p stub!\n",
2272 iface, point.x, point.y, stroke_width, stroke_style, transform, tolerance, contains);
2274 return E_NOTIMPL;
2277 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_FillContainsPoint(ID2D1RectangleGeometry *iface,
2278 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
2280 FIXME("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p stub!\n",
2281 iface, point.x, point.y, transform, tolerance, contains);
2283 return E_NOTIMPL;
2286 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_CompareWithGeometry(ID2D1RectangleGeometry *iface,
2287 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
2289 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
2290 iface, geometry, transform, tolerance, relation);
2292 return E_NOTIMPL;
2295 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Simplify(ID2D1RectangleGeometry *iface,
2296 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
2297 ID2D1SimplifiedGeometrySink *sink)
2299 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2300 iface, option, transform, tolerance, sink);
2302 return E_NOTIMPL;
2305 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Tessellate(ID2D1RectangleGeometry *iface,
2306 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
2308 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
2310 return E_NOTIMPL;
2313 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_CombineWithGeometry(ID2D1RectangleGeometry *iface,
2314 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
2315 float tolerance, ID2D1SimplifiedGeometrySink *sink)
2317 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2318 iface, geometry, combine_mode, transform, tolerance, sink);
2320 return E_NOTIMPL;
2323 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Outline(ID2D1RectangleGeometry *iface,
2324 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
2326 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
2328 return E_NOTIMPL;
2331 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputeArea(ID2D1RectangleGeometry *iface,
2332 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
2334 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
2336 return E_NOTIMPL;
2339 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputeLength(ID2D1RectangleGeometry *iface,
2340 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
2342 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
2344 return E_NOTIMPL;
2347 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputePointAtLength(ID2D1RectangleGeometry *iface,
2348 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
2349 D2D1_POINT_2F *tangent)
2351 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
2352 iface, length, transform, tolerance, point, tangent);
2354 return E_NOTIMPL;
2357 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Widen(ID2D1RectangleGeometry *iface, float stroke_width,
2358 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
2359 ID2D1SimplifiedGeometrySink *sink)
2361 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
2362 iface, stroke_width, stroke_style, transform, tolerance, sink);
2364 return E_NOTIMPL;
2367 static void STDMETHODCALLTYPE d2d_rectangle_geometry_GetRect(ID2D1RectangleGeometry *iface, D2D1_RECT_F *rect)
2369 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
2371 TRACE("iface %p, rect %p.\n", iface, rect);
2373 *rect = geometry->u.rectangle.rect;
2376 static const struct ID2D1RectangleGeometryVtbl d2d_rectangle_geometry_vtbl =
2378 d2d_rectangle_geometry_QueryInterface,
2379 d2d_rectangle_geometry_AddRef,
2380 d2d_rectangle_geometry_Release,
2381 d2d_rectangle_geometry_GetFactory,
2382 d2d_rectangle_geometry_GetBounds,
2383 d2d_rectangle_geometry_GetWidenedBounds,
2384 d2d_rectangle_geometry_StrokeContainsPoint,
2385 d2d_rectangle_geometry_FillContainsPoint,
2386 d2d_rectangle_geometry_CompareWithGeometry,
2387 d2d_rectangle_geometry_Simplify,
2388 d2d_rectangle_geometry_Tessellate,
2389 d2d_rectangle_geometry_CombineWithGeometry,
2390 d2d_rectangle_geometry_Outline,
2391 d2d_rectangle_geometry_ComputeArea,
2392 d2d_rectangle_geometry_ComputeLength,
2393 d2d_rectangle_geometry_ComputePointAtLength,
2394 d2d_rectangle_geometry_Widen,
2395 d2d_rectangle_geometry_GetRect,
2398 HRESULT d2d_rectangle_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_RECT_F *rect)
2400 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl);
2401 geometry->u.rectangle.rect = *rect;
2403 if (!(geometry->vertices = HeapAlloc(GetProcessHeap(), 0, 4 * sizeof(*geometry->vertices))))
2405 d2d_geometry_cleanup(geometry);
2406 return E_OUTOFMEMORY;
2408 geometry->vertex_count = 4;
2409 if (!d2d_array_reserve((void **)&geometry->faces, &geometry->faces_size, 2, sizeof(*geometry->faces)))
2411 d2d_geometry_cleanup(geometry);
2412 return E_OUTOFMEMORY;
2414 geometry->face_count = 2;
2416 geometry->vertices[0].x = min(rect->left, rect->right);
2417 geometry->vertices[0].y = min(rect->top, rect->bottom);
2418 geometry->vertices[1].x = min(rect->left, rect->right);
2419 geometry->vertices[1].y = max(rect->top, rect->bottom);
2420 geometry->vertices[2].x = max(rect->left, rect->right);
2421 geometry->vertices[2].y = min(rect->top, rect->bottom);
2422 geometry->vertices[3].x = max(rect->left, rect->right);
2423 geometry->vertices[3].y = max(rect->top, rect->bottom);
2425 geometry->faces[0].v[0] = 0;
2426 geometry->faces[0].v[1] = 2;
2427 geometry->faces[0].v[2] = 1;
2428 geometry->faces[1].v[0] = 1;
2429 geometry->faces[1].v[1] = 2;
2430 geometry->faces[1].v[2] = 3;
2432 return S_OK;
2435 static inline struct d2d_geometry *impl_from_ID2D1TransformedGeometry(ID2D1TransformedGeometry *iface)
2437 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
2440 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_QueryInterface(ID2D1TransformedGeometry *iface,
2441 REFIID iid, void **out)
2443 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
2445 if (IsEqualGUID(iid, &IID_ID2D1TransformedGeometry)
2446 || IsEqualGUID(iid, &IID_ID2D1Geometry)
2447 || IsEqualGUID(iid, &IID_ID2D1Resource)
2448 || IsEqualGUID(iid, &IID_IUnknown))
2450 ID2D1TransformedGeometry_AddRef(iface);
2451 *out = iface;
2452 return S_OK;
2455 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
2457 *out = NULL;
2458 return E_NOINTERFACE;
2461 static ULONG STDMETHODCALLTYPE d2d_transformed_geometry_AddRef(ID2D1TransformedGeometry *iface)
2463 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
2464 ULONG refcount = InterlockedIncrement(&geometry->refcount);
2466 TRACE("%p increasing refcount to %u.\n", iface, refcount);
2468 return refcount;
2471 static ULONG STDMETHODCALLTYPE d2d_transformed_geometry_Release(ID2D1TransformedGeometry *iface)
2473 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
2474 ULONG refcount = InterlockedDecrement(&geometry->refcount);
2476 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
2478 if (!refcount)
2480 geometry->beziers = NULL;
2481 geometry->faces = NULL;
2482 geometry->vertices = NULL;
2483 ID2D1Geometry_Release(geometry->u.transformed.src_geometry);
2484 d2d_geometry_cleanup(geometry);
2485 HeapFree(GetProcessHeap(), 0, geometry);
2488 return refcount;
2491 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetFactory(ID2D1TransformedGeometry *iface,
2492 ID2D1Factory **factory)
2494 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
2496 TRACE("iface %p, factory %p.\n", iface, factory);
2498 ID2D1Factory_AddRef(*factory = geometry->factory);
2501 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_GetBounds(ID2D1TransformedGeometry *iface,
2502 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
2504 FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
2506 return E_NOTIMPL;
2509 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_GetWidenedBounds(ID2D1TransformedGeometry *iface,
2510 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
2511 float tolerance, D2D1_RECT_F *bounds)
2513 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
2514 iface, stroke_width, stroke_style, transform, tolerance, bounds);
2516 return E_NOTIMPL;
2519 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_StrokeContainsPoint(ID2D1TransformedGeometry *iface,
2520 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
2521 float tolerance, BOOL *contains)
2523 FIXME("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
2524 "transform %p, tolerance %.8e, contains %p stub!\n",
2525 iface, point.x, point.y, stroke_width, stroke_style, transform, tolerance, contains);
2527 return E_NOTIMPL;
2530 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_FillContainsPoint(ID2D1TransformedGeometry *iface,
2531 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
2533 FIXME("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p stub!\n",
2534 iface, point.x, point.y, transform, tolerance, contains);
2536 return E_NOTIMPL;
2539 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_CompareWithGeometry(ID2D1TransformedGeometry *iface,
2540 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
2542 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
2543 iface, geometry, transform, tolerance, relation);
2545 return E_NOTIMPL;
2548 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Simplify(ID2D1TransformedGeometry *iface,
2549 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
2550 ID2D1SimplifiedGeometrySink *sink)
2552 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2553 iface, option, transform, tolerance, sink);
2555 return E_NOTIMPL;
2558 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Tessellate(ID2D1TransformedGeometry *iface,
2559 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
2561 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
2563 return E_NOTIMPL;
2566 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_CombineWithGeometry(ID2D1TransformedGeometry *iface,
2567 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
2568 float tolerance, ID2D1SimplifiedGeometrySink *sink)
2570 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2571 iface, geometry, combine_mode, transform, tolerance, sink);
2573 return E_NOTIMPL;
2576 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Outline(ID2D1TransformedGeometry *iface,
2577 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
2579 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
2581 return E_NOTIMPL;
2584 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputeArea(ID2D1TransformedGeometry *iface,
2585 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
2587 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
2589 return E_NOTIMPL;
2592 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputeLength(ID2D1TransformedGeometry *iface,
2593 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
2595 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
2597 return E_NOTIMPL;
2600 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputePointAtLength(ID2D1TransformedGeometry *iface,
2601 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
2602 D2D1_POINT_2F *tangent)
2604 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
2605 iface, length, transform, tolerance, point, tangent);
2607 return E_NOTIMPL;
2610 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Widen(ID2D1TransformedGeometry *iface, float stroke_width,
2611 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
2612 ID2D1SimplifiedGeometrySink *sink)
2614 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
2615 iface, stroke_width, stroke_style, transform, tolerance, sink);
2617 return E_NOTIMPL;
2620 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetSourceGeometry(ID2D1TransformedGeometry *iface,
2621 ID2D1Geometry **src_geometry)
2623 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
2625 TRACE("iface %p, src_geometry %p.\n", iface, src_geometry);
2627 ID2D1Geometry_AddRef(*src_geometry = geometry->u.transformed.src_geometry);
2630 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetTransform(ID2D1TransformedGeometry *iface,
2631 D2D1_MATRIX_3X2_F *transform)
2633 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
2635 TRACE("iface %p, transform %p.\n", iface, transform);
2637 *transform = geometry->transform;
2640 static const struct ID2D1TransformedGeometryVtbl d2d_transformed_geometry_vtbl =
2642 d2d_transformed_geometry_QueryInterface,
2643 d2d_transformed_geometry_AddRef,
2644 d2d_transformed_geometry_Release,
2645 d2d_transformed_geometry_GetFactory,
2646 d2d_transformed_geometry_GetBounds,
2647 d2d_transformed_geometry_GetWidenedBounds,
2648 d2d_transformed_geometry_StrokeContainsPoint,
2649 d2d_transformed_geometry_FillContainsPoint,
2650 d2d_transformed_geometry_CompareWithGeometry,
2651 d2d_transformed_geometry_Simplify,
2652 d2d_transformed_geometry_Tessellate,
2653 d2d_transformed_geometry_CombineWithGeometry,
2654 d2d_transformed_geometry_Outline,
2655 d2d_transformed_geometry_ComputeArea,
2656 d2d_transformed_geometry_ComputeLength,
2657 d2d_transformed_geometry_ComputePointAtLength,
2658 d2d_transformed_geometry_Widen,
2659 d2d_transformed_geometry_GetSourceGeometry,
2660 d2d_transformed_geometry_GetTransform,
2663 void d2d_transformed_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
2664 ID2D1Geometry *src_geometry, const D2D_MATRIX_3X2_F *transform)
2666 struct d2d_geometry *src_impl;
2668 d2d_geometry_init(geometry, factory, transform, (ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl);
2669 ID2D1Geometry_AddRef(geometry->u.transformed.src_geometry = src_geometry);
2670 src_impl = unsafe_impl_from_ID2D1Geometry(src_geometry);
2671 geometry->vertices = src_impl->vertices;
2672 geometry->vertex_count = src_impl->vertex_count;
2673 geometry->faces = src_impl->faces;
2674 geometry->face_count = src_impl->face_count;
2675 geometry->beziers = src_impl->beziers;
2676 geometry->bezier_count = src_impl->bezier_count;
2679 struct d2d_geometry *unsafe_impl_from_ID2D1Geometry(ID2D1Geometry *iface)
2681 if (!iface)
2682 return NULL;
2683 assert(iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl
2684 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl
2685 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl);
2686 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);