reg/tests: Test case sensitivity when creating and deleting registry keys.
[wine.git] / dlls / d2d1 / geometry.c
blob31a3eda4bdd25d44a6ccbfa200c0cb1443519e7c
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_FIGURE_FLAG_CLOSED 0x00000001u
30 #define D2D_FIGURE_FLAG_HOLLOW 0x00000002u
32 #define D2D_CDT_EDGE_FLAG_FREED 0x80000000u
33 #define D2D_CDT_EDGE_FLAG_VISITED(r) (1u << (r))
35 #define D2D_FP_EPS (1.0f / (1 << FLT_MANT_DIG))
37 static const D2D1_MATRIX_3X2_F identity =
39 1.0f, 0.0f,
40 0.0f, 1.0f,
41 0.0f, 0.0f,
44 enum d2d_cdt_edge_next
46 D2D_EDGE_NEXT_ORIGIN = 0,
47 D2D_EDGE_NEXT_ROT = 1,
48 D2D_EDGE_NEXT_SYM = 2,
49 D2D_EDGE_NEXT_TOR = 3,
52 enum d2d_vertex_type
54 D2D_VERTEX_TYPE_NONE,
55 D2D_VERTEX_TYPE_LINE,
56 D2D_VERTEX_TYPE_BEZIER,
59 struct d2d_figure
61 D2D1_POINT_2F *vertices;
62 size_t vertices_size;
63 enum d2d_vertex_type *vertex_types;
64 size_t vertex_types_size;
65 size_t vertex_count;
67 D2D1_POINT_2F *bezier_controls;
68 size_t bezier_controls_size;
69 size_t bezier_control_count;
71 D2D1_RECT_F bounds;
72 unsigned int flags;
75 struct d2d_cdt_edge_ref
77 size_t idx;
78 enum d2d_cdt_edge_next r;
81 struct d2d_cdt_edge
83 struct d2d_cdt_edge_ref next[4];
84 size_t vertex[2];
85 unsigned int flags;
88 struct d2d_cdt
90 struct d2d_cdt_edge *edges;
91 size_t edges_size;
92 size_t edge_count;
93 size_t free_edge;
95 const D2D1_POINT_2F *vertices;
98 struct d2d_geometry_intersection
100 size_t figure_idx;
101 size_t segment_idx;
102 float t;
103 D2D1_POINT_2F p;
106 struct d2d_geometry_intersections
108 struct d2d_geometry_intersection *intersections;
109 size_t intersections_size;
110 size_t intersection_count;
113 struct d2d_fp_two_vec2
115 float x[2];
116 float y[2];
119 struct d2d_fp_fin
121 float *now, *other;
122 size_t length;
125 static void d2d_bezier_vertex_set(struct d2d_bezier_vertex *b,
126 const D2D1_POINT_2F *p, float u, float v, float sign)
128 b->position = *p;
129 b->texcoord.u = u;
130 b->texcoord.v = v;
131 b->texcoord.sign = sign;
134 static void d2d_face_set(struct d2d_face *f, UINT16 v0, UINT16 v1, UINT16 v2)
136 f->v[0] = v0;
137 f->v[1] = v1;
138 f->v[2] = v2;
141 static void d2d_outline_vertex_set(struct d2d_outline_vertex *v, float x, float y,
142 float prev_x, float prev_y, float next_x, float next_y)
144 d2d_point_set(&v->position, x, y);
145 d2d_point_set(&v->prev, prev_x, prev_y);
146 d2d_point_set(&v->next, next_x, next_y);
149 static void d2d_bezier_outline_vertex_set(struct d2d_bezier_outline_vertex *b, const D2D1_POINT_2F *position,
150 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2,
151 float prev_x, float prev_y, float next_x, float next_y)
153 b->position = *position;
154 b->p0 = *p0;
155 b->p1 = *p1;
156 b->p2 = *p2;
157 d2d_point_set(&b->prev, prev_x, prev_y);
158 d2d_point_set(&b->next, next_x, next_y);
161 static void d2d_fp_two_sum(float *out, float a, float b)
163 float a_virt, a_round, b_virt, b_round;
165 out[1] = a + b;
166 b_virt = out[1] - a;
167 a_virt = out[1] - b_virt;
168 b_round = b - b_virt;
169 a_round = a - a_virt;
170 out[0] = a_round + b_round;
173 static void d2d_fp_fast_two_sum(float *out, float a, float b)
175 float b_virt;
177 out[1] = a + b;
178 b_virt = out[1] - a;
179 out[0] = b - b_virt;
182 static void d2d_fp_two_two_sum(float *out, const float *a, const float *b)
184 float sum[2];
186 d2d_fp_two_sum(out, a[0], b[0]);
187 d2d_fp_two_sum(sum, a[1], out[1]);
188 d2d_fp_two_sum(&out[1], sum[0], b[1]);
189 d2d_fp_two_sum(&out[2], sum[1], out[2]);
192 static void d2d_fp_two_diff_tail(float *out, float a, float b, float x)
194 float a_virt, a_round, b_virt, b_round;
196 b_virt = a - x;
197 a_virt = x + b_virt;
198 b_round = b_virt - b;
199 a_round = a - a_virt;
200 *out = a_round + b_round;
203 static void d2d_fp_two_two_diff(float *out, const float *a, const float *b)
205 float sum[2], diff;
207 diff = a[0] - b[0];
208 d2d_fp_two_diff_tail(out, a[0], b[0], diff);
209 d2d_fp_two_sum(sum, a[1], diff);
210 diff = sum[0] - b[1];
211 d2d_fp_two_diff_tail(&out[1], sum[0], b[1], diff);
212 d2d_fp_two_sum(&out[2], sum[1], diff);
215 static void d2d_fp_split(float *out, float a)
217 float a_big, c;
219 c = a * ((1 << (FLT_MANT_DIG / 2)) + 1.0f);
220 a_big = c - a;
221 out[1] = c - a_big;
222 out[0] = a - out[1];
225 static void d2d_fp_two_product_presplit(float *out, float a, float b, const float *b_split)
227 float a_split[2], err1, err2, err3;
229 out[1] = a * b;
230 d2d_fp_split(a_split, a);
231 err1 = out[1] - (a_split[1] * b_split[1]);
232 err2 = err1 - (a_split[0] * b_split[1]);
233 err3 = err2 - (a_split[1] * b_split[0]);
234 out[0] = (a_split[0] * b_split[0]) - err3;
237 static void d2d_fp_two_product(float *out, float a, float b)
239 float b_split[2];
241 d2d_fp_split(b_split, b);
242 d2d_fp_two_product_presplit(out, a, b, b_split);
245 static void d2d_fp_square(float *out, float a)
247 float a_split[2], err1, err2;
249 out[1] = a * a;
250 d2d_fp_split(a_split, a);
251 err1 = out[1] - (a_split[1] * a_split[1]);
252 err2 = err1 - ((a_split[1] + a_split[1]) * a_split[0]);
253 out[0] = (a_split[0] * a_split[0]) - err2;
256 static float d2d_fp_estimate(float *a, size_t len)
258 float out = a[0];
259 size_t idx = 1;
261 while (idx < len)
262 out += a[idx++];
264 return out;
267 static void d2d_fp_fast_expansion_sum_zeroelim(float *out, size_t *out_len,
268 const float *a, size_t a_len, const float *b, size_t b_len)
270 float sum[2], q, a_curr, b_curr;
271 size_t a_idx, b_idx, out_idx;
273 a_curr = a[0];
274 b_curr = b[0];
275 a_idx = b_idx = 0;
276 if ((b_curr > a_curr) == (b_curr > -a_curr))
278 q = a_curr;
279 a_curr = a[++a_idx];
281 else
283 q = b_curr;
284 b_curr = b[++b_idx];
286 out_idx = 0;
287 if (a_idx < a_len && b_idx < b_len)
289 if ((b_curr > a_curr) == (b_curr > -a_curr))
291 d2d_fp_fast_two_sum(sum, a_curr, q);
292 a_curr = a[++a_idx];
294 else
296 d2d_fp_fast_two_sum(sum, b_curr, q);
297 b_curr = b[++b_idx];
299 if (sum[0] != 0.0f)
300 out[out_idx++] = sum[0];
301 q = sum[1];
302 while (a_idx < a_len && b_idx < b_len)
304 if ((b_curr > a_curr) == (b_curr > -a_curr))
306 d2d_fp_two_sum(sum, q, a_curr);
307 a_curr = a[++a_idx];
309 else
311 d2d_fp_two_sum(sum, q, b_curr);
312 b_curr = b[++b_idx];
314 if (sum[0] != 0.0f)
315 out[out_idx++] = sum[0];
316 q = sum[1];
319 while (a_idx < a_len)
321 d2d_fp_two_sum(sum, q, a_curr);
322 a_curr = a[++a_idx];
323 if (sum[0] != 0.0f)
324 out[out_idx++] = sum[0];
325 q = sum[1];
327 while (b_idx < b_len)
329 d2d_fp_two_sum(sum, q, b_curr);
330 b_curr = b[++b_idx];
331 if (sum[0] != 0.0f)
332 out[out_idx++] = sum[0];
333 q = sum[1];
335 if (q != 0.0f || !out_idx)
336 out[out_idx++] = q;
338 *out_len = out_idx;
341 static void d2d_fp_scale_expansion_zeroelim(float *out, size_t *out_len, const float *a, size_t a_len, float b)
343 float product[2], sum[2], b_split[2], q[2], a_curr;
344 size_t a_idx, out_idx;
346 d2d_fp_split(b_split, b);
347 d2d_fp_two_product_presplit(q, a[0], b, b_split);
348 out_idx = 0;
349 if (q[0] != 0.0f)
350 out[out_idx++] = q[0];
351 for (a_idx = 1; a_idx < a_len; ++a_idx)
353 a_curr = a[a_idx];
354 d2d_fp_two_product_presplit(product, a_curr, b, b_split);
355 d2d_fp_two_sum(sum, q[1], product[0]);
356 if (sum[0] != 0.0f)
357 out[out_idx++] = sum[0];
358 d2d_fp_fast_two_sum(q, product[1], sum[1]);
359 if (q[0] != 0.0f)
360 out[out_idx++] = q[0];
362 if (q[1] != 0.0f || !out_idx)
363 out[out_idx++] = q[1];
365 *out_len = out_idx;
368 static void d2d_point_subtract(D2D1_POINT_2F *out,
369 const D2D1_POINT_2F *a, const D2D1_POINT_2F *b)
371 out->x = a->x - b->x;
372 out->y = a->y - b->y;
375 static void d2d_point_scale(D2D1_POINT_2F *p, float scale)
377 p->x *= scale;
378 p->y *= scale;
381 static void d2d_point_lerp(D2D1_POINT_2F *out,
382 const D2D1_POINT_2F *a, const D2D1_POINT_2F *b, float t)
384 out->x = a->x * (1.0f - t) + b->x * t;
385 out->y = a->y * (1.0f - t) + b->y * t;
388 static float d2d_point_dot(const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1)
390 return p0->x * p1->x + p0->y * p1->y;
393 static void d2d_point_normalise(D2D1_POINT_2F *p)
395 float l;
397 if ((l = sqrtf(d2d_point_dot(p, p))) != 0.0f)
398 d2d_point_scale(p, 1.0f / l);
401 /* This implementation is based on the paper "Adaptive Precision
402 * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
403 * associated (Public Domain) code by Jonathan Richard Shewchuk. */
404 static float d2d_point_ccw(const D2D1_POINT_2F *a, const D2D1_POINT_2F *b, const D2D1_POINT_2F *c)
406 static const float err_bound_result = (3.0f + 8.0f * D2D_FP_EPS) * D2D_FP_EPS;
407 static const float err_bound_a = (3.0f + 16.0f * D2D_FP_EPS) * D2D_FP_EPS;
408 static const float err_bound_b = (2.0f + 12.0f * D2D_FP_EPS) * D2D_FP_EPS;
409 static const float err_bound_c = (9.0f + 64.0f * D2D_FP_EPS) * D2D_FP_EPS * D2D_FP_EPS;
410 float det_d[16], det_c2[12], det_c1[8], det_b[4], temp4[4], temp2a[2], temp2b[2], abxacy[2], abyacx[2];
411 size_t det_d_len, det_c2_len, det_c1_len;
412 float det, det_sum, err_bound;
413 struct d2d_fp_two_vec2 ab, ac;
415 ab.x[1] = b->x - a->x;
416 ab.y[1] = b->y - a->y;
417 ac.x[1] = c->x - a->x;
418 ac.y[1] = c->y - a->y;
420 abxacy[1] = ab.x[1] * ac.y[1];
421 abyacx[1] = ab.y[1] * ac.x[1];
422 det = abxacy[1] - abyacx[1];
424 if (abxacy[1] > 0.0f)
426 if (abyacx[1] <= 0.0f)
427 return det;
428 det_sum = abxacy[1] + abyacx[1];
430 else if (abxacy[1] < 0.0f)
432 if (abyacx[1] >= 0.0f)
433 return det;
434 det_sum = -abxacy[1] - abyacx[1];
436 else
438 return det;
441 err_bound = err_bound_a * det_sum;
442 if (det >= err_bound || -det >= err_bound)
443 return det;
445 d2d_fp_two_product(abxacy, ab.x[1], ac.y[1]);
446 d2d_fp_two_product(abyacx, ab.y[1], ac.x[1]);
447 d2d_fp_two_two_diff(det_b, abxacy, abyacx);
449 det = d2d_fp_estimate(det_b, 4);
450 err_bound = err_bound_b * det_sum;
451 if (det >= err_bound || -det >= err_bound)
452 return det;
454 d2d_fp_two_diff_tail(&ab.x[0], b->x, a->x, ab.x[1]);
455 d2d_fp_two_diff_tail(&ab.y[0], b->y, a->y, ab.y[1]);
456 d2d_fp_two_diff_tail(&ac.x[0], c->x, a->x, ac.x[1]);
457 d2d_fp_two_diff_tail(&ac.y[0], c->y, a->y, ac.y[1]);
459 if (ab.x[0] == 0.0f && ab.y[0] == 0.0f && ac.x[0] == 0.0f && ac.y[0] == 0.0f)
460 return det;
462 err_bound = err_bound_c * det_sum + err_bound_result * fabsf(det);
463 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]);
464 if (det >= err_bound || -det >= err_bound)
465 return det;
467 d2d_fp_two_product(temp2a, ab.x[0], ac.y[1]);
468 d2d_fp_two_product(temp2b, ab.y[0], ac.x[1]);
469 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
470 d2d_fp_fast_expansion_sum_zeroelim(det_c1, &det_c1_len, det_b, 4, temp4, 4);
472 d2d_fp_two_product(temp2a, ab.x[1], ac.y[0]);
473 d2d_fp_two_product(temp2b, ab.y[1], ac.x[0]);
474 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
475 d2d_fp_fast_expansion_sum_zeroelim(det_c2, &det_c2_len, det_c1, det_c1_len, temp4, 4);
477 d2d_fp_two_product(temp2a, ab.x[0], ac.y[0]);
478 d2d_fp_two_product(temp2b, ab.y[0], ac.x[0]);
479 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
480 d2d_fp_fast_expansion_sum_zeroelim(det_d, &det_d_len, det_c2, det_c2_len, temp4, 4);
482 return det_d[det_d_len - 1];
485 static BOOL d2d_array_reserve(void **elements, size_t *capacity, size_t element_count, size_t element_size)
487 size_t new_capacity, max_capacity;
488 void *new_elements;
490 if (element_count <= *capacity)
491 return TRUE;
493 max_capacity = ~(size_t)0 / element_size;
494 if (max_capacity < element_count)
495 return FALSE;
497 new_capacity = max(*capacity, 4);
498 while (new_capacity < element_count && new_capacity <= max_capacity / 2)
499 new_capacity *= 2;
501 if (new_capacity < element_count)
502 new_capacity = max_capacity;
504 if (*elements)
505 new_elements = HeapReAlloc(GetProcessHeap(), 0, *elements, new_capacity * element_size);
506 else
507 new_elements = HeapAlloc(GetProcessHeap(), 0, new_capacity * element_size);
509 if (!new_elements)
510 return FALSE;
512 *elements = new_elements;
513 *capacity = new_capacity;
514 return TRUE;
517 static BOOL d2d_figure_insert_vertex(struct d2d_figure *figure, size_t idx, D2D1_POINT_2F vertex)
519 if (!d2d_array_reserve((void **)&figure->vertices, &figure->vertices_size,
520 figure->vertex_count + 1, sizeof(*figure->vertices)))
522 ERR("Failed to grow vertices array.\n");
523 return FALSE;
526 if (!d2d_array_reserve((void **)&figure->vertex_types, &figure->vertex_types_size,
527 figure->vertex_count + 1, sizeof(*figure->vertex_types)))
529 ERR("Failed to grow vertex types array.\n");
530 return FALSE;
533 memmove(&figure->vertices[idx + 1], &figure->vertices[idx],
534 (figure->vertex_count - idx) * sizeof(*figure->vertices));
535 memmove(&figure->vertex_types[idx + 1], &figure->vertex_types[idx],
536 (figure->vertex_count - idx) * sizeof(*figure->vertex_types));
537 figure->vertices[idx] = vertex;
538 figure->vertex_types[idx] = D2D_VERTEX_TYPE_NONE;
539 d2d_rect_expand(&figure->bounds, &vertex);
540 ++figure->vertex_count;
541 return TRUE;
544 static BOOL d2d_figure_add_vertex(struct d2d_figure *figure, D2D1_POINT_2F vertex)
546 size_t last = figure->vertex_count - 1;
548 if (figure->vertex_count && figure->vertex_types[last] == D2D_VERTEX_TYPE_LINE
549 && !memcmp(&figure->vertices[last], &vertex, sizeof(vertex)))
550 return TRUE;
552 if (!d2d_array_reserve((void **)&figure->vertices, &figure->vertices_size,
553 figure->vertex_count + 1, sizeof(*figure->vertices)))
555 ERR("Failed to grow vertices array.\n");
556 return FALSE;
559 if (!d2d_array_reserve((void **)&figure->vertex_types, &figure->vertex_types_size,
560 figure->vertex_count + 1, sizeof(*figure->vertex_types)))
562 ERR("Failed to grow vertex types array.\n");
563 return FALSE;
566 figure->vertices[figure->vertex_count] = vertex;
567 figure->vertex_types[figure->vertex_count] = D2D_VERTEX_TYPE_NONE;
568 d2d_rect_expand(&figure->bounds, &vertex);
569 ++figure->vertex_count;
570 return TRUE;
573 static BOOL d2d_figure_add_bezier_control(struct d2d_figure *figure, const D2D1_POINT_2F *p)
575 if (!d2d_array_reserve((void **)&figure->bezier_controls, &figure->bezier_controls_size,
576 figure->bezier_control_count + 1, sizeof(*figure->bezier_controls)))
578 ERR("Failed to grow bezier controls array.\n");
579 return FALSE;
582 figure->bezier_controls[figure->bezier_control_count++] = *p;
584 return TRUE;
587 static void d2d_cdt_edge_rot(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
589 dst->idx = src->idx;
590 dst->r = (src->r + D2D_EDGE_NEXT_ROT) & 3;
593 static void d2d_cdt_edge_sym(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
595 dst->idx = src->idx;
596 dst->r = (src->r + D2D_EDGE_NEXT_SYM) & 3;
599 static void d2d_cdt_edge_tor(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
601 dst->idx = src->idx;
602 dst->r = (src->r + D2D_EDGE_NEXT_TOR) & 3;
605 static void d2d_cdt_edge_next_left(const struct d2d_cdt *cdt,
606 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
608 d2d_cdt_edge_rot(dst, &cdt->edges[src->idx].next[(src->r + D2D_EDGE_NEXT_TOR) & 3]);
611 static void d2d_cdt_edge_next_origin(const struct d2d_cdt *cdt,
612 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
614 *dst = cdt->edges[src->idx].next[src->r];
617 static void d2d_cdt_edge_prev_origin(const struct d2d_cdt *cdt,
618 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
620 d2d_cdt_edge_rot(dst, &cdt->edges[src->idx].next[(src->r + D2D_EDGE_NEXT_ROT) & 3]);
623 static size_t d2d_cdt_edge_origin(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
625 return cdt->edges[e->idx].vertex[e->r >> 1];
628 static size_t d2d_cdt_edge_destination(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
630 return cdt->edges[e->idx].vertex[!(e->r >> 1)];
633 static void d2d_cdt_edge_set_origin(const struct d2d_cdt *cdt,
634 const struct d2d_cdt_edge_ref *e, size_t vertex)
636 cdt->edges[e->idx].vertex[e->r >> 1] = vertex;
639 static void d2d_cdt_edge_set_destination(const struct d2d_cdt *cdt,
640 const struct d2d_cdt_edge_ref *e, size_t vertex)
642 cdt->edges[e->idx].vertex[!(e->r >> 1)] = vertex;
645 static float d2d_cdt_ccw(const struct d2d_cdt *cdt, size_t a, size_t b, size_t c)
647 return d2d_point_ccw(&cdt->vertices[a], &cdt->vertices[b], &cdt->vertices[c]);
650 static BOOL d2d_cdt_rightof(const struct d2d_cdt *cdt, size_t p, const struct d2d_cdt_edge_ref *e)
652 return d2d_cdt_ccw(cdt, p, d2d_cdt_edge_destination(cdt, e), d2d_cdt_edge_origin(cdt, e)) > 0.0f;
655 static BOOL d2d_cdt_leftof(const struct d2d_cdt *cdt, size_t p, const struct d2d_cdt_edge_ref *e)
657 return d2d_cdt_ccw(cdt, p, d2d_cdt_edge_origin(cdt, e), d2d_cdt_edge_destination(cdt, e)) > 0.0f;
660 /* |ax ay|
661 * |bx by| */
662 static void d2d_fp_four_det2x2(float *out, float ax, float ay, float bx, float by)
664 float axby[2], aybx[2];
666 d2d_fp_two_product(axby, ax, by);
667 d2d_fp_two_product(aybx, ay, bx);
668 d2d_fp_two_two_diff(out, axby, aybx);
671 /* (a->x² + a->y²) * det2x2 */
672 static void d2d_fp_sub_det3x3(float *out, size_t *out_len, const struct d2d_fp_two_vec2 *a, const float *det2x2)
674 size_t axd_len, ayd_len, axxd_len, ayyd_len;
675 float axd[8], ayd[8], axxd[16], ayyd[16];
677 d2d_fp_scale_expansion_zeroelim(axd, &axd_len, det2x2, 4, a->x[1]);
678 d2d_fp_scale_expansion_zeroelim(axxd, &axxd_len, axd, axd_len, a->x[1]);
679 d2d_fp_scale_expansion_zeroelim(ayd, &ayd_len, det2x2, 4, a->y[1]);
680 d2d_fp_scale_expansion_zeroelim(ayyd, &ayyd_len, ayd, ayd_len, a->y[1]);
681 d2d_fp_fast_expansion_sum_zeroelim(out, out_len, axxd, axxd_len, ayyd, ayyd_len);
684 /* det_abt = det_ab * c[0]
685 * fin += c[0] * (az * b - bz * a + c[1] * det_ab * 2.0f) */
686 static void d2d_cdt_incircle_refine1(struct d2d_fp_fin *fin, float *det_abt, size_t *det_abt_len,
687 const float *det_ab, float a, const float *az, float b, const float *bz, const float *c)
689 size_t temp48_len, temp32_len, temp16a_len, temp16b_len, temp16c_len, temp8_len;
690 float temp48[48], temp32[32], temp16a[16], temp16b[16], temp16c[16], temp8[8];
691 float *swap;
693 d2d_fp_scale_expansion_zeroelim(det_abt, det_abt_len, det_ab, 4, c[0]);
694 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, det_abt, *det_abt_len, 2.0f * c[1]);
695 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, az, 4, c[0]);
696 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, temp8, temp8_len, b);
697 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, bz, 4, c[0]);
698 d2d_fp_scale_expansion_zeroelim(temp16c, &temp16c_len, temp8, temp8_len, -a);
699 d2d_fp_fast_expansion_sum_zeroelim(temp32, &temp32_len, temp16a, temp16a_len, temp16b, temp16b_len);
700 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16c, temp16c_len, temp32, temp32_len);
701 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
702 swap = fin->now; fin->now = fin->other; fin->other = swap;
705 static void d2d_cdt_incircle_refine2(struct d2d_fp_fin *fin, const struct d2d_fp_two_vec2 *a,
706 const struct d2d_fp_two_vec2 *b, const float *bz, const struct d2d_fp_two_vec2 *c, const float *cz,
707 const float *axt_det_bc, size_t axt_det_bc_len, const float *ayt_det_bc, size_t ayt_det_bc_len)
709 size_t temp64_len, temp48_len, temp32a_len, temp32b_len, temp16a_len, temp16b_len, temp8_len;
710 float temp64[64], temp48[48], temp32a[32], temp32b[32], temp16a[16], temp16b[16], temp8[8];
711 float bct[8], bctt[4], temp4a[4], temp4b[4], temp2a[2], temp2b[2];
712 size_t bct_len, bctt_len;
713 float *swap;
715 /* 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]) */
716 /* bctt = b->x[0] * c->y[0] + c->x[0] * b->y[0] */
717 if (b->x[0] != 0.0f || b->y[0] != 0.0f || c->x[0] != 0.0f || c->y[0] != 0.0f)
719 d2d_fp_two_product(temp2a, b->x[0], c->y[1]);
720 d2d_fp_two_product(temp2b, b->x[1], c->y[0]);
721 d2d_fp_two_two_sum(temp4a, temp2a, temp2b);
722 d2d_fp_two_product(temp2a, c->x[0], -b->y[1]);
723 d2d_fp_two_product(temp2b, c->x[1], -b->y[0]);
724 d2d_fp_two_two_sum(temp4b, temp2a, temp2b);
725 d2d_fp_fast_expansion_sum_zeroelim(bct, &bct_len, temp4a, 4, temp4b, 4);
727 d2d_fp_two_product(temp2a, b->x[0], c->y[0]);
728 d2d_fp_two_product(temp2b, c->x[0], b->y[0]);
729 d2d_fp_two_two_diff(bctt, temp2a, temp2b);
730 bctt_len = 4;
732 else
734 bct[0] = 0.0f;
735 bct_len = 1;
736 bctt[0] = 0.0f;
737 bctt_len = 1;
740 if (a->x[0] != 0.0f)
742 size_t axt_bct_len, axt_bctt_len;
743 float axt_bct[16], axt_bctt[8];
745 /* fin += a->x[0] * (axt_det_bc + bct * 2.0f * a->x[1]) */
746 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, axt_det_bc, axt_det_bc_len, a->x[0]);
747 d2d_fp_scale_expansion_zeroelim(axt_bct, &axt_bct_len, bct, bct_len, a->x[0]);
748 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, axt_bct, axt_bct_len, 2.0f * a->x[1]);
749 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16a, temp16a_len, temp32a, temp32a_len);
750 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
751 swap = fin->now; fin->now = fin->other; fin->other = swap;
753 if (b->y[0] != 0.0f)
755 /* fin += a->x[0] * cz * b->y[0] */
756 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, cz, 4, a->x[0]);
757 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, temp8, temp8_len, b->y[0]);
758 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp16a, temp16a_len);
759 swap = fin->now; fin->now = fin->other; fin->other = swap;
762 if (c->y[0] != 0.0f)
764 /* fin -= a->x[0] * bz * c->y[0] */
765 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, bz, 4, -a->x[0]);
766 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, temp8, temp8_len, c->y[0]);
767 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp16a, temp16a_len);
768 swap = fin->now; fin->now = fin->other; fin->other = swap;
771 /* fin += a->x[0] * (bct * a->x[0] + bctt * (2.0f * a->x[1] + a->x[0])) */
772 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, axt_bct, axt_bct_len, a->x[0]);
773 d2d_fp_scale_expansion_zeroelim(axt_bctt, &axt_bctt_len, bctt, bctt_len, a->x[0]);
774 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, axt_bctt, axt_bctt_len, 2.0f * a->x[1]);
775 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, axt_bctt, axt_bctt_len, a->x[0]);
776 d2d_fp_fast_expansion_sum_zeroelim(temp32b, &temp32b_len, temp16a, temp16a_len, temp16b, temp16b_len);
777 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, temp32a, temp32a_len, temp32b, temp32b_len);
778 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp64, temp64_len);
779 swap = fin->now; fin->now = fin->other; fin->other = swap;
782 if (a->y[0] != 0.0f)
784 size_t ayt_bct_len, ayt_bctt_len;
785 float ayt_bct[16], ayt_bctt[8];
787 /* fin += a->y[0] * (ayt_det_bc + bct * 2.0f * a->y[1]) */
788 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, ayt_det_bc, ayt_det_bc_len, a->y[0]);
789 d2d_fp_scale_expansion_zeroelim(ayt_bct, &ayt_bct_len, bct, bct_len, a->y[0]);
790 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, ayt_bct, ayt_bct_len, 2.0f * a->y[1]);
791 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16a, temp16a_len, temp32a, temp32a_len);
792 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
793 swap = fin->now; fin->now = fin->other; fin->other = swap;
795 /* fin += a->y[0] * (bct * a->y[0] + bctt * (2.0f * a->y[1] + a->y[0])) */
796 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, ayt_bct, ayt_bct_len, a->y[0]);
797 d2d_fp_scale_expansion_zeroelim(ayt_bctt, &ayt_bctt_len, bctt, bctt_len, a->y[0]);
798 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, ayt_bctt, ayt_bctt_len, 2.0f * a->y[1]);
799 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, ayt_bctt, ayt_bctt_len, a->y[0]);
800 d2d_fp_fast_expansion_sum_zeroelim(temp32b, &temp32b_len, temp16a, temp16a_len, temp16b, temp16b_len);
801 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, temp32a, temp32a_len, temp32b, temp32b_len);
802 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp64, temp64_len);
803 swap = fin->now; fin->now = fin->other; fin->other = swap;
807 /* Determine if point D is inside or outside the circle defined by points A,
808 * B, C. As explained in the paper by Guibas and Stolfi, this is equivalent to
809 * calculating the signed volume of the tetrahedron defined by projecting the
810 * points onto the paraboloid of revolution x = x² + y²,
811 * λ:(x, y) → (x, y, x² + y²). I.e., D is inside the cirlce if
813 * |λ(A) 1|
814 * |λ(B) 1| > 0
815 * |λ(C) 1|
816 * |λ(D) 1|
818 * After translating D to the origin, that becomes:
820 * |λ(A-D)|
821 * |λ(B-D)| > 0
822 * |λ(C-D)|
824 * This implementation is based on the paper "Adaptive Precision
825 * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
826 * associated (Public Domain) code by Jonathan Richard Shewchuk. */
827 static BOOL d2d_cdt_incircle(const struct d2d_cdt *cdt, size_t a, size_t b, size_t c, size_t d)
829 static const float err_bound_result = (3.0f + 8.0f * D2D_FP_EPS) * D2D_FP_EPS;
830 static const float err_bound_a = (10.0f + 96.0f * D2D_FP_EPS) * D2D_FP_EPS;
831 static const float err_bound_b = (4.0f + 48.0f * D2D_FP_EPS) * D2D_FP_EPS;
832 static const float err_bound_c = (44.0f + 576.0f * D2D_FP_EPS) * D2D_FP_EPS * D2D_FP_EPS;
834 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;
835 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];
836 float fin1[1152], fin2[1152], temp64[64], sub_det_a[32], sub_det_b[32], sub_det_c[32];
837 float det_bc[4], det_ca[4], det_ab[4], daz[4], dbz[4], dcz[4], temp2a[2], temp2b[2];
838 size_t temp64_len, sub_det_a_len, sub_det_b_len, sub_det_c_len;
839 float dbxdcy, dbydcx, dcxday, dcydax, daxdby, daydbx;
840 const D2D1_POINT_2F *p = cdt->vertices;
841 struct d2d_fp_two_vec2 da, db, dc;
842 float permanent, err_bound, det;
843 struct d2d_fp_fin fin;
845 da.x[1] = p[a].x - p[d].x;
846 da.y[1] = p[a].y - p[d].y;
847 db.x[1] = p[b].x - p[d].x;
848 db.y[1] = p[b].y - p[d].y;
849 dc.x[1] = p[c].x - p[d].x;
850 dc.y[1] = p[c].y - p[d].y;
852 daz[3] = da.x[1] * da.x[1] + da.y[1] * da.y[1];
853 dbxdcy = db.x[1] * dc.y[1];
854 dbydcx = db.y[1] * dc.x[1];
856 dbz[3] = db.x[1] * db.x[1] + db.y[1] * db.y[1];
857 dcxday = dc.x[1] * da.y[1];
858 dcydax = dc.y[1] * da.x[1];
860 dcz[3] = dc.x[1] * dc.x[1] + dc.y[1] * dc.y[1];
861 daxdby = da.x[1] * db.y[1];
862 daydbx = da.y[1] * db.x[1];
864 det = daz[3] * (dbxdcy - dbydcx) + dbz[3] * (dcxday - dcydax) + dcz[3] * (daxdby - daydbx);
865 permanent = daz[3] * (fabsf(dbxdcy) + fabsf(dbydcx))
866 + dbz[3] * (fabsf(dcxday) + fabsf(dcydax))
867 + dcz[3] * (fabsf(daxdby) + fabsf(daydbx));
868 err_bound = err_bound_a * permanent;
869 if (det > err_bound || -det > err_bound)
870 return det > 0.0f;
872 fin.now = fin1;
873 fin.other = fin2;
875 d2d_fp_four_det2x2(det_bc, db.x[1], db.y[1], dc.x[1], dc.y[1]);
876 d2d_fp_sub_det3x3(sub_det_a, &sub_det_a_len, &da, det_bc);
878 d2d_fp_four_det2x2(det_ca, dc.x[1], dc.y[1], da.x[1], da.y[1]);
879 d2d_fp_sub_det3x3(sub_det_b, &sub_det_b_len, &db, det_ca);
881 d2d_fp_four_det2x2(det_ab, da.x[1], da.y[1], db.x[1], db.y[1]);
882 d2d_fp_sub_det3x3(sub_det_c, &sub_det_c_len, &dc, det_ab);
884 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, sub_det_a, sub_det_a_len, sub_det_b, sub_det_b_len);
885 d2d_fp_fast_expansion_sum_zeroelim(fin.now, &fin.length, temp64, temp64_len, sub_det_c, sub_det_c_len);
886 det = d2d_fp_estimate(fin.now, fin.length);
887 err_bound = err_bound_b * permanent;
888 if (det >= err_bound || -det >= err_bound)
889 return det > 0.0f;
891 d2d_fp_two_diff_tail(&da.x[0], p[a].x, p[d].x, da.x[1]);
892 d2d_fp_two_diff_tail(&da.y[0], p[a].y, p[d].y, da.y[1]);
893 d2d_fp_two_diff_tail(&db.x[0], p[b].x, p[d].x, db.x[1]);
894 d2d_fp_two_diff_tail(&db.y[0], p[b].y, p[d].y, db.y[1]);
895 d2d_fp_two_diff_tail(&dc.x[0], p[c].x, p[d].x, dc.x[1]);
896 d2d_fp_two_diff_tail(&dc.y[0], p[c].y, p[d].y, dc.y[1]);
897 if (da.x[0] == 0.0f && db.x[0] == 0.0f && dc.x[0] == 0.0f
898 && da.y[0] == 0.0f && db.y[0] == 0.0f && dc.y[0] == 0.0f)
899 return det > 0.0f;
901 err_bound = err_bound_c * permanent + err_bound_result * fabsf(det);
902 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]))
903 + 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]))
904 + (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]))
905 + 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]))
906 + (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]))
907 + 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]));
908 if (det >= err_bound || -det >= err_bound)
909 return det > 0.0f;
911 if (db.x[0] != 0.0f || db.y[0] != 0.0f || dc.x[0] != 0.0f || dc.y[0] != 0.0f)
913 d2d_fp_square(temp2a, da.x[1]);
914 d2d_fp_square(temp2b, da.y[1]);
915 d2d_fp_two_two_sum(daz, temp2a, temp2b);
917 if (dc.x[0] != 0.0f || dc.y[0] != 0.0f || da.x[0] != 0.0f || da.y[0] != 0.0f)
919 d2d_fp_square(temp2a, db.x[1]);
920 d2d_fp_square(temp2b, db.y[1]);
921 d2d_fp_two_two_sum(dbz, temp2a, temp2b);
923 if (da.x[0] != 0.0f || da.y[0] != 0.0f || db.x[0] != 0.0f || db.y[0] != 0.0f)
925 d2d_fp_square(temp2a, dc.x[1]);
926 d2d_fp_square(temp2b, dc.y[1]);
927 d2d_fp_two_two_sum(dcz, temp2a, temp2b);
930 if (da.x[0] != 0.0f)
931 d2d_cdt_incircle_refine1(&fin, axt_det_bc, &axt_det_bc_len, det_bc, dc.y[1], dcz, db.y[1], dbz, da.x);
932 if (da.y[0] != 0.0f)
933 d2d_cdt_incircle_refine1(&fin, ayt_det_bc, &ayt_det_bc_len, det_bc, db.x[1], dbz, dc.x[1], dcz, da.y);
934 if (db.x[0] != 0.0f)
935 d2d_cdt_incircle_refine1(&fin, bxt_det_ca, &bxt_det_ca_len, det_ca, da.y[1], daz, dc.y[1], dcz, db.x);
936 if (db.y[0] != 0.0f)
937 d2d_cdt_incircle_refine1(&fin, byt_det_ca, &byt_det_ca_len, det_ca, dc.x[1], dcz, da.x[1], daz, db.y);
938 if (dc.x[0] != 0.0f)
939 d2d_cdt_incircle_refine1(&fin, cxt_det_ab, &cxt_det_ab_len, det_ab, db.y[1], dbz, da.y[1], daz, dc.x);
940 if (dc.y[0] != 0.0f)
941 d2d_cdt_incircle_refine1(&fin, cyt_det_ab, &cyt_det_ab_len, det_ab, da.x[1], daz, db.x[1], dbz, dc.y);
943 if (da.x[0] != 0.0f || da.y[0] != 0.0f)
944 d2d_cdt_incircle_refine2(&fin, &da, &db, dbz, &dc, dcz,
945 axt_det_bc, axt_det_bc_len, ayt_det_bc, ayt_det_bc_len);
946 if (db.x[0] != 0.0f || db.y[0] != 0.0f)
947 d2d_cdt_incircle_refine2(&fin, &db, &dc, dcz, &da, daz,
948 bxt_det_ca, bxt_det_ca_len, byt_det_ca, byt_det_ca_len);
949 if (dc.x[0] != 0.0f || dc.y[0] != 0.0f)
950 d2d_cdt_incircle_refine2(&fin, &dc, &da, daz, &db, dbz,
951 cxt_det_ab, cxt_det_ab_len, cyt_det_ab, cyt_det_ab_len);
953 return fin.now[fin.length - 1] > 0.0f;
956 static void d2d_cdt_splice(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *a,
957 const struct d2d_cdt_edge_ref *b)
959 struct d2d_cdt_edge_ref ta, tb, alpha, beta;
961 ta = cdt->edges[a->idx].next[a->r];
962 tb = cdt->edges[b->idx].next[b->r];
963 cdt->edges[a->idx].next[a->r] = tb;
964 cdt->edges[b->idx].next[b->r] = ta;
966 d2d_cdt_edge_rot(&alpha, &ta);
967 d2d_cdt_edge_rot(&beta, &tb);
969 ta = cdt->edges[alpha.idx].next[alpha.r];
970 tb = cdt->edges[beta.idx].next[beta.r];
971 cdt->edges[alpha.idx].next[alpha.r] = tb;
972 cdt->edges[beta.idx].next[beta.r] = ta;
975 static BOOL d2d_cdt_create_edge(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *e)
977 struct d2d_cdt_edge *edge;
979 if (cdt->free_edge != ~0u)
981 e->idx = cdt->free_edge;
982 cdt->free_edge = cdt->edges[e->idx].next[D2D_EDGE_NEXT_ORIGIN].idx;
984 else
986 if (!d2d_array_reserve((void **)&cdt->edges, &cdt->edges_size, cdt->edge_count + 1, sizeof(*cdt->edges)))
988 ERR("Failed to grow edges array.\n");
989 return FALSE;
991 e->idx = cdt->edge_count++;
993 e->r = 0;
995 edge = &cdt->edges[e->idx];
996 edge->next[D2D_EDGE_NEXT_ORIGIN] = *e;
997 d2d_cdt_edge_tor(&edge->next[D2D_EDGE_NEXT_ROT], e);
998 d2d_cdt_edge_sym(&edge->next[D2D_EDGE_NEXT_SYM], e);
999 d2d_cdt_edge_rot(&edge->next[D2D_EDGE_NEXT_TOR], e);
1000 edge->flags = 0;
1002 return TRUE;
1005 static void d2d_cdt_destroy_edge(struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
1007 struct d2d_cdt_edge_ref next, sym, prev;
1009 d2d_cdt_edge_next_origin(cdt, &next, e);
1010 if (next.idx != e->idx || next.r != e->r)
1012 d2d_cdt_edge_prev_origin(cdt, &prev, e);
1013 d2d_cdt_splice(cdt, e, &prev);
1016 d2d_cdt_edge_sym(&sym, e);
1018 d2d_cdt_edge_next_origin(cdt, &next, &sym);
1019 if (next.idx != sym.idx || next.r != sym.r)
1021 d2d_cdt_edge_prev_origin(cdt, &prev, &sym);
1022 d2d_cdt_splice(cdt, &sym, &prev);
1025 cdt->edges[e->idx].flags |= D2D_CDT_EDGE_FLAG_FREED;
1026 cdt->edges[e->idx].next[D2D_EDGE_NEXT_ORIGIN].idx = cdt->free_edge;
1027 cdt->free_edge = e->idx;
1030 static BOOL d2d_cdt_connect(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *e,
1031 const struct d2d_cdt_edge_ref *a, const struct d2d_cdt_edge_ref *b)
1033 struct d2d_cdt_edge_ref tmp;
1035 if (!d2d_cdt_create_edge(cdt, e))
1036 return FALSE;
1037 d2d_cdt_edge_set_origin(cdt, e, d2d_cdt_edge_destination(cdt, a));
1038 d2d_cdt_edge_set_destination(cdt, e, d2d_cdt_edge_origin(cdt, b));
1039 d2d_cdt_edge_next_left(cdt, &tmp, a);
1040 d2d_cdt_splice(cdt, e, &tmp);
1041 d2d_cdt_edge_sym(&tmp, e);
1042 d2d_cdt_splice(cdt, &tmp, b);
1044 return TRUE;
1047 static BOOL d2d_cdt_merge(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *left_outer,
1048 struct d2d_cdt_edge_ref *left_inner, struct d2d_cdt_edge_ref *right_inner,
1049 struct d2d_cdt_edge_ref *right_outer)
1051 struct d2d_cdt_edge_ref base_edge, tmp;
1053 /* Create the base edge between both parts. */
1054 for (;;)
1056 if (d2d_cdt_leftof(cdt, d2d_cdt_edge_origin(cdt, right_inner), left_inner))
1058 d2d_cdt_edge_next_left(cdt, left_inner, left_inner);
1060 else if (d2d_cdt_rightof(cdt, d2d_cdt_edge_origin(cdt, left_inner), right_inner))
1062 d2d_cdt_edge_sym(&tmp, right_inner);
1063 d2d_cdt_edge_next_origin(cdt, right_inner, &tmp);
1065 else
1067 break;
1071 d2d_cdt_edge_sym(&tmp, right_inner);
1072 if (!d2d_cdt_connect(cdt, &base_edge, &tmp, left_inner))
1073 return FALSE;
1074 if (d2d_cdt_edge_origin(cdt, left_inner) == d2d_cdt_edge_origin(cdt, left_outer))
1075 d2d_cdt_edge_sym(left_outer, &base_edge);
1076 if (d2d_cdt_edge_origin(cdt, right_inner) == d2d_cdt_edge_origin(cdt, right_outer))
1077 *right_outer = base_edge;
1079 for (;;)
1081 struct d2d_cdt_edge_ref left_candidate, right_candidate, sym_base_edge;
1082 BOOL left_valid, right_valid;
1084 /* Find the left candidate. */
1085 d2d_cdt_edge_sym(&sym_base_edge, &base_edge);
1086 d2d_cdt_edge_next_origin(cdt, &left_candidate, &sym_base_edge);
1087 if ((left_valid = d2d_cdt_leftof(cdt, d2d_cdt_edge_destination(cdt, &left_candidate), &sym_base_edge)))
1089 d2d_cdt_edge_next_origin(cdt, &tmp, &left_candidate);
1090 while (d2d_cdt_edge_destination(cdt, &tmp) != d2d_cdt_edge_destination(cdt, &sym_base_edge)
1091 && d2d_cdt_incircle(cdt,
1092 d2d_cdt_edge_origin(cdt, &sym_base_edge), d2d_cdt_edge_destination(cdt, &sym_base_edge),
1093 d2d_cdt_edge_destination(cdt, &left_candidate), d2d_cdt_edge_destination(cdt, &tmp)))
1095 d2d_cdt_destroy_edge(cdt, &left_candidate);
1096 left_candidate = tmp;
1097 d2d_cdt_edge_next_origin(cdt, &tmp, &left_candidate);
1100 d2d_cdt_edge_sym(&left_candidate, &left_candidate);
1102 /* Find the right candidate. */
1103 d2d_cdt_edge_prev_origin(cdt, &right_candidate, &base_edge);
1104 if ((right_valid = d2d_cdt_rightof(cdt, d2d_cdt_edge_destination(cdt, &right_candidate), &base_edge)))
1106 d2d_cdt_edge_prev_origin(cdt, &tmp, &right_candidate);
1107 while (d2d_cdt_edge_destination(cdt, &tmp) != d2d_cdt_edge_destination(cdt, &base_edge)
1108 && d2d_cdt_incircle(cdt,
1109 d2d_cdt_edge_origin(cdt, &sym_base_edge), d2d_cdt_edge_destination(cdt, &sym_base_edge),
1110 d2d_cdt_edge_destination(cdt, &right_candidate), d2d_cdt_edge_destination(cdt, &tmp)))
1112 d2d_cdt_destroy_edge(cdt, &right_candidate);
1113 right_candidate = tmp;
1114 d2d_cdt_edge_prev_origin(cdt, &tmp, &right_candidate);
1118 if (!left_valid && !right_valid)
1119 break;
1121 /* Connect the appropriate candidate with the base edge. */
1122 if (!left_valid || (right_valid && d2d_cdt_incircle(cdt,
1123 d2d_cdt_edge_origin(cdt, &left_candidate), d2d_cdt_edge_destination(cdt, &left_candidate),
1124 d2d_cdt_edge_origin(cdt, &right_candidate), d2d_cdt_edge_destination(cdt, &right_candidate))))
1126 if (!d2d_cdt_connect(cdt, &base_edge, &right_candidate, &sym_base_edge))
1127 return FALSE;
1129 else
1131 if (!d2d_cdt_connect(cdt, &base_edge, &sym_base_edge, &left_candidate))
1132 return FALSE;
1136 return TRUE;
1139 /* Create a Delaunay triangulation from a set of vertices. This is an
1140 * implementation of the divide-and-conquer algorithm described by Guibas and
1141 * Stolfi. Should be called with at least two vertices. */
1142 static BOOL d2d_cdt_triangulate(struct d2d_cdt *cdt, size_t start_vertex, size_t vertex_count,
1143 struct d2d_cdt_edge_ref *left_edge, struct d2d_cdt_edge_ref *right_edge)
1145 struct d2d_cdt_edge_ref left_inner, left_outer, right_inner, right_outer, tmp;
1146 size_t cut;
1148 /* Only two vertices, create a single edge. */
1149 if (vertex_count == 2)
1151 struct d2d_cdt_edge_ref a;
1153 if (!d2d_cdt_create_edge(cdt, &a))
1154 return FALSE;
1155 d2d_cdt_edge_set_origin(cdt, &a, start_vertex);
1156 d2d_cdt_edge_set_destination(cdt, &a, start_vertex + 1);
1158 *left_edge = a;
1159 d2d_cdt_edge_sym(right_edge, &a);
1161 return TRUE;
1164 /* Three vertices, create a triangle. */
1165 if (vertex_count == 3)
1167 struct d2d_cdt_edge_ref a, b, c;
1168 float det;
1170 if (!d2d_cdt_create_edge(cdt, &a))
1171 return FALSE;
1172 if (!d2d_cdt_create_edge(cdt, &b))
1173 return FALSE;
1174 d2d_cdt_edge_sym(&tmp, &a);
1175 d2d_cdt_splice(cdt, &tmp, &b);
1177 d2d_cdt_edge_set_origin(cdt, &a, start_vertex);
1178 d2d_cdt_edge_set_destination(cdt, &a, start_vertex + 1);
1179 d2d_cdt_edge_set_origin(cdt, &b, start_vertex + 1);
1180 d2d_cdt_edge_set_destination(cdt, &b, start_vertex + 2);
1182 det = d2d_cdt_ccw(cdt, start_vertex, start_vertex + 1, start_vertex + 2);
1183 if (det != 0.0f && !d2d_cdt_connect(cdt, &c, &b, &a))
1184 return FALSE;
1186 if (det < 0.0f)
1188 d2d_cdt_edge_sym(left_edge, &c);
1189 *right_edge = c;
1191 else
1193 *left_edge = a;
1194 d2d_cdt_edge_sym(right_edge, &b);
1197 return TRUE;
1200 /* More than tree vertices, divide. */
1201 cut = vertex_count / 2;
1202 if (!d2d_cdt_triangulate(cdt, start_vertex, cut, &left_outer, &left_inner))
1203 return FALSE;
1204 if (!d2d_cdt_triangulate(cdt, start_vertex + cut, vertex_count - cut, &right_inner, &right_outer))
1205 return FALSE;
1206 /* Merge the left and right parts. */
1207 if (!d2d_cdt_merge(cdt, &left_outer, &left_inner, &right_inner, &right_outer))
1208 return FALSE;
1210 *left_edge = left_outer;
1211 *right_edge = right_outer;
1212 return TRUE;
1215 static int d2d_cdt_compare_vertices(const void *a, const void *b)
1217 const D2D1_POINT_2F *p0 = a;
1218 const D2D1_POINT_2F *p1 = b;
1219 float diff = p0->x - p1->x;
1221 if (diff == 0.0f)
1222 diff = p0->y - p1->y;
1224 return diff == 0.0f ? 0 : (diff > 0.0f ? 1 : -1);
1227 /* Determine whether a given point is inside the geometry, using the current
1228 * fill mode rule. */
1229 static BOOL d2d_path_geometry_point_inside(const struct d2d_geometry *geometry,
1230 const D2D1_POINT_2F *probe, BOOL triangles_only)
1232 const D2D1_POINT_2F *p0, *p1;
1233 D2D1_POINT_2F v_p, v_probe;
1234 unsigned int score;
1235 size_t i, j, last;
1237 for (i = 0, score = 0; i < geometry->u.path.figure_count; ++i)
1239 const struct d2d_figure *figure = &geometry->u.path.figures[i];
1241 if (probe->x < figure->bounds.left || probe->x > figure->bounds.right
1242 || probe->y < figure->bounds.top || probe->y > figure->bounds.bottom)
1243 continue;
1245 last = figure->vertex_count - 1;
1246 if (!triangles_only)
1248 while (last && figure->vertex_types[last] == D2D_VERTEX_TYPE_NONE)
1249 --last;
1251 p0 = &figure->vertices[last];
1252 for (j = 0; j <= last; ++j)
1254 if (!triangles_only && figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
1255 continue;
1257 p1 = &figure->vertices[j];
1258 d2d_point_subtract(&v_p, p1, p0);
1259 d2d_point_subtract(&v_probe, probe, p0);
1261 if ((probe->y < p0->y) != (probe->y < p1->y) && v_probe.x < v_p.x * (v_probe.y / v_p.y))
1263 if (geometry->u.path.fill_mode == D2D1_FILL_MODE_ALTERNATE || (probe->y < p0->y))
1264 ++score;
1265 else
1266 --score;
1269 p0 = p1;
1273 return geometry->u.path.fill_mode == D2D1_FILL_MODE_ALTERNATE ? score & 1 : score;
1276 static BOOL d2d_path_geometry_add_fill_face(struct d2d_geometry *geometry, const struct d2d_cdt *cdt,
1277 const struct d2d_cdt_edge_ref *base_edge)
1279 struct d2d_cdt_edge_ref tmp;
1280 struct d2d_face *face;
1281 D2D1_POINT_2F probe;
1283 if (cdt->edges[base_edge->idx].flags & D2D_CDT_EDGE_FLAG_VISITED(base_edge->r))
1284 return TRUE;
1286 if (!d2d_array_reserve((void **)&geometry->fill.faces, &geometry->fill.faces_size,
1287 geometry->fill.face_count + 1, sizeof(*geometry->fill.faces)))
1289 ERR("Failed to grow faces array.\n");
1290 return FALSE;
1293 face = &geometry->fill.faces[geometry->fill.face_count];
1295 /* It may seem tempting to use the center of the face as probe origin, but
1296 * multiplying by powers of two works much better for preserving accuracy. */
1298 tmp = *base_edge;
1299 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1300 face->v[0] = d2d_cdt_edge_origin(cdt, &tmp);
1301 probe.x = cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.25f;
1302 probe.y = cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.25f;
1304 d2d_cdt_edge_next_left(cdt, &tmp, &tmp);
1305 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1306 face->v[1] = d2d_cdt_edge_origin(cdt, &tmp);
1307 probe.x += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.25f;
1308 probe.y += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.25f;
1310 d2d_cdt_edge_next_left(cdt, &tmp, &tmp);
1311 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1312 face->v[2] = d2d_cdt_edge_origin(cdt, &tmp);
1313 probe.x += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.50f;
1314 probe.y += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.50f;
1316 if (d2d_cdt_leftof(cdt, face->v[2], base_edge) && d2d_path_geometry_point_inside(geometry, &probe, TRUE))
1317 ++geometry->fill.face_count;
1319 return TRUE;
1322 static BOOL d2d_cdt_generate_faces(const struct d2d_cdt *cdt, struct d2d_geometry *geometry)
1324 struct d2d_cdt_edge_ref base_edge;
1325 size_t i;
1327 for (i = 0; i < cdt->edge_count; ++i)
1329 if (cdt->edges[i].flags & D2D_CDT_EDGE_FLAG_FREED)
1330 continue;
1332 base_edge.idx = i;
1333 base_edge.r = 0;
1334 if (!d2d_path_geometry_add_fill_face(geometry, cdt, &base_edge))
1335 goto fail;
1336 d2d_cdt_edge_sym(&base_edge, &base_edge);
1337 if (!d2d_path_geometry_add_fill_face(geometry, cdt, &base_edge))
1338 goto fail;
1341 return TRUE;
1343 fail:
1344 HeapFree(GetProcessHeap(), 0, geometry->fill.faces);
1345 geometry->fill.faces = NULL;
1346 geometry->fill.faces_size = 0;
1347 geometry->fill.face_count = 0;
1348 return FALSE;
1351 static BOOL d2d_cdt_fixup(struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *base_edge)
1353 struct d2d_cdt_edge_ref candidate, next, new_base;
1354 unsigned int count = 0;
1356 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1357 if (next.idx == base_edge->idx)
1359 ERR("Degenerate face.\n");
1360 return FALSE;
1363 candidate = next;
1364 while (d2d_cdt_edge_destination(cdt, &next) != d2d_cdt_edge_origin(cdt, base_edge))
1366 if (d2d_cdt_incircle(cdt, d2d_cdt_edge_origin(cdt, base_edge), d2d_cdt_edge_destination(cdt, base_edge),
1367 d2d_cdt_edge_destination(cdt, &candidate), d2d_cdt_edge_destination(cdt, &next)))
1368 candidate = next;
1369 d2d_cdt_edge_next_left(cdt, &next, &next);
1370 ++count;
1373 if (count > 1)
1375 d2d_cdt_edge_next_left(cdt, &next, &candidate);
1376 if (d2d_cdt_edge_destination(cdt, &next) == d2d_cdt_edge_origin(cdt, base_edge))
1377 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1378 else
1379 next = *base_edge;
1380 if (!d2d_cdt_connect(cdt, &new_base, &candidate, &next))
1381 return FALSE;
1382 if (!d2d_cdt_fixup(cdt, &new_base))
1383 return FALSE;
1384 d2d_cdt_edge_sym(&new_base, &new_base);
1385 if (!d2d_cdt_fixup(cdt, &new_base))
1386 return FALSE;
1389 return TRUE;
1392 static void d2d_cdt_cut_edges(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *end_edge,
1393 const struct d2d_cdt_edge_ref *base_edge, size_t start_vertex, size_t end_vertex)
1395 struct d2d_cdt_edge_ref next;
1396 float ccw;
1398 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1399 if (d2d_cdt_edge_destination(cdt, &next) == end_vertex)
1401 *end_edge = next;
1402 return;
1405 ccw = d2d_cdt_ccw(cdt, d2d_cdt_edge_destination(cdt, &next), end_vertex, start_vertex);
1406 if (ccw == 0.0f)
1408 *end_edge = next;
1409 return;
1412 if (ccw > 0.0f)
1413 d2d_cdt_edge_next_left(cdt, &next, &next);
1415 d2d_cdt_edge_sym(&next, &next);
1416 d2d_cdt_cut_edges(cdt, end_edge, &next, start_vertex, end_vertex);
1417 d2d_cdt_destroy_edge(cdt, &next);
1420 static BOOL d2d_cdt_insert_segment(struct d2d_cdt *cdt, struct d2d_geometry *geometry,
1421 const struct d2d_cdt_edge_ref *origin, struct d2d_cdt_edge_ref *edge, size_t end_vertex)
1423 struct d2d_cdt_edge_ref base_edge, current, new_origin, next, target;
1424 size_t current_destination, current_origin;
1426 for (current = *origin;; current = next)
1428 d2d_cdt_edge_next_origin(cdt, &next, &current);
1430 current_destination = d2d_cdt_edge_destination(cdt, &current);
1431 if (current_destination == end_vertex)
1433 d2d_cdt_edge_sym(edge, &current);
1434 return TRUE;
1437 current_origin = d2d_cdt_edge_origin(cdt, &current);
1438 if (d2d_cdt_ccw(cdt, end_vertex, current_origin, current_destination) == 0.0f
1439 && (cdt->vertices[current_destination].x > cdt->vertices[current_origin].x)
1440 == (cdt->vertices[end_vertex].x > cdt->vertices[current_origin].x)
1441 && (cdt->vertices[current_destination].y > cdt->vertices[current_origin].y)
1442 == (cdt->vertices[end_vertex].y > cdt->vertices[current_origin].y))
1444 d2d_cdt_edge_sym(&new_origin, &current);
1445 return d2d_cdt_insert_segment(cdt, geometry, &new_origin, edge, end_vertex);
1448 if (d2d_cdt_rightof(cdt, end_vertex, &next) && d2d_cdt_leftof(cdt, end_vertex, &current))
1450 d2d_cdt_edge_next_left(cdt, &base_edge, &current);
1452 d2d_cdt_edge_sym(&base_edge, &base_edge);
1453 d2d_cdt_cut_edges(cdt, &target, &base_edge, d2d_cdt_edge_origin(cdt, origin), end_vertex);
1454 d2d_cdt_destroy_edge(cdt, &base_edge);
1456 if (!d2d_cdt_connect(cdt, &base_edge, &target, &current))
1457 return FALSE;
1458 *edge = base_edge;
1459 if (!d2d_cdt_fixup(cdt, &base_edge))
1460 return FALSE;
1461 d2d_cdt_edge_sym(&base_edge, &base_edge);
1462 if (!d2d_cdt_fixup(cdt, &base_edge))
1463 return FALSE;
1465 if (d2d_cdt_edge_origin(cdt, edge) == end_vertex)
1466 return TRUE;
1467 new_origin = *edge;
1468 return d2d_cdt_insert_segment(cdt, geometry, &new_origin, edge, end_vertex);
1471 if (next.idx == origin->idx)
1473 ERR("Triangle not found.\n");
1474 return FALSE;
1479 static BOOL d2d_cdt_insert_segments(struct d2d_cdt *cdt, struct d2d_geometry *geometry)
1481 size_t start_vertex, end_vertex, i, j, k;
1482 struct d2d_cdt_edge_ref edge, new_edge;
1483 const struct d2d_figure *figure;
1484 const D2D1_POINT_2F *p;
1485 BOOL found;
1487 for (i = 0; i < geometry->u.path.figure_count; ++i)
1489 figure = &geometry->u.path.figures[i];
1491 /* Degenerate figure. */
1492 if (figure->vertex_count < 2)
1493 continue;
1495 p = bsearch(&figure->vertices[figure->vertex_count - 1], cdt->vertices,
1496 geometry->fill.vertex_count, sizeof(*p), d2d_cdt_compare_vertices);
1497 start_vertex = p - cdt->vertices;
1499 for (k = 0, found = FALSE; k < cdt->edge_count; ++k)
1501 if (cdt->edges[k].flags & D2D_CDT_EDGE_FLAG_FREED)
1502 continue;
1504 edge.idx = k;
1505 edge.r = 0;
1507 if (d2d_cdt_edge_origin(cdt, &edge) == start_vertex)
1509 found = TRUE;
1510 break;
1512 d2d_cdt_edge_sym(&edge, &edge);
1513 if (d2d_cdt_edge_origin(cdt, &edge) == start_vertex)
1515 found = TRUE;
1516 break;
1520 if (!found)
1522 ERR("Edge not found.\n");
1523 return FALSE;
1526 for (j = 0; j < figure->vertex_count; start_vertex = end_vertex, ++j)
1528 p = bsearch(&figure->vertices[j], cdt->vertices,
1529 geometry->fill.vertex_count, sizeof(*p), d2d_cdt_compare_vertices);
1530 end_vertex = p - cdt->vertices;
1532 if (start_vertex == end_vertex)
1533 continue;
1535 if (!d2d_cdt_insert_segment(cdt, geometry, &edge, &new_edge, end_vertex))
1536 return FALSE;
1537 edge = new_edge;
1541 return TRUE;
1544 static BOOL d2d_geometry_intersections_add(struct d2d_geometry_intersections *i,
1545 size_t figure_idx, size_t segment_idx, float t, D2D1_POINT_2F p)
1547 struct d2d_geometry_intersection *intersection;
1549 if (!d2d_array_reserve((void **)&i->intersections, &i->intersections_size,
1550 i->intersection_count + 1, sizeof(*i->intersections)))
1552 ERR("Failed to grow intersections array.\n");
1553 return FALSE;
1556 intersection = &i->intersections[i->intersection_count++];
1557 intersection->figure_idx = figure_idx;
1558 intersection->segment_idx = segment_idx;
1559 intersection->t = t;
1560 intersection->p = p;
1562 return TRUE;
1565 static int d2d_geometry_intersections_compare(const void *a, const void *b)
1567 const struct d2d_geometry_intersection *i0 = a;
1568 const struct d2d_geometry_intersection *i1 = b;
1570 if (i0->figure_idx != i1->figure_idx)
1571 return i0->figure_idx - i1->figure_idx;
1572 if (i0->segment_idx != i1->segment_idx)
1573 return i0->segment_idx - i1->segment_idx;
1574 if (i0->t != i1->t)
1575 return i0->t > i1->t ? 1 : -1;
1576 return 0;
1579 /* Intersect the geometry's segments with themselves. This uses the
1580 * straightforward approach of testing everything against everything, but
1581 * there certainly exist more scalable algorithms for this. */
1582 /* FIXME: Beziers can't currently self-intersect. */
1583 static BOOL d2d_geometry_intersect_self(struct d2d_geometry *geometry)
1585 D2D1_POINT_2F p0, p1, q0, q1, v_p, v_q, v_qp, intersection;
1586 struct d2d_geometry_intersections intersections = {0};
1587 struct d2d_figure *figure_p, *figure_q;
1588 size_t i, j, k, l, max_l;
1589 BOOL ret = FALSE;
1590 float s, t, det;
1592 for (i = 0; i < geometry->u.path.figure_count; ++i)
1594 figure_p = &geometry->u.path.figures[i];
1595 p0 = figure_p->vertices[figure_p->vertex_count - 1];
1596 for (k = 0; k < figure_p->vertex_count; p0 = p1, ++k)
1598 p1 = figure_p->vertices[k];
1599 d2d_point_subtract(&v_p, &p1, &p0);
1600 for (j = 0; j < i || (j == i && k); ++j)
1602 figure_q = &geometry->u.path.figures[j];
1604 if (figure_p->bounds.left > figure_q->bounds.right
1605 || figure_q->bounds.left > figure_p->bounds.right
1606 || figure_p->bounds.top > figure_q->bounds.bottom
1607 || figure_q->bounds.top > figure_p->bounds.bottom)
1608 continue;
1610 max_l = j == i ? k - 1 : figure_q->vertex_count;
1611 q0 = figure_q->vertices[figure_q->vertex_count - 1];
1612 for (l = 0; l < max_l; q0 = q1, ++l)
1614 q1 = figure_q->vertices[l];
1615 d2d_point_subtract(&v_q, &q1, &q0);
1616 d2d_point_subtract(&v_qp, &p0, &q0);
1618 det = v_p.x * v_q.y - v_p.y * v_q.x;
1619 if (det == 0.0f)
1620 continue;
1622 s = (v_q.x * v_qp.y - v_q.y * v_qp.x) / det;
1623 t = (v_p.x * v_qp.y - v_p.y * v_qp.x) / det;
1625 if (s < 0.0f || s > 1.0f || t < 0.0f || t > 1.0f)
1626 continue;
1628 intersection.x = p0.x + v_p.x * s;
1629 intersection.y = p0.y + v_p.y * s;
1631 if (t > 0.0f && t < 1.0f
1632 && !d2d_geometry_intersections_add(&intersections, j, l, t, intersection))
1633 goto done;
1635 if (s > 0.0f && s < 1.0f
1636 && !d2d_geometry_intersections_add(&intersections, i, k, s, intersection))
1637 goto done;
1643 qsort(intersections.intersections, intersections.intersection_count,
1644 sizeof(*intersections.intersections), d2d_geometry_intersections_compare);
1645 for (i = 0; i < intersections.intersection_count; ++i)
1647 const struct d2d_geometry_intersection *inter = &intersections.intersections[i];
1649 if (!i || inter->figure_idx != intersections.intersections[i - 1].figure_idx)
1650 j = 0;
1652 if (!d2d_figure_insert_vertex(&geometry->u.path.figures[inter->figure_idx],
1653 inter->segment_idx + j, inter->p))
1654 goto done;
1655 ++j;
1658 ret = TRUE;
1660 done:
1661 HeapFree(GetProcessHeap(), 0, intersections.intersections);
1662 return ret;
1665 static HRESULT d2d_path_geometry_triangulate(struct d2d_geometry *geometry)
1667 struct d2d_cdt_edge_ref left_edge, right_edge;
1668 size_t vertex_count, i, j;
1669 struct d2d_cdt cdt = {0};
1670 D2D1_POINT_2F *vertices;
1672 for (i = 0, vertex_count = 0; i < geometry->u.path.figure_count; ++i)
1674 vertex_count += geometry->u.path.figures[i].vertex_count;
1677 if (vertex_count < 3)
1679 WARN("Geometry has %lu vertices.\n", (long)vertex_count);
1680 return S_OK;
1683 if (!(vertices = HeapAlloc(GetProcessHeap(), 0, vertex_count * sizeof(*vertices))))
1684 return E_OUTOFMEMORY;
1686 for (i = 0, j = 0; i < geometry->u.path.figure_count; ++i)
1688 memcpy(&vertices[j], geometry->u.path.figures[i].vertices,
1689 geometry->u.path.figures[i].vertex_count * sizeof(*vertices));
1690 j += geometry->u.path.figures[i].vertex_count;
1693 /* Sort vertices, eliminate duplicates. */
1694 qsort(vertices, vertex_count, sizeof(*vertices), d2d_cdt_compare_vertices);
1695 for (i = 1; i < vertex_count; ++i)
1697 if (!memcmp(&vertices[i - 1], &vertices[i], sizeof(*vertices)))
1699 --vertex_count;
1700 memmove(&vertices[i], &vertices[i + 1], (vertex_count - i) * sizeof(*vertices));
1701 --i;
1705 geometry->fill.vertices = vertices;
1706 geometry->fill.vertex_count = vertex_count;
1708 cdt.free_edge = ~0u;
1709 cdt.vertices = vertices;
1710 if (!d2d_cdt_triangulate(&cdt, 0, vertex_count, &left_edge, &right_edge))
1711 goto fail;
1712 if (!d2d_cdt_insert_segments(&cdt, geometry))
1713 goto fail;
1714 if (!d2d_cdt_generate_faces(&cdt, geometry))
1715 goto fail;
1717 HeapFree(GetProcessHeap(), 0, cdt.edges);
1718 return S_OK;
1720 fail:
1721 geometry->fill.vertices = NULL;
1722 geometry->fill.vertex_count = 0;
1723 HeapFree(GetProcessHeap(), 0, vertices);
1724 HeapFree(GetProcessHeap(), 0, cdt.edges);
1725 return E_FAIL;
1728 static BOOL d2d_path_geometry_add_figure(struct d2d_geometry *geometry)
1730 struct d2d_figure *figure;
1732 if (!d2d_array_reserve((void **)&geometry->u.path.figures, &geometry->u.path.figures_size,
1733 geometry->u.path.figure_count + 1, sizeof(*geometry->u.path.figures)))
1735 ERR("Failed to grow figures array.\n");
1736 return FALSE;
1739 figure = &geometry->u.path.figures[geometry->u.path.figure_count];
1740 memset(figure, 0, sizeof(*figure));
1741 figure->bounds.left = FLT_MAX;
1742 figure->bounds.top = FLT_MAX;
1743 figure->bounds.right = -FLT_MAX;
1744 figure->bounds.bottom = -FLT_MAX;
1746 ++geometry->u.path.figure_count;
1747 return TRUE;
1750 static BOOL d2d_geometry_outline_add_join(struct d2d_geometry *geometry,
1751 const D2D1_POINT_2F *prev, const D2D1_POINT_2F *p0, const D2D1_POINT_2F *next)
1753 D2D1_POINT_2F q_prev, q_next;
1754 struct d2d_outline_vertex *v;
1755 struct d2d_face *f;
1756 size_t base_idx;
1757 float ccw;
1759 if (!d2d_array_reserve((void **)&geometry->outline.vertices, &geometry->outline.vertices_size,
1760 geometry->outline.vertex_count + 4, sizeof(*geometry->outline.vertices)))
1762 ERR("Failed to grow outline vertices array.\n");
1763 return FALSE;
1765 base_idx = geometry->outline.vertex_count;
1766 v = &geometry->outline.vertices[base_idx];
1768 if (!d2d_array_reserve((void **)&geometry->outline.faces, &geometry->outline.faces_size,
1769 geometry->outline.face_count + 2, sizeof(*geometry->outline.faces)))
1771 ERR("Failed to grow outline faces array.\n");
1772 return FALSE;
1774 f = &geometry->outline.faces[geometry->outline.face_count];
1776 d2d_point_subtract(&q_prev, p0, prev);
1777 d2d_point_subtract(&q_next, next, p0);
1779 d2d_point_normalise(&q_prev);
1780 d2d_point_normalise(&q_next);
1782 ccw = d2d_point_ccw(p0, prev, next);
1783 if (ccw == 0.0f)
1785 d2d_outline_vertex_set(&v[0], p0->x, p0->y, q_prev.x, q_prev.y, q_prev.x, q_prev.y);
1786 d2d_outline_vertex_set(&v[1], p0->x, p0->y, -q_prev.x, -q_prev.y, -q_prev.x, -q_prev.y);
1787 d2d_outline_vertex_set(&v[2], p0->x + 25.0f * q_prev.x, p0->y + 25.0f * q_prev.y,
1788 -q_prev.x, -q_prev.y, -q_prev.x, -q_prev.y);
1789 d2d_outline_vertex_set(&v[3], p0->x + 25.0f * q_prev.x, p0->y + 25.0f * q_prev.y,
1790 q_prev.x, q_prev.y, q_prev.x, q_prev.y);
1792 else if (ccw < 0.0f)
1794 d2d_outline_vertex_set(&v[0], p0->x, p0->y, 0.0f, 0.0f, 0.0f, 0.0f);
1795 d2d_outline_vertex_set(&v[1], p0->x, p0->y, -q_next.x, -q_next.y, -q_next.x, -q_next.y);
1796 d2d_outline_vertex_set(&v[2], p0->x, p0->y, -q_next.x, -q_next.y, -q_prev.x, -q_prev.y);
1797 d2d_outline_vertex_set(&v[3], p0->x, p0->y, -q_prev.x, -q_prev.y, -q_prev.x, -q_prev.y);
1799 else
1801 d2d_outline_vertex_set(&v[0], p0->x, p0->y, 0.0f, 0.0f, 0.0f, 0.0f);
1802 d2d_outline_vertex_set(&v[1], p0->x, p0->y, q_prev.x, q_prev.y, q_prev.x, q_prev.y);
1803 d2d_outline_vertex_set(&v[2], p0->x, p0->y, q_prev.x, q_prev.y, q_next.x, q_next.y);
1804 d2d_outline_vertex_set(&v[3], p0->x, p0->y, q_next.x, q_next.y, q_next.x, q_next.y);
1806 geometry->outline.vertex_count += 4;
1808 d2d_face_set(&f[0], base_idx + 1, base_idx + 0, base_idx + 2);
1809 d2d_face_set(&f[1], base_idx + 2, base_idx + 0, base_idx + 3);
1810 geometry->outline.face_count += 2;
1812 return TRUE;
1815 static BOOL d2d_geometry_outline_add_line_segment(struct d2d_geometry *geometry,
1816 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *next)
1818 struct d2d_outline_vertex *v;
1819 D2D1_POINT_2F q_next;
1820 struct d2d_face *f;
1821 size_t base_idx;
1823 if (!d2d_array_reserve((void **)&geometry->outline.vertices, &geometry->outline.vertices_size,
1824 geometry->outline.vertex_count + 4, sizeof(*geometry->outline.vertices)))
1826 ERR("Failed to grow outline vertices array.\n");
1827 return FALSE;
1829 base_idx = geometry->outline.vertex_count;
1830 v = &geometry->outline.vertices[base_idx];
1832 if (!d2d_array_reserve((void **)&geometry->outline.faces, &geometry->outline.faces_size,
1833 geometry->outline.face_count + 2, sizeof(*geometry->outline.faces)))
1835 ERR("Failed to grow outline faces array.\n");
1836 return FALSE;
1838 f = &geometry->outline.faces[geometry->outline.face_count];
1840 d2d_point_subtract(&q_next, next, p0);
1841 d2d_point_normalise(&q_next);
1843 d2d_outline_vertex_set(&v[0], p0->x, p0->y, q_next.x, q_next.y, q_next.x, q_next.y);
1844 d2d_outline_vertex_set(&v[1], p0->x, p0->y, -q_next.x, -q_next.y, -q_next.x, -q_next.y);
1845 d2d_outline_vertex_set(&v[2], next->x, next->y, q_next.x, q_next.y, q_next.x, q_next.y);
1846 d2d_outline_vertex_set(&v[3], next->x, next->y, -q_next.x, -q_next.y, -q_next.x, -q_next.y);
1847 geometry->outline.vertex_count += 4;
1849 d2d_face_set(&f[0], base_idx + 0, base_idx + 1, base_idx + 2);
1850 d2d_face_set(&f[1], base_idx + 2, base_idx + 1, base_idx + 3);
1851 geometry->outline.face_count += 2;
1853 return TRUE;
1856 static BOOL d2d_geometry_outline_add_bezier_segment(struct d2d_geometry *geometry,
1857 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2)
1859 struct d2d_bezier_outline_vertex *b;
1860 D2D1_POINT_2F r0, r1, r2;
1861 D2D1_POINT_2F q0, q1, q2;
1862 struct d2d_face *f;
1863 size_t base_idx;
1865 if (!d2d_array_reserve((void **)&geometry->outline.beziers, &geometry->outline.beziers_size,
1866 geometry->outline.bezier_count + 7, sizeof(*geometry->outline.beziers)))
1868 ERR("Failed to grow outline beziers array.\n");
1869 return FALSE;
1871 base_idx = geometry->outline.bezier_count;
1872 b = &geometry->outline.beziers[base_idx];
1874 if (!d2d_array_reserve((void **)&geometry->outline.bezier_faces, &geometry->outline.bezier_faces_size,
1875 geometry->outline.bezier_face_count + 5, sizeof(*geometry->outline.bezier_faces)))
1877 ERR("Failed to grow outline faces array.\n");
1878 return FALSE;
1880 f = &geometry->outline.bezier_faces[geometry->outline.bezier_face_count];
1882 d2d_point_lerp(&q0, p0, p1, 0.5f);
1883 d2d_point_lerp(&q1, p1, p2, 0.5f);
1884 d2d_point_lerp(&q2, &q0, &q1, 0.5f);
1886 d2d_point_subtract(&r0, &q0, p0);
1887 d2d_point_subtract(&r1, &q1, &q0);
1888 d2d_point_subtract(&r2, p2, &q1);
1890 d2d_point_normalise(&r0);
1891 d2d_point_normalise(&r1);
1892 d2d_point_normalise(&r2);
1894 if (d2d_point_ccw(p0, p1, p2) > 0.0f)
1896 d2d_point_scale(&r0, -1.0f);
1897 d2d_point_scale(&r1, -1.0f);
1898 d2d_point_scale(&r2, -1.0f);
1901 d2d_bezier_outline_vertex_set(&b[0], p0, p0, p1, p2, r0.x, r0.y, r0.x, r0.y);
1902 d2d_bezier_outline_vertex_set(&b[1], p0, p0, p1, p2, -r0.x, -r0.y, -r0.x, -r0.y);
1903 d2d_bezier_outline_vertex_set(&b[2], &q0, p0, p1, p2, r0.x, r0.y, r1.x, r1.y);
1904 d2d_bezier_outline_vertex_set(&b[3], &q2, p0, p1, p2, -r1.x, -r1.y, -r1.x, -r1.y);
1905 d2d_bezier_outline_vertex_set(&b[4], &q1, p0, p1, p2, r1.x, r1.y, r2.x, r2.y);
1906 d2d_bezier_outline_vertex_set(&b[5], p2, p0, p1, p2, -r2.x, -r2.y, -r2.x, -r2.y);
1907 d2d_bezier_outline_vertex_set(&b[6], p2, p0, p1, p2, r2.x, r2.y, r2.x, r2.y);
1908 geometry->outline.bezier_count += 7;
1910 d2d_face_set(&f[0], base_idx + 0, base_idx + 1, base_idx + 2);
1911 d2d_face_set(&f[1], base_idx + 2, base_idx + 1, base_idx + 3);
1912 d2d_face_set(&f[2], base_idx + 3, base_idx + 4, base_idx + 2);
1913 d2d_face_set(&f[3], base_idx + 5, base_idx + 4, base_idx + 3);
1914 d2d_face_set(&f[4], base_idx + 5, base_idx + 6, base_idx + 4);
1915 geometry->outline.bezier_face_count += 5;
1917 return TRUE;
1920 static BOOL d2d_geometry_add_figure_outline(struct d2d_geometry *geometry,
1921 struct d2d_figure *figure, D2D1_FIGURE_END figure_end)
1923 const D2D1_POINT_2F *prev, *p0, *next;
1924 enum d2d_vertex_type prev_type, type;
1925 size_t bezier_idx, i;
1927 for (i = 0, bezier_idx = 0; i < figure->vertex_count; ++i)
1929 type = figure->vertex_types[i];
1930 if (type == D2D_VERTEX_TYPE_NONE)
1931 continue;
1933 p0 = &figure->vertices[i];
1935 if (!i)
1937 prev_type = figure->vertex_types[figure->vertex_count - 1];
1938 if (prev_type == D2D_VERTEX_TYPE_BEZIER)
1939 prev = &figure->bezier_controls[figure->bezier_control_count - 1];
1940 else
1941 prev = &figure->vertices[figure->vertex_count - 1];
1943 else
1945 prev_type = figure->vertex_types[i - 1];
1946 if (prev_type == D2D_VERTEX_TYPE_BEZIER)
1947 prev = &figure->bezier_controls[bezier_idx - 1];
1948 else
1949 prev = &figure->vertices[i - 1];
1952 if (type == D2D_VERTEX_TYPE_BEZIER)
1953 next = &figure->bezier_controls[bezier_idx++];
1954 else if (i == figure->vertex_count - 1)
1955 next = &figure->vertices[0];
1956 else
1957 next = &figure->vertices[i + 1];
1959 if ((figure_end == D2D1_FIGURE_END_CLOSED || (i && i < figure->vertex_count - 1))
1960 && !d2d_geometry_outline_add_join(geometry, prev, p0, next))
1962 ERR("Failed to add join.\n");
1963 return FALSE;
1966 if (type == D2D_VERTEX_TYPE_LINE && (figure_end == D2D1_FIGURE_END_CLOSED || i < figure->vertex_count - 1)
1967 && !d2d_geometry_outline_add_line_segment(geometry, p0, next))
1969 ERR("Failed to add line segment.\n");
1970 return FALSE;
1972 else if (type == D2D_VERTEX_TYPE_BEZIER)
1974 const D2D1_POINT_2F *p2;
1976 if (i == figure->vertex_count - 1)
1977 p2 = &figure->vertices[0];
1978 else
1979 p2 = &figure->vertices[i + 1];
1981 if (!d2d_geometry_outline_add_bezier_segment(geometry, p0, next, p2))
1983 ERR("Failed to add bezier segment.\n");
1984 return FALSE;
1989 return TRUE;
1992 static void d2d_geometry_cleanup(struct d2d_geometry *geometry)
1994 HeapFree(GetProcessHeap(), 0, geometry->outline.bezier_faces);
1995 HeapFree(GetProcessHeap(), 0, geometry->outline.beziers);
1996 HeapFree(GetProcessHeap(), 0, geometry->outline.faces);
1997 HeapFree(GetProcessHeap(), 0, geometry->outline.vertices);
1998 HeapFree(GetProcessHeap(), 0, geometry->fill.bezier_vertices);
1999 HeapFree(GetProcessHeap(), 0, geometry->fill.faces);
2000 HeapFree(GetProcessHeap(), 0, geometry->fill.vertices);
2001 ID2D1Factory_Release(geometry->factory);
2004 static void d2d_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
2005 const D2D1_MATRIX_3X2_F *transform, const struct ID2D1GeometryVtbl *vtbl)
2007 geometry->ID2D1Geometry_iface.lpVtbl = vtbl;
2008 geometry->refcount = 1;
2009 ID2D1Factory_AddRef(geometry->factory = factory);
2010 geometry->transform = *transform;
2013 static inline struct d2d_geometry *impl_from_ID2D1GeometrySink(ID2D1GeometrySink *iface)
2015 return CONTAINING_RECORD(iface, struct d2d_geometry, u.path.ID2D1GeometrySink_iface);
2018 static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_QueryInterface(ID2D1GeometrySink *iface, REFIID iid, void **out)
2020 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
2022 if (IsEqualGUID(iid, &IID_ID2D1GeometrySink)
2023 || IsEqualGUID(iid, &IID_ID2D1SimplifiedGeometrySink)
2024 || IsEqualGUID(iid, &IID_IUnknown))
2026 ID2D1GeometrySink_AddRef(iface);
2027 *out = iface;
2028 return S_OK;
2031 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
2033 *out = NULL;
2034 return E_NOINTERFACE;
2037 static ULONG STDMETHODCALLTYPE d2d_geometry_sink_AddRef(ID2D1GeometrySink *iface)
2039 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2041 TRACE("iface %p.\n", iface);
2043 return ID2D1Geometry_AddRef(&geometry->ID2D1Geometry_iface);
2046 static ULONG STDMETHODCALLTYPE d2d_geometry_sink_Release(ID2D1GeometrySink *iface)
2048 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2050 TRACE("iface %p.\n", iface);
2052 return ID2D1Geometry_Release(&geometry->ID2D1Geometry_iface);
2055 static void STDMETHODCALLTYPE d2d_geometry_sink_SetFillMode(ID2D1GeometrySink *iface, D2D1_FILL_MODE mode)
2057 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2059 TRACE("iface %p, mode %#x.\n", iface, mode);
2061 if (geometry->u.path.state == D2D_GEOMETRY_STATE_CLOSED)
2062 return;
2063 geometry->u.path.fill_mode = mode;
2066 static void STDMETHODCALLTYPE d2d_geometry_sink_SetSegmentFlags(ID2D1GeometrySink *iface, D2D1_PATH_SEGMENT flags)
2068 FIXME("iface %p, flags %#x stub!\n", iface, flags);
2071 static void STDMETHODCALLTYPE d2d_geometry_sink_BeginFigure(ID2D1GeometrySink *iface,
2072 D2D1_POINT_2F start_point, D2D1_FIGURE_BEGIN figure_begin)
2074 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2075 struct d2d_figure *figure;
2077 TRACE("iface %p, start_point {%.8e, %.8e}, figure_begin %#x.\n",
2078 iface, start_point.x, start_point.y, figure_begin);
2080 if (geometry->u.path.state != D2D_GEOMETRY_STATE_OPEN)
2082 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2083 return;
2086 if (figure_begin != D2D1_FIGURE_BEGIN_FILLED)
2087 FIXME("Ignoring figure_begin %#x.\n", figure_begin);
2089 if (!d2d_path_geometry_add_figure(geometry))
2091 ERR("Failed to add figure.\n");
2092 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2093 return;
2096 figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2097 if (figure_begin == D2D1_FIGURE_BEGIN_HOLLOW)
2098 figure->flags |= D2D_FIGURE_FLAG_HOLLOW;
2100 if (!d2d_figure_add_vertex(figure, start_point))
2102 ERR("Failed to add vertex.\n");
2103 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2104 return;
2107 geometry->u.path.state = D2D_GEOMETRY_STATE_FIGURE;
2110 static void STDMETHODCALLTYPE d2d_geometry_sink_AddLines(ID2D1GeometrySink *iface,
2111 const D2D1_POINT_2F *points, UINT32 count)
2113 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2114 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2115 unsigned int i;
2117 TRACE("iface %p, points %p, count %u.\n", iface, points, count);
2119 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2121 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2122 return;
2125 for (i = 0; i < count; ++i)
2127 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_LINE;
2128 if (!d2d_figure_add_vertex(figure, points[i]))
2130 ERR("Failed to add vertex.\n");
2131 return;
2135 geometry->u.path.segment_count += count;
2138 static void STDMETHODCALLTYPE d2d_geometry_sink_AddBeziers(ID2D1GeometrySink *iface,
2139 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
2141 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2142 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2143 D2D1_POINT_2F p;
2144 unsigned int i;
2146 TRACE("iface %p, beziers %p, count %u.\n", iface, beziers, count);
2148 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2150 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2151 return;
2154 for (i = 0; i < count; ++i)
2156 /* FIXME: This tries to approximate a cubic bezier with a quadratic one. */
2157 p.x = (beziers[i].point1.x + beziers[i].point2.x) * 0.75f;
2158 p.y = (beziers[i].point1.y + beziers[i].point2.y) * 0.75f;
2159 p.x -= (figure->vertices[figure->vertex_count - 1].x + beziers[i].point3.x) * 0.25f;
2160 p.y -= (figure->vertices[figure->vertex_count - 1].y + beziers[i].point3.y) * 0.25f;
2161 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_BEZIER;
2163 if (!d2d_figure_add_bezier_control(figure, &p))
2165 ERR("Failed to add bezier control.\n");
2166 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2167 return;
2170 if (!d2d_figure_add_vertex(figure, beziers[i].point3))
2172 ERR("Failed to add bezier vertex.\n");
2173 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2174 return;
2178 geometry->u.path.segment_count += count;
2181 static void STDMETHODCALLTYPE d2d_geometry_sink_EndFigure(ID2D1GeometrySink *iface, D2D1_FIGURE_END figure_end)
2183 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2184 struct d2d_figure *figure;
2186 TRACE("iface %p, figure_end %#x.\n", iface, figure_end);
2188 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2190 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2191 return;
2194 figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2195 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_LINE;
2196 if (figure_end == D2D1_FIGURE_END_CLOSED)
2198 ++geometry->u.path.segment_count;
2199 figure->flags |= D2D_FIGURE_FLAG_CLOSED;
2200 if (!memcmp(&figure->vertices[0], &figure->vertices[figure->vertex_count - 1], sizeof(*figure->vertices)))
2201 --figure->vertex_count;
2204 if (!d2d_geometry_add_figure_outline(geometry, figure, figure_end))
2206 ERR("Failed to add figure outline.\n");
2207 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2208 return;
2211 geometry->u.path.state = D2D_GEOMETRY_STATE_OPEN;
2214 static void d2d_path_geometry_free_figures(struct d2d_geometry *geometry)
2216 size_t i;
2218 if (!geometry->u.path.figures)
2219 return;
2221 for (i = 0; i < geometry->u.path.figure_count; ++i)
2223 HeapFree(GetProcessHeap(), 0, geometry->u.path.figures[i].bezier_controls);
2224 HeapFree(GetProcessHeap(), 0, geometry->u.path.figures[i].vertices);
2226 HeapFree(GetProcessHeap(), 0, geometry->u.path.figures);
2227 geometry->u.path.figures = NULL;
2228 geometry->u.path.figures_size = 0;
2231 static HRESULT d2d_geometry_resolve_beziers(struct d2d_geometry *geometry)
2233 size_t bezier_idx, control_idx, i, j;
2235 for (i = 0; i < geometry->u.path.figure_count; ++i)
2237 geometry->fill.bezier_vertex_count += 3 * geometry->u.path.figures[i].bezier_control_count;
2240 if (!(geometry->fill.bezier_vertices = HeapAlloc(GetProcessHeap(), 0,
2241 geometry->fill.bezier_vertex_count * sizeof(*geometry->fill.bezier_vertices))))
2243 ERR("Failed to allocate bezier vertices array.\n");
2244 geometry->fill.bezier_vertex_count = 0;
2245 return E_OUTOFMEMORY;
2248 for (i = 0, bezier_idx = 0; i < geometry->u.path.figure_count; ++i)
2250 struct d2d_figure *figure = &geometry->u.path.figures[i];
2251 if (figure->bezier_control_count)
2253 for (j = 0, control_idx = 0; j < figure->vertex_count; ++j)
2255 const D2D1_POINT_2F *p0, *p1, *p2;
2256 struct d2d_bezier_vertex *b;
2257 float sign = -1.0f;
2259 if (figure->vertex_types[j] != D2D_VERTEX_TYPE_BEZIER)
2260 continue;
2262 b = &geometry->fill.bezier_vertices[bezier_idx * 3];
2263 p0 = &figure->vertices[j];
2264 p1 = &figure->bezier_controls[control_idx++];
2266 if (d2d_path_geometry_point_inside(geometry, p1, FALSE))
2268 sign = 1.0f;
2269 d2d_figure_insert_vertex(figure, j + 1, *p1);
2270 /* Inserting a vertex potentially invalidates p0. */
2271 p0 = &figure->vertices[j];
2272 ++j;
2275 if (j == figure->vertex_count - 1)
2276 p2 = &figure->vertices[0];
2277 else
2278 p2 = &figure->vertices[j + 1];
2280 d2d_bezier_vertex_set(&b[0], p0, 0.0f, 0.0f, sign);
2281 d2d_bezier_vertex_set(&b[1], p1, 0.5f, 0.0f, sign);
2282 d2d_bezier_vertex_set(&b[2], p2, 1.0f, 1.0f, sign);
2283 ++bezier_idx;
2288 return TRUE;
2291 static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_Close(ID2D1GeometrySink *iface)
2293 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2294 HRESULT hr = E_FAIL;
2296 TRACE("iface %p.\n", iface);
2298 if (geometry->u.path.state != D2D_GEOMETRY_STATE_OPEN)
2300 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
2301 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2302 return D2DERR_WRONG_STATE;
2304 geometry->u.path.state = D2D_GEOMETRY_STATE_CLOSED;
2306 if (!d2d_geometry_intersect_self(geometry))
2307 goto done;
2308 if (FAILED(hr = d2d_geometry_resolve_beziers(geometry)))
2309 goto done;
2310 if (FAILED(hr = d2d_path_geometry_triangulate(geometry)))
2311 goto done;
2313 done:
2314 if (FAILED(hr))
2316 HeapFree(GetProcessHeap(), 0, geometry->fill.bezier_vertices);
2317 geometry->fill.bezier_vertex_count = 0;
2318 d2d_path_geometry_free_figures(geometry);
2319 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2321 return hr;
2324 static void STDMETHODCALLTYPE d2d_geometry_sink_AddLine(ID2D1GeometrySink *iface, D2D1_POINT_2F point)
2326 TRACE("iface %p, point {%.8e, %.8e}.\n", iface, point.x, point.y);
2328 d2d_geometry_sink_AddLines(iface, &point, 1);
2331 static void STDMETHODCALLTYPE d2d_geometry_sink_AddBezier(ID2D1GeometrySink *iface, const D2D1_BEZIER_SEGMENT *bezier)
2333 TRACE("iface %p, bezier %p.\n", iface, bezier);
2335 d2d_geometry_sink_AddBeziers(iface, bezier, 1);
2338 static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBezier(ID2D1GeometrySink *iface,
2339 const D2D1_QUADRATIC_BEZIER_SEGMENT *bezier)
2341 TRACE("iface %p, bezier %p.\n", iface, bezier);
2343 ID2D1GeometrySink_AddQuadraticBeziers(iface, bezier, 1);
2346 static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBeziers(ID2D1GeometrySink *iface,
2347 const D2D1_QUADRATIC_BEZIER_SEGMENT *beziers, UINT32 bezier_count)
2349 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2350 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2351 unsigned int i;
2353 TRACE("iface %p, beziers %p, bezier_count %u.\n", iface, beziers, bezier_count);
2355 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2357 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2358 return;
2361 for (i = 0; i < bezier_count; ++i)
2363 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_BEZIER;
2364 if (!d2d_figure_add_bezier_control(figure, &beziers[i].point1))
2366 ERR("Failed to add bezier.\n");
2367 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2368 return;
2371 if (!d2d_figure_add_vertex(figure, beziers[i].point2))
2373 ERR("Failed to add bezier vertex.\n");
2374 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2375 return;
2379 geometry->u.path.segment_count += bezier_count;
2382 static void STDMETHODCALLTYPE d2d_geometry_sink_AddArc(ID2D1GeometrySink *iface, const D2D1_ARC_SEGMENT *arc)
2384 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2386 FIXME("iface %p, arc %p stub!\n", iface, arc);
2388 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2390 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2391 return;
2394 if (!d2d_figure_add_vertex(&geometry->u.path.figures[geometry->u.path.figure_count - 1], arc->point))
2396 ERR("Failed to add vertex.\n");
2397 return;
2400 ++geometry->u.path.segment_count;
2403 static const struct ID2D1GeometrySinkVtbl d2d_geometry_sink_vtbl =
2405 d2d_geometry_sink_QueryInterface,
2406 d2d_geometry_sink_AddRef,
2407 d2d_geometry_sink_Release,
2408 d2d_geometry_sink_SetFillMode,
2409 d2d_geometry_sink_SetSegmentFlags,
2410 d2d_geometry_sink_BeginFigure,
2411 d2d_geometry_sink_AddLines,
2412 d2d_geometry_sink_AddBeziers,
2413 d2d_geometry_sink_EndFigure,
2414 d2d_geometry_sink_Close,
2415 d2d_geometry_sink_AddLine,
2416 d2d_geometry_sink_AddBezier,
2417 d2d_geometry_sink_AddQuadraticBezier,
2418 d2d_geometry_sink_AddQuadraticBeziers,
2419 d2d_geometry_sink_AddArc,
2422 static inline struct d2d_geometry *impl_from_ID2D1PathGeometry(ID2D1PathGeometry *iface)
2424 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
2427 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_QueryInterface(ID2D1PathGeometry *iface, REFIID iid, void **out)
2429 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
2431 if (IsEqualGUID(iid, &IID_ID2D1PathGeometry)
2432 || IsEqualGUID(iid, &IID_ID2D1Geometry)
2433 || IsEqualGUID(iid, &IID_ID2D1Resource)
2434 || IsEqualGUID(iid, &IID_IUnknown))
2436 ID2D1PathGeometry_AddRef(iface);
2437 *out = iface;
2438 return S_OK;
2441 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
2443 *out = NULL;
2444 return E_NOINTERFACE;
2447 static ULONG STDMETHODCALLTYPE d2d_path_geometry_AddRef(ID2D1PathGeometry *iface)
2449 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2450 ULONG refcount = InterlockedIncrement(&geometry->refcount);
2452 TRACE("%p increasing refcount to %u.\n", iface, refcount);
2454 return refcount;
2457 static ULONG STDMETHODCALLTYPE d2d_path_geometry_Release(ID2D1PathGeometry *iface)
2459 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2460 ULONG refcount = InterlockedDecrement(&geometry->refcount);
2462 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
2464 if (!refcount)
2466 d2d_path_geometry_free_figures(geometry);
2467 d2d_geometry_cleanup(geometry);
2468 HeapFree(GetProcessHeap(), 0, geometry);
2471 return refcount;
2474 static void STDMETHODCALLTYPE d2d_path_geometry_GetFactory(ID2D1PathGeometry *iface, ID2D1Factory **factory)
2476 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2478 TRACE("iface %p, factory %p.\n", iface, factory);
2480 ID2D1Factory_AddRef(*factory = geometry->factory);
2483 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetBounds(ID2D1PathGeometry *iface,
2484 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
2486 FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
2488 return E_NOTIMPL;
2491 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetWidenedBounds(ID2D1PathGeometry *iface, float stroke_width,
2492 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_RECT_F *bounds)
2494 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
2495 iface, stroke_width, stroke_style, transform, tolerance, bounds);
2497 return E_NOTIMPL;
2500 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_StrokeContainsPoint(ID2D1PathGeometry *iface,
2501 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
2502 float tolerance, BOOL *contains)
2504 FIXME("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
2505 "transform %p, tolerance %.8e, contains %p stub!\n",
2506 iface, point.x, point.y, stroke_width, stroke_style, transform, tolerance, contains);
2508 return E_NOTIMPL;
2511 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_FillContainsPoint(ID2D1PathGeometry *iface,
2512 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
2514 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2515 D2D1_MATRIX_3X2_F g_i;
2517 TRACE("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p.\n",
2518 iface, point.x, point.y, transform, tolerance, contains);
2520 if (transform)
2522 if (!d2d_matrix_invert(&g_i, transform))
2523 return D2DERR_UNSUPPORTED_OPERATION;
2524 d2d_point_transform(&point, &g_i, point.x, point.y);
2527 *contains = !!d2d_path_geometry_point_inside(geometry, &point, FALSE);
2529 TRACE("-> %#x.\n", *contains);
2531 return S_OK;
2534 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_CompareWithGeometry(ID2D1PathGeometry *iface,
2535 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
2537 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
2538 iface, geometry, transform, tolerance, relation);
2540 return E_NOTIMPL;
2543 static void d2d_geometry_flatten_cubic(ID2D1SimplifiedGeometrySink *sink, const D2D1_POINT_2F *p0,
2544 const D2D1_BEZIER_SEGMENT *b, float tolerance)
2546 D2D1_BEZIER_SEGMENT b0, b1;
2547 D2D1_POINT_2F q;
2548 float d;
2550 /* It's certainly possible to calculate the maximum deviation of the
2551 * approximation from the curve, but it's a little involved. Instead, note
2552 * that if the control points were evenly spaced and collinear, p1 would
2553 * be exactly between p0 and p2, and p2 would be exactly between p1 and
2554 * p3. The deviation is a decent enough approximation, and much easier to
2555 * calculate.
2557 * p1' = (p0 + p2) / 2
2558 * p2' = (p1 + p3) / 2
2559 * d = ‖p1 - p1'‖₁ + ‖p2 - p2'‖₁ */
2560 d2d_point_lerp(&q, p0, &b->point2, 0.5f);
2561 d2d_point_subtract(&q, &b->point1, &q);
2562 d = fabsf(q.x) + fabsf(q.y);
2563 d2d_point_lerp(&q, &b->point1, &b->point3, 0.5f);
2564 d2d_point_subtract(&q, &b->point2, &q);
2565 d += fabsf(q.x) + fabsf(q.y);
2566 if (d < tolerance)
2568 ID2D1SimplifiedGeometrySink_AddLines(sink, &b->point3, 1);
2569 return;
2572 d2d_point_lerp(&q, &b->point1, &b->point2, 0.5f);
2574 b1.point3 = b->point3;
2575 d2d_point_lerp(&b1.point2, &b1.point3, &b->point2, 0.5f);
2576 d2d_point_lerp(&b1.point1, &b1.point2, &q, 0.5f);
2578 d2d_point_lerp(&b0.point1, p0, &b->point1, 0.5f);
2579 d2d_point_lerp(&b0.point2, &b0.point1, &q, 0.5f);
2580 d2d_point_lerp(&b0.point3, &b0.point2, &b1.point1, 0.5f);
2582 d2d_geometry_flatten_cubic(sink, p0, &b0, tolerance);
2583 ID2D1SimplifiedGeometrySink_SetSegmentFlags(sink, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN);
2584 d2d_geometry_flatten_cubic(sink, &b0.point3, &b1, tolerance);
2585 ID2D1SimplifiedGeometrySink_SetSegmentFlags(sink, D2D1_PATH_SEGMENT_NONE);
2588 static void d2d_geometry_simplify_quadratic(ID2D1SimplifiedGeometrySink *sink,
2589 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_POINT_2F *p0,
2590 const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2, float tolerance)
2592 D2D1_BEZIER_SEGMENT b;
2594 d2d_point_lerp(&b.point1, p0, p1, 2.0f / 3.0f);
2595 d2d_point_lerp(&b.point2, p2, p1, 2.0f / 3.0f);
2596 b.point3 = *p2;
2598 if (option == D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES)
2599 d2d_geometry_flatten_cubic(sink, p0, &b, tolerance);
2600 else
2601 ID2D1SimplifiedGeometrySink_AddBeziers(sink, &b, 1);
2604 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *iface,
2605 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
2606 ID2D1SimplifiedGeometrySink *sink)
2608 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2609 enum d2d_vertex_type type = D2D_VERTEX_TYPE_NONE;
2610 unsigned int i, j, bezier_idx;
2611 D2D1_FIGURE_BEGIN begin;
2612 D2D1_POINT_2F p, p1, p2;
2613 D2D1_FIGURE_END end;
2615 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
2616 iface, option, transform, tolerance, sink);
2618 ID2D1SimplifiedGeometrySink_SetFillMode(sink, geometry->u.path.fill_mode);
2619 for (i = 0; i < geometry->u.path.figure_count; ++i)
2621 const struct d2d_figure *figure = &geometry->u.path.figures[i];
2623 for (j = 0; j < figure->vertex_count; ++j)
2625 if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
2626 continue;
2628 p = figure->vertices[j];
2629 if (transform)
2630 d2d_point_transform(&p, transform, p.x, p.y);
2631 begin = figure->flags & D2D_FIGURE_FLAG_HOLLOW ? D2D1_FIGURE_BEGIN_HOLLOW : D2D1_FIGURE_BEGIN_FILLED;
2632 ID2D1SimplifiedGeometrySink_BeginFigure(sink, p, begin);
2633 type = figure->vertex_types[j];
2634 break;
2637 for (bezier_idx = 0, ++j; j < figure->vertex_count; ++j)
2639 if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
2640 continue;
2642 switch (type)
2644 case D2D_VERTEX_TYPE_LINE:
2645 p = figure->vertices[j];
2646 if (transform)
2647 d2d_point_transform(&p, transform, p.x, p.y);
2648 ID2D1SimplifiedGeometrySink_AddLines(sink, &p, 1);
2649 break;
2651 case D2D_VERTEX_TYPE_BEZIER:
2652 p1 = figure->bezier_controls[bezier_idx++];
2653 if (transform)
2654 d2d_point_transform(&p1, transform, p1.x, p1.y);
2655 p2 = figure->vertices[j];
2656 if (transform)
2657 d2d_point_transform(&p2, transform, p2.x, p2.y);
2658 d2d_geometry_simplify_quadratic(sink, option, &p, &p1, &p2, tolerance);
2659 p = p2;
2660 break;
2662 default:
2663 FIXME("Unhandled vertex type %#x.\n", type);
2664 p = figure->vertices[j];
2665 if (transform)
2666 d2d_point_transform(&p, transform, p.x, p.y);
2667 ID2D1SimplifiedGeometrySink_AddLines(sink, &p, 1);
2668 break;
2671 type = figure->vertex_types[j];
2674 if (type == D2D_VERTEX_TYPE_BEZIER)
2676 p1 = figure->bezier_controls[bezier_idx++];
2677 if (transform)
2678 d2d_point_transform(&p1, transform, p1.x, p1.y);
2679 p2 = figure->vertices[0];
2680 if (transform)
2681 d2d_point_transform(&p2, transform, p2.x, p2.y);
2682 d2d_geometry_simplify_quadratic(sink, option, &p, &p1, &p2, tolerance);
2685 end = figure->flags & D2D_FIGURE_FLAG_CLOSED ? D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN;
2686 ID2D1SimplifiedGeometrySink_EndFigure(sink, end);
2689 return S_OK;
2692 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Tessellate(ID2D1PathGeometry *iface,
2693 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
2695 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
2697 return E_NOTIMPL;
2700 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_CombineWithGeometry(ID2D1PathGeometry *iface,
2701 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
2702 float tolerance, ID2D1SimplifiedGeometrySink *sink)
2704 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2705 iface, geometry, combine_mode, transform, tolerance, sink);
2707 return E_NOTIMPL;
2710 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Outline(ID2D1PathGeometry *iface,
2711 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
2713 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
2715 return E_NOTIMPL;
2718 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeArea(ID2D1PathGeometry *iface,
2719 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
2721 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
2723 return E_NOTIMPL;
2726 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeLength(ID2D1PathGeometry *iface,
2727 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
2729 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
2731 return E_NOTIMPL;
2734 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputePointAtLength(ID2D1PathGeometry *iface, float length,
2735 const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point, D2D1_POINT_2F *tangent)
2737 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
2738 iface, length, transform, tolerance, point, tangent);
2740 return E_NOTIMPL;
2743 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Widen(ID2D1PathGeometry *iface, float stroke_width,
2744 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
2745 ID2D1SimplifiedGeometrySink *sink)
2747 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
2748 iface, stroke_width, stroke_style, transform, tolerance, sink);
2750 return E_NOTIMPL;
2753 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Open(ID2D1PathGeometry *iface, ID2D1GeometrySink **sink)
2755 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2757 TRACE("iface %p, sink %p.\n", iface, sink);
2759 if (geometry->u.path.state != D2D_GEOMETRY_STATE_INITIAL)
2760 return D2DERR_WRONG_STATE;
2762 *sink = &geometry->u.path.ID2D1GeometrySink_iface;
2763 ID2D1GeometrySink_AddRef(*sink);
2765 geometry->u.path.state = D2D_GEOMETRY_STATE_OPEN;
2767 return S_OK;
2770 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Stream(ID2D1PathGeometry *iface, ID2D1GeometrySink *sink)
2772 FIXME("iface %p, sink %p stub!\n", iface, sink);
2774 return E_NOTIMPL;
2777 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetSegmentCount(ID2D1PathGeometry *iface, UINT32 *count)
2779 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2781 TRACE("iface %p, count %p.\n", iface, count);
2783 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
2784 return D2DERR_WRONG_STATE;
2786 *count = geometry->u.path.segment_count;
2788 return S_OK;
2791 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetFigureCount(ID2D1PathGeometry *iface, UINT32 *count)
2793 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
2795 TRACE("iface %p, count %p.\n", iface, count);
2797 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
2798 return D2DERR_WRONG_STATE;
2800 *count = geometry->u.path.figure_count;
2802 return S_OK;
2805 static const struct ID2D1PathGeometryVtbl d2d_path_geometry_vtbl =
2807 d2d_path_geometry_QueryInterface,
2808 d2d_path_geometry_AddRef,
2809 d2d_path_geometry_Release,
2810 d2d_path_geometry_GetFactory,
2811 d2d_path_geometry_GetBounds,
2812 d2d_path_geometry_GetWidenedBounds,
2813 d2d_path_geometry_StrokeContainsPoint,
2814 d2d_path_geometry_FillContainsPoint,
2815 d2d_path_geometry_CompareWithGeometry,
2816 d2d_path_geometry_Simplify,
2817 d2d_path_geometry_Tessellate,
2818 d2d_path_geometry_CombineWithGeometry,
2819 d2d_path_geometry_Outline,
2820 d2d_path_geometry_ComputeArea,
2821 d2d_path_geometry_ComputeLength,
2822 d2d_path_geometry_ComputePointAtLength,
2823 d2d_path_geometry_Widen,
2824 d2d_path_geometry_Open,
2825 d2d_path_geometry_Stream,
2826 d2d_path_geometry_GetSegmentCount,
2827 d2d_path_geometry_GetFigureCount,
2830 void d2d_path_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory)
2832 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl);
2833 geometry->u.path.ID2D1GeometrySink_iface.lpVtbl = &d2d_geometry_sink_vtbl;
2836 static inline struct d2d_geometry *impl_from_ID2D1RectangleGeometry(ID2D1RectangleGeometry *iface)
2838 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
2841 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_QueryInterface(ID2D1RectangleGeometry *iface,
2842 REFIID iid, void **out)
2844 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
2846 if (IsEqualGUID(iid, &IID_ID2D1RectangleGeometry)
2847 || IsEqualGUID(iid, &IID_ID2D1Geometry)
2848 || IsEqualGUID(iid, &IID_ID2D1Resource)
2849 || IsEqualGUID(iid, &IID_IUnknown))
2851 ID2D1RectangleGeometry_AddRef(iface);
2852 *out = iface;
2853 return S_OK;
2856 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
2858 *out = NULL;
2859 return E_NOINTERFACE;
2862 static ULONG STDMETHODCALLTYPE d2d_rectangle_geometry_AddRef(ID2D1RectangleGeometry *iface)
2864 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
2865 ULONG refcount = InterlockedIncrement(&geometry->refcount);
2867 TRACE("%p increasing refcount to %u.\n", iface, refcount);
2869 return refcount;
2872 static ULONG STDMETHODCALLTYPE d2d_rectangle_geometry_Release(ID2D1RectangleGeometry *iface)
2874 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
2875 ULONG refcount = InterlockedDecrement(&geometry->refcount);
2877 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
2879 if (!refcount)
2881 d2d_geometry_cleanup(geometry);
2882 HeapFree(GetProcessHeap(), 0, geometry);
2885 return refcount;
2888 static void STDMETHODCALLTYPE d2d_rectangle_geometry_GetFactory(ID2D1RectangleGeometry *iface, ID2D1Factory **factory)
2890 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
2892 TRACE("iface %p, factory %p.\n", iface, factory);
2894 ID2D1Factory_AddRef(*factory = geometry->factory);
2897 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_GetBounds(ID2D1RectangleGeometry *iface,
2898 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
2900 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
2901 D2D1_RECT_F *rect;
2902 D2D1_POINT_2F p;
2904 TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
2906 rect = &geometry->u.rectangle.rect;
2907 if (!transform)
2909 *bounds = *rect;
2910 return S_OK;
2913 bounds->left = FLT_MAX;
2914 bounds->top = FLT_MAX;
2915 bounds->right = -FLT_MAX;
2916 bounds->bottom = -FLT_MAX;
2918 d2d_point_transform(&p, transform, rect->left, rect->top);
2919 d2d_rect_expand(bounds, &p);
2920 d2d_point_transform(&p, transform, rect->left, rect->bottom);
2921 d2d_rect_expand(bounds, &p);
2922 d2d_point_transform(&p, transform, rect->right, rect->bottom);
2923 d2d_rect_expand(bounds, &p);
2924 d2d_point_transform(&p, transform, rect->right, rect->top);
2925 d2d_rect_expand(bounds, &p);
2927 return S_OK;
2930 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_GetWidenedBounds(ID2D1RectangleGeometry *iface,
2931 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
2932 float tolerance, D2D1_RECT_F *bounds)
2934 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
2935 iface, stroke_width, stroke_style, transform, tolerance, bounds);
2937 return E_NOTIMPL;
2940 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_StrokeContainsPoint(ID2D1RectangleGeometry *iface,
2941 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
2942 float tolerance, BOOL *contains)
2944 FIXME("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
2945 "transform %p, tolerance %.8e, contains %p stub!\n",
2946 iface, point.x, point.y, stroke_width, stroke_style, transform, tolerance, contains);
2948 return E_NOTIMPL;
2951 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_FillContainsPoint(ID2D1RectangleGeometry *iface,
2952 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
2954 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
2955 D2D1_RECT_F *rect = &geometry->u.rectangle.rect;
2956 float dx, dy;
2958 TRACE("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p.\n",
2959 iface, point.x, point.y, transform, tolerance, contains);
2961 if (transform)
2963 D2D1_MATRIX_3X2_F g_i;
2965 if (!d2d_matrix_invert(&g_i, transform))
2966 return D2DERR_UNSUPPORTED_OPERATION;
2967 d2d_point_transform(&point, &g_i, point.x, point.y);
2970 if (tolerance == 0.0f)
2971 tolerance = D2D1_DEFAULT_FLATTENING_TOLERANCE;
2973 dx = max(fabsf((rect->right + rect->left) / 2.0f - point.x) - (rect->right - rect->left) / 2.0f, 0.0f);
2974 dy = max(fabsf((rect->bottom + rect->top) / 2.0f - point.y) - (rect->bottom - rect->top) / 2.0f, 0.0f);
2976 *contains = tolerance * tolerance > (dx * dx + dy * dy);
2977 return S_OK;
2980 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_CompareWithGeometry(ID2D1RectangleGeometry *iface,
2981 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
2983 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
2984 iface, geometry, transform, tolerance, relation);
2986 return E_NOTIMPL;
2989 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Simplify(ID2D1RectangleGeometry *iface,
2990 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
2991 ID2D1SimplifiedGeometrySink *sink)
2993 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
2994 D2D1_RECT_F *rect = &geometry->u.rectangle.rect;
2995 D2D1_POINT_2F p[4];
2996 unsigned int i;
2998 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
2999 iface, option, transform, tolerance, sink);
3001 d2d_point_set(&p[0], rect->left, rect->top);
3002 d2d_point_set(&p[1], rect->right, rect->top);
3003 d2d_point_set(&p[2], rect->right, rect->bottom);
3004 d2d_point_set(&p[3], rect->left, rect->bottom);
3006 if (transform)
3008 for (i = 0; i < ARRAY_SIZE(p); ++i)
3010 d2d_point_transform(&p[i], transform, p[i].x, p[i].y);
3014 ID2D1SimplifiedGeometrySink_SetFillMode(sink, D2D1_FILL_MODE_ALTERNATE);
3015 ID2D1SimplifiedGeometrySink_BeginFigure(sink, p[0], D2D1_FIGURE_BEGIN_FILLED);
3016 ID2D1SimplifiedGeometrySink_AddLines(sink, &p[1], 3);
3017 ID2D1SimplifiedGeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
3019 return S_OK;
3022 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Tessellate(ID2D1RectangleGeometry *iface,
3023 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
3025 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
3027 return E_NOTIMPL;
3030 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_CombineWithGeometry(ID2D1RectangleGeometry *iface,
3031 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
3032 float tolerance, ID2D1SimplifiedGeometrySink *sink)
3034 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
3035 iface, geometry, combine_mode, transform, tolerance, sink);
3037 return E_NOTIMPL;
3040 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Outline(ID2D1RectangleGeometry *iface,
3041 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
3043 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
3045 return E_NOTIMPL;
3048 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputeArea(ID2D1RectangleGeometry *iface,
3049 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
3051 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
3053 return E_NOTIMPL;
3056 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputeLength(ID2D1RectangleGeometry *iface,
3057 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
3059 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
3061 return E_NOTIMPL;
3064 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputePointAtLength(ID2D1RectangleGeometry *iface,
3065 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
3066 D2D1_POINT_2F *tangent)
3068 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
3069 iface, length, transform, tolerance, point, tangent);
3071 return E_NOTIMPL;
3074 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Widen(ID2D1RectangleGeometry *iface, float stroke_width,
3075 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
3076 ID2D1SimplifiedGeometrySink *sink)
3078 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
3079 iface, stroke_width, stroke_style, transform, tolerance, sink);
3081 return E_NOTIMPL;
3084 static void STDMETHODCALLTYPE d2d_rectangle_geometry_GetRect(ID2D1RectangleGeometry *iface, D2D1_RECT_F *rect)
3086 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
3088 TRACE("iface %p, rect %p.\n", iface, rect);
3090 *rect = geometry->u.rectangle.rect;
3093 static const struct ID2D1RectangleGeometryVtbl d2d_rectangle_geometry_vtbl =
3095 d2d_rectangle_geometry_QueryInterface,
3096 d2d_rectangle_geometry_AddRef,
3097 d2d_rectangle_geometry_Release,
3098 d2d_rectangle_geometry_GetFactory,
3099 d2d_rectangle_geometry_GetBounds,
3100 d2d_rectangle_geometry_GetWidenedBounds,
3101 d2d_rectangle_geometry_StrokeContainsPoint,
3102 d2d_rectangle_geometry_FillContainsPoint,
3103 d2d_rectangle_geometry_CompareWithGeometry,
3104 d2d_rectangle_geometry_Simplify,
3105 d2d_rectangle_geometry_Tessellate,
3106 d2d_rectangle_geometry_CombineWithGeometry,
3107 d2d_rectangle_geometry_Outline,
3108 d2d_rectangle_geometry_ComputeArea,
3109 d2d_rectangle_geometry_ComputeLength,
3110 d2d_rectangle_geometry_ComputePointAtLength,
3111 d2d_rectangle_geometry_Widen,
3112 d2d_rectangle_geometry_GetRect,
3115 HRESULT d2d_rectangle_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_RECT_F *rect)
3117 struct d2d_face *f;
3118 D2D1_POINT_2F *v;
3119 float l, r, t, b;
3121 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl);
3122 geometry->u.rectangle.rect = *rect;
3124 if (!(geometry->fill.vertices = HeapAlloc(GetProcessHeap(), 0, 4 * sizeof(*geometry->fill.vertices))))
3125 goto fail;
3126 if (!d2d_array_reserve((void **)&geometry->fill.faces,
3127 &geometry->fill.faces_size, 2, sizeof(*geometry->fill.faces)))
3128 goto fail;
3130 l = min(rect->left, rect->right);
3131 r = max(rect->left, rect->right);
3132 t = min(rect->top, rect->bottom);
3133 b = max(rect->top, rect->bottom);
3135 v = geometry->fill.vertices;
3136 d2d_point_set(&v[0], l, t);
3137 d2d_point_set(&v[1], l, b);
3138 d2d_point_set(&v[2], r, b);
3139 d2d_point_set(&v[3], r, t);
3140 geometry->fill.vertex_count = 4;
3142 f = geometry->fill.faces;
3143 d2d_face_set(&f[0], 1, 2, 0);
3144 d2d_face_set(&f[1], 0, 2, 3);
3145 geometry->fill.face_count = 2;
3147 if (!d2d_geometry_outline_add_line_segment(geometry, &v[0], &v[1]))
3148 goto fail;
3149 if (!d2d_geometry_outline_add_line_segment(geometry, &v[1], &v[2]))
3150 goto fail;
3151 if (!d2d_geometry_outline_add_line_segment(geometry, &v[2], &v[3]))
3152 goto fail;
3153 if (!d2d_geometry_outline_add_line_segment(geometry, &v[3], &v[0]))
3154 goto fail;
3156 if (!d2d_geometry_outline_add_join(geometry, &v[3], &v[0], &v[1]))
3157 goto fail;
3158 if (!d2d_geometry_outline_add_join(geometry, &v[0], &v[1], &v[2]))
3159 goto fail;
3160 if (!d2d_geometry_outline_add_join(geometry, &v[1], &v[2], &v[3]))
3161 goto fail;
3162 if (!d2d_geometry_outline_add_join(geometry, &v[2], &v[3], &v[0]))
3163 goto fail;
3165 return S_OK;
3167 fail:
3168 d2d_geometry_cleanup(geometry);
3169 return E_OUTOFMEMORY;
3172 static inline struct d2d_geometry *impl_from_ID2D1TransformedGeometry(ID2D1TransformedGeometry *iface)
3174 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
3177 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_QueryInterface(ID2D1TransformedGeometry *iface,
3178 REFIID iid, void **out)
3180 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
3182 if (IsEqualGUID(iid, &IID_ID2D1TransformedGeometry)
3183 || IsEqualGUID(iid, &IID_ID2D1Geometry)
3184 || IsEqualGUID(iid, &IID_ID2D1Resource)
3185 || IsEqualGUID(iid, &IID_IUnknown))
3187 ID2D1TransformedGeometry_AddRef(iface);
3188 *out = iface;
3189 return S_OK;
3192 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
3194 *out = NULL;
3195 return E_NOINTERFACE;
3198 static ULONG STDMETHODCALLTYPE d2d_transformed_geometry_AddRef(ID2D1TransformedGeometry *iface)
3200 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
3201 ULONG refcount = InterlockedIncrement(&geometry->refcount);
3203 TRACE("%p increasing refcount to %u.\n", iface, refcount);
3205 return refcount;
3208 static ULONG STDMETHODCALLTYPE d2d_transformed_geometry_Release(ID2D1TransformedGeometry *iface)
3210 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
3211 ULONG refcount = InterlockedDecrement(&geometry->refcount);
3213 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
3215 if (!refcount)
3217 geometry->outline.bezier_faces = NULL;
3218 geometry->outline.beziers = NULL;
3219 geometry->outline.faces = NULL;
3220 geometry->outline.vertices = NULL;
3221 geometry->fill.bezier_vertices = NULL;
3222 geometry->fill.faces = NULL;
3223 geometry->fill.vertices = NULL;
3224 ID2D1Geometry_Release(geometry->u.transformed.src_geometry);
3225 d2d_geometry_cleanup(geometry);
3226 HeapFree(GetProcessHeap(), 0, geometry);
3229 return refcount;
3232 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetFactory(ID2D1TransformedGeometry *iface,
3233 ID2D1Factory **factory)
3235 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
3237 TRACE("iface %p, factory %p.\n", iface, factory);
3239 ID2D1Factory_AddRef(*factory = geometry->factory);
3242 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_GetBounds(ID2D1TransformedGeometry *iface,
3243 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
3245 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
3246 D2D1_MATRIX_3X2_F g;
3248 TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
3250 g = geometry->transform;
3251 if (transform)
3252 d2d_matrix_multiply(&g, transform);
3254 return ID2D1Geometry_GetBounds(geometry->u.transformed.src_geometry, &g, bounds);
3257 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_GetWidenedBounds(ID2D1TransformedGeometry *iface,
3258 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
3259 float tolerance, D2D1_RECT_F *bounds)
3261 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
3262 iface, stroke_width, stroke_style, transform, tolerance, bounds);
3264 return E_NOTIMPL;
3267 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_StrokeContainsPoint(ID2D1TransformedGeometry *iface,
3268 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
3269 float tolerance, BOOL *contains)
3271 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
3272 D2D1_MATRIX_3X2_F g;
3274 TRACE("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
3275 "transform %p, tolerance %.8e, contains %p.\n",
3276 iface, point.x, point.y, stroke_width, stroke_style, transform, tolerance, contains);
3278 g = geometry->transform;
3279 if (transform)
3280 d2d_matrix_multiply(&g, transform);
3282 return ID2D1Geometry_StrokeContainsPoint(geometry->u.transformed.src_geometry, point, stroke_width, stroke_style,
3283 &g, tolerance, contains);
3286 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_FillContainsPoint(ID2D1TransformedGeometry *iface,
3287 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
3289 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
3290 D2D1_MATRIX_3X2_F g;
3292 TRACE("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p.\n",
3293 iface, point.x, point.y, transform, tolerance, contains);
3295 g = geometry->transform;
3296 if (transform)
3297 d2d_matrix_multiply(&g, transform);
3299 return ID2D1Geometry_FillContainsPoint(geometry->u.transformed.src_geometry, point, &g, tolerance, contains);
3302 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_CompareWithGeometry(ID2D1TransformedGeometry *iface,
3303 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
3305 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
3306 iface, geometry, transform, tolerance, relation);
3308 return E_NOTIMPL;
3311 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Simplify(ID2D1TransformedGeometry *iface,
3312 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
3313 ID2D1SimplifiedGeometrySink *sink)
3315 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
3316 D2D1_MATRIX_3X2_F g;
3318 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
3319 iface, option, transform, tolerance, sink);
3321 g = geometry->transform;
3322 if (transform)
3323 d2d_matrix_multiply(&g, transform);
3325 return ID2D1Geometry_Simplify(geometry->u.transformed.src_geometry, option, &g, tolerance, sink);
3328 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Tessellate(ID2D1TransformedGeometry *iface,
3329 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
3331 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
3333 return E_NOTIMPL;
3336 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_CombineWithGeometry(ID2D1TransformedGeometry *iface,
3337 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
3338 float tolerance, ID2D1SimplifiedGeometrySink *sink)
3340 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
3341 iface, geometry, combine_mode, transform, tolerance, sink);
3343 return E_NOTIMPL;
3346 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Outline(ID2D1TransformedGeometry *iface,
3347 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
3349 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
3351 return E_NOTIMPL;
3354 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputeArea(ID2D1TransformedGeometry *iface,
3355 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
3357 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
3359 return E_NOTIMPL;
3362 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputeLength(ID2D1TransformedGeometry *iface,
3363 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
3365 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
3367 return E_NOTIMPL;
3370 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputePointAtLength(ID2D1TransformedGeometry *iface,
3371 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
3372 D2D1_POINT_2F *tangent)
3374 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
3375 iface, length, transform, tolerance, point, tangent);
3377 return E_NOTIMPL;
3380 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Widen(ID2D1TransformedGeometry *iface, float stroke_width,
3381 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
3382 ID2D1SimplifiedGeometrySink *sink)
3384 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
3385 iface, stroke_width, stroke_style, transform, tolerance, sink);
3387 return E_NOTIMPL;
3390 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetSourceGeometry(ID2D1TransformedGeometry *iface,
3391 ID2D1Geometry **src_geometry)
3393 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
3395 TRACE("iface %p, src_geometry %p.\n", iface, src_geometry);
3397 ID2D1Geometry_AddRef(*src_geometry = geometry->u.transformed.src_geometry);
3400 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetTransform(ID2D1TransformedGeometry *iface,
3401 D2D1_MATRIX_3X2_F *transform)
3403 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
3405 TRACE("iface %p, transform %p.\n", iface, transform);
3407 *transform = geometry->u.transformed.transform;
3410 static const struct ID2D1TransformedGeometryVtbl d2d_transformed_geometry_vtbl =
3412 d2d_transformed_geometry_QueryInterface,
3413 d2d_transformed_geometry_AddRef,
3414 d2d_transformed_geometry_Release,
3415 d2d_transformed_geometry_GetFactory,
3416 d2d_transformed_geometry_GetBounds,
3417 d2d_transformed_geometry_GetWidenedBounds,
3418 d2d_transformed_geometry_StrokeContainsPoint,
3419 d2d_transformed_geometry_FillContainsPoint,
3420 d2d_transformed_geometry_CompareWithGeometry,
3421 d2d_transformed_geometry_Simplify,
3422 d2d_transformed_geometry_Tessellate,
3423 d2d_transformed_geometry_CombineWithGeometry,
3424 d2d_transformed_geometry_Outline,
3425 d2d_transformed_geometry_ComputeArea,
3426 d2d_transformed_geometry_ComputeLength,
3427 d2d_transformed_geometry_ComputePointAtLength,
3428 d2d_transformed_geometry_Widen,
3429 d2d_transformed_geometry_GetSourceGeometry,
3430 d2d_transformed_geometry_GetTransform,
3433 void d2d_transformed_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
3434 ID2D1Geometry *src_geometry, const D2D_MATRIX_3X2_F *transform)
3436 struct d2d_geometry *src_impl;
3437 D2D_MATRIX_3X2_F g;
3439 src_impl = unsafe_impl_from_ID2D1Geometry(src_geometry);
3441 g = src_impl->transform;
3442 d2d_matrix_multiply(&g, transform);
3443 d2d_geometry_init(geometry, factory, &g, (ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl);
3444 ID2D1Geometry_AddRef(geometry->u.transformed.src_geometry = src_geometry);
3445 geometry->u.transformed.transform = *transform;
3446 geometry->fill = src_impl->fill;
3447 geometry->outline = src_impl->outline;
3450 struct d2d_geometry *unsafe_impl_from_ID2D1Geometry(ID2D1Geometry *iface)
3452 if (!iface)
3453 return NULL;
3454 assert(iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl
3455 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl
3456 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl);
3457 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);