wined3d: Get resource info from the texture in wined3d_surface_blt().
[wine.git] / dlls / d2d1 / geometry.c
blob9fa1783b9213aafd8775d578084ed2e2a5c2f429
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_geometry_intersection
87 size_t figure_idx;
88 size_t segment_idx;
89 float t;
90 D2D1_POINT_2F p;
93 struct d2d_geometry_intersections
95 struct d2d_geometry_intersection *intersections;
96 size_t intersections_size;
97 size_t intersection_count;
100 struct d2d_fp_two_vec2
102 float x[2];
103 float y[2];
106 struct d2d_fp_fin
108 float *now, *other;
109 size_t length;
112 static void d2d_fp_two_sum(float *out, float a, float b)
114 float a_virt, a_round, b_virt, b_round;
116 out[1] = a + b;
117 b_virt = out[1] - a;
118 a_virt = out[1] - b_virt;
119 b_round = b - b_virt;
120 a_round = a - a_virt;
121 out[0] = a_round + b_round;
124 static void d2d_fp_fast_two_sum(float *out, float a, float b)
126 float b_virt;
128 out[1] = a + b;
129 b_virt = out[1] - a;
130 out[0] = b - b_virt;
133 static void d2d_fp_two_two_sum(float *out, const float *a, const float *b)
135 float sum[2];
137 d2d_fp_two_sum(out, a[0], b[0]);
138 d2d_fp_two_sum(sum, a[1], out[1]);
139 d2d_fp_two_sum(&out[1], sum[0], b[1]);
140 d2d_fp_two_sum(&out[2], sum[1], out[2]);
143 static void d2d_fp_two_diff_tail(float *out, float a, float b, float x)
145 float a_virt, a_round, b_virt, b_round;
147 b_virt = a - x;
148 a_virt = x + b_virt;
149 b_round = b_virt - b;
150 a_round = a - a_virt;
151 *out = a_round + b_round;
154 static void d2d_fp_two_two_diff(float *out, const float *a, const float *b)
156 float sum[2], diff;
158 diff = a[0] - b[0];
159 d2d_fp_two_diff_tail(out, a[0], b[0], diff);
160 d2d_fp_two_sum(sum, a[1], diff);
161 diff = sum[0] - b[1];
162 d2d_fp_two_diff_tail(&out[1], sum[0], b[1], diff);
163 d2d_fp_two_sum(&out[2], sum[1], diff);
166 static void d2d_fp_split(float *out, float a)
168 float a_big, c;
170 c = a * ((1 << (FLT_MANT_DIG / 2)) + 1.0f);
171 a_big = c - a;
172 out[1] = c - a_big;
173 out[0] = a - out[1];
176 static void d2d_fp_two_product_presplit(float *out, float a, float b, const float *b_split)
178 float a_split[2], err1, err2, err3;
180 out[1] = a * b;
181 d2d_fp_split(a_split, a);
182 err1 = out[1] - (a_split[1] * b_split[1]);
183 err2 = err1 - (a_split[0] * b_split[1]);
184 err3 = err2 - (a_split[1] * b_split[0]);
185 out[0] = (a_split[0] * b_split[0]) - err3;
188 static void d2d_fp_two_product(float *out, float a, float b)
190 float b_split[2];
192 d2d_fp_split(b_split, b);
193 d2d_fp_two_product_presplit(out, a, b, b_split);
196 static void d2d_fp_square(float *out, float a)
198 float a_split[2], err1, err2;
200 out[1] = a * a;
201 d2d_fp_split(a_split, a);
202 err1 = out[1] - (a_split[1] * a_split[1]);
203 err2 = err1 - ((a_split[1] + a_split[1]) * a_split[0]);
204 out[0] = (a_split[0] * a_split[0]) - err2;
207 static float d2d_fp_estimate(float *a, size_t len)
209 float out = a[0];
210 size_t idx = 1;
212 while (idx < len)
213 out += a[idx++];
215 return out;
218 static void d2d_fp_fast_expansion_sum_zeroelim(float *out, size_t *out_len,
219 const float *a, size_t a_len, const float *b, size_t b_len)
221 float sum[2], q, a_curr, b_curr;
222 size_t a_idx, b_idx, out_idx;
224 a_curr = a[0];
225 b_curr = b[0];
226 a_idx = b_idx = 0;
227 if ((b_curr > a_curr) == (b_curr > -a_curr))
229 q = a_curr;
230 a_curr = a[++a_idx];
232 else
234 q = b_curr;
235 b_curr = b[++b_idx];
237 out_idx = 0;
238 if (a_idx < a_len && b_idx < b_len)
240 if ((b_curr > a_curr) == (b_curr > -a_curr))
242 d2d_fp_fast_two_sum(sum, a_curr, q);
243 a_curr = a[++a_idx];
245 else
247 d2d_fp_fast_two_sum(sum, b_curr, q);
248 b_curr = b[++b_idx];
250 if (sum[0] != 0.0f)
251 out[out_idx++] = sum[0];
252 q = sum[1];
253 while (a_idx < a_len && b_idx < b_len)
255 if ((b_curr > a_curr) == (b_curr > -a_curr))
257 d2d_fp_two_sum(sum, q, a_curr);
258 a_curr = a[++a_idx];
260 else
262 d2d_fp_two_sum(sum, q, b_curr);
263 b_curr = b[++b_idx];
265 if (sum[0] != 0.0f)
266 out[out_idx++] = sum[0];
267 q = sum[1];
270 while (a_idx < a_len)
272 d2d_fp_two_sum(sum, q, a_curr);
273 a_curr = a[++a_idx];
274 if (sum[0] != 0.0f)
275 out[out_idx++] = sum[0];
276 q = sum[1];
278 while (b_idx < b_len)
280 d2d_fp_two_sum(sum, q, b_curr);
281 b_curr = b[++b_idx];
282 if (sum[0] != 0.0f)
283 out[out_idx++] = sum[0];
284 q = sum[1];
286 if (q != 0.0f || !out_idx)
287 out[out_idx++] = q;
289 *out_len = out_idx;
292 static void d2d_fp_scale_expansion_zeroelim(float *out, size_t *out_len, const float *a, size_t a_len, float b)
294 float product[2], sum[2], b_split[2], q[2], a_curr;
295 size_t a_idx, out_idx;
297 d2d_fp_split(b_split, b);
298 d2d_fp_two_product_presplit(q, a[0], b, b_split);
299 out_idx = 0;
300 if (q[0] != 0.0f)
301 out[out_idx++] = q[0];
302 for (a_idx = 1; a_idx < a_len; ++a_idx)
304 a_curr = a[a_idx];
305 d2d_fp_two_product_presplit(product, a_curr, b, b_split);
306 d2d_fp_two_sum(sum, q[1], product[0]);
307 if (sum[0] != 0.0f)
308 out[out_idx++] = sum[0];
309 d2d_fp_fast_two_sum(q, product[1], sum[1]);
310 if (q[0] != 0.0f)
311 out[out_idx++] = q[0];
313 if (q[1] != 0.0f || !out_idx)
314 out[out_idx++] = q[1];
316 *out_len = out_idx;
319 static void d2d_point_subtract(D2D1_POINT_2F *out,
320 const D2D1_POINT_2F *a, const D2D1_POINT_2F *b)
322 out->x = a->x - b->x;
323 out->y = a->y - b->y;
326 /* This implementation is based on the paper "Adaptive Precision
327 * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
328 * associated (Public Domain) code by Jonathan Richard Shewchuk. */
329 static float d2d_point_ccw(const D2D1_POINT_2F *a, const D2D1_POINT_2F *b, const D2D1_POINT_2F *c)
331 static const float err_bound_result = (3.0f + 8.0f * D2D_FP_EPS) * D2D_FP_EPS;
332 static const float err_bound_a = (3.0f + 16.0f * D2D_FP_EPS) * D2D_FP_EPS;
333 static const float err_bound_b = (2.0f + 12.0f * D2D_FP_EPS) * D2D_FP_EPS;
334 static const float err_bound_c = (9.0f + 64.0f * D2D_FP_EPS) * D2D_FP_EPS * D2D_FP_EPS;
335 float det_d[16], det_c2[12], det_c1[8], det_b[4], temp4[4], temp2a[2], temp2b[2], abxacy[2], abyacx[2];
336 size_t det_d_len, det_c2_len, det_c1_len;
337 float det, det_sum, err_bound;
338 struct d2d_fp_two_vec2 ab, ac;
340 ab.x[1] = b->x - a->x;
341 ab.y[1] = b->y - a->y;
342 ac.x[1] = c->x - a->x;
343 ac.y[1] = c->y - a->y;
345 abxacy[1] = ab.x[1] * ac.y[1];
346 abyacx[1] = ab.y[1] * ac.x[1];
347 det = abxacy[1] - abyacx[1];
349 if (abxacy[1] > 0.0f)
351 if (abyacx[1] <= 0.0f)
352 return det;
353 det_sum = abxacy[1] + abyacx[1];
355 else if (abxacy[1] < 0.0f)
357 if (abyacx[1] >= 0.0f)
358 return det;
359 det_sum = -abxacy[1] - abyacx[1];
361 else
363 return det;
366 err_bound = err_bound_a * det_sum;
367 if (det >= err_bound || -det >= err_bound)
368 return det;
370 d2d_fp_two_product(abxacy, ab.x[1], ac.y[1]);
371 d2d_fp_two_product(abyacx, ab.y[1], ac.x[1]);
372 d2d_fp_two_two_diff(det_b, abxacy, abyacx);
374 det = d2d_fp_estimate(det_b, 4);
375 err_bound = err_bound_b * det_sum;
376 if (det >= err_bound || -det >= err_bound)
377 return det;
379 d2d_fp_two_diff_tail(&ab.x[0], b->x, a->x, ab.x[1]);
380 d2d_fp_two_diff_tail(&ab.y[0], b->y, a->y, ab.y[1]);
381 d2d_fp_two_diff_tail(&ac.x[0], c->x, a->x, ac.x[1]);
382 d2d_fp_two_diff_tail(&ac.y[0], c->y, a->y, ac.y[1]);
384 if (ab.x[0] == 0.0f && ab.y[0] == 0.0f && ac.x[0] == 0.0f && ac.y[0] == 0.0f)
385 return det;
387 err_bound = err_bound_c * det_sum + err_bound_result * fabsf(det);
388 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]);
389 if (det >= err_bound || -det >= err_bound)
390 return det;
392 d2d_fp_two_product(temp2a, ab.x[0], ac.y[1]);
393 d2d_fp_two_product(temp2b, ab.y[0], ac.x[1]);
394 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
395 d2d_fp_fast_expansion_sum_zeroelim(det_c1, &det_c1_len, det_b, 4, temp4, 4);
397 d2d_fp_two_product(temp2a, ab.x[1], ac.y[0]);
398 d2d_fp_two_product(temp2b, ab.y[1], ac.x[0]);
399 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
400 d2d_fp_fast_expansion_sum_zeroelim(det_c2, &det_c2_len, det_c1, det_c1_len, temp4, 4);
402 d2d_fp_two_product(temp2a, ab.x[0], ac.y[0]);
403 d2d_fp_two_product(temp2b, ab.y[0], ac.x[0]);
404 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
405 d2d_fp_fast_expansion_sum_zeroelim(det_d, &det_d_len, det_c2, det_c2_len, temp4, 4);
407 return det_d[det_d_len - 1];
410 static BOOL d2d_array_reserve(void **elements, size_t *capacity, size_t element_count, size_t element_size)
412 size_t new_capacity, max_capacity;
413 void *new_elements;
415 if (element_count <= *capacity)
416 return TRUE;
418 max_capacity = ~(size_t)0 / element_size;
419 if (max_capacity < element_count)
420 return FALSE;
422 new_capacity = max(*capacity, 4);
423 while (new_capacity < element_count && new_capacity <= max_capacity / 2)
424 new_capacity *= 2;
426 if (new_capacity < element_count)
427 new_capacity = max_capacity;
429 if (*elements)
430 new_elements = HeapReAlloc(GetProcessHeap(), 0, *elements, new_capacity * element_size);
431 else
432 new_elements = HeapAlloc(GetProcessHeap(), 0, new_capacity * element_size);
434 if (!new_elements)
435 return FALSE;
437 *elements = new_elements;
438 *capacity = new_capacity;
439 return TRUE;
442 static void d2d_figure_update_bounds(struct d2d_figure *figure, D2D1_POINT_2F vertex)
444 if (vertex.x < figure->bounds.left)
445 figure->bounds.left = vertex.x;
446 if (vertex.x > figure->bounds.right)
447 figure->bounds.right = vertex.x;
448 if (vertex.y < figure->bounds.top)
449 figure->bounds.top = vertex.y;
450 if (vertex.y > figure->bounds.bottom)
451 figure->bounds.bottom = vertex.y;
454 static BOOL d2d_figure_insert_vertex(struct d2d_figure *figure, size_t idx, D2D1_POINT_2F vertex)
456 if (!d2d_array_reserve((void **)&figure->vertices, &figure->vertices_size,
457 figure->vertex_count + 1, sizeof(*figure->vertices)))
459 ERR("Failed to grow vertices array.\n");
460 return FALSE;
463 memmove(&figure->vertices[idx + 1], &figure->vertices[idx],
464 (figure->vertex_count - idx) * sizeof(*figure->vertices));
465 figure->vertices[idx] = vertex;
466 d2d_figure_update_bounds(figure, vertex);
467 ++figure->vertex_count;
468 return TRUE;
471 static BOOL d2d_figure_add_vertex(struct d2d_figure *figure, D2D1_POINT_2F vertex)
473 if (!d2d_array_reserve((void **)&figure->vertices, &figure->vertices_size,
474 figure->vertex_count + 1, sizeof(*figure->vertices)))
476 ERR("Failed to grow vertices array.\n");
477 return FALSE;
480 figure->vertices[figure->vertex_count] = vertex;
481 d2d_figure_update_bounds(figure, vertex);
482 ++figure->vertex_count;
483 return TRUE;
486 /* FIXME: No inside/outside testing is done for beziers. */
487 static BOOL d2d_figure_add_bezier(struct d2d_figure *figure, D2D1_POINT_2F p0, D2D1_POINT_2F p1, D2D1_POINT_2F p2)
489 struct d2d_bezier *b;
490 unsigned int idx1, idx2;
491 float sign;
493 if (!d2d_array_reserve((void **)&figure->beziers, &figure->beziers_size,
494 figure->bezier_count + 1, sizeof(*figure->beziers)))
496 ERR("Failed to grow beziers array.\n");
497 return FALSE;
500 if (d2d_point_ccw(&p0, &p1, &p2) > 0.0f)
502 sign = -1.0f;
503 idx1 = 1;
504 idx2 = 2;
506 else
508 sign = 1.0f;
509 idx1 = 2;
510 idx2 = 1;
513 b = &figure->beziers[figure->bezier_count];
514 b->v[0].position = p0;
515 b->v[0].texcoord.u = 0.0f;
516 b->v[0].texcoord.v = 0.0f;
517 b->v[0].texcoord.sign = sign;
518 b->v[idx1].position = p1;
519 b->v[idx1].texcoord.u = 0.5f;
520 b->v[idx1].texcoord.v = 0.0f;
521 b->v[idx1].texcoord.sign = sign;
522 b->v[idx2].position = p2;
523 b->v[idx2].texcoord.u = 1.0f;
524 b->v[idx2].texcoord.v = 1.0f;
525 b->v[idx2].texcoord.sign = sign;
526 ++figure->bezier_count;
528 if (sign > 0.0f && !d2d_figure_add_vertex(figure, p1))
529 return FALSE;
530 if (!d2d_figure_add_vertex(figure, p2))
531 return FALSE;
532 return TRUE;
535 static void d2d_cdt_edge_rot(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
537 dst->idx = src->idx;
538 dst->r = (src->r + D2D_EDGE_NEXT_ROT) & 3;
541 static void d2d_cdt_edge_sym(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
543 dst->idx = src->idx;
544 dst->r = (src->r + D2D_EDGE_NEXT_SYM) & 3;
547 static void d2d_cdt_edge_tor(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
549 dst->idx = src->idx;
550 dst->r = (src->r + D2D_EDGE_NEXT_TOR) & 3;
553 static void d2d_cdt_edge_next_left(const struct d2d_cdt *cdt,
554 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
556 d2d_cdt_edge_rot(dst, &cdt->edges[src->idx].next[(src->r + D2D_EDGE_NEXT_TOR) & 3]);
559 static void d2d_cdt_edge_next_origin(const struct d2d_cdt *cdt,
560 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
562 *dst = cdt->edges[src->idx].next[src->r];
565 static void d2d_cdt_edge_prev_origin(const struct d2d_cdt *cdt,
566 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
568 d2d_cdt_edge_rot(dst, &cdt->edges[src->idx].next[(src->r + D2D_EDGE_NEXT_ROT) & 3]);
571 static size_t d2d_cdt_edge_origin(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
573 return cdt->edges[e->idx].vertex[e->r >> 1];
576 static size_t d2d_cdt_edge_destination(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
578 return cdt->edges[e->idx].vertex[!(e->r >> 1)];
581 static void d2d_cdt_edge_set_origin(const struct d2d_cdt *cdt,
582 const struct d2d_cdt_edge_ref *e, size_t vertex)
584 cdt->edges[e->idx].vertex[e->r >> 1] = vertex;
587 static void d2d_cdt_edge_set_destination(const struct d2d_cdt *cdt,
588 const struct d2d_cdt_edge_ref *e, size_t vertex)
590 cdt->edges[e->idx].vertex[!(e->r >> 1)] = vertex;
593 static float d2d_cdt_ccw(const struct d2d_cdt *cdt, size_t a, size_t b, size_t c)
595 return d2d_point_ccw(&cdt->vertices[a], &cdt->vertices[b], &cdt->vertices[c]);
598 static BOOL d2d_cdt_rightof(const struct d2d_cdt *cdt, size_t p, const struct d2d_cdt_edge_ref *e)
600 return d2d_cdt_ccw(cdt, p, d2d_cdt_edge_destination(cdt, e), d2d_cdt_edge_origin(cdt, e)) > 0.0f;
603 static BOOL d2d_cdt_leftof(const struct d2d_cdt *cdt, size_t p, const struct d2d_cdt_edge_ref *e)
605 return d2d_cdt_ccw(cdt, p, d2d_cdt_edge_origin(cdt, e), d2d_cdt_edge_destination(cdt, e)) > 0.0f;
608 /* |ax ay|
609 * |bx by| */
610 static void d2d_fp_four_det2x2(float *out, float ax, float ay, float bx, float by)
612 float axby[2], aybx[2];
614 d2d_fp_two_product(axby, ax, by);
615 d2d_fp_two_product(aybx, ay, bx);
616 d2d_fp_two_two_diff(out, axby, aybx);
619 /* (a->x² + a->y²) * det2x2 */
620 static void d2d_fp_sub_det3x3(float *out, size_t *out_len, const struct d2d_fp_two_vec2 *a, const float *det2x2)
622 size_t axd_len, ayd_len, axxd_len, ayyd_len;
623 float axd[8], ayd[8], axxd[16], ayyd[16];
625 d2d_fp_scale_expansion_zeroelim(axd, &axd_len, det2x2, 4, a->x[1]);
626 d2d_fp_scale_expansion_zeroelim(axxd, &axxd_len, axd, axd_len, a->x[1]);
627 d2d_fp_scale_expansion_zeroelim(ayd, &ayd_len, det2x2, 4, a->y[1]);
628 d2d_fp_scale_expansion_zeroelim(ayyd, &ayyd_len, ayd, ayd_len, a->y[1]);
629 d2d_fp_fast_expansion_sum_zeroelim(out, out_len, axxd, axxd_len, ayyd, ayyd_len);
632 /* det_abt = det_ab * c[0]
633 * fin += c[0] * (az * b - bz * a + c[1] * det_ab * 2.0f) */
634 static void d2d_cdt_incircle_refine1(struct d2d_fp_fin *fin, float *det_abt, size_t *det_abt_len,
635 const float *det_ab, float a, const float *az, float b, const float *bz, const float *c)
637 size_t temp48_len, temp32_len, temp16a_len, temp16b_len, temp16c_len, temp8_len;
638 float temp48[48], temp32[32], temp16a[16], temp16b[16], temp16c[16], temp8[8];
639 float *swap;
641 d2d_fp_scale_expansion_zeroelim(det_abt, det_abt_len, det_ab, 4, c[0]);
642 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, det_abt, *det_abt_len, 2.0f * c[1]);
643 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, az, 4, c[0]);
644 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, temp8, temp8_len, b);
645 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, bz, 4, c[0]);
646 d2d_fp_scale_expansion_zeroelim(temp16c, &temp16c_len, temp8, temp8_len, -a);
647 d2d_fp_fast_expansion_sum_zeroelim(temp32, &temp32_len, temp16a, temp16a_len, temp16b, temp16b_len);
648 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16c, temp16c_len, temp32, temp32_len);
649 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
650 swap = fin->now; fin->now = fin->other; fin->other = swap;
653 static void d2d_cdt_incircle_refine2(struct d2d_fp_fin *fin, const struct d2d_fp_two_vec2 *a,
654 const struct d2d_fp_two_vec2 *b, const float *bz, const struct d2d_fp_two_vec2 *c, const float *cz,
655 const float *axt_det_bc, size_t axt_det_bc_len, const float *ayt_det_bc, size_t ayt_det_bc_len)
657 size_t temp64_len, temp48_len, temp32a_len, temp32b_len, temp16a_len, temp16b_len, temp8_len;
658 float temp64[64], temp48[48], temp32a[32], temp32b[32], temp16a[16], temp16b[16], temp8[8];
659 float bct[8], bctt[4], temp4a[4], temp4b[4], temp2a[2], temp2b[2];
660 size_t bct_len, bctt_len;
661 float *swap;
663 /* 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]) */
664 /* bctt = b->x[0] * c->y[0] + c->x[0] * b->y[0] */
665 if (b->x[0] != 0.0f || b->y[0] != 0.0f || c->x[0] != 0.0f || c->y[0] != 0.0f)
667 d2d_fp_two_product(temp2a, b->x[0], c->y[1]);
668 d2d_fp_two_product(temp2b, b->x[1], c->y[0]);
669 d2d_fp_two_two_sum(temp4a, temp2a, temp2b);
670 d2d_fp_two_product(temp2a, c->x[0], -b->y[1]);
671 d2d_fp_two_product(temp2b, c->x[1], -b->y[0]);
672 d2d_fp_two_two_sum(temp4b, temp2a, temp2b);
673 d2d_fp_fast_expansion_sum_zeroelim(bct, &bct_len, temp4a, 4, temp4b, 4);
675 d2d_fp_two_product(temp2a, b->x[0], c->y[0]);
676 d2d_fp_two_product(temp2b, c->x[0], b->y[0]);
677 d2d_fp_two_two_diff(bctt, temp2a, temp2b);
678 bctt_len = 4;
680 else
682 bct[0] = 0.0f;
683 bct_len = 1;
684 bctt[0] = 0.0f;
685 bctt_len = 1;
688 if (a->x[0] != 0.0f)
690 size_t axt_bct_len, axt_bctt_len;
691 float axt_bct[16], axt_bctt[8];
693 /* fin += a->x[0] * (axt_det_bc + bct * 2.0f * a->x[1]) */
694 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, axt_det_bc, axt_det_bc_len, a->x[0]);
695 d2d_fp_scale_expansion_zeroelim(axt_bct, &axt_bct_len, bct, bct_len, a->x[0]);
696 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, axt_bct, axt_bct_len, 2.0f * a->x[1]);
697 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16a, temp16a_len, temp32a, temp32a_len);
698 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
699 swap = fin->now; fin->now = fin->other; fin->other = swap;
701 if (b->y[0] != 0.0f)
703 /* fin += a->x[0] * cz * b->y[0] */
704 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, cz, 4, a->x[0]);
705 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, temp8, temp8_len, b->y[0]);
706 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp16a, temp16a_len);
707 swap = fin->now; fin->now = fin->other; fin->other = swap;
710 if (c->y[0] != 0.0f)
712 /* fin -= a->x[0] * bz * c->y[0] */
713 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, bz, 4, -a->x[0]);
714 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, temp8, temp8_len, c->y[0]);
715 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp16a, temp16a_len);
716 swap = fin->now; fin->now = fin->other; fin->other = swap;
719 /* fin += a->x[0] * (bct * a->x[0] + bctt * (2.0f * a->x[1] + a->x[0])) */
720 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, axt_bct, axt_bct_len, a->x[0]);
721 d2d_fp_scale_expansion_zeroelim(axt_bctt, &axt_bctt_len, bctt, bctt_len, a->x[0]);
722 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, axt_bctt, axt_bctt_len, 2.0f * a->x[1]);
723 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, axt_bctt, axt_bctt_len, a->x[0]);
724 d2d_fp_fast_expansion_sum_zeroelim(temp32b, &temp32b_len, temp16a, temp16a_len, temp16b, temp16b_len);
725 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, temp32a, temp32a_len, temp32b, temp32b_len);
726 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp64, temp64_len);
727 swap = fin->now; fin->now = fin->other; fin->other = swap;
730 if (a->y[0] != 0.0f)
732 size_t ayt_bct_len, ayt_bctt_len;
733 float ayt_bct[16], ayt_bctt[8];
735 /* fin += a->y[0] * (ayt_det_bc + bct * 2.0f * a->y[1]) */
736 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, ayt_det_bc, ayt_det_bc_len, a->y[0]);
737 d2d_fp_scale_expansion_zeroelim(ayt_bct, &ayt_bct_len, bct, bct_len, a->y[0]);
738 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, ayt_bct, ayt_bct_len, 2.0f * a->y[1]);
739 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16a, temp16a_len, temp32a, temp32a_len);
740 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
741 swap = fin->now; fin->now = fin->other; fin->other = swap;
743 /* fin += a->y[0] * (bct * a->y[0] + bctt * (2.0f * a->y[1] + a->y[0])) */
744 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, ayt_bct, ayt_bct_len, a->y[0]);
745 d2d_fp_scale_expansion_zeroelim(ayt_bctt, &ayt_bctt_len, bctt, bctt_len, a->y[0]);
746 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, ayt_bctt, ayt_bctt_len, 2.0f * a->y[1]);
747 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, ayt_bctt, ayt_bctt_len, a->y[0]);
748 d2d_fp_fast_expansion_sum_zeroelim(temp32b, &temp32b_len, temp16a, temp16a_len, temp16b, temp16b_len);
749 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, temp32a, temp32a_len, temp32b, temp32b_len);
750 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp64, temp64_len);
751 swap = fin->now; fin->now = fin->other; fin->other = swap;
755 /* Determine if point D is inside or outside the circle defined by points A,
756 * B, C. As explained in the paper by Guibas and Stolfi, this is equivalent to
757 * calculating the signed volume of the tetrahedron defined by projecting the
758 * points onto the paraboloid of revolution x = x² + y²,
759 * λ:(x, y) → (x, y, x² + y²). I.e., D is inside the cirlce if
761 * |λ(A) 1|
762 * |λ(B) 1| > 0
763 * |λ(C) 1|
764 * |λ(D) 1|
766 * After translating D to the origin, that becomes:
768 * |λ(A-D)|
769 * |λ(B-D)| > 0
770 * |λ(C-D)|
772 * This implementation is based on the paper "Adaptive Precision
773 * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
774 * associated (Public Domain) code by Jonathan Richard Shewchuk. */
775 static BOOL d2d_cdt_incircle(const struct d2d_cdt *cdt, size_t a, size_t b, size_t c, size_t d)
777 static const float err_bound_result = (3.0f + 8.0f * D2D_FP_EPS) * D2D_FP_EPS;
778 static const float err_bound_a = (10.0f + 96.0f * D2D_FP_EPS) * D2D_FP_EPS;
779 static const float err_bound_b = (4.0f + 48.0f * D2D_FP_EPS) * D2D_FP_EPS;
780 static const float err_bound_c = (44.0f + 576.0f * D2D_FP_EPS) * D2D_FP_EPS * D2D_FP_EPS;
782 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;
783 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];
784 float fin1[1152], fin2[1152], temp64[64], sub_det_a[32], sub_det_b[32], sub_det_c[32];
785 float det_bc[4], det_ca[4], det_ab[4], daz[4], dbz[4], dcz[4], temp2a[2], temp2b[2];
786 size_t temp64_len, sub_det_a_len, sub_det_b_len, sub_det_c_len;
787 float dbxdcy, dbydcx, dcxday, dcydax, daxdby, daydbx;
788 const D2D1_POINT_2F *p = cdt->vertices;
789 struct d2d_fp_two_vec2 da, db, dc;
790 float permanent, err_bound, det;
791 struct d2d_fp_fin fin;
793 da.x[1] = p[a].x - p[d].x;
794 da.y[1] = p[a].y - p[d].y;
795 db.x[1] = p[b].x - p[d].x;
796 db.y[1] = p[b].y - p[d].y;
797 dc.x[1] = p[c].x - p[d].x;
798 dc.y[1] = p[c].y - p[d].y;
800 daz[3] = da.x[1] * da.x[1] + da.y[1] * da.y[1];
801 dbxdcy = db.x[1] * dc.y[1];
802 dbydcx = db.y[1] * dc.x[1];
804 dbz[3] = db.x[1] * db.x[1] + db.y[1] * db.y[1];
805 dcxday = dc.x[1] * da.y[1];
806 dcydax = dc.y[1] * da.x[1];
808 dcz[3] = dc.x[1] * dc.x[1] + dc.y[1] * dc.y[1];
809 daxdby = da.x[1] * db.y[1];
810 daydbx = da.y[1] * db.x[1];
812 det = daz[3] * (dbxdcy - dbydcx) + dbz[3] * (dcxday - dcydax) + dcz[3] * (daxdby - daydbx);
813 permanent = daz[3] * (fabsf(dbxdcy) + fabsf(dbydcx))
814 + dbz[3] * (fabsf(dcxday) + fabsf(dcydax))
815 + dcz[3] * (fabsf(daxdby) + fabsf(daydbx));
816 err_bound = err_bound_a * permanent;
817 if (det > err_bound || -det > err_bound)
818 return det > 0.0f;
820 fin.now = fin1;
821 fin.other = fin2;
823 d2d_fp_four_det2x2(det_bc, db.x[1], db.y[1], dc.x[1], dc.y[1]);
824 d2d_fp_sub_det3x3(sub_det_a, &sub_det_a_len, &da, det_bc);
826 d2d_fp_four_det2x2(det_ca, dc.x[1], dc.y[1], da.x[1], da.y[1]);
827 d2d_fp_sub_det3x3(sub_det_b, &sub_det_b_len, &db, det_ca);
829 d2d_fp_four_det2x2(det_ab, da.x[1], da.y[1], db.x[1], db.y[1]);
830 d2d_fp_sub_det3x3(sub_det_c, &sub_det_c_len, &dc, det_ab);
832 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, sub_det_a, sub_det_a_len, sub_det_b, sub_det_b_len);
833 d2d_fp_fast_expansion_sum_zeroelim(fin.now, &fin.length, temp64, temp64_len, sub_det_c, sub_det_c_len);
834 det = d2d_fp_estimate(fin.now, fin.length);
835 err_bound = err_bound_b * permanent;
836 if (det >= err_bound || -det >= err_bound)
837 return det > 0.0f;
839 d2d_fp_two_diff_tail(&da.x[0], p[a].x, p[d].x, da.x[1]);
840 d2d_fp_two_diff_tail(&da.y[0], p[a].y, p[d].y, da.y[1]);
841 d2d_fp_two_diff_tail(&db.x[0], p[b].x, p[d].x, db.x[1]);
842 d2d_fp_two_diff_tail(&db.y[0], p[b].y, p[d].y, db.y[1]);
843 d2d_fp_two_diff_tail(&dc.x[0], p[c].x, p[d].x, dc.x[1]);
844 d2d_fp_two_diff_tail(&dc.y[0], p[c].y, p[d].y, dc.y[1]);
845 if (da.x[0] == 0.0f && db.x[0] == 0.0f && dc.x[0] == 0.0f
846 && da.y[0] == 0.0f && db.y[0] == 0.0f && dc.y[0] == 0.0f)
847 return det > 0.0f;
849 err_bound = err_bound_c * permanent + err_bound_result * fabsf(det);
850 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]))
851 + 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]))
852 + (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]))
853 + 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]))
854 + (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]))
855 + 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]));
856 if (det >= err_bound || -det >= err_bound)
857 return det > 0.0f;
859 if (db.x[0] != 0.0f || db.y[0] != 0.0f || dc.x[0] != 0.0f || dc.y[0] != 0.0f)
861 d2d_fp_square(temp2a, da.x[1]);
862 d2d_fp_square(temp2b, da.y[1]);
863 d2d_fp_two_two_sum(daz, temp2a, temp2b);
865 if (dc.x[0] != 0.0f || dc.y[0] != 0.0f || da.x[0] != 0.0f || da.y[0] != 0.0f)
867 d2d_fp_square(temp2a, db.x[1]);
868 d2d_fp_square(temp2b, db.y[1]);
869 d2d_fp_two_two_sum(dbz, temp2a, temp2b);
871 if (da.x[0] != 0.0f || da.y[0] != 0.0f || db.x[0] != 0.0f || db.y[0] != 0.0f)
873 d2d_fp_square(temp2a, dc.x[1]);
874 d2d_fp_square(temp2b, dc.y[1]);
875 d2d_fp_two_two_sum(dcz, temp2a, temp2b);
878 if (da.x[0] != 0.0f)
879 d2d_cdt_incircle_refine1(&fin, axt_det_bc, &axt_det_bc_len, det_bc, dc.y[1], dcz, db.y[1], dbz, da.x);
880 if (da.y[0] != 0.0f)
881 d2d_cdt_incircle_refine1(&fin, ayt_det_bc, &ayt_det_bc_len, det_bc, db.x[1], dbz, dc.x[1], dcz, da.y);
882 if (db.x[0] != 0.0f)
883 d2d_cdt_incircle_refine1(&fin, bxt_det_ca, &bxt_det_ca_len, det_ca, da.y[1], daz, dc.y[1], dcz, db.x);
884 if (db.y[0] != 0.0f)
885 d2d_cdt_incircle_refine1(&fin, byt_det_ca, &byt_det_ca_len, det_ca, dc.x[1], dcz, da.x[1], daz, db.y);
886 if (dc.x[0] != 0.0f)
887 d2d_cdt_incircle_refine1(&fin, cxt_det_ab, &cxt_det_ab_len, det_ab, db.y[1], dbz, da.y[1], daz, dc.x);
888 if (dc.y[0] != 0.0f)
889 d2d_cdt_incircle_refine1(&fin, cyt_det_ab, &cyt_det_ab_len, det_ab, da.x[1], daz, db.x[1], dbz, dc.y);
891 if (da.x[0] != 0.0f || da.y[0] != 0.0f)
892 d2d_cdt_incircle_refine2(&fin, &da, &db, dbz, &dc, dcz,
893 axt_det_bc, axt_det_bc_len, ayt_det_bc, ayt_det_bc_len);
894 if (db.x[0] != 0.0f || db.y[0] != 0.0f)
895 d2d_cdt_incircle_refine2(&fin, &db, &dc, dcz, &da, daz,
896 bxt_det_ca, bxt_det_ca_len, byt_det_ca, byt_det_ca_len);
897 if (dc.x[0] != 0.0f || dc.y[0] != 0.0f)
898 d2d_cdt_incircle_refine2(&fin, &dc, &da, daz, &db, dbz,
899 cxt_det_ab, cxt_det_ab_len, cyt_det_ab, cyt_det_ab_len);
901 return fin.now[fin.length - 1] > 0.0f;
904 static void d2d_cdt_splice(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *a,
905 const struct d2d_cdt_edge_ref *b)
907 struct d2d_cdt_edge_ref ta, tb, alpha, beta;
909 ta = cdt->edges[a->idx].next[a->r];
910 tb = cdt->edges[b->idx].next[b->r];
911 cdt->edges[a->idx].next[a->r] = tb;
912 cdt->edges[b->idx].next[b->r] = ta;
914 d2d_cdt_edge_rot(&alpha, &ta);
915 d2d_cdt_edge_rot(&beta, &tb);
917 ta = cdt->edges[alpha.idx].next[alpha.r];
918 tb = cdt->edges[beta.idx].next[beta.r];
919 cdt->edges[alpha.idx].next[alpha.r] = tb;
920 cdt->edges[beta.idx].next[beta.r] = ta;
923 static BOOL d2d_cdt_create_edge(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *e)
925 struct d2d_cdt_edge *edge;
927 if (cdt->free_edge != ~0u)
929 e->idx = cdt->free_edge;
930 cdt->free_edge = cdt->edges[e->idx].next[D2D_EDGE_NEXT_ORIGIN].idx;
932 else
934 if (!d2d_array_reserve((void **)&cdt->edges, &cdt->edges_size, cdt->edge_count + 1, sizeof(*cdt->edges)))
936 ERR("Failed to grow edges array.\n");
937 return FALSE;
939 e->idx = cdt->edge_count++;
941 e->r = 0;
943 edge = &cdt->edges[e->idx];
944 edge->next[D2D_EDGE_NEXT_ORIGIN] = *e;
945 d2d_cdt_edge_tor(&edge->next[D2D_EDGE_NEXT_ROT], e);
946 d2d_cdt_edge_sym(&edge->next[D2D_EDGE_NEXT_SYM], e);
947 d2d_cdt_edge_rot(&edge->next[D2D_EDGE_NEXT_TOR], e);
948 edge->flags = 0;
950 return TRUE;
953 static void d2d_cdt_destroy_edge(struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
955 struct d2d_cdt_edge_ref next, sym, prev;
957 d2d_cdt_edge_next_origin(cdt, &next, e);
958 if (next.idx != e->idx || next.r != e->r)
960 d2d_cdt_edge_prev_origin(cdt, &prev, e);
961 d2d_cdt_splice(cdt, e, &prev);
964 d2d_cdt_edge_sym(&sym, e);
966 d2d_cdt_edge_next_origin(cdt, &next, &sym);
967 if (next.idx != sym.idx || next.r != sym.r)
969 d2d_cdt_edge_prev_origin(cdt, &prev, &sym);
970 d2d_cdt_splice(cdt, &sym, &prev);
973 cdt->edges[e->idx].flags |= D2D_CDT_EDGE_FLAG_FREED;
974 cdt->edges[e->idx].next[D2D_EDGE_NEXT_ORIGIN].idx = cdt->free_edge;
975 cdt->free_edge = e->idx;
978 static BOOL d2d_cdt_connect(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *e,
979 const struct d2d_cdt_edge_ref *a, const struct d2d_cdt_edge_ref *b)
981 struct d2d_cdt_edge_ref tmp;
983 if (!d2d_cdt_create_edge(cdt, e))
984 return FALSE;
985 d2d_cdt_edge_set_origin(cdt, e, d2d_cdt_edge_destination(cdt, a));
986 d2d_cdt_edge_set_destination(cdt, e, d2d_cdt_edge_origin(cdt, b));
987 d2d_cdt_edge_next_left(cdt, &tmp, a);
988 d2d_cdt_splice(cdt, e, &tmp);
989 d2d_cdt_edge_sym(&tmp, e);
990 d2d_cdt_splice(cdt, &tmp, b);
992 return TRUE;
995 static BOOL d2d_cdt_merge(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *left_outer,
996 struct d2d_cdt_edge_ref *left_inner, struct d2d_cdt_edge_ref *right_inner,
997 struct d2d_cdt_edge_ref *right_outer)
999 struct d2d_cdt_edge_ref base_edge, tmp;
1001 /* Create the base edge between both parts. */
1002 for (;;)
1004 if (d2d_cdt_leftof(cdt, d2d_cdt_edge_origin(cdt, right_inner), left_inner))
1006 d2d_cdt_edge_next_left(cdt, left_inner, left_inner);
1008 else if (d2d_cdt_rightof(cdt, d2d_cdt_edge_origin(cdt, left_inner), right_inner))
1010 d2d_cdt_edge_sym(&tmp, right_inner);
1011 d2d_cdt_edge_next_origin(cdt, right_inner, &tmp);
1013 else
1015 break;
1019 d2d_cdt_edge_sym(&tmp, right_inner);
1020 if (!d2d_cdt_connect(cdt, &base_edge, &tmp, left_inner))
1021 return FALSE;
1022 if (d2d_cdt_edge_origin(cdt, left_inner) == d2d_cdt_edge_origin(cdt, left_outer))
1023 d2d_cdt_edge_sym(left_outer, &base_edge);
1024 if (d2d_cdt_edge_origin(cdt, right_inner) == d2d_cdt_edge_origin(cdt, right_outer))
1025 *right_outer = base_edge;
1027 for (;;)
1029 struct d2d_cdt_edge_ref left_candidate, right_candidate, sym_base_edge;
1030 BOOL left_valid, right_valid;
1032 /* Find the left candidate. */
1033 d2d_cdt_edge_sym(&sym_base_edge, &base_edge);
1034 d2d_cdt_edge_next_origin(cdt, &left_candidate, &sym_base_edge);
1035 if ((left_valid = d2d_cdt_leftof(cdt, d2d_cdt_edge_destination(cdt, &left_candidate), &sym_base_edge)))
1037 d2d_cdt_edge_next_origin(cdt, &tmp, &left_candidate);
1038 while (d2d_cdt_edge_destination(cdt, &tmp) != d2d_cdt_edge_destination(cdt, &sym_base_edge)
1039 && d2d_cdt_incircle(cdt,
1040 d2d_cdt_edge_origin(cdt, &sym_base_edge), d2d_cdt_edge_destination(cdt, &sym_base_edge),
1041 d2d_cdt_edge_destination(cdt, &left_candidate), d2d_cdt_edge_destination(cdt, &tmp)))
1043 d2d_cdt_destroy_edge(cdt, &left_candidate);
1044 left_candidate = tmp;
1045 d2d_cdt_edge_next_origin(cdt, &tmp, &left_candidate);
1048 d2d_cdt_edge_sym(&left_candidate, &left_candidate);
1050 /* Find the right candidate. */
1051 d2d_cdt_edge_prev_origin(cdt, &right_candidate, &base_edge);
1052 if ((right_valid = d2d_cdt_rightof(cdt, d2d_cdt_edge_destination(cdt, &right_candidate), &base_edge)))
1054 d2d_cdt_edge_prev_origin(cdt, &tmp, &right_candidate);
1055 while (d2d_cdt_edge_destination(cdt, &tmp) != d2d_cdt_edge_destination(cdt, &base_edge)
1056 && d2d_cdt_incircle(cdt,
1057 d2d_cdt_edge_origin(cdt, &sym_base_edge), d2d_cdt_edge_destination(cdt, &sym_base_edge),
1058 d2d_cdt_edge_destination(cdt, &right_candidate), d2d_cdt_edge_destination(cdt, &tmp)))
1060 d2d_cdt_destroy_edge(cdt, &right_candidate);
1061 right_candidate = tmp;
1062 d2d_cdt_edge_prev_origin(cdt, &tmp, &right_candidate);
1066 if (!left_valid && !right_valid)
1067 break;
1069 /* Connect the appropriate candidate with the base edge. */
1070 if (!left_valid || (right_valid && d2d_cdt_incircle(cdt,
1071 d2d_cdt_edge_origin(cdt, &left_candidate), d2d_cdt_edge_destination(cdt, &left_candidate),
1072 d2d_cdt_edge_origin(cdt, &right_candidate), d2d_cdt_edge_destination(cdt, &right_candidate))))
1074 if (!d2d_cdt_connect(cdt, &base_edge, &right_candidate, &sym_base_edge))
1075 return FALSE;
1077 else
1079 if (!d2d_cdt_connect(cdt, &base_edge, &sym_base_edge, &left_candidate))
1080 return FALSE;
1084 return TRUE;
1087 /* Create a Delaunay triangulation from a set of vertices. This is an
1088 * implementation of the divide-and-conquer algorithm described by Guibas and
1089 * Stolfi. Should be called with at least two vertices. */
1090 static BOOL d2d_cdt_triangulate(struct d2d_cdt *cdt, size_t start_vertex, size_t vertex_count,
1091 struct d2d_cdt_edge_ref *left_edge, struct d2d_cdt_edge_ref *right_edge)
1093 struct d2d_cdt_edge_ref left_inner, left_outer, right_inner, right_outer, tmp;
1094 size_t cut;
1096 /* Only two vertices, create a single edge. */
1097 if (vertex_count == 2)
1099 struct d2d_cdt_edge_ref a;
1101 if (!d2d_cdt_create_edge(cdt, &a))
1102 return FALSE;
1103 d2d_cdt_edge_set_origin(cdt, &a, start_vertex);
1104 d2d_cdt_edge_set_destination(cdt, &a, start_vertex + 1);
1106 *left_edge = a;
1107 d2d_cdt_edge_sym(right_edge, &a);
1109 return TRUE;
1112 /* Three vertices, create a triangle. */
1113 if (vertex_count == 3)
1115 struct d2d_cdt_edge_ref a, b, c;
1116 float det;
1118 if (!d2d_cdt_create_edge(cdt, &a))
1119 return FALSE;
1120 if (!d2d_cdt_create_edge(cdt, &b))
1121 return FALSE;
1122 d2d_cdt_edge_sym(&tmp, &a);
1123 d2d_cdt_splice(cdt, &tmp, &b);
1125 d2d_cdt_edge_set_origin(cdt, &a, start_vertex);
1126 d2d_cdt_edge_set_destination(cdt, &a, start_vertex + 1);
1127 d2d_cdt_edge_set_origin(cdt, &b, start_vertex + 1);
1128 d2d_cdt_edge_set_destination(cdt, &b, start_vertex + 2);
1130 det = d2d_cdt_ccw(cdt, start_vertex, start_vertex + 1, start_vertex + 2);
1131 if (det != 0.0f && !d2d_cdt_connect(cdt, &c, &b, &a))
1132 return FALSE;
1134 if (det < 0.0f)
1136 d2d_cdt_edge_sym(left_edge, &c);
1137 *right_edge = c;
1139 else
1141 *left_edge = a;
1142 d2d_cdt_edge_sym(right_edge, &b);
1145 return TRUE;
1148 /* More than tree vertices, divide. */
1149 cut = vertex_count / 2;
1150 if (!d2d_cdt_triangulate(cdt, start_vertex, cut, &left_outer, &left_inner))
1151 return FALSE;
1152 if (!d2d_cdt_triangulate(cdt, start_vertex + cut, vertex_count - cut, &right_inner, &right_outer))
1153 return FALSE;
1154 /* Merge the left and right parts. */
1155 if (!d2d_cdt_merge(cdt, &left_outer, &left_inner, &right_inner, &right_outer))
1156 return FALSE;
1158 *left_edge = left_outer;
1159 *right_edge = right_outer;
1160 return TRUE;
1163 static int d2d_cdt_compare_vertices(const void *a, const void *b)
1165 const D2D1_POINT_2F *p0 = a;
1166 const D2D1_POINT_2F *p1 = b;
1167 float diff = p0->x - p1->x;
1169 if (diff == 0.0f)
1170 diff = p0->y - p1->y;
1172 return diff == 0.0f ? 0 : (diff > 0.0f ? 1 : -1);
1175 /* Determine whether a given point is inside the geometry, using the current
1176 * fill mode rule. */
1177 static BOOL d2d_path_geometry_point_inside(const struct d2d_geometry *geometry, const D2D1_POINT_2F *probe)
1179 const D2D1_POINT_2F *p0, *p1;
1180 D2D1_POINT_2F v_p, v_probe;
1181 unsigned int score;
1182 size_t i, j;
1184 for (i = 0, score = 0; i < geometry->u.path.figure_count; ++i)
1186 const struct d2d_figure *figure = &geometry->u.path.figures[i];
1188 if (probe->x < figure->bounds.left || probe->x > figure->bounds.right
1189 || probe->y < figure->bounds.top || probe->y > figure->bounds.bottom)
1190 continue;
1192 p0 = &figure->vertices[figure->vertex_count - 1];
1193 for (j = 0; j < figure->vertex_count; p0 = p1, ++j)
1195 p1 = &figure->vertices[j];
1196 d2d_point_subtract(&v_p, p1, p0);
1197 d2d_point_subtract(&v_probe, probe, p0);
1199 if ((probe->y < p0->y) != (probe->y < p1->y) && v_probe.x < v_p.x * (v_probe.y / v_p.y))
1201 if (geometry->u.path.fill_mode == D2D1_FILL_MODE_ALTERNATE || (probe->y < p0->y))
1202 ++score;
1203 else
1204 --score;
1209 return geometry->u.path.fill_mode == D2D1_FILL_MODE_ALTERNATE ? score & 1 : score;
1212 static BOOL d2d_path_geometry_add_face(struct d2d_geometry *geometry, const struct d2d_cdt *cdt,
1213 const struct d2d_cdt_edge_ref *base_edge)
1215 struct d2d_cdt_edge_ref tmp;
1216 struct d2d_face *face;
1217 D2D1_POINT_2F probe;
1219 if (cdt->edges[base_edge->idx].flags & D2D_CDT_EDGE_FLAG_VISITED(base_edge->r))
1220 return TRUE;
1222 if (!d2d_array_reserve((void **)&geometry->faces, &geometry->faces_size,
1223 geometry->face_count + 1, sizeof(*geometry->faces)))
1225 ERR("Failed to grow faces array.\n");
1226 return FALSE;
1229 face = &geometry->faces[geometry->face_count];
1231 /* It may seem tempting to use the center of the face as probe origin, but
1232 * multiplying by powers of two works much better for preserving accuracy. */
1234 tmp = *base_edge;
1235 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1236 face->v[0] = d2d_cdt_edge_origin(cdt, &tmp);
1237 probe.x = cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.25f;
1238 probe.y = cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.25f;
1240 d2d_cdt_edge_next_left(cdt, &tmp, &tmp);
1241 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1242 face->v[1] = d2d_cdt_edge_origin(cdt, &tmp);
1243 probe.x += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.25f;
1244 probe.y += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.25f;
1246 d2d_cdt_edge_next_left(cdt, &tmp, &tmp);
1247 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1248 face->v[2] = d2d_cdt_edge_origin(cdt, &tmp);
1249 probe.x += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.50f;
1250 probe.y += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.50f;
1252 if (d2d_cdt_leftof(cdt, face->v[2], base_edge) && d2d_path_geometry_point_inside(geometry, &probe))
1253 ++geometry->face_count;
1255 return TRUE;
1258 static BOOL d2d_cdt_generate_faces(const struct d2d_cdt *cdt, struct d2d_geometry *geometry)
1260 struct d2d_cdt_edge_ref base_edge;
1261 size_t i;
1263 for (i = 0; i < cdt->edge_count; ++i)
1265 if (cdt->edges[i].flags & D2D_CDT_EDGE_FLAG_FREED)
1266 continue;
1268 base_edge.idx = i;
1269 base_edge.r = 0;
1270 if (!d2d_path_geometry_add_face(geometry, cdt, &base_edge))
1271 goto fail;
1272 d2d_cdt_edge_sym(&base_edge, &base_edge);
1273 if (!d2d_path_geometry_add_face(geometry, cdt, &base_edge))
1274 goto fail;
1277 return TRUE;
1279 fail:
1280 HeapFree(GetProcessHeap(), 0, geometry->faces);
1281 geometry->faces = NULL;
1282 geometry->faces_size = 0;
1283 geometry->face_count = 0;
1284 return FALSE;
1287 static BOOL d2d_cdt_fixup(struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *base_edge)
1289 struct d2d_cdt_edge_ref candidate, next, new_base;
1290 unsigned int count = 0;
1292 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1293 if (next.idx == base_edge->idx)
1295 ERR("Degenerate face.\n");
1296 return FALSE;
1299 candidate = next;
1300 while (d2d_cdt_edge_destination(cdt, &next) != d2d_cdt_edge_origin(cdt, base_edge))
1302 if (d2d_cdt_incircle(cdt, d2d_cdt_edge_origin(cdt, base_edge), d2d_cdt_edge_destination(cdt, base_edge),
1303 d2d_cdt_edge_destination(cdt, &candidate), d2d_cdt_edge_destination(cdt, &next)))
1304 candidate = next;
1305 d2d_cdt_edge_next_left(cdt, &next, &next);
1306 ++count;
1309 if (count > 1)
1311 d2d_cdt_edge_next_left(cdt, &next, &candidate);
1312 if (d2d_cdt_edge_destination(cdt, &next) == d2d_cdt_edge_origin(cdt, base_edge))
1313 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1314 else
1315 next = *base_edge;
1316 if (!d2d_cdt_connect(cdt, &new_base, &candidate, &next))
1317 return FALSE;
1318 if (!d2d_cdt_fixup(cdt, &new_base))
1319 return FALSE;
1320 d2d_cdt_edge_sym(&new_base, &new_base);
1321 if (!d2d_cdt_fixup(cdt, &new_base))
1322 return FALSE;
1325 return TRUE;
1328 static void d2d_cdt_cut_edges(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *end_edge,
1329 const struct d2d_cdt_edge_ref *base_edge, size_t start_vertex, size_t end_vertex)
1331 struct d2d_cdt_edge_ref next;
1332 float ccw;
1334 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1335 if (d2d_cdt_edge_destination(cdt, &next) == end_vertex)
1337 *end_edge = next;
1338 return;
1341 ccw = d2d_cdt_ccw(cdt, d2d_cdt_edge_destination(cdt, &next), end_vertex, start_vertex);
1342 if (ccw == 0.0f)
1344 *end_edge = next;
1345 return;
1348 if (ccw > 0.0f)
1349 d2d_cdt_edge_next_left(cdt, &next, &next);
1351 d2d_cdt_edge_sym(&next, &next);
1352 d2d_cdt_cut_edges(cdt, end_edge, &next, start_vertex, end_vertex);
1353 d2d_cdt_destroy_edge(cdt, &next);
1356 static BOOL d2d_cdt_insert_segment(struct d2d_cdt *cdt, struct d2d_geometry *geometry,
1357 const struct d2d_cdt_edge_ref *origin, struct d2d_cdt_edge_ref *edge, size_t end_vertex)
1359 struct d2d_cdt_edge_ref base_edge, current, new_origin, next, target;
1360 size_t current_destination, current_origin;
1362 for (current = *origin;; current = next)
1364 d2d_cdt_edge_next_origin(cdt, &next, &current);
1366 current_destination = d2d_cdt_edge_destination(cdt, &current);
1367 if (current_destination == end_vertex)
1369 d2d_cdt_edge_sym(edge, &current);
1370 return TRUE;
1373 current_origin = d2d_cdt_edge_origin(cdt, &current);
1374 if (d2d_cdt_ccw(cdt, end_vertex, current_origin, current_destination) == 0.0f
1375 && (cdt->vertices[current_destination].x > cdt->vertices[current_origin].x)
1376 == (cdt->vertices[end_vertex].x > cdt->vertices[current_origin].x)
1377 && (cdt->vertices[current_destination].y > cdt->vertices[current_origin].y)
1378 == (cdt->vertices[end_vertex].y > cdt->vertices[current_origin].y))
1380 d2d_cdt_edge_sym(&new_origin, &current);
1381 return d2d_cdt_insert_segment(cdt, geometry, &new_origin, edge, end_vertex);
1384 if (d2d_cdt_rightof(cdt, end_vertex, &next) && d2d_cdt_leftof(cdt, end_vertex, &current))
1386 d2d_cdt_edge_next_left(cdt, &base_edge, &current);
1388 d2d_cdt_edge_sym(&base_edge, &base_edge);
1389 d2d_cdt_cut_edges(cdt, &target, &base_edge, d2d_cdt_edge_origin(cdt, origin), end_vertex);
1390 d2d_cdt_destroy_edge(cdt, &base_edge);
1392 if (!d2d_cdt_connect(cdt, &base_edge, &target, &current))
1393 return FALSE;
1394 *edge = base_edge;
1395 if (!d2d_cdt_fixup(cdt, &base_edge))
1396 return FALSE;
1397 d2d_cdt_edge_sym(&base_edge, &base_edge);
1398 if (!d2d_cdt_fixup(cdt, &base_edge))
1399 return FALSE;
1401 if (d2d_cdt_edge_origin(cdt, edge) == end_vertex)
1402 return TRUE;
1403 new_origin = *edge;
1404 return d2d_cdt_insert_segment(cdt, geometry, &new_origin, edge, end_vertex);
1407 if (next.idx == origin->idx)
1409 ERR("Triangle not found.\n");
1410 return FALSE;
1415 static BOOL d2d_cdt_insert_segments(struct d2d_cdt *cdt, struct d2d_geometry *geometry)
1417 size_t start_vertex, end_vertex, i, j, k;
1418 struct d2d_cdt_edge_ref edge, new_edge;
1419 const struct d2d_figure *figure;
1420 const D2D1_POINT_2F *p;
1421 BOOL found;
1423 for (i = 0; i < geometry->u.path.figure_count; ++i)
1425 figure = &geometry->u.path.figures[i];
1427 p = bsearch(&figure->vertices[figure->vertex_count - 1], cdt->vertices,
1428 geometry->vertex_count, sizeof(*p), d2d_cdt_compare_vertices);
1429 start_vertex = p - cdt->vertices;
1431 for (k = 0, found = FALSE; k < cdt->edge_count; ++k)
1433 if (cdt->edges[k].flags & D2D_CDT_EDGE_FLAG_FREED)
1434 continue;
1436 edge.idx = k;
1437 edge.r = 0;
1439 if (d2d_cdt_edge_origin(cdt, &edge) == start_vertex)
1441 found = TRUE;
1442 break;
1444 d2d_cdt_edge_sym(&edge, &edge);
1445 if (d2d_cdt_edge_origin(cdt, &edge) == start_vertex)
1447 found = TRUE;
1448 break;
1452 if (!found)
1454 ERR("Edge not found.\n");
1455 return FALSE;
1458 for (j = 0; j < figure->vertex_count; start_vertex = end_vertex, ++j)
1460 p = bsearch(&figure->vertices[j], cdt->vertices,
1461 geometry->vertex_count, sizeof(*p), d2d_cdt_compare_vertices);
1462 end_vertex = p - cdt->vertices;
1464 if (start_vertex == end_vertex)
1465 continue;
1467 if (!d2d_cdt_insert_segment(cdt, geometry, &edge, &new_edge, end_vertex))
1468 return FALSE;
1469 edge = new_edge;
1473 return TRUE;
1476 static BOOL d2d_geometry_intersections_add(struct d2d_geometry_intersections *i,
1477 size_t figure_idx, size_t segment_idx, float t, D2D1_POINT_2F p)
1479 struct d2d_geometry_intersection *intersection;
1481 if (!d2d_array_reserve((void **)&i->intersections, &i->intersections_size,
1482 i->intersection_count + 1, sizeof(*i->intersections)))
1484 ERR("Failed to grow intersections array.\n");
1485 return FALSE;
1488 intersection = &i->intersections[i->intersection_count++];
1489 intersection->figure_idx = figure_idx;
1490 intersection->segment_idx = segment_idx;
1491 intersection->t = t;
1492 intersection->p = p;
1494 return TRUE;
1497 static int d2d_geometry_intersections_compare(const void *a, const void *b)
1499 const struct d2d_geometry_intersection *i0 = a;
1500 const struct d2d_geometry_intersection *i1 = b;
1502 if (i0->figure_idx != i1->figure_idx)
1503 return i0->figure_idx - i1->figure_idx;
1504 if (i0->segment_idx != i1->segment_idx)
1505 return i0->segment_idx - i1->segment_idx;
1506 if (i0->t != i1->t)
1507 return i0->t > i1->t ? 1 : -1;
1508 return 0;
1511 /* Intersect the geometry's segments with themselves. This uses the
1512 * straightforward approach of testing everything against everything, but
1513 * there certainly exist more scalable algorithms for this. */
1514 /* FIXME: Beziers can't currently self-intersect. */
1515 static BOOL d2d_geometry_intersect_self(struct d2d_geometry *geometry)
1517 D2D1_POINT_2F p0, p1, q0, q1, v_p, v_q, v_qp, intersection;
1518 struct d2d_geometry_intersections intersections = {0};
1519 struct d2d_figure *figure_p, *figure_q;
1520 size_t i, j, k, l, max_l;
1521 BOOL ret = FALSE;
1522 float s, t, det;
1524 for (i = 0; i < geometry->u.path.figure_count; ++i)
1526 figure_p = &geometry->u.path.figures[i];
1527 p0 = figure_p->vertices[figure_p->vertex_count - 1];
1528 for (k = 0; k < figure_p->vertex_count; p0 = p1, ++k)
1530 p1 = figure_p->vertices[k];
1531 d2d_point_subtract(&v_p, &p1, &p0);
1532 for (j = 0; j < i || (j == i && k); ++j)
1534 figure_q = &geometry->u.path.figures[j];
1536 if (figure_p->bounds.left > figure_q->bounds.right
1537 || figure_q->bounds.left > figure_p->bounds.right
1538 || figure_p->bounds.top > figure_q->bounds.bottom
1539 || figure_q->bounds.top > figure_p->bounds.bottom)
1540 continue;
1542 max_l = j == i ? k - 1 : figure_q->vertex_count;
1543 q0 = figure_q->vertices[figure_q->vertex_count - 1];
1544 for (l = 0; l < max_l; q0 = q1, ++l)
1546 q1 = figure_q->vertices[l];
1547 d2d_point_subtract(&v_q, &q1, &q0);
1548 d2d_point_subtract(&v_qp, &p0, &q0);
1550 det = v_p.x * v_q.y - v_p.y * v_q.x;
1551 if (det == 0.0f)
1552 continue;
1554 s = (v_q.x * v_qp.y - v_q.y * v_qp.x) / det;
1555 t = (v_p.x * v_qp.y - v_p.y * v_qp.x) / det;
1557 if (s < 0.0f || s > 1.0f || t < 0.0f || t > 1.0f)
1558 continue;
1560 intersection.x = p0.x + v_p.x * s;
1561 intersection.y = p0.y + v_p.y * s;
1563 if (t > 0.0f && t < 1.0f
1564 && !d2d_geometry_intersections_add(&intersections, j, l, t, intersection))
1565 goto done;
1567 if (s > 0.0f && s < 1.0f
1568 && !d2d_geometry_intersections_add(&intersections, i, k, s, intersection))
1569 goto done;
1575 qsort(intersections.intersections, intersections.intersection_count,
1576 sizeof(*intersections.intersections), d2d_geometry_intersections_compare);
1577 for (i = 0; i < intersections.intersection_count; ++i)
1579 const struct d2d_geometry_intersection *inter = &intersections.intersections[i];
1581 if (!i || inter->figure_idx != intersections.intersections[i - 1].figure_idx)
1582 j = 0;
1584 if (!d2d_figure_insert_vertex(&geometry->u.path.figures[inter->figure_idx],
1585 inter->segment_idx + j, inter->p))
1586 goto done;
1587 ++j;
1590 ret = TRUE;
1592 done:
1593 HeapFree(GetProcessHeap(), 0, intersections.intersections);
1594 return ret;
1597 static HRESULT d2d_path_geometry_triangulate(struct d2d_geometry *geometry)
1599 struct d2d_cdt_edge_ref left_edge, right_edge;
1600 size_t vertex_count, i, j;
1601 struct d2d_cdt cdt = {0};
1602 D2D1_POINT_2F *vertices;
1604 for (i = 0, vertex_count = 0; i < geometry->u.path.figure_count; ++i)
1606 vertex_count += geometry->u.path.figures[i].vertex_count;
1609 if (vertex_count < 3)
1611 WARN("Geometry has %lu vertices.\n", (long)vertex_count);
1612 return S_OK;
1615 if (!(vertices = HeapAlloc(GetProcessHeap(), 0, vertex_count * sizeof(*vertices))))
1616 return E_OUTOFMEMORY;
1618 for (i = 0, j = 0; i < geometry->u.path.figure_count; ++i)
1620 memcpy(&vertices[j], geometry->u.path.figures[i].vertices,
1621 geometry->u.path.figures[i].vertex_count * sizeof(*vertices));
1622 j += geometry->u.path.figures[i].vertex_count;
1625 /* Sort vertices, eliminate duplicates. */
1626 qsort(vertices, vertex_count, sizeof(*vertices), d2d_cdt_compare_vertices);
1627 for (i = 1; i < vertex_count; ++i)
1629 if (!memcmp(&vertices[i - 1], &vertices[i], sizeof(*vertices)))
1631 --vertex_count;
1632 memmove(&vertices[i], &vertices[i + 1], (vertex_count - i) * sizeof(*vertices));
1633 --i;
1637 geometry->vertices = vertices;
1638 geometry->vertex_count = vertex_count;
1640 cdt.free_edge = ~0u;
1641 cdt.vertices = vertices;
1642 if (!d2d_cdt_triangulate(&cdt, 0, vertex_count, &left_edge, &right_edge))
1643 goto fail;
1644 if (!d2d_cdt_insert_segments(&cdt, geometry))
1645 goto fail;
1646 if (!d2d_cdt_generate_faces(&cdt, geometry))
1647 goto fail;
1649 HeapFree(GetProcessHeap(), 0, cdt.edges);
1650 return S_OK;
1652 fail:
1653 geometry->vertices = NULL;
1654 geometry->vertex_count = 0;
1655 HeapFree(GetProcessHeap(), 0, vertices);
1656 HeapFree(GetProcessHeap(), 0, cdt.edges);
1657 return E_FAIL;
1660 static BOOL d2d_path_geometry_add_figure(struct d2d_geometry *geometry)
1662 struct d2d_figure *figure;
1664 if (!d2d_array_reserve((void **)&geometry->u.path.figures, &geometry->u.path.figures_size,
1665 geometry->u.path.figure_count + 1, sizeof(*geometry->u.path.figures)))
1667 ERR("Failed to grow figures array.\n");
1668 return FALSE;
1671 figure = &geometry->u.path.figures[geometry->u.path.figure_count];
1672 memset(figure, 0, sizeof(*figure));
1673 figure->bounds.left = FLT_MAX;
1674 figure->bounds.top = FLT_MAX;
1675 figure->bounds.right = -FLT_MAX;
1676 figure->bounds.bottom = -FLT_MAX;
1678 ++geometry->u.path.figure_count;
1679 return TRUE;
1682 static void d2d_geometry_cleanup(struct d2d_geometry *geometry)
1684 HeapFree(GetProcessHeap(), 0, geometry->beziers);
1685 HeapFree(GetProcessHeap(), 0, geometry->faces);
1686 HeapFree(GetProcessHeap(), 0, geometry->vertices);
1687 ID2D1Factory_Release(geometry->factory);
1690 static void d2d_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
1691 const D2D1_MATRIX_3X2_F *transform, const struct ID2D1GeometryVtbl *vtbl)
1693 geometry->ID2D1Geometry_iface.lpVtbl = vtbl;
1694 geometry->refcount = 1;
1695 ID2D1Factory_AddRef(geometry->factory = factory);
1696 geometry->transform = *transform;
1699 static inline struct d2d_geometry *impl_from_ID2D1GeometrySink(ID2D1GeometrySink *iface)
1701 return CONTAINING_RECORD(iface, struct d2d_geometry, u.path.ID2D1GeometrySink_iface);
1704 static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_QueryInterface(ID2D1GeometrySink *iface, REFIID iid, void **out)
1706 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
1708 if (IsEqualGUID(iid, &IID_ID2D1GeometrySink)
1709 || IsEqualGUID(iid, &IID_ID2D1SimplifiedGeometrySink)
1710 || IsEqualGUID(iid, &IID_IUnknown))
1712 ID2D1GeometrySink_AddRef(iface);
1713 *out = iface;
1714 return S_OK;
1717 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
1719 *out = NULL;
1720 return E_NOINTERFACE;
1723 static ULONG STDMETHODCALLTYPE d2d_geometry_sink_AddRef(ID2D1GeometrySink *iface)
1725 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1727 TRACE("iface %p.\n", iface);
1729 return ID2D1Geometry_AddRef(&geometry->ID2D1Geometry_iface);
1732 static ULONG STDMETHODCALLTYPE d2d_geometry_sink_Release(ID2D1GeometrySink *iface)
1734 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1736 TRACE("iface %p.\n", iface);
1738 return ID2D1Geometry_Release(&geometry->ID2D1Geometry_iface);
1741 static void STDMETHODCALLTYPE d2d_geometry_sink_SetFillMode(ID2D1GeometrySink *iface, D2D1_FILL_MODE mode)
1743 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1745 TRACE("iface %p, mode %#x.\n", iface, mode);
1747 geometry->u.path.fill_mode = mode;
1750 static void STDMETHODCALLTYPE d2d_geometry_sink_SetSegmentFlags(ID2D1GeometrySink *iface, D2D1_PATH_SEGMENT flags)
1752 FIXME("iface %p, flags %#x stub!\n", iface, flags);
1755 static void STDMETHODCALLTYPE d2d_geometry_sink_BeginFigure(ID2D1GeometrySink *iface,
1756 D2D1_POINT_2F start_point, D2D1_FIGURE_BEGIN figure_begin)
1758 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1760 TRACE("iface %p, start_point {%.8e, %.8e}, figure_begin %#x.\n",
1761 iface, start_point.x, start_point.y, figure_begin);
1763 if (geometry->u.path.state != D2D_GEOMETRY_STATE_OPEN)
1765 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1766 return;
1769 if (figure_begin != D2D1_FIGURE_BEGIN_FILLED)
1770 FIXME("Ignoring figure_begin %#x.\n", figure_begin);
1772 if (!d2d_path_geometry_add_figure(geometry))
1774 ERR("Failed to add figure.\n");
1775 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1776 return;
1779 if (!d2d_figure_add_vertex(&geometry->u.path.figures[geometry->u.path.figure_count - 1], start_point))
1780 ERR("Failed to add vertex.\n");
1782 geometry->u.path.state = D2D_GEOMETRY_STATE_FIGURE;
1783 ++geometry->u.path.segment_count;
1786 static void STDMETHODCALLTYPE d2d_geometry_sink_AddLines(ID2D1GeometrySink *iface,
1787 const D2D1_POINT_2F *points, UINT32 count)
1789 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1790 unsigned int i;
1792 TRACE("iface %p, points %p, count %u.\n", iface, points, count);
1794 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
1796 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1797 return;
1800 for (i = 0; i < count; ++i)
1802 if (!d2d_figure_add_vertex(&geometry->u.path.figures[geometry->u.path.figure_count - 1], points[i]))
1804 ERR("Failed to add vertex.\n");
1805 return;
1809 geometry->u.path.segment_count += count;
1812 static void STDMETHODCALLTYPE d2d_geometry_sink_AddBeziers(ID2D1GeometrySink *iface,
1813 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
1815 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1816 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
1817 D2D1_POINT_2F p;
1818 unsigned int i;
1820 TRACE("iface %p, beziers %p, count %u.\n", iface, beziers, count);
1822 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
1824 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1825 return;
1828 for (i = 0; i < count; ++i)
1830 /* FIXME: This tries to approximate a cubic bezier with a quadratic one. */
1831 p.x = (beziers[i].point1.x + beziers[i].point2.x) * 0.75f;
1832 p.y = (beziers[i].point1.y + beziers[i].point2.y) * 0.75f;
1833 p.x -= (figure->vertices[figure->vertex_count - 1].x + beziers[i].point3.x) * 0.25f;
1834 p.y -= (figure->vertices[figure->vertex_count - 1].y + beziers[i].point3.y) * 0.25f;
1835 if (!d2d_figure_add_bezier(figure, figure->vertices[figure->vertex_count - 1], p, beziers[i].point3))
1837 ERR("Failed to add bezier.\n");
1838 return;
1842 geometry->u.path.segment_count += count;
1845 static void STDMETHODCALLTYPE d2d_geometry_sink_EndFigure(ID2D1GeometrySink *iface, D2D1_FIGURE_END figure_end)
1847 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1849 TRACE("iface %p, figure_end %#x.\n", iface, figure_end);
1851 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
1853 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1854 return;
1857 if (figure_end != D2D1_FIGURE_END_CLOSED)
1858 FIXME("Ignoring figure_end %#x.\n", figure_end);
1860 geometry->u.path.state = D2D_GEOMETRY_STATE_OPEN;
1863 static void d2d_path_geometry_free_figures(struct d2d_geometry *geometry)
1865 size_t i;
1867 if (!geometry->u.path.figures)
1868 return;
1870 for (i = 0; i < geometry->u.path.figure_count; ++i)
1872 HeapFree(GetProcessHeap(), 0, geometry->u.path.figures[i].beziers);
1873 HeapFree(GetProcessHeap(), 0, geometry->u.path.figures[i].vertices);
1875 HeapFree(GetProcessHeap(), 0, geometry->u.path.figures);
1876 geometry->u.path.figures = NULL;
1877 geometry->u.path.figures_size = 0;
1880 static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_Close(ID2D1GeometrySink *iface)
1882 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1883 HRESULT hr = E_FAIL;
1884 size_t i, start;
1886 TRACE("iface %p.\n", iface);
1888 if (geometry->u.path.state != D2D_GEOMETRY_STATE_OPEN)
1890 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
1891 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1892 return D2DERR_WRONG_STATE;
1894 geometry->u.path.state = D2D_GEOMETRY_STATE_CLOSED;
1896 if (!d2d_geometry_intersect_self(geometry))
1897 goto done;
1898 if (FAILED(hr = d2d_path_geometry_triangulate(geometry)))
1899 goto done;
1901 for (i = 0; i < geometry->u.path.figure_count; ++i)
1903 geometry->bezier_count += geometry->u.path.figures[i].bezier_count;
1906 if (!(geometry->beziers = HeapAlloc(GetProcessHeap(), 0,
1907 geometry->bezier_count * sizeof(*geometry->beziers))))
1909 ERR("Failed to allocate beziers array.\n");
1910 geometry->bezier_count = 0;
1911 hr = E_OUTOFMEMORY;
1912 goto done;
1915 for (i = 0, start = 0; i < geometry->u.path.figure_count; ++i)
1917 struct d2d_figure *figure = &geometry->u.path.figures[i];
1918 if (figure->bezier_count)
1920 memcpy(&geometry->beziers[start], figure->beziers,
1921 figure->bezier_count * sizeof(*figure->beziers));
1922 start += figure->bezier_count;
1926 done:
1927 d2d_path_geometry_free_figures(geometry);
1928 if (FAILED(hr))
1929 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1930 return hr;
1933 static void STDMETHODCALLTYPE d2d_geometry_sink_AddLine(ID2D1GeometrySink *iface, D2D1_POINT_2F point)
1935 TRACE("iface %p, point {%.8e, %.8e}.\n", iface, point.x, point.y);
1937 d2d_geometry_sink_AddLines(iface, &point, 1);
1940 static void STDMETHODCALLTYPE d2d_geometry_sink_AddBezier(ID2D1GeometrySink *iface, const D2D1_BEZIER_SEGMENT *bezier)
1942 TRACE("iface %p, bezier %p.\n", iface, bezier);
1944 d2d_geometry_sink_AddBeziers(iface, bezier, 1);
1947 static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBezier(ID2D1GeometrySink *iface,
1948 const D2D1_QUADRATIC_BEZIER_SEGMENT *bezier)
1950 TRACE("iface %p, bezier %p.\n", iface, bezier);
1952 ID2D1GeometrySink_AddQuadraticBeziers(iface, bezier, 1);
1955 static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBeziers(ID2D1GeometrySink *iface,
1956 const D2D1_QUADRATIC_BEZIER_SEGMENT *beziers, UINT32 bezier_count)
1958 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1959 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
1960 unsigned int i;
1962 TRACE("iface %p, beziers %p, bezier_count %u.\n", iface, beziers, bezier_count);
1964 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
1966 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1967 return;
1970 for (i = 0; i < bezier_count; ++i)
1972 if (!d2d_figure_add_bezier(figure, figure->vertices[figure->vertex_count - 1],
1973 beziers[i].point1, beziers[i].point2))
1975 ERR("Failed to add bezier.\n");
1976 return;
1980 geometry->u.path.segment_count += bezier_count;
1983 static void STDMETHODCALLTYPE d2d_geometry_sink_AddArc(ID2D1GeometrySink *iface, const D2D1_ARC_SEGMENT *arc)
1985 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1987 FIXME("iface %p, arc %p stub!\n", iface, arc);
1989 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
1991 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1992 return;
1995 if (!d2d_figure_add_vertex(&geometry->u.path.figures[geometry->u.path.figure_count - 1], arc->point))
1997 ERR("Failed to add vertex.\n");
1998 return;
2001 ++geometry->u.path.segment_count;
2004 static const struct ID2D1GeometrySinkVtbl d2d_geometry_sink_vtbl =
2006 d2d_geometry_sink_QueryInterface,
2007 d2d_geometry_sink_AddRef,
2008 d2d_geometry_sink_Release,
2009 d2d_geometry_sink_SetFillMode,
2010 d2d_geometry_sink_SetSegmentFlags,
2011 d2d_geometry_sink_BeginFigure,
2012 d2d_geometry_sink_AddLines,
2013 d2d_geometry_sink_AddBeziers,
2014 d2d_geometry_sink_EndFigure,
2015 d2d_geometry_sink_Close,
2016 d2d_geometry_sink_AddLine,
2017 d2d_geometry_sink_AddBezier,
2018 d2d_geometry_sink_AddQuadraticBezier,
2019 d2d_geometry_sink_AddQuadraticBeziers,
2020 d2d_geometry_sink_AddArc,
2023 static inline struct d2d_geometry *impl_from_ID2D1PathGeometry(ID2D1PathGeometry *iface)
2025 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
2028 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_QueryInterface(ID2D1PathGeometry *iface, REFIID iid, void **out)
2030 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
2032 if (IsEqualGUID(iid, &IID_ID2D1PathGeometry)
2033 || IsEqualGUID(iid, &IID_ID2D1Geometry)
2034 || IsEqualGUID(iid, &IID_ID2D1Resource)
2035 || IsEqualGUID(iid, &IID_IUnknown))
2037 ID2D1PathGeometry_AddRef(iface);
2038 *out = iface;
2039 return S_OK;
2042 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
2044 *out = NULL;
2045 return E_NOINTERFACE;
2048 static ULONG STDMETHODCALLTYPE d2d_path_geometry_AddRef(ID2D1PathGeometry *iface)
2050 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2051 ULONG refcount = InterlockedIncrement(&geometry->refcount);
2053 TRACE("%p increasing refcount to %u.\n", iface, refcount);
2055 return refcount;
2058 static ULONG STDMETHODCALLTYPE d2d_path_geometry_Release(ID2D1PathGeometry *iface)
2060 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2061 ULONG refcount = InterlockedDecrement(&geometry->refcount);
2063 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
2065 if (!refcount)
2067 d2d_path_geometry_free_figures(geometry);
2068 d2d_geometry_cleanup(geometry);
2069 HeapFree(GetProcessHeap(), 0, geometry);
2072 return refcount;
2075 static void STDMETHODCALLTYPE d2d_path_geometry_GetFactory(ID2D1PathGeometry *iface, ID2D1Factory **factory)
2077 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2079 TRACE("iface %p, factory %p.\n", iface, factory);
2081 ID2D1Factory_AddRef(*factory = geometry->factory);
2084 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetBounds(ID2D1PathGeometry *iface,
2085 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
2087 FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
2089 return E_NOTIMPL;
2092 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetWidenedBounds(ID2D1PathGeometry *iface, float stroke_width,
2093 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_RECT_F *bounds)
2095 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
2096 iface, stroke_width, stroke_style, transform, tolerance, bounds);
2098 return E_NOTIMPL;
2101 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_StrokeContainsPoint(ID2D1PathGeometry *iface,
2102 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
2103 float tolerance, BOOL *contains)
2105 FIXME("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
2106 "transform %p, tolerance %.8e, contains %p stub!\n",
2107 iface, point.x, point.y, stroke_width, stroke_style, transform, tolerance, contains);
2109 return E_NOTIMPL;
2112 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_FillContainsPoint(ID2D1PathGeometry *iface,
2113 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
2115 FIXME("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p stub!\n",
2116 iface, point.x, point.y, transform, tolerance, contains);
2118 return E_NOTIMPL;
2121 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_CompareWithGeometry(ID2D1PathGeometry *iface,
2122 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
2124 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
2125 iface, geometry, transform, tolerance, relation);
2127 return E_NOTIMPL;
2130 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *iface,
2131 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
2132 ID2D1SimplifiedGeometrySink *sink)
2134 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2135 iface, option, transform, tolerance, sink);
2137 return E_NOTIMPL;
2140 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Tessellate(ID2D1PathGeometry *iface,
2141 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
2143 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
2145 return E_NOTIMPL;
2148 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_CombineWithGeometry(ID2D1PathGeometry *iface,
2149 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
2150 float tolerance, ID2D1SimplifiedGeometrySink *sink)
2152 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2153 iface, geometry, combine_mode, transform, tolerance, sink);
2155 return E_NOTIMPL;
2158 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Outline(ID2D1PathGeometry *iface,
2159 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
2161 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
2163 return E_NOTIMPL;
2166 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeArea(ID2D1PathGeometry *iface,
2167 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
2169 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
2171 return E_NOTIMPL;
2174 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeLength(ID2D1PathGeometry *iface,
2175 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
2177 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
2179 return E_NOTIMPL;
2182 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputePointAtLength(ID2D1PathGeometry *iface, float length,
2183 const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point, D2D1_POINT_2F *tangent)
2185 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
2186 iface, length, transform, tolerance, point, tangent);
2188 return E_NOTIMPL;
2191 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Widen(ID2D1PathGeometry *iface, float stroke_width,
2192 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
2193 ID2D1SimplifiedGeometrySink *sink)
2195 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
2196 iface, stroke_width, stroke_style, transform, tolerance, sink);
2198 return E_NOTIMPL;
2201 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Open(ID2D1PathGeometry *iface, ID2D1GeometrySink **sink)
2203 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2205 TRACE("iface %p, sink %p.\n", iface, sink);
2207 if (geometry->u.path.state != D2D_GEOMETRY_STATE_INITIAL)
2208 return D2DERR_WRONG_STATE;
2210 *sink = &geometry->u.path.ID2D1GeometrySink_iface;
2211 ID2D1GeometrySink_AddRef(*sink);
2213 geometry->u.path.state = D2D_GEOMETRY_STATE_OPEN;
2215 return S_OK;
2218 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Stream(ID2D1PathGeometry *iface, ID2D1GeometrySink *sink)
2220 FIXME("iface %p, sink %p stub!\n", iface, sink);
2222 return E_NOTIMPL;
2225 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetSegmentCount(ID2D1PathGeometry *iface, UINT32 *count)
2227 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2229 TRACE("iface %p, count %p.\n", iface, count);
2231 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
2232 return D2DERR_WRONG_STATE;
2234 *count = geometry->u.path.segment_count;
2236 return S_OK;
2239 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetFigureCount(ID2D1PathGeometry *iface, UINT32 *count)
2241 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2243 TRACE("iface %p, count %p.\n", iface, count);
2245 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
2246 return D2DERR_WRONG_STATE;
2248 *count = geometry->u.path.figure_count;
2250 return S_OK;
2253 static const struct ID2D1PathGeometryVtbl d2d_path_geometry_vtbl =
2255 d2d_path_geometry_QueryInterface,
2256 d2d_path_geometry_AddRef,
2257 d2d_path_geometry_Release,
2258 d2d_path_geometry_GetFactory,
2259 d2d_path_geometry_GetBounds,
2260 d2d_path_geometry_GetWidenedBounds,
2261 d2d_path_geometry_StrokeContainsPoint,
2262 d2d_path_geometry_FillContainsPoint,
2263 d2d_path_geometry_CompareWithGeometry,
2264 d2d_path_geometry_Simplify,
2265 d2d_path_geometry_Tessellate,
2266 d2d_path_geometry_CombineWithGeometry,
2267 d2d_path_geometry_Outline,
2268 d2d_path_geometry_ComputeArea,
2269 d2d_path_geometry_ComputeLength,
2270 d2d_path_geometry_ComputePointAtLength,
2271 d2d_path_geometry_Widen,
2272 d2d_path_geometry_Open,
2273 d2d_path_geometry_Stream,
2274 d2d_path_geometry_GetSegmentCount,
2275 d2d_path_geometry_GetFigureCount,
2278 void d2d_path_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory)
2280 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl);
2281 geometry->u.path.ID2D1GeometrySink_iface.lpVtbl = &d2d_geometry_sink_vtbl;
2284 static inline struct d2d_geometry *impl_from_ID2D1RectangleGeometry(ID2D1RectangleGeometry *iface)
2286 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
2289 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_QueryInterface(ID2D1RectangleGeometry *iface,
2290 REFIID iid, void **out)
2292 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
2294 if (IsEqualGUID(iid, &IID_ID2D1RectangleGeometry)
2295 || IsEqualGUID(iid, &IID_ID2D1Geometry)
2296 || IsEqualGUID(iid, &IID_ID2D1Resource)
2297 || IsEqualGUID(iid, &IID_IUnknown))
2299 ID2D1RectangleGeometry_AddRef(iface);
2300 *out = iface;
2301 return S_OK;
2304 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
2306 *out = NULL;
2307 return E_NOINTERFACE;
2310 static ULONG STDMETHODCALLTYPE d2d_rectangle_geometry_AddRef(ID2D1RectangleGeometry *iface)
2312 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
2313 ULONG refcount = InterlockedIncrement(&geometry->refcount);
2315 TRACE("%p increasing refcount to %u.\n", iface, refcount);
2317 return refcount;
2320 static ULONG STDMETHODCALLTYPE d2d_rectangle_geometry_Release(ID2D1RectangleGeometry *iface)
2322 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
2323 ULONG refcount = InterlockedDecrement(&geometry->refcount);
2325 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
2327 if (!refcount)
2329 d2d_geometry_cleanup(geometry);
2330 HeapFree(GetProcessHeap(), 0, geometry);
2333 return refcount;
2336 static void STDMETHODCALLTYPE d2d_rectangle_geometry_GetFactory(ID2D1RectangleGeometry *iface, ID2D1Factory **factory)
2338 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
2340 TRACE("iface %p, factory %p.\n", iface, factory);
2342 ID2D1Factory_AddRef(*factory = geometry->factory);
2345 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_GetBounds(ID2D1RectangleGeometry *iface,
2346 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
2348 FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
2350 return E_NOTIMPL;
2353 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_GetWidenedBounds(ID2D1RectangleGeometry *iface,
2354 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
2355 float tolerance, D2D1_RECT_F *bounds)
2357 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
2358 iface, stroke_width, stroke_style, transform, tolerance, bounds);
2360 return E_NOTIMPL;
2363 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_StrokeContainsPoint(ID2D1RectangleGeometry *iface,
2364 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
2365 float tolerance, BOOL *contains)
2367 FIXME("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
2368 "transform %p, tolerance %.8e, contains %p stub!\n",
2369 iface, point.x, point.y, stroke_width, stroke_style, transform, tolerance, contains);
2371 return E_NOTIMPL;
2374 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_FillContainsPoint(ID2D1RectangleGeometry *iface,
2375 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
2377 FIXME("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p stub!\n",
2378 iface, point.x, point.y, transform, tolerance, contains);
2380 return E_NOTIMPL;
2383 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_CompareWithGeometry(ID2D1RectangleGeometry *iface,
2384 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
2386 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
2387 iface, geometry, transform, tolerance, relation);
2389 return E_NOTIMPL;
2392 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Simplify(ID2D1RectangleGeometry *iface,
2393 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
2394 ID2D1SimplifiedGeometrySink *sink)
2396 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2397 iface, option, transform, tolerance, sink);
2399 return E_NOTIMPL;
2402 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Tessellate(ID2D1RectangleGeometry *iface,
2403 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
2405 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
2407 return E_NOTIMPL;
2410 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_CombineWithGeometry(ID2D1RectangleGeometry *iface,
2411 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
2412 float tolerance, ID2D1SimplifiedGeometrySink *sink)
2414 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2415 iface, geometry, combine_mode, transform, tolerance, sink);
2417 return E_NOTIMPL;
2420 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Outline(ID2D1RectangleGeometry *iface,
2421 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
2423 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
2425 return E_NOTIMPL;
2428 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputeArea(ID2D1RectangleGeometry *iface,
2429 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
2431 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
2433 return E_NOTIMPL;
2436 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputeLength(ID2D1RectangleGeometry *iface,
2437 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
2439 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
2441 return E_NOTIMPL;
2444 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputePointAtLength(ID2D1RectangleGeometry *iface,
2445 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
2446 D2D1_POINT_2F *tangent)
2448 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
2449 iface, length, transform, tolerance, point, tangent);
2451 return E_NOTIMPL;
2454 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Widen(ID2D1RectangleGeometry *iface, float stroke_width,
2455 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
2456 ID2D1SimplifiedGeometrySink *sink)
2458 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
2459 iface, stroke_width, stroke_style, transform, tolerance, sink);
2461 return E_NOTIMPL;
2464 static void STDMETHODCALLTYPE d2d_rectangle_geometry_GetRect(ID2D1RectangleGeometry *iface, D2D1_RECT_F *rect)
2466 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
2468 TRACE("iface %p, rect %p.\n", iface, rect);
2470 *rect = geometry->u.rectangle.rect;
2473 static const struct ID2D1RectangleGeometryVtbl d2d_rectangle_geometry_vtbl =
2475 d2d_rectangle_geometry_QueryInterface,
2476 d2d_rectangle_geometry_AddRef,
2477 d2d_rectangle_geometry_Release,
2478 d2d_rectangle_geometry_GetFactory,
2479 d2d_rectangle_geometry_GetBounds,
2480 d2d_rectangle_geometry_GetWidenedBounds,
2481 d2d_rectangle_geometry_StrokeContainsPoint,
2482 d2d_rectangle_geometry_FillContainsPoint,
2483 d2d_rectangle_geometry_CompareWithGeometry,
2484 d2d_rectangle_geometry_Simplify,
2485 d2d_rectangle_geometry_Tessellate,
2486 d2d_rectangle_geometry_CombineWithGeometry,
2487 d2d_rectangle_geometry_Outline,
2488 d2d_rectangle_geometry_ComputeArea,
2489 d2d_rectangle_geometry_ComputeLength,
2490 d2d_rectangle_geometry_ComputePointAtLength,
2491 d2d_rectangle_geometry_Widen,
2492 d2d_rectangle_geometry_GetRect,
2495 HRESULT d2d_rectangle_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_RECT_F *rect)
2497 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl);
2498 geometry->u.rectangle.rect = *rect;
2500 if (!(geometry->vertices = HeapAlloc(GetProcessHeap(), 0, 4 * sizeof(*geometry->vertices))))
2502 d2d_geometry_cleanup(geometry);
2503 return E_OUTOFMEMORY;
2505 geometry->vertex_count = 4;
2506 if (!d2d_array_reserve((void **)&geometry->faces, &geometry->faces_size, 2, sizeof(*geometry->faces)))
2508 d2d_geometry_cleanup(geometry);
2509 return E_OUTOFMEMORY;
2511 geometry->face_count = 2;
2513 geometry->vertices[0].x = min(rect->left, rect->right);
2514 geometry->vertices[0].y = min(rect->top, rect->bottom);
2515 geometry->vertices[1].x = min(rect->left, rect->right);
2516 geometry->vertices[1].y = max(rect->top, rect->bottom);
2517 geometry->vertices[2].x = max(rect->left, rect->right);
2518 geometry->vertices[2].y = min(rect->top, rect->bottom);
2519 geometry->vertices[3].x = max(rect->left, rect->right);
2520 geometry->vertices[3].y = max(rect->top, rect->bottom);
2522 geometry->faces[0].v[0] = 0;
2523 geometry->faces[0].v[1] = 2;
2524 geometry->faces[0].v[2] = 1;
2525 geometry->faces[1].v[0] = 1;
2526 geometry->faces[1].v[1] = 2;
2527 geometry->faces[1].v[2] = 3;
2529 return S_OK;
2532 static inline struct d2d_geometry *impl_from_ID2D1TransformedGeometry(ID2D1TransformedGeometry *iface)
2534 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
2537 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_QueryInterface(ID2D1TransformedGeometry *iface,
2538 REFIID iid, void **out)
2540 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
2542 if (IsEqualGUID(iid, &IID_ID2D1TransformedGeometry)
2543 || IsEqualGUID(iid, &IID_ID2D1Geometry)
2544 || IsEqualGUID(iid, &IID_ID2D1Resource)
2545 || IsEqualGUID(iid, &IID_IUnknown))
2547 ID2D1TransformedGeometry_AddRef(iface);
2548 *out = iface;
2549 return S_OK;
2552 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
2554 *out = NULL;
2555 return E_NOINTERFACE;
2558 static ULONG STDMETHODCALLTYPE d2d_transformed_geometry_AddRef(ID2D1TransformedGeometry *iface)
2560 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
2561 ULONG refcount = InterlockedIncrement(&geometry->refcount);
2563 TRACE("%p increasing refcount to %u.\n", iface, refcount);
2565 return refcount;
2568 static ULONG STDMETHODCALLTYPE d2d_transformed_geometry_Release(ID2D1TransformedGeometry *iface)
2570 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
2571 ULONG refcount = InterlockedDecrement(&geometry->refcount);
2573 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
2575 if (!refcount)
2577 geometry->beziers = NULL;
2578 geometry->faces = NULL;
2579 geometry->vertices = NULL;
2580 ID2D1Geometry_Release(geometry->u.transformed.src_geometry);
2581 d2d_geometry_cleanup(geometry);
2582 HeapFree(GetProcessHeap(), 0, geometry);
2585 return refcount;
2588 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetFactory(ID2D1TransformedGeometry *iface,
2589 ID2D1Factory **factory)
2591 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
2593 TRACE("iface %p, factory %p.\n", iface, factory);
2595 ID2D1Factory_AddRef(*factory = geometry->factory);
2598 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_GetBounds(ID2D1TransformedGeometry *iface,
2599 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
2601 FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
2603 return E_NOTIMPL;
2606 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_GetWidenedBounds(ID2D1TransformedGeometry *iface,
2607 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
2608 float tolerance, D2D1_RECT_F *bounds)
2610 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
2611 iface, stroke_width, stroke_style, transform, tolerance, bounds);
2613 return E_NOTIMPL;
2616 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_StrokeContainsPoint(ID2D1TransformedGeometry *iface,
2617 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
2618 float tolerance, BOOL *contains)
2620 FIXME("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
2621 "transform %p, tolerance %.8e, contains %p stub!\n",
2622 iface, point.x, point.y, stroke_width, stroke_style, transform, tolerance, contains);
2624 return E_NOTIMPL;
2627 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_FillContainsPoint(ID2D1TransformedGeometry *iface,
2628 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
2630 FIXME("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p stub!\n",
2631 iface, point.x, point.y, transform, tolerance, contains);
2633 return E_NOTIMPL;
2636 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_CompareWithGeometry(ID2D1TransformedGeometry *iface,
2637 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
2639 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
2640 iface, geometry, transform, tolerance, relation);
2642 return E_NOTIMPL;
2645 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Simplify(ID2D1TransformedGeometry *iface,
2646 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
2647 ID2D1SimplifiedGeometrySink *sink)
2649 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2650 iface, option, transform, tolerance, sink);
2652 return E_NOTIMPL;
2655 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Tessellate(ID2D1TransformedGeometry *iface,
2656 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
2658 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
2660 return E_NOTIMPL;
2663 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_CombineWithGeometry(ID2D1TransformedGeometry *iface,
2664 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
2665 float tolerance, ID2D1SimplifiedGeometrySink *sink)
2667 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2668 iface, geometry, combine_mode, transform, tolerance, sink);
2670 return E_NOTIMPL;
2673 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Outline(ID2D1TransformedGeometry *iface,
2674 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
2676 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
2678 return E_NOTIMPL;
2681 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputeArea(ID2D1TransformedGeometry *iface,
2682 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
2684 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
2686 return E_NOTIMPL;
2689 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputeLength(ID2D1TransformedGeometry *iface,
2690 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
2692 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
2694 return E_NOTIMPL;
2697 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputePointAtLength(ID2D1TransformedGeometry *iface,
2698 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
2699 D2D1_POINT_2F *tangent)
2701 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
2702 iface, length, transform, tolerance, point, tangent);
2704 return E_NOTIMPL;
2707 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Widen(ID2D1TransformedGeometry *iface, float stroke_width,
2708 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
2709 ID2D1SimplifiedGeometrySink *sink)
2711 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
2712 iface, stroke_width, stroke_style, transform, tolerance, sink);
2714 return E_NOTIMPL;
2717 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetSourceGeometry(ID2D1TransformedGeometry *iface,
2718 ID2D1Geometry **src_geometry)
2720 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
2722 TRACE("iface %p, src_geometry %p.\n", iface, src_geometry);
2724 ID2D1Geometry_AddRef(*src_geometry = geometry->u.transformed.src_geometry);
2727 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetTransform(ID2D1TransformedGeometry *iface,
2728 D2D1_MATRIX_3X2_F *transform)
2730 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
2732 TRACE("iface %p, transform %p.\n", iface, transform);
2734 *transform = geometry->transform;
2737 static const struct ID2D1TransformedGeometryVtbl d2d_transformed_geometry_vtbl =
2739 d2d_transformed_geometry_QueryInterface,
2740 d2d_transformed_geometry_AddRef,
2741 d2d_transformed_geometry_Release,
2742 d2d_transformed_geometry_GetFactory,
2743 d2d_transformed_geometry_GetBounds,
2744 d2d_transformed_geometry_GetWidenedBounds,
2745 d2d_transformed_geometry_StrokeContainsPoint,
2746 d2d_transformed_geometry_FillContainsPoint,
2747 d2d_transformed_geometry_CompareWithGeometry,
2748 d2d_transformed_geometry_Simplify,
2749 d2d_transformed_geometry_Tessellate,
2750 d2d_transformed_geometry_CombineWithGeometry,
2751 d2d_transformed_geometry_Outline,
2752 d2d_transformed_geometry_ComputeArea,
2753 d2d_transformed_geometry_ComputeLength,
2754 d2d_transformed_geometry_ComputePointAtLength,
2755 d2d_transformed_geometry_Widen,
2756 d2d_transformed_geometry_GetSourceGeometry,
2757 d2d_transformed_geometry_GetTransform,
2760 void d2d_transformed_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
2761 ID2D1Geometry *src_geometry, const D2D_MATRIX_3X2_F *transform)
2763 struct d2d_geometry *src_impl;
2765 d2d_geometry_init(geometry, factory, transform, (ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl);
2766 ID2D1Geometry_AddRef(geometry->u.transformed.src_geometry = src_geometry);
2767 src_impl = unsafe_impl_from_ID2D1Geometry(src_geometry);
2768 geometry->vertices = src_impl->vertices;
2769 geometry->vertex_count = src_impl->vertex_count;
2770 geometry->faces = src_impl->faces;
2771 geometry->face_count = src_impl->face_count;
2772 geometry->beziers = src_impl->beziers;
2773 geometry->bezier_count = src_impl->bezier_count;
2776 struct d2d_geometry *unsafe_impl_from_ID2D1Geometry(ID2D1Geometry *iface)
2778 if (!iface)
2779 return NULL;
2780 assert(iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl
2781 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl
2782 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl);
2783 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);