makefiles: Don't use standard libs for programs that specify -nodefaultlibs.
[wine/zf.git] / dlls / d2d1 / geometry.c
blobc18b648aef41a447ff01411f9ad196726d7dc79d
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 "d2d1_private.h"
20 #include <float.h>
22 WINE_DEFAULT_DEBUG_CHANNEL(d2d);
24 #define D2D_FIGURE_FLAG_CLOSED 0x00000001u
25 #define D2D_FIGURE_FLAG_HOLLOW 0x00000002u
27 #define D2D_CDT_EDGE_FLAG_FREED 0x80000000u
28 #define D2D_CDT_EDGE_FLAG_VISITED(r) (1u << (r))
30 #define D2D_FP_EPS (1.0f / (1 << FLT_MANT_DIG))
32 static const D2D1_MATRIX_3X2_F identity =
34 1.0f, 0.0f,
35 0.0f, 1.0f,
36 0.0f, 0.0f,
39 enum d2d_cdt_edge_next
41 D2D_EDGE_NEXT_ORIGIN = 0,
42 D2D_EDGE_NEXT_ROT = 1,
43 D2D_EDGE_NEXT_SYM = 2,
44 D2D_EDGE_NEXT_TOR = 3,
47 enum d2d_vertex_type
49 D2D_VERTEX_TYPE_NONE,
50 D2D_VERTEX_TYPE_LINE,
51 D2D_VERTEX_TYPE_BEZIER,
52 D2D_VERTEX_TYPE_SPLIT_BEZIER,
55 struct d2d_segment_idx
57 size_t figure_idx;
58 size_t vertex_idx;
59 size_t control_idx;
62 struct d2d_figure
64 D2D1_POINT_2F *vertices;
65 size_t vertices_size;
66 enum d2d_vertex_type *vertex_types;
67 size_t vertex_types_size;
68 size_t vertex_count;
70 D2D1_POINT_2F *bezier_controls;
71 size_t bezier_controls_size;
72 size_t bezier_control_count;
74 D2D1_POINT_2F *original_bezier_controls;
75 size_t original_bezier_control_count;
77 D2D1_RECT_F bounds;
78 unsigned int flags;
81 struct d2d_cdt_edge_ref
83 size_t idx;
84 enum d2d_cdt_edge_next r;
87 struct d2d_cdt_edge
89 struct d2d_cdt_edge_ref next[4];
90 size_t vertex[2];
91 unsigned int flags;
94 struct d2d_cdt
96 struct d2d_cdt_edge *edges;
97 size_t edges_size;
98 size_t edge_count;
99 size_t free_edge;
101 const D2D1_POINT_2F *vertices;
104 struct d2d_geometry_intersection
106 size_t figure_idx;
107 size_t vertex_idx;
108 size_t control_idx;
109 float t;
110 D2D1_POINT_2F p;
113 struct d2d_geometry_intersections
115 struct d2d_geometry_intersection *intersections;
116 size_t intersections_size;
117 size_t intersection_count;
120 struct d2d_fp_two_vec2
122 float x[2];
123 float y[2];
126 struct d2d_fp_fin
128 float *now, *other;
129 size_t length;
132 static void d2d_curve_vertex_set(struct d2d_curve_vertex *b,
133 const D2D1_POINT_2F *p, float u, float v, float sign)
135 b->position = *p;
136 b->texcoord.u = u;
137 b->texcoord.v = v;
138 b->texcoord.sign = sign;
141 static void d2d_face_set(struct d2d_face *f, UINT16 v0, UINT16 v1, UINT16 v2)
143 f->v[0] = v0;
144 f->v[1] = v1;
145 f->v[2] = v2;
148 static void d2d_outline_vertex_set(struct d2d_outline_vertex *v, float x, float y,
149 float prev_x, float prev_y, float next_x, float next_y)
151 d2d_point_set(&v->position, x, y);
152 d2d_point_set(&v->prev, prev_x, prev_y);
153 d2d_point_set(&v->next, next_x, next_y);
156 static void d2d_curve_outline_vertex_set(struct d2d_curve_outline_vertex *a, const D2D1_POINT_2F *position,
157 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2,
158 float prev_x, float prev_y, float next_x, float next_y)
160 a->position = *position;
161 a->p0 = *p0;
162 a->p1 = *p1;
163 a->p2 = *p2;
164 d2d_point_set(&a->prev, prev_x, prev_y);
165 d2d_point_set(&a->next, next_x, next_y);
168 static void d2d_fp_two_sum(float *out, float a, float b)
170 float a_virt, a_round, b_virt, b_round;
172 out[1] = a + b;
173 b_virt = out[1] - a;
174 a_virt = out[1] - b_virt;
175 b_round = b - b_virt;
176 a_round = a - a_virt;
177 out[0] = a_round + b_round;
180 static void d2d_fp_fast_two_sum(float *out, float a, float b)
182 float b_virt;
184 out[1] = a + b;
185 b_virt = out[1] - a;
186 out[0] = b - b_virt;
189 static void d2d_fp_two_two_sum(float *out, const float *a, const float *b)
191 float sum[2];
193 d2d_fp_two_sum(out, a[0], b[0]);
194 d2d_fp_two_sum(sum, a[1], out[1]);
195 d2d_fp_two_sum(&out[1], sum[0], b[1]);
196 d2d_fp_two_sum(&out[2], sum[1], out[2]);
199 static void d2d_fp_two_diff_tail(float *out, float a, float b, float x)
201 float a_virt, a_round, b_virt, b_round;
203 b_virt = a - x;
204 a_virt = x + b_virt;
205 b_round = b_virt - b;
206 a_round = a - a_virt;
207 *out = a_round + b_round;
210 static void d2d_fp_two_two_diff(float *out, const float *a, const float *b)
212 float sum[2], diff;
214 diff = a[0] - b[0];
215 d2d_fp_two_diff_tail(out, a[0], b[0], diff);
216 d2d_fp_two_sum(sum, a[1], diff);
217 diff = sum[0] - b[1];
218 d2d_fp_two_diff_tail(&out[1], sum[0], b[1], diff);
219 d2d_fp_two_sum(&out[2], sum[1], diff);
222 static void d2d_fp_split(float *out, float a)
224 float a_big, c;
226 c = a * ((1 << (FLT_MANT_DIG / 2)) + 1.0f);
227 a_big = c - a;
228 out[1] = c - a_big;
229 out[0] = a - out[1];
232 static void d2d_fp_two_product_presplit(float *out, float a, float b, const float *b_split)
234 float a_split[2], err1, err2, err3;
236 out[1] = a * b;
237 d2d_fp_split(a_split, a);
238 err1 = out[1] - (a_split[1] * b_split[1]);
239 err2 = err1 - (a_split[0] * b_split[1]);
240 err3 = err2 - (a_split[1] * b_split[0]);
241 out[0] = (a_split[0] * b_split[0]) - err3;
244 static void d2d_fp_two_product(float *out, float a, float b)
246 float b_split[2];
248 d2d_fp_split(b_split, b);
249 d2d_fp_two_product_presplit(out, a, b, b_split);
252 static void d2d_fp_square(float *out, float a)
254 float a_split[2], err1, err2;
256 out[1] = a * a;
257 d2d_fp_split(a_split, a);
258 err1 = out[1] - (a_split[1] * a_split[1]);
259 err2 = err1 - ((a_split[1] + a_split[1]) * a_split[0]);
260 out[0] = (a_split[0] * a_split[0]) - err2;
263 static float d2d_fp_estimate(float *a, size_t len)
265 float out = a[0];
266 size_t idx = 1;
268 while (idx < len)
269 out += a[idx++];
271 return out;
274 static void d2d_fp_fast_expansion_sum_zeroelim(float *out, size_t *out_len,
275 const float *a, size_t a_len, const float *b, size_t b_len)
277 float sum[2], q, a_curr, b_curr;
278 size_t a_idx, b_idx, out_idx;
280 a_curr = a[0];
281 b_curr = b[0];
282 a_idx = b_idx = 0;
283 if ((b_curr > a_curr) == (b_curr > -a_curr))
285 q = a_curr;
286 a_curr = a[++a_idx];
288 else
290 q = b_curr;
291 b_curr = b[++b_idx];
293 out_idx = 0;
294 if (a_idx < a_len && b_idx < b_len)
296 if ((b_curr > a_curr) == (b_curr > -a_curr))
298 d2d_fp_fast_two_sum(sum, a_curr, q);
299 a_curr = a[++a_idx];
301 else
303 d2d_fp_fast_two_sum(sum, b_curr, q);
304 b_curr = b[++b_idx];
306 if (sum[0] != 0.0f)
307 out[out_idx++] = sum[0];
308 q = sum[1];
309 while (a_idx < a_len && b_idx < b_len)
311 if ((b_curr > a_curr) == (b_curr > -a_curr))
313 d2d_fp_two_sum(sum, q, a_curr);
314 a_curr = a[++a_idx];
316 else
318 d2d_fp_two_sum(sum, q, b_curr);
319 b_curr = b[++b_idx];
321 if (sum[0] != 0.0f)
322 out[out_idx++] = sum[0];
323 q = sum[1];
326 while (a_idx < a_len)
328 d2d_fp_two_sum(sum, q, a_curr);
329 a_curr = a[++a_idx];
330 if (sum[0] != 0.0f)
331 out[out_idx++] = sum[0];
332 q = sum[1];
334 while (b_idx < b_len)
336 d2d_fp_two_sum(sum, q, b_curr);
337 b_curr = b[++b_idx];
338 if (sum[0] != 0.0f)
339 out[out_idx++] = sum[0];
340 q = sum[1];
342 if (q != 0.0f || !out_idx)
343 out[out_idx++] = q;
345 *out_len = out_idx;
348 static void d2d_fp_scale_expansion_zeroelim(float *out, size_t *out_len, const float *a, size_t a_len, float b)
350 float product[2], sum[2], b_split[2], q[2], a_curr;
351 size_t a_idx, out_idx;
353 d2d_fp_split(b_split, b);
354 d2d_fp_two_product_presplit(q, a[0], b, b_split);
355 out_idx = 0;
356 if (q[0] != 0.0f)
357 out[out_idx++] = q[0];
358 for (a_idx = 1; a_idx < a_len; ++a_idx)
360 a_curr = a[a_idx];
361 d2d_fp_two_product_presplit(product, a_curr, b, b_split);
362 d2d_fp_two_sum(sum, q[1], product[0]);
363 if (sum[0] != 0.0f)
364 out[out_idx++] = sum[0];
365 d2d_fp_fast_two_sum(q, product[1], sum[1]);
366 if (q[0] != 0.0f)
367 out[out_idx++] = q[0];
369 if (q[1] != 0.0f || !out_idx)
370 out[out_idx++] = q[1];
372 *out_len = out_idx;
375 static void d2d_point_subtract(D2D1_POINT_2F *out,
376 const D2D1_POINT_2F *a, const D2D1_POINT_2F *b)
378 out->x = a->x - b->x;
379 out->y = a->y - b->y;
382 static void d2d_point_scale(D2D1_POINT_2F *p, float scale)
384 p->x *= scale;
385 p->y *= scale;
388 static void d2d_point_lerp(D2D1_POINT_2F *out,
389 const D2D1_POINT_2F *a, const D2D1_POINT_2F *b, float t)
391 out->x = a->x * (1.0f - t) + b->x * t;
392 out->y = a->y * (1.0f - t) + b->y * t;
395 static void d2d_point_calculate_bezier(D2D1_POINT_2F *out, const D2D1_POINT_2F *p0,
396 const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2, float t)
398 float t_c = 1.0f - t;
400 out->x = t_c * (t_c * p0->x + t * p1->x) + t * (t_c * p1->x + t * p2->x);
401 out->y = t_c * (t_c * p0->y + t * p1->y) + t * (t_c * p1->y + t * p2->y);
404 static void d2d_point_normalise(D2D1_POINT_2F *p)
406 float l;
408 if ((l = sqrtf(d2d_point_dot(p, p))) != 0.0f)
409 d2d_point_scale(p, 1.0f / l);
412 /* This implementation is based on the paper "Adaptive Precision
413 * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
414 * associated (Public Domain) code by Jonathan Richard Shewchuk. */
415 static float d2d_point_ccw(const D2D1_POINT_2F *a, const D2D1_POINT_2F *b, const D2D1_POINT_2F *c)
417 static const float err_bound_result = (3.0f + 8.0f * D2D_FP_EPS) * D2D_FP_EPS;
418 static const float err_bound_a = (3.0f + 16.0f * D2D_FP_EPS) * D2D_FP_EPS;
419 static const float err_bound_b = (2.0f + 12.0f * D2D_FP_EPS) * D2D_FP_EPS;
420 static const float err_bound_c = (9.0f + 64.0f * D2D_FP_EPS) * D2D_FP_EPS * D2D_FP_EPS;
421 float det_d[16], det_c2[12], det_c1[8], det_b[4], temp4[4], temp2a[2], temp2b[2], abxacy[2], abyacx[2];
422 size_t det_d_len, det_c2_len, det_c1_len;
423 float det, det_sum, err_bound;
424 struct d2d_fp_two_vec2 ab, ac;
426 ab.x[1] = b->x - a->x;
427 ab.y[1] = b->y - a->y;
428 ac.x[1] = c->x - a->x;
429 ac.y[1] = c->y - a->y;
431 abxacy[1] = ab.x[1] * ac.y[1];
432 abyacx[1] = ab.y[1] * ac.x[1];
433 det = abxacy[1] - abyacx[1];
435 if (abxacy[1] > 0.0f)
437 if (abyacx[1] <= 0.0f)
438 return det;
439 det_sum = abxacy[1] + abyacx[1];
441 else if (abxacy[1] < 0.0f)
443 if (abyacx[1] >= 0.0f)
444 return det;
445 det_sum = -abxacy[1] - abyacx[1];
447 else
449 return det;
452 err_bound = err_bound_a * det_sum;
453 if (det >= err_bound || -det >= err_bound)
454 return det;
456 d2d_fp_two_product(abxacy, ab.x[1], ac.y[1]);
457 d2d_fp_two_product(abyacx, ab.y[1], ac.x[1]);
458 d2d_fp_two_two_diff(det_b, abxacy, abyacx);
460 det = d2d_fp_estimate(det_b, 4);
461 err_bound = err_bound_b * det_sum;
462 if (det >= err_bound || -det >= err_bound)
463 return det;
465 d2d_fp_two_diff_tail(&ab.x[0], b->x, a->x, ab.x[1]);
466 d2d_fp_two_diff_tail(&ab.y[0], b->y, a->y, ab.y[1]);
467 d2d_fp_two_diff_tail(&ac.x[0], c->x, a->x, ac.x[1]);
468 d2d_fp_two_diff_tail(&ac.y[0], c->y, a->y, ac.y[1]);
470 if (ab.x[0] == 0.0f && ab.y[0] == 0.0f && ac.x[0] == 0.0f && ac.y[0] == 0.0f)
471 return det;
473 err_bound = err_bound_c * det_sum + err_bound_result * fabsf(det);
474 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]);
475 if (det >= err_bound || -det >= err_bound)
476 return det;
478 d2d_fp_two_product(temp2a, ab.x[0], ac.y[1]);
479 d2d_fp_two_product(temp2b, ab.y[0], ac.x[1]);
480 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
481 d2d_fp_fast_expansion_sum_zeroelim(det_c1, &det_c1_len, det_b, 4, temp4, 4);
483 d2d_fp_two_product(temp2a, ab.x[1], ac.y[0]);
484 d2d_fp_two_product(temp2b, ab.y[1], ac.x[0]);
485 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
486 d2d_fp_fast_expansion_sum_zeroelim(det_c2, &det_c2_len, det_c1, det_c1_len, temp4, 4);
488 d2d_fp_two_product(temp2a, ab.x[0], ac.y[0]);
489 d2d_fp_two_product(temp2b, ab.y[0], ac.x[0]);
490 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
491 d2d_fp_fast_expansion_sum_zeroelim(det_d, &det_d_len, det_c2, det_c2_len, temp4, 4);
493 return det_d[det_d_len - 1];
496 static void d2d_rect_union(D2D1_RECT_F *l, const D2D1_RECT_F *r)
498 l->left = min(l->left, r->left);
499 l->top = min(l->top, r->top);
500 l->right = max(l->right, r->right);
501 l->bottom = max(l->bottom, r->bottom);
504 static BOOL d2d_rect_check_overlap(const D2D_RECT_F *p, const D2D_RECT_F *q)
506 return p->left < q->right && p->top < q->bottom && p->right > q->left && p->bottom > q->top;
509 static void d2d_rect_get_bezier_bounds(D2D_RECT_F *bounds, const D2D1_POINT_2F *p0,
510 const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2)
512 D2D1_POINT_2F p;
513 float root;
515 bounds->left = p0->x;
516 bounds->top = p0->y;
517 bounds->right = p0->x;
518 bounds->bottom = p0->y;
520 d2d_rect_expand(bounds, p2);
522 /* f(t) = (1 - t)²P₀ + 2(1 - t)tP₁ + t²P₂
523 * f'(t) = 2(1 - t)(P₁ - P₀) + 2t(P₂ - P₁)
524 * = 2(P₂ - 2P₁ + P₀)t + 2(P₁ - P₀)
526 * f'(t) = 0
527 * t = (P₀ - P₁) / (P₂ - 2P₁ + P₀) */
528 root = (p0->x - p1->x) / (p2->x - 2.0f * p1->x + p0->x);
529 if (root > 0.0f && root < 1.0f)
531 d2d_point_calculate_bezier(&p, p0, p1, p2, root);
532 d2d_rect_expand(bounds, &p);
535 root = (p0->y - p1->y) / (p2->y - 2.0f * p1->y + p0->y);
536 if (root > 0.0f && root < 1.0f)
538 d2d_point_calculate_bezier(&p, p0, p1, p2, root);
539 d2d_rect_expand(bounds, &p);
543 static void d2d_rect_get_bezier_segment_bounds(D2D_RECT_F *bounds, const D2D1_POINT_2F *p0,
544 const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2, float start, float end)
546 D2D1_POINT_2F q[3], r[2];
548 d2d_point_lerp(&r[0], p0, p1, start);
549 d2d_point_lerp(&r[1], p1, p2, start);
550 d2d_point_lerp(&q[0], &r[0], &r[1], start);
552 end = (end - start) / (1.0f - start);
553 d2d_point_lerp(&q[1], &q[0], &r[1], end);
554 d2d_point_lerp(&r[0], &r[1], p2, end);
555 d2d_point_lerp(&q[2], &q[1], &r[0], end);
557 d2d_rect_get_bezier_bounds(bounds, &q[0], &q[1], &q[2]);
560 static BOOL d2d_figure_insert_vertex(struct d2d_figure *figure, size_t idx, D2D1_POINT_2F vertex)
562 if (!d2d_array_reserve((void **)&figure->vertices, &figure->vertices_size,
563 figure->vertex_count + 1, sizeof(*figure->vertices)))
565 ERR("Failed to grow vertices array.\n");
566 return FALSE;
569 if (!d2d_array_reserve((void **)&figure->vertex_types, &figure->vertex_types_size,
570 figure->vertex_count + 1, sizeof(*figure->vertex_types)))
572 ERR("Failed to grow vertex types array.\n");
573 return FALSE;
576 memmove(&figure->vertices[idx + 1], &figure->vertices[idx],
577 (figure->vertex_count - idx) * sizeof(*figure->vertices));
578 memmove(&figure->vertex_types[idx + 1], &figure->vertex_types[idx],
579 (figure->vertex_count - idx) * sizeof(*figure->vertex_types));
580 figure->vertices[idx] = vertex;
581 figure->vertex_types[idx] = D2D_VERTEX_TYPE_NONE;
582 d2d_rect_expand(&figure->bounds, &vertex);
583 ++figure->vertex_count;
584 return TRUE;
587 static BOOL d2d_figure_add_vertex(struct d2d_figure *figure, D2D1_POINT_2F vertex)
589 size_t last = figure->vertex_count - 1;
591 if (figure->vertex_count && figure->vertex_types[last] == D2D_VERTEX_TYPE_LINE
592 && !memcmp(&figure->vertices[last], &vertex, sizeof(vertex)))
593 return TRUE;
595 if (!d2d_array_reserve((void **)&figure->vertices, &figure->vertices_size,
596 figure->vertex_count + 1, sizeof(*figure->vertices)))
598 ERR("Failed to grow vertices array.\n");
599 return FALSE;
602 if (!d2d_array_reserve((void **)&figure->vertex_types, &figure->vertex_types_size,
603 figure->vertex_count + 1, sizeof(*figure->vertex_types)))
605 ERR("Failed to grow vertex types array.\n");
606 return FALSE;
609 figure->vertices[figure->vertex_count] = vertex;
610 figure->vertex_types[figure->vertex_count] = D2D_VERTEX_TYPE_NONE;
611 d2d_rect_expand(&figure->bounds, &vertex);
612 ++figure->vertex_count;
613 return TRUE;
616 static BOOL d2d_figure_insert_bezier_control(struct d2d_figure *figure, size_t idx, const D2D1_POINT_2F *p)
618 if (!d2d_array_reserve((void **)&figure->bezier_controls, &figure->bezier_controls_size,
619 figure->bezier_control_count + 1, sizeof(*figure->bezier_controls)))
621 ERR("Failed to grow bezier controls array.\n");
622 return FALSE;
625 memmove(&figure->bezier_controls[idx + 1], &figure->bezier_controls[idx],
626 (figure->bezier_control_count - idx) * sizeof(*figure->bezier_controls));
627 figure->bezier_controls[idx] = *p;
628 ++figure->bezier_control_count;
630 return TRUE;
633 static BOOL d2d_figure_add_bezier_control(struct d2d_figure *figure, const D2D1_POINT_2F *p)
635 if (!d2d_array_reserve((void **)&figure->bezier_controls, &figure->bezier_controls_size,
636 figure->bezier_control_count + 1, sizeof(*figure->bezier_controls)))
638 ERR("Failed to grow bezier controls array.\n");
639 return FALSE;
642 figure->bezier_controls[figure->bezier_control_count++] = *p;
644 return TRUE;
647 static void d2d_cdt_edge_rot(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
649 dst->idx = src->idx;
650 dst->r = (src->r + D2D_EDGE_NEXT_ROT) & 3;
653 static void d2d_cdt_edge_sym(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
655 dst->idx = src->idx;
656 dst->r = (src->r + D2D_EDGE_NEXT_SYM) & 3;
659 static void d2d_cdt_edge_tor(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
661 dst->idx = src->idx;
662 dst->r = (src->r + D2D_EDGE_NEXT_TOR) & 3;
665 static void d2d_cdt_edge_next_left(const struct d2d_cdt *cdt,
666 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
668 d2d_cdt_edge_rot(dst, &cdt->edges[src->idx].next[(src->r + D2D_EDGE_NEXT_TOR) & 3]);
671 static void d2d_cdt_edge_next_origin(const struct d2d_cdt *cdt,
672 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
674 *dst = cdt->edges[src->idx].next[src->r];
677 static void d2d_cdt_edge_prev_origin(const struct d2d_cdt *cdt,
678 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
680 d2d_cdt_edge_rot(dst, &cdt->edges[src->idx].next[(src->r + D2D_EDGE_NEXT_ROT) & 3]);
683 static size_t d2d_cdt_edge_origin(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
685 return cdt->edges[e->idx].vertex[e->r >> 1];
688 static size_t d2d_cdt_edge_destination(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
690 return cdt->edges[e->idx].vertex[!(e->r >> 1)];
693 static void d2d_cdt_edge_set_origin(const struct d2d_cdt *cdt,
694 const struct d2d_cdt_edge_ref *e, size_t vertex)
696 cdt->edges[e->idx].vertex[e->r >> 1] = vertex;
699 static void d2d_cdt_edge_set_destination(const struct d2d_cdt *cdt,
700 const struct d2d_cdt_edge_ref *e, size_t vertex)
702 cdt->edges[e->idx].vertex[!(e->r >> 1)] = vertex;
705 static float d2d_cdt_ccw(const struct d2d_cdt *cdt, size_t a, size_t b, size_t c)
707 return d2d_point_ccw(&cdt->vertices[a], &cdt->vertices[b], &cdt->vertices[c]);
710 static BOOL d2d_cdt_rightof(const struct d2d_cdt *cdt, size_t p, const struct d2d_cdt_edge_ref *e)
712 return d2d_cdt_ccw(cdt, p, d2d_cdt_edge_destination(cdt, e), d2d_cdt_edge_origin(cdt, e)) > 0.0f;
715 static BOOL d2d_cdt_leftof(const struct d2d_cdt *cdt, size_t p, const struct d2d_cdt_edge_ref *e)
717 return d2d_cdt_ccw(cdt, p, d2d_cdt_edge_origin(cdt, e), d2d_cdt_edge_destination(cdt, e)) > 0.0f;
720 /* |ax ay|
721 * |bx by| */
722 static void d2d_fp_four_det2x2(float *out, float ax, float ay, float bx, float by)
724 float axby[2], aybx[2];
726 d2d_fp_two_product(axby, ax, by);
727 d2d_fp_two_product(aybx, ay, bx);
728 d2d_fp_two_two_diff(out, axby, aybx);
731 /* (a->x² + a->y²) * det2x2 */
732 static void d2d_fp_sub_det3x3(float *out, size_t *out_len, const struct d2d_fp_two_vec2 *a, const float *det2x2)
734 size_t axd_len, ayd_len, axxd_len, ayyd_len;
735 float axd[8], ayd[8], axxd[16], ayyd[16];
737 d2d_fp_scale_expansion_zeroelim(axd, &axd_len, det2x2, 4, a->x[1]);
738 d2d_fp_scale_expansion_zeroelim(axxd, &axxd_len, axd, axd_len, a->x[1]);
739 d2d_fp_scale_expansion_zeroelim(ayd, &ayd_len, det2x2, 4, a->y[1]);
740 d2d_fp_scale_expansion_zeroelim(ayyd, &ayyd_len, ayd, ayd_len, a->y[1]);
741 d2d_fp_fast_expansion_sum_zeroelim(out, out_len, axxd, axxd_len, ayyd, ayyd_len);
744 /* det_abt = det_ab * c[0]
745 * fin += c[0] * (az * b - bz * a + c[1] * det_ab * 2.0f) */
746 static void d2d_cdt_incircle_refine1(struct d2d_fp_fin *fin, float *det_abt, size_t *det_abt_len,
747 const float *det_ab, float a, const float *az, float b, const float *bz, const float *c)
749 size_t temp48_len, temp32_len, temp16a_len, temp16b_len, temp16c_len, temp8_len;
750 float temp48[48], temp32[32], temp16a[16], temp16b[16], temp16c[16], temp8[8];
751 float *swap;
753 d2d_fp_scale_expansion_zeroelim(det_abt, det_abt_len, det_ab, 4, c[0]);
754 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, det_abt, *det_abt_len, 2.0f * c[1]);
755 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, az, 4, c[0]);
756 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, temp8, temp8_len, b);
757 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, bz, 4, c[0]);
758 d2d_fp_scale_expansion_zeroelim(temp16c, &temp16c_len, temp8, temp8_len, -a);
759 d2d_fp_fast_expansion_sum_zeroelim(temp32, &temp32_len, temp16a, temp16a_len, temp16b, temp16b_len);
760 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16c, temp16c_len, temp32, temp32_len);
761 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
762 swap = fin->now; fin->now = fin->other; fin->other = swap;
765 static void d2d_cdt_incircle_refine2(struct d2d_fp_fin *fin, const struct d2d_fp_two_vec2 *a,
766 const struct d2d_fp_two_vec2 *b, const float *bz, const struct d2d_fp_two_vec2 *c, const float *cz,
767 const float *axt_det_bc, size_t axt_det_bc_len, const float *ayt_det_bc, size_t ayt_det_bc_len)
769 size_t temp64_len, temp48_len, temp32a_len, temp32b_len, temp16a_len, temp16b_len, temp8_len;
770 float temp64[64], temp48[48], temp32a[32], temp32b[32], temp16a[16], temp16b[16], temp8[8];
771 float bct[8], bctt[4], temp4a[4], temp4b[4], temp2a[2], temp2b[2];
772 size_t bct_len, bctt_len;
773 float *swap;
775 /* 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]) */
776 /* bctt = b->x[0] * c->y[0] + c->x[0] * b->y[0] */
777 if (b->x[0] != 0.0f || b->y[0] != 0.0f || c->x[0] != 0.0f || c->y[0] != 0.0f)
779 d2d_fp_two_product(temp2a, b->x[0], c->y[1]);
780 d2d_fp_two_product(temp2b, b->x[1], c->y[0]);
781 d2d_fp_two_two_sum(temp4a, temp2a, temp2b);
782 d2d_fp_two_product(temp2a, c->x[0], -b->y[1]);
783 d2d_fp_two_product(temp2b, c->x[1], -b->y[0]);
784 d2d_fp_two_two_sum(temp4b, temp2a, temp2b);
785 d2d_fp_fast_expansion_sum_zeroelim(bct, &bct_len, temp4a, 4, temp4b, 4);
787 d2d_fp_two_product(temp2a, b->x[0], c->y[0]);
788 d2d_fp_two_product(temp2b, c->x[0], b->y[0]);
789 d2d_fp_two_two_diff(bctt, temp2a, temp2b);
790 bctt_len = 4;
792 else
794 bct[0] = 0.0f;
795 bct_len = 1;
796 bctt[0] = 0.0f;
797 bctt_len = 1;
800 if (a->x[0] != 0.0f)
802 size_t axt_bct_len, axt_bctt_len;
803 float axt_bct[16], axt_bctt[8];
805 /* fin += a->x[0] * (axt_det_bc + bct * 2.0f * a->x[1]) */
806 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, axt_det_bc, axt_det_bc_len, a->x[0]);
807 d2d_fp_scale_expansion_zeroelim(axt_bct, &axt_bct_len, bct, bct_len, a->x[0]);
808 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, axt_bct, axt_bct_len, 2.0f * a->x[1]);
809 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16a, temp16a_len, temp32a, temp32a_len);
810 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
811 swap = fin->now; fin->now = fin->other; fin->other = swap;
813 if (b->y[0] != 0.0f)
815 /* fin += a->x[0] * cz * b->y[0] */
816 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, cz, 4, a->x[0]);
817 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, temp8, temp8_len, b->y[0]);
818 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp16a, temp16a_len);
819 swap = fin->now; fin->now = fin->other; fin->other = swap;
822 if (c->y[0] != 0.0f)
824 /* fin -= a->x[0] * bz * c->y[0] */
825 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, bz, 4, -a->x[0]);
826 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, temp8, temp8_len, c->y[0]);
827 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp16a, temp16a_len);
828 swap = fin->now; fin->now = fin->other; fin->other = swap;
831 /* fin += a->x[0] * (bct * a->x[0] + bctt * (2.0f * a->x[1] + a->x[0])) */
832 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, axt_bct, axt_bct_len, a->x[0]);
833 d2d_fp_scale_expansion_zeroelim(axt_bctt, &axt_bctt_len, bctt, bctt_len, a->x[0]);
834 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, axt_bctt, axt_bctt_len, 2.0f * a->x[1]);
835 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, axt_bctt, axt_bctt_len, a->x[0]);
836 d2d_fp_fast_expansion_sum_zeroelim(temp32b, &temp32b_len, temp16a, temp16a_len, temp16b, temp16b_len);
837 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, temp32a, temp32a_len, temp32b, temp32b_len);
838 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp64, temp64_len);
839 swap = fin->now; fin->now = fin->other; fin->other = swap;
842 if (a->y[0] != 0.0f)
844 size_t ayt_bct_len, ayt_bctt_len;
845 float ayt_bct[16], ayt_bctt[8];
847 /* fin += a->y[0] * (ayt_det_bc + bct * 2.0f * a->y[1]) */
848 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, ayt_det_bc, ayt_det_bc_len, a->y[0]);
849 d2d_fp_scale_expansion_zeroelim(ayt_bct, &ayt_bct_len, bct, bct_len, a->y[0]);
850 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, ayt_bct, ayt_bct_len, 2.0f * a->y[1]);
851 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16a, temp16a_len, temp32a, temp32a_len);
852 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
853 swap = fin->now; fin->now = fin->other; fin->other = swap;
855 /* fin += a->y[0] * (bct * a->y[0] + bctt * (2.0f * a->y[1] + a->y[0])) */
856 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, ayt_bct, ayt_bct_len, a->y[0]);
857 d2d_fp_scale_expansion_zeroelim(ayt_bctt, &ayt_bctt_len, bctt, bctt_len, a->y[0]);
858 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, ayt_bctt, ayt_bctt_len, 2.0f * a->y[1]);
859 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, ayt_bctt, ayt_bctt_len, a->y[0]);
860 d2d_fp_fast_expansion_sum_zeroelim(temp32b, &temp32b_len, temp16a, temp16a_len, temp16b, temp16b_len);
861 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, temp32a, temp32a_len, temp32b, temp32b_len);
862 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp64, temp64_len);
863 swap = fin->now; fin->now = fin->other; fin->other = swap;
867 /* Determine if point D is inside or outside the circle defined by points A,
868 * B, C. As explained in the paper by Guibas and Stolfi, this is equivalent to
869 * calculating the signed volume of the tetrahedron defined by projecting the
870 * points onto the paraboloid of revolution x = x² + y²,
871 * λ:(x, y) → (x, y, x² + y²). I.e., D is inside the cirlce if
873 * |λ(A) 1|
874 * |λ(B) 1| > 0
875 * |λ(C) 1|
876 * |λ(D) 1|
878 * After translating D to the origin, that becomes:
880 * |λ(A-D)|
881 * |λ(B-D)| > 0
882 * |λ(C-D)|
884 * This implementation is based on the paper "Adaptive Precision
885 * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
886 * associated (Public Domain) code by Jonathan Richard Shewchuk. */
887 static BOOL d2d_cdt_incircle(const struct d2d_cdt *cdt, size_t a, size_t b, size_t c, size_t d)
889 static const float err_bound_result = (3.0f + 8.0f * D2D_FP_EPS) * D2D_FP_EPS;
890 static const float err_bound_a = (10.0f + 96.0f * D2D_FP_EPS) * D2D_FP_EPS;
891 static const float err_bound_b = (4.0f + 48.0f * D2D_FP_EPS) * D2D_FP_EPS;
892 static const float err_bound_c = (44.0f + 576.0f * D2D_FP_EPS) * D2D_FP_EPS * D2D_FP_EPS;
894 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;
895 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];
896 float fin1[1152], fin2[1152], temp64[64], sub_det_a[32], sub_det_b[32], sub_det_c[32];
897 float det_bc[4], det_ca[4], det_ab[4], daz[4], dbz[4], dcz[4], temp2a[2], temp2b[2];
898 size_t temp64_len, sub_det_a_len, sub_det_b_len, sub_det_c_len;
899 float dbxdcy, dbydcx, dcxday, dcydax, daxdby, daydbx;
900 const D2D1_POINT_2F *p = cdt->vertices;
901 struct d2d_fp_two_vec2 da, db, dc;
902 float permanent, err_bound, det;
903 struct d2d_fp_fin fin;
905 da.x[1] = p[a].x - p[d].x;
906 da.y[1] = p[a].y - p[d].y;
907 db.x[1] = p[b].x - p[d].x;
908 db.y[1] = p[b].y - p[d].y;
909 dc.x[1] = p[c].x - p[d].x;
910 dc.y[1] = p[c].y - p[d].y;
912 daz[3] = da.x[1] * da.x[1] + da.y[1] * da.y[1];
913 dbxdcy = db.x[1] * dc.y[1];
914 dbydcx = db.y[1] * dc.x[1];
916 dbz[3] = db.x[1] * db.x[1] + db.y[1] * db.y[1];
917 dcxday = dc.x[1] * da.y[1];
918 dcydax = dc.y[1] * da.x[1];
920 dcz[3] = dc.x[1] * dc.x[1] + dc.y[1] * dc.y[1];
921 daxdby = da.x[1] * db.y[1];
922 daydbx = da.y[1] * db.x[1];
924 det = daz[3] * (dbxdcy - dbydcx) + dbz[3] * (dcxday - dcydax) + dcz[3] * (daxdby - daydbx);
925 permanent = daz[3] * (fabsf(dbxdcy) + fabsf(dbydcx))
926 + dbz[3] * (fabsf(dcxday) + fabsf(dcydax))
927 + dcz[3] * (fabsf(daxdby) + fabsf(daydbx));
928 err_bound = err_bound_a * permanent;
929 if (det > err_bound || -det > err_bound)
930 return det > 0.0f;
932 fin.now = fin1;
933 fin.other = fin2;
935 d2d_fp_four_det2x2(det_bc, db.x[1], db.y[1], dc.x[1], dc.y[1]);
936 d2d_fp_sub_det3x3(sub_det_a, &sub_det_a_len, &da, det_bc);
938 d2d_fp_four_det2x2(det_ca, dc.x[1], dc.y[1], da.x[1], da.y[1]);
939 d2d_fp_sub_det3x3(sub_det_b, &sub_det_b_len, &db, det_ca);
941 d2d_fp_four_det2x2(det_ab, da.x[1], da.y[1], db.x[1], db.y[1]);
942 d2d_fp_sub_det3x3(sub_det_c, &sub_det_c_len, &dc, det_ab);
944 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, sub_det_a, sub_det_a_len, sub_det_b, sub_det_b_len);
945 d2d_fp_fast_expansion_sum_zeroelim(fin.now, &fin.length, temp64, temp64_len, sub_det_c, sub_det_c_len);
946 det = d2d_fp_estimate(fin.now, fin.length);
947 err_bound = err_bound_b * permanent;
948 if (det >= err_bound || -det >= err_bound)
949 return det > 0.0f;
951 d2d_fp_two_diff_tail(&da.x[0], p[a].x, p[d].x, da.x[1]);
952 d2d_fp_two_diff_tail(&da.y[0], p[a].y, p[d].y, da.y[1]);
953 d2d_fp_two_diff_tail(&db.x[0], p[b].x, p[d].x, db.x[1]);
954 d2d_fp_two_diff_tail(&db.y[0], p[b].y, p[d].y, db.y[1]);
955 d2d_fp_two_diff_tail(&dc.x[0], p[c].x, p[d].x, dc.x[1]);
956 d2d_fp_two_diff_tail(&dc.y[0], p[c].y, p[d].y, dc.y[1]);
957 if (da.x[0] == 0.0f && db.x[0] == 0.0f && dc.x[0] == 0.0f
958 && da.y[0] == 0.0f && db.y[0] == 0.0f && dc.y[0] == 0.0f)
959 return det > 0.0f;
961 err_bound = err_bound_c * permanent + err_bound_result * fabsf(det);
962 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]))
963 + 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]))
964 + (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]))
965 + 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]))
966 + (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]))
967 + 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]));
968 if (det >= err_bound || -det >= err_bound)
969 return det > 0.0f;
971 if (db.x[0] != 0.0f || db.y[0] != 0.0f || dc.x[0] != 0.0f || dc.y[0] != 0.0f)
973 d2d_fp_square(temp2a, da.x[1]);
974 d2d_fp_square(temp2b, da.y[1]);
975 d2d_fp_two_two_sum(daz, temp2a, temp2b);
977 if (dc.x[0] != 0.0f || dc.y[0] != 0.0f || da.x[0] != 0.0f || da.y[0] != 0.0f)
979 d2d_fp_square(temp2a, db.x[1]);
980 d2d_fp_square(temp2b, db.y[1]);
981 d2d_fp_two_two_sum(dbz, temp2a, temp2b);
983 if (da.x[0] != 0.0f || da.y[0] != 0.0f || db.x[0] != 0.0f || db.y[0] != 0.0f)
985 d2d_fp_square(temp2a, dc.x[1]);
986 d2d_fp_square(temp2b, dc.y[1]);
987 d2d_fp_two_two_sum(dcz, temp2a, temp2b);
990 if (da.x[0] != 0.0f)
991 d2d_cdt_incircle_refine1(&fin, axt_det_bc, &axt_det_bc_len, det_bc, dc.y[1], dcz, db.y[1], dbz, da.x);
992 if (da.y[0] != 0.0f)
993 d2d_cdt_incircle_refine1(&fin, ayt_det_bc, &ayt_det_bc_len, det_bc, db.x[1], dbz, dc.x[1], dcz, da.y);
994 if (db.x[0] != 0.0f)
995 d2d_cdt_incircle_refine1(&fin, bxt_det_ca, &bxt_det_ca_len, det_ca, da.y[1], daz, dc.y[1], dcz, db.x);
996 if (db.y[0] != 0.0f)
997 d2d_cdt_incircle_refine1(&fin, byt_det_ca, &byt_det_ca_len, det_ca, dc.x[1], dcz, da.x[1], daz, db.y);
998 if (dc.x[0] != 0.0f)
999 d2d_cdt_incircle_refine1(&fin, cxt_det_ab, &cxt_det_ab_len, det_ab, db.y[1], dbz, da.y[1], daz, dc.x);
1000 if (dc.y[0] != 0.0f)
1001 d2d_cdt_incircle_refine1(&fin, cyt_det_ab, &cyt_det_ab_len, det_ab, da.x[1], daz, db.x[1], dbz, dc.y);
1003 if (da.x[0] != 0.0f || da.y[0] != 0.0f)
1004 d2d_cdt_incircle_refine2(&fin, &da, &db, dbz, &dc, dcz,
1005 axt_det_bc, axt_det_bc_len, ayt_det_bc, ayt_det_bc_len);
1006 if (db.x[0] != 0.0f || db.y[0] != 0.0f)
1007 d2d_cdt_incircle_refine2(&fin, &db, &dc, dcz, &da, daz,
1008 bxt_det_ca, bxt_det_ca_len, byt_det_ca, byt_det_ca_len);
1009 if (dc.x[0] != 0.0f || dc.y[0] != 0.0f)
1010 d2d_cdt_incircle_refine2(&fin, &dc, &da, daz, &db, dbz,
1011 cxt_det_ab, cxt_det_ab_len, cyt_det_ab, cyt_det_ab_len);
1013 return fin.now[fin.length - 1] > 0.0f;
1016 static void d2d_cdt_splice(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *a,
1017 const struct d2d_cdt_edge_ref *b)
1019 struct d2d_cdt_edge_ref ta, tb, alpha, beta;
1021 ta = cdt->edges[a->idx].next[a->r];
1022 tb = cdt->edges[b->idx].next[b->r];
1023 cdt->edges[a->idx].next[a->r] = tb;
1024 cdt->edges[b->idx].next[b->r] = ta;
1026 d2d_cdt_edge_rot(&alpha, &ta);
1027 d2d_cdt_edge_rot(&beta, &tb);
1029 ta = cdt->edges[alpha.idx].next[alpha.r];
1030 tb = cdt->edges[beta.idx].next[beta.r];
1031 cdt->edges[alpha.idx].next[alpha.r] = tb;
1032 cdt->edges[beta.idx].next[beta.r] = ta;
1035 static BOOL d2d_cdt_create_edge(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *e)
1037 struct d2d_cdt_edge *edge;
1039 if (cdt->free_edge != ~0u)
1041 e->idx = cdt->free_edge;
1042 cdt->free_edge = cdt->edges[e->idx].next[D2D_EDGE_NEXT_ORIGIN].idx;
1044 else
1046 if (!d2d_array_reserve((void **)&cdt->edges, &cdt->edges_size, cdt->edge_count + 1, sizeof(*cdt->edges)))
1048 ERR("Failed to grow edges array.\n");
1049 return FALSE;
1051 e->idx = cdt->edge_count++;
1053 e->r = 0;
1055 edge = &cdt->edges[e->idx];
1056 edge->next[D2D_EDGE_NEXT_ORIGIN] = *e;
1057 d2d_cdt_edge_tor(&edge->next[D2D_EDGE_NEXT_ROT], e);
1058 d2d_cdt_edge_sym(&edge->next[D2D_EDGE_NEXT_SYM], e);
1059 d2d_cdt_edge_rot(&edge->next[D2D_EDGE_NEXT_TOR], e);
1060 edge->flags = 0;
1062 return TRUE;
1065 static void d2d_cdt_destroy_edge(struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
1067 struct d2d_cdt_edge_ref next, sym, prev;
1069 d2d_cdt_edge_next_origin(cdt, &next, e);
1070 if (next.idx != e->idx || next.r != e->r)
1072 d2d_cdt_edge_prev_origin(cdt, &prev, e);
1073 d2d_cdt_splice(cdt, e, &prev);
1076 d2d_cdt_edge_sym(&sym, e);
1078 d2d_cdt_edge_next_origin(cdt, &next, &sym);
1079 if (next.idx != sym.idx || next.r != sym.r)
1081 d2d_cdt_edge_prev_origin(cdt, &prev, &sym);
1082 d2d_cdt_splice(cdt, &sym, &prev);
1085 cdt->edges[e->idx].flags |= D2D_CDT_EDGE_FLAG_FREED;
1086 cdt->edges[e->idx].next[D2D_EDGE_NEXT_ORIGIN].idx = cdt->free_edge;
1087 cdt->free_edge = e->idx;
1090 static BOOL d2d_cdt_connect(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *e,
1091 const struct d2d_cdt_edge_ref *a, const struct d2d_cdt_edge_ref *b)
1093 struct d2d_cdt_edge_ref tmp;
1095 if (!d2d_cdt_create_edge(cdt, e))
1096 return FALSE;
1097 d2d_cdt_edge_set_origin(cdt, e, d2d_cdt_edge_destination(cdt, a));
1098 d2d_cdt_edge_set_destination(cdt, e, d2d_cdt_edge_origin(cdt, b));
1099 d2d_cdt_edge_next_left(cdt, &tmp, a);
1100 d2d_cdt_splice(cdt, e, &tmp);
1101 d2d_cdt_edge_sym(&tmp, e);
1102 d2d_cdt_splice(cdt, &tmp, b);
1104 return TRUE;
1107 static BOOL d2d_cdt_merge(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *left_outer,
1108 struct d2d_cdt_edge_ref *left_inner, struct d2d_cdt_edge_ref *right_inner,
1109 struct d2d_cdt_edge_ref *right_outer)
1111 struct d2d_cdt_edge_ref base_edge, tmp;
1113 /* Create the base edge between both parts. */
1114 for (;;)
1116 if (d2d_cdt_leftof(cdt, d2d_cdt_edge_origin(cdt, right_inner), left_inner))
1118 d2d_cdt_edge_next_left(cdt, left_inner, left_inner);
1120 else if (d2d_cdt_rightof(cdt, d2d_cdt_edge_origin(cdt, left_inner), right_inner))
1122 d2d_cdt_edge_sym(&tmp, right_inner);
1123 d2d_cdt_edge_next_origin(cdt, right_inner, &tmp);
1125 else
1127 break;
1131 d2d_cdt_edge_sym(&tmp, right_inner);
1132 if (!d2d_cdt_connect(cdt, &base_edge, &tmp, left_inner))
1133 return FALSE;
1134 if (d2d_cdt_edge_origin(cdt, left_inner) == d2d_cdt_edge_origin(cdt, left_outer))
1135 d2d_cdt_edge_sym(left_outer, &base_edge);
1136 if (d2d_cdt_edge_origin(cdt, right_inner) == d2d_cdt_edge_origin(cdt, right_outer))
1137 *right_outer = base_edge;
1139 for (;;)
1141 struct d2d_cdt_edge_ref left_candidate, right_candidate, sym_base_edge;
1142 BOOL left_valid, right_valid;
1144 /* Find the left candidate. */
1145 d2d_cdt_edge_sym(&sym_base_edge, &base_edge);
1146 d2d_cdt_edge_next_origin(cdt, &left_candidate, &sym_base_edge);
1147 if ((left_valid = d2d_cdt_leftof(cdt, d2d_cdt_edge_destination(cdt, &left_candidate), &sym_base_edge)))
1149 d2d_cdt_edge_next_origin(cdt, &tmp, &left_candidate);
1150 while (d2d_cdt_edge_destination(cdt, &tmp) != d2d_cdt_edge_destination(cdt, &sym_base_edge)
1151 && d2d_cdt_incircle(cdt,
1152 d2d_cdt_edge_origin(cdt, &sym_base_edge), d2d_cdt_edge_destination(cdt, &sym_base_edge),
1153 d2d_cdt_edge_destination(cdt, &left_candidate), d2d_cdt_edge_destination(cdt, &tmp)))
1155 d2d_cdt_destroy_edge(cdt, &left_candidate);
1156 left_candidate = tmp;
1157 d2d_cdt_edge_next_origin(cdt, &tmp, &left_candidate);
1160 d2d_cdt_edge_sym(&left_candidate, &left_candidate);
1162 /* Find the right candidate. */
1163 d2d_cdt_edge_prev_origin(cdt, &right_candidate, &base_edge);
1164 if ((right_valid = d2d_cdt_rightof(cdt, d2d_cdt_edge_destination(cdt, &right_candidate), &base_edge)))
1166 d2d_cdt_edge_prev_origin(cdt, &tmp, &right_candidate);
1167 while (d2d_cdt_edge_destination(cdt, &tmp) != d2d_cdt_edge_destination(cdt, &base_edge)
1168 && d2d_cdt_incircle(cdt,
1169 d2d_cdt_edge_origin(cdt, &sym_base_edge), d2d_cdt_edge_destination(cdt, &sym_base_edge),
1170 d2d_cdt_edge_destination(cdt, &right_candidate), d2d_cdt_edge_destination(cdt, &tmp)))
1172 d2d_cdt_destroy_edge(cdt, &right_candidate);
1173 right_candidate = tmp;
1174 d2d_cdt_edge_prev_origin(cdt, &tmp, &right_candidate);
1178 if (!left_valid && !right_valid)
1179 break;
1181 /* Connect the appropriate candidate with the base edge. */
1182 if (!left_valid || (right_valid && d2d_cdt_incircle(cdt,
1183 d2d_cdt_edge_origin(cdt, &left_candidate), d2d_cdt_edge_destination(cdt, &left_candidate),
1184 d2d_cdt_edge_origin(cdt, &right_candidate), d2d_cdt_edge_destination(cdt, &right_candidate))))
1186 if (!d2d_cdt_connect(cdt, &base_edge, &right_candidate, &sym_base_edge))
1187 return FALSE;
1189 else
1191 if (!d2d_cdt_connect(cdt, &base_edge, &sym_base_edge, &left_candidate))
1192 return FALSE;
1196 return TRUE;
1199 /* Create a Delaunay triangulation from a set of vertices. This is an
1200 * implementation of the divide-and-conquer algorithm described by Guibas and
1201 * Stolfi. Should be called with at least two vertices. */
1202 static BOOL d2d_cdt_triangulate(struct d2d_cdt *cdt, size_t start_vertex, size_t vertex_count,
1203 struct d2d_cdt_edge_ref *left_edge, struct d2d_cdt_edge_ref *right_edge)
1205 struct d2d_cdt_edge_ref left_inner, left_outer, right_inner, right_outer, tmp;
1206 size_t cut;
1208 /* Only two vertices, create a single edge. */
1209 if (vertex_count == 2)
1211 struct d2d_cdt_edge_ref a;
1213 if (!d2d_cdt_create_edge(cdt, &a))
1214 return FALSE;
1215 d2d_cdt_edge_set_origin(cdt, &a, start_vertex);
1216 d2d_cdt_edge_set_destination(cdt, &a, start_vertex + 1);
1218 *left_edge = a;
1219 d2d_cdt_edge_sym(right_edge, &a);
1221 return TRUE;
1224 /* Three vertices, create a triangle. */
1225 if (vertex_count == 3)
1227 struct d2d_cdt_edge_ref a, b, c;
1228 float det;
1230 if (!d2d_cdt_create_edge(cdt, &a))
1231 return FALSE;
1232 if (!d2d_cdt_create_edge(cdt, &b))
1233 return FALSE;
1234 d2d_cdt_edge_sym(&tmp, &a);
1235 d2d_cdt_splice(cdt, &tmp, &b);
1237 d2d_cdt_edge_set_origin(cdt, &a, start_vertex);
1238 d2d_cdt_edge_set_destination(cdt, &a, start_vertex + 1);
1239 d2d_cdt_edge_set_origin(cdt, &b, start_vertex + 1);
1240 d2d_cdt_edge_set_destination(cdt, &b, start_vertex + 2);
1242 det = d2d_cdt_ccw(cdt, start_vertex, start_vertex + 1, start_vertex + 2);
1243 if (det != 0.0f && !d2d_cdt_connect(cdt, &c, &b, &a))
1244 return FALSE;
1246 if (det < 0.0f)
1248 d2d_cdt_edge_sym(left_edge, &c);
1249 *right_edge = c;
1251 else
1253 *left_edge = a;
1254 d2d_cdt_edge_sym(right_edge, &b);
1257 return TRUE;
1260 /* More than tree vertices, divide. */
1261 cut = vertex_count / 2;
1262 if (!d2d_cdt_triangulate(cdt, start_vertex, cut, &left_outer, &left_inner))
1263 return FALSE;
1264 if (!d2d_cdt_triangulate(cdt, start_vertex + cut, vertex_count - cut, &right_inner, &right_outer))
1265 return FALSE;
1266 /* Merge the left and right parts. */
1267 if (!d2d_cdt_merge(cdt, &left_outer, &left_inner, &right_inner, &right_outer))
1268 return FALSE;
1270 *left_edge = left_outer;
1271 *right_edge = right_outer;
1272 return TRUE;
1275 static int __cdecl d2d_cdt_compare_vertices(const void *a, const void *b)
1277 const D2D1_POINT_2F *p0 = a;
1278 const D2D1_POINT_2F *p1 = b;
1279 float diff = p0->x - p1->x;
1281 if (diff == 0.0f)
1282 diff = p0->y - p1->y;
1284 return diff == 0.0f ? 0 : (diff > 0.0f ? 1 : -1);
1287 /* Determine whether a given point is inside the geometry, using the current
1288 * fill mode rule. */
1289 static BOOL d2d_path_geometry_point_inside(const struct d2d_geometry *geometry,
1290 const D2D1_POINT_2F *probe, BOOL triangles_only)
1292 const D2D1_POINT_2F *p0, *p1;
1293 D2D1_POINT_2F v_p, v_probe;
1294 unsigned int score;
1295 size_t i, j, last;
1297 for (i = 0, score = 0; i < geometry->u.path.figure_count; ++i)
1299 const struct d2d_figure *figure = &geometry->u.path.figures[i];
1301 if (probe->x < figure->bounds.left || probe->x > figure->bounds.right
1302 || probe->y < figure->bounds.top || probe->y > figure->bounds.bottom)
1303 continue;
1305 last = figure->vertex_count - 1;
1306 if (!triangles_only)
1308 while (last && figure->vertex_types[last] == D2D_VERTEX_TYPE_NONE)
1309 --last;
1311 p0 = &figure->vertices[last];
1312 for (j = 0; j <= last; ++j)
1314 if (!triangles_only && figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
1315 continue;
1317 p1 = &figure->vertices[j];
1318 d2d_point_subtract(&v_p, p1, p0);
1319 d2d_point_subtract(&v_probe, probe, p0);
1321 if ((probe->y < p0->y) != (probe->y < p1->y) && v_probe.x < v_p.x * (v_probe.y / v_p.y))
1323 if (geometry->u.path.fill_mode == D2D1_FILL_MODE_ALTERNATE || (probe->y < p0->y))
1324 ++score;
1325 else
1326 --score;
1329 p0 = p1;
1333 return geometry->u.path.fill_mode == D2D1_FILL_MODE_ALTERNATE ? score & 1 : score;
1336 static BOOL d2d_path_geometry_add_fill_face(struct d2d_geometry *geometry, const struct d2d_cdt *cdt,
1337 const struct d2d_cdt_edge_ref *base_edge)
1339 struct d2d_cdt_edge_ref tmp;
1340 struct d2d_face *face;
1341 D2D1_POINT_2F probe;
1343 if (cdt->edges[base_edge->idx].flags & D2D_CDT_EDGE_FLAG_VISITED(base_edge->r))
1344 return TRUE;
1346 if (!d2d_array_reserve((void **)&geometry->fill.faces, &geometry->fill.faces_size,
1347 geometry->fill.face_count + 1, sizeof(*geometry->fill.faces)))
1349 ERR("Failed to grow faces array.\n");
1350 return FALSE;
1353 face = &geometry->fill.faces[geometry->fill.face_count];
1355 /* It may seem tempting to use the center of the face as probe origin, but
1356 * multiplying by powers of two works much better for preserving accuracy. */
1358 tmp = *base_edge;
1359 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1360 face->v[0] = d2d_cdt_edge_origin(cdt, &tmp);
1361 probe.x = cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.25f;
1362 probe.y = cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.25f;
1364 d2d_cdt_edge_next_left(cdt, &tmp, &tmp);
1365 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1366 face->v[1] = d2d_cdt_edge_origin(cdt, &tmp);
1367 probe.x += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.25f;
1368 probe.y += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.25f;
1370 d2d_cdt_edge_next_left(cdt, &tmp, &tmp);
1371 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1372 face->v[2] = d2d_cdt_edge_origin(cdt, &tmp);
1373 probe.x += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.50f;
1374 probe.y += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.50f;
1376 if (d2d_cdt_leftof(cdt, face->v[2], base_edge) && d2d_path_geometry_point_inside(geometry, &probe, TRUE))
1377 ++geometry->fill.face_count;
1379 return TRUE;
1382 static BOOL d2d_cdt_generate_faces(const struct d2d_cdt *cdt, struct d2d_geometry *geometry)
1384 struct d2d_cdt_edge_ref base_edge;
1385 size_t i;
1387 for (i = 0; i < cdt->edge_count; ++i)
1389 if (cdt->edges[i].flags & D2D_CDT_EDGE_FLAG_FREED)
1390 continue;
1392 base_edge.idx = i;
1393 base_edge.r = 0;
1394 if (!d2d_path_geometry_add_fill_face(geometry, cdt, &base_edge))
1395 goto fail;
1396 d2d_cdt_edge_sym(&base_edge, &base_edge);
1397 if (!d2d_path_geometry_add_fill_face(geometry, cdt, &base_edge))
1398 goto fail;
1401 return TRUE;
1403 fail:
1404 heap_free(geometry->fill.faces);
1405 geometry->fill.faces = NULL;
1406 geometry->fill.faces_size = 0;
1407 geometry->fill.face_count = 0;
1408 return FALSE;
1411 static BOOL d2d_cdt_fixup(struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *base_edge)
1413 struct d2d_cdt_edge_ref candidate, next, new_base;
1414 unsigned int count = 0;
1416 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1417 if (next.idx == base_edge->idx)
1419 ERR("Degenerate face.\n");
1420 return FALSE;
1423 candidate = next;
1424 while (d2d_cdt_edge_destination(cdt, &next) != d2d_cdt_edge_origin(cdt, base_edge))
1426 if (d2d_cdt_incircle(cdt, d2d_cdt_edge_origin(cdt, base_edge), d2d_cdt_edge_destination(cdt, base_edge),
1427 d2d_cdt_edge_destination(cdt, &candidate), d2d_cdt_edge_destination(cdt, &next)))
1428 candidate = next;
1429 d2d_cdt_edge_next_left(cdt, &next, &next);
1430 ++count;
1433 if (count > 1)
1435 d2d_cdt_edge_next_left(cdt, &next, &candidate);
1436 if (d2d_cdt_edge_destination(cdt, &next) == d2d_cdt_edge_origin(cdt, base_edge))
1437 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1438 else
1439 next = *base_edge;
1440 if (!d2d_cdt_connect(cdt, &new_base, &candidate, &next))
1441 return FALSE;
1442 if (!d2d_cdt_fixup(cdt, &new_base))
1443 return FALSE;
1444 d2d_cdt_edge_sym(&new_base, &new_base);
1445 if (!d2d_cdt_fixup(cdt, &new_base))
1446 return FALSE;
1449 return TRUE;
1452 static void d2d_cdt_cut_edges(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *end_edge,
1453 const struct d2d_cdt_edge_ref *base_edge, size_t start_vertex, size_t end_vertex)
1455 struct d2d_cdt_edge_ref next;
1456 float ccw;
1458 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1459 if (d2d_cdt_edge_destination(cdt, &next) == end_vertex)
1461 *end_edge = next;
1462 return;
1465 ccw = d2d_cdt_ccw(cdt, d2d_cdt_edge_destination(cdt, &next), end_vertex, start_vertex);
1466 if (ccw == 0.0f)
1468 *end_edge = next;
1469 return;
1472 if (ccw > 0.0f)
1473 d2d_cdt_edge_next_left(cdt, &next, &next);
1475 d2d_cdt_edge_sym(&next, &next);
1476 d2d_cdt_cut_edges(cdt, end_edge, &next, start_vertex, end_vertex);
1477 d2d_cdt_destroy_edge(cdt, &next);
1480 static BOOL d2d_cdt_insert_segment(struct d2d_cdt *cdt, struct d2d_geometry *geometry,
1481 const struct d2d_cdt_edge_ref *origin, struct d2d_cdt_edge_ref *edge, size_t end_vertex)
1483 struct d2d_cdt_edge_ref base_edge, current, new_origin, next, target;
1484 size_t current_destination, current_origin;
1486 for (current = *origin;; current = next)
1488 d2d_cdt_edge_next_origin(cdt, &next, &current);
1490 current_destination = d2d_cdt_edge_destination(cdt, &current);
1491 if (current_destination == end_vertex)
1493 d2d_cdt_edge_sym(edge, &current);
1494 return TRUE;
1497 current_origin = d2d_cdt_edge_origin(cdt, &current);
1498 if (d2d_cdt_ccw(cdt, end_vertex, current_origin, current_destination) == 0.0f
1499 && (cdt->vertices[current_destination].x > cdt->vertices[current_origin].x)
1500 == (cdt->vertices[end_vertex].x > cdt->vertices[current_origin].x)
1501 && (cdt->vertices[current_destination].y > cdt->vertices[current_origin].y)
1502 == (cdt->vertices[end_vertex].y > cdt->vertices[current_origin].y))
1504 d2d_cdt_edge_sym(&new_origin, &current);
1505 return d2d_cdt_insert_segment(cdt, geometry, &new_origin, edge, end_vertex);
1508 if (d2d_cdt_rightof(cdt, end_vertex, &next) && d2d_cdt_leftof(cdt, end_vertex, &current))
1510 d2d_cdt_edge_next_left(cdt, &base_edge, &current);
1512 d2d_cdt_edge_sym(&base_edge, &base_edge);
1513 d2d_cdt_cut_edges(cdt, &target, &base_edge, d2d_cdt_edge_origin(cdt, origin), end_vertex);
1514 d2d_cdt_destroy_edge(cdt, &base_edge);
1516 if (!d2d_cdt_connect(cdt, &base_edge, &target, &current))
1517 return FALSE;
1518 *edge = base_edge;
1519 if (!d2d_cdt_fixup(cdt, &base_edge))
1520 return FALSE;
1521 d2d_cdt_edge_sym(&base_edge, &base_edge);
1522 if (!d2d_cdt_fixup(cdt, &base_edge))
1523 return FALSE;
1525 if (d2d_cdt_edge_origin(cdt, edge) == end_vertex)
1526 return TRUE;
1527 new_origin = *edge;
1528 return d2d_cdt_insert_segment(cdt, geometry, &new_origin, edge, end_vertex);
1531 if (next.idx == origin->idx)
1533 ERR("Triangle not found.\n");
1534 return FALSE;
1539 static BOOL d2d_cdt_insert_segments(struct d2d_cdt *cdt, struct d2d_geometry *geometry)
1541 size_t start_vertex, end_vertex, i, j, k;
1542 struct d2d_cdt_edge_ref edge, new_edge;
1543 const struct d2d_figure *figure;
1544 const D2D1_POINT_2F *p;
1545 BOOL found;
1547 for (i = 0; i < geometry->u.path.figure_count; ++i)
1549 figure = &geometry->u.path.figures[i];
1551 if (figure->flags & D2D_FIGURE_FLAG_HOLLOW)
1552 continue;
1554 /* Degenerate figure. */
1555 if (figure->vertex_count < 2)
1556 continue;
1558 p = bsearch(&figure->vertices[figure->vertex_count - 1], cdt->vertices,
1559 geometry->fill.vertex_count, sizeof(*p), d2d_cdt_compare_vertices);
1560 start_vertex = p - cdt->vertices;
1562 for (k = 0, found = FALSE; k < cdt->edge_count; ++k)
1564 if (cdt->edges[k].flags & D2D_CDT_EDGE_FLAG_FREED)
1565 continue;
1567 edge.idx = k;
1568 edge.r = 0;
1570 if (d2d_cdt_edge_origin(cdt, &edge) == start_vertex)
1572 found = TRUE;
1573 break;
1575 d2d_cdt_edge_sym(&edge, &edge);
1576 if (d2d_cdt_edge_origin(cdt, &edge) == start_vertex)
1578 found = TRUE;
1579 break;
1583 if (!found)
1585 ERR("Edge not found.\n");
1586 return FALSE;
1589 for (j = 0; j < figure->vertex_count; start_vertex = end_vertex, ++j)
1591 p = bsearch(&figure->vertices[j], cdt->vertices,
1592 geometry->fill.vertex_count, sizeof(*p), d2d_cdt_compare_vertices);
1593 end_vertex = p - cdt->vertices;
1595 if (start_vertex == end_vertex)
1596 continue;
1598 if (!d2d_cdt_insert_segment(cdt, geometry, &edge, &new_edge, end_vertex))
1599 return FALSE;
1600 edge = new_edge;
1604 return TRUE;
1607 static BOOL d2d_geometry_intersections_add(struct d2d_geometry_intersections *i,
1608 const struct d2d_segment_idx *segment_idx, float t, D2D1_POINT_2F p)
1610 struct d2d_geometry_intersection *intersection;
1612 if (!d2d_array_reserve((void **)&i->intersections, &i->intersections_size,
1613 i->intersection_count + 1, sizeof(*i->intersections)))
1615 ERR("Failed to grow intersections array.\n");
1616 return FALSE;
1619 intersection = &i->intersections[i->intersection_count++];
1620 intersection->figure_idx = segment_idx->figure_idx;
1621 intersection->vertex_idx = segment_idx->vertex_idx;
1622 intersection->control_idx = segment_idx->control_idx;
1623 intersection->t = t;
1624 intersection->p = p;
1626 return TRUE;
1629 static int __cdecl d2d_geometry_intersections_compare(const void *a, const void *b)
1631 const struct d2d_geometry_intersection *i0 = a;
1632 const struct d2d_geometry_intersection *i1 = b;
1634 if (i0->figure_idx != i1->figure_idx)
1635 return i0->figure_idx - i1->figure_idx;
1636 if (i0->vertex_idx != i1->vertex_idx)
1637 return i0->vertex_idx - i1->vertex_idx;
1638 if (i0->t != i1->t)
1639 return i0->t > i1->t ? 1 : -1;
1640 return 0;
1643 static BOOL d2d_geometry_intersect_line_line(struct d2d_geometry *geometry,
1644 struct d2d_geometry_intersections *intersections, const struct d2d_segment_idx *idx_p,
1645 const struct d2d_segment_idx *idx_q)
1647 D2D1_POINT_2F v_p, v_q, v_qp, intersection;
1648 const D2D1_POINT_2F *p[2], *q[2];
1649 const struct d2d_figure *figure;
1650 float s, t, det;
1651 size_t next;
1653 figure = &geometry->u.path.figures[idx_p->figure_idx];
1654 p[0] = &figure->vertices[idx_p->vertex_idx];
1655 next = idx_p->vertex_idx + 1;
1656 if (next == figure->vertex_count)
1657 next = 0;
1658 p[1] = &figure->vertices[next];
1660 figure = &geometry->u.path.figures[idx_q->figure_idx];
1661 q[0] = &figure->vertices[idx_q->vertex_idx];
1662 next = idx_q->vertex_idx + 1;
1663 if (next == figure->vertex_count)
1664 next = 0;
1665 q[1] = &figure->vertices[next];
1667 d2d_point_subtract(&v_p, p[1], p[0]);
1668 d2d_point_subtract(&v_q, q[1], q[0]);
1669 d2d_point_subtract(&v_qp, p[0], q[0]);
1671 det = v_p.x * v_q.y - v_p.y * v_q.x;
1672 if (det == 0.0f)
1673 return TRUE;
1675 s = (v_q.x * v_qp.y - v_q.y * v_qp.x) / det;
1676 t = (v_p.x * v_qp.y - v_p.y * v_qp.x) / det;
1678 if (s < 0.0f || s > 1.0f || t < 0.0f || t > 1.0f)
1679 return TRUE;
1681 intersection.x = p[0]->x + v_p.x * s;
1682 intersection.y = p[0]->y + v_p.y * s;
1684 if (s > 0.0f && s < 1.0f && !d2d_geometry_intersections_add(intersections, idx_p, s, intersection))
1685 return FALSE;
1687 if (t > 0.0f && t < 1.0f && !d2d_geometry_intersections_add(intersections, idx_q, t, intersection))
1688 return FALSE;
1690 return TRUE;
1693 static BOOL d2d_geometry_add_bezier_line_intersections(struct d2d_geometry *geometry,
1694 struct d2d_geometry_intersections *intersections, const struct d2d_segment_idx *idx_p,
1695 const D2D1_POINT_2F **p, const struct d2d_segment_idx *idx_q, const D2D1_POINT_2F **q, float s)
1697 D2D1_POINT_2F intersection;
1698 float t;
1700 d2d_point_calculate_bezier(&intersection, p[0], p[1], p[2], s);
1701 if (fabsf(q[1]->x - q[0]->x) > fabsf(q[1]->y - q[0]->y))
1702 t = (intersection.x - q[0]->x) / (q[1]->x - q[0]->x);
1703 else
1704 t = (intersection.y - q[0]->y) / (q[1]->y - q[0]->y);
1705 if (t < 0.0f || t > 1.0f)
1706 return TRUE;
1708 d2d_point_lerp(&intersection, q[0], q[1], t);
1710 if (s > 0.0f && s < 1.0f && !d2d_geometry_intersections_add(intersections, idx_p, s, intersection))
1711 return FALSE;
1713 if (t > 0.0f && t < 1.0f && !d2d_geometry_intersections_add(intersections, idx_q, t, intersection))
1714 return FALSE;
1716 return TRUE;
1719 static BOOL d2d_geometry_intersect_bezier_line(struct d2d_geometry *geometry,
1720 struct d2d_geometry_intersections *intersections,
1721 const struct d2d_segment_idx *idx_p, const struct d2d_segment_idx *idx_q)
1723 const D2D1_POINT_2F *p[3], *q[2];
1724 const struct d2d_figure *figure;
1725 float y[3], root, theta, d, e;
1726 size_t next;
1728 figure = &geometry->u.path.figures[idx_p->figure_idx];
1729 p[0] = &figure->vertices[idx_p->vertex_idx];
1730 p[1] = &figure->bezier_controls[idx_p->control_idx];
1731 next = idx_p->vertex_idx + 1;
1732 if (next == figure->vertex_count)
1733 next = 0;
1734 p[2] = &figure->vertices[next];
1736 figure = &geometry->u.path.figures[idx_q->figure_idx];
1737 q[0] = &figure->vertices[idx_q->vertex_idx];
1738 next = idx_q->vertex_idx + 1;
1739 if (next == figure->vertex_count)
1740 next = 0;
1741 q[1] = &figure->vertices[next];
1743 /* Align the line with x-axis. */
1744 theta = -atan2f(q[1]->y - q[0]->y, q[1]->x - q[0]->x);
1745 y[0] = (p[0]->x - q[0]->x) * sinf(theta) + (p[0]->y - q[0]->y) * cosf(theta);
1746 y[1] = (p[1]->x - q[0]->x) * sinf(theta) + (p[1]->y - q[0]->y) * cosf(theta);
1747 y[2] = (p[2]->x - q[0]->x) * sinf(theta) + (p[2]->y - q[0]->y) * cosf(theta);
1749 /* Intersect the transformed curve with the x-axis.
1751 * f(t) = (1 - t)²P₀ + 2(1 - t)tP₁ + t²P₂
1752 * = (P₀ - 2P₁ + P₂)t² + 2(P₁ - P₀)t + P₀
1754 * a = P₀ - 2P₁ + P₂
1755 * b = 2(P₁ - P₀)
1756 * c = P₀
1758 * f(t) = 0
1759 * t = (-b ± √(b² - 4ac)) / 2a
1760 * = (-2(P₁ - P₀) ± √((2(P₁ - P₀))² - 4((P₀ - 2P₁ + P₂)P₀))) / 2(P₀ - 2P₁ + P₂)
1761 * = (2P₀ - 2P₁ ± √(4P₀² + 4P₁² - 8P₀P₁ - 4P₀² + 8P₀P₁ - 4P₀P₂)) / (2P₀ - 4P₁ + 2P₂)
1762 * = (P₀ - P₁ ± √(P₁² - P₀P₂)) / (P₀ - 2P₁ + P₂) */
1764 d = y[0] - 2 * y[1] + y[2];
1765 if (d == 0.0f)
1767 /* P₀ - 2P₁ + P₂ = 0
1768 * f(t) = (P₀ - 2P₁ + P₂)t² + 2(P₁ - P₀)t + P₀ = 0
1769 * t = -P₀ / 2(P₁ - P₀) */
1770 root = -y[0] / (2.0f * (y[1] - y[0]));
1771 if (root < 0.0f || root > 1.0f)
1772 return TRUE;
1774 return d2d_geometry_add_bezier_line_intersections(geometry, intersections, idx_p, p, idx_q, q, root);
1777 e = y[1] * y[1] - y[0] * y[2];
1778 if (e < 0.0f)
1779 return TRUE;
1781 root = (y[0] - y[1] + sqrtf(e)) / d;
1782 if (root >= 0.0f && root <= 1.0f && !d2d_geometry_add_bezier_line_intersections(geometry,
1783 intersections, idx_p, p, idx_q, q, root))
1784 return FALSE;
1786 root = (y[0] - y[1] - sqrtf(e)) / d;
1787 if (root >= 0.0f && root <= 1.0f && !d2d_geometry_add_bezier_line_intersections(geometry,
1788 intersections, idx_p, p, idx_q, q, root))
1789 return FALSE;
1791 return TRUE;
1794 static BOOL d2d_geometry_intersect_bezier_bezier(struct d2d_geometry *geometry,
1795 struct d2d_geometry_intersections *intersections,
1796 const struct d2d_segment_idx *idx_p, float start_p, float end_p,
1797 const struct d2d_segment_idx *idx_q, float start_q, float end_q)
1799 const D2D1_POINT_2F *p[3], *q[3];
1800 const struct d2d_figure *figure;
1801 D2D_RECT_F p_bounds, q_bounds;
1802 D2D1_POINT_2F intersection;
1803 float centre_p, centre_q;
1804 size_t next;
1806 figure = &geometry->u.path.figures[idx_p->figure_idx];
1807 p[0] = &figure->vertices[idx_p->vertex_idx];
1808 p[1] = &figure->bezier_controls[idx_p->control_idx];
1809 next = idx_p->vertex_idx + 1;
1810 if (next == figure->vertex_count)
1811 next = 0;
1812 p[2] = &figure->vertices[next];
1814 figure = &geometry->u.path.figures[idx_q->figure_idx];
1815 q[0] = &figure->vertices[idx_q->vertex_idx];
1816 q[1] = &figure->bezier_controls[idx_q->control_idx];
1817 next = idx_q->vertex_idx + 1;
1818 if (next == figure->vertex_count)
1819 next = 0;
1820 q[2] = &figure->vertices[next];
1822 d2d_rect_get_bezier_segment_bounds(&p_bounds, p[0], p[1], p[2], start_p, end_p);
1823 d2d_rect_get_bezier_segment_bounds(&q_bounds, q[0], q[1], q[2], start_q, end_q);
1825 if (!d2d_rect_check_overlap(&p_bounds, &q_bounds))
1826 return TRUE;
1828 centre_p = (start_p + end_p) / 2.0f;
1829 centre_q = (start_q + end_q) / 2.0f;
1831 if (end_p - start_p < 1e-3f)
1833 d2d_point_calculate_bezier(&intersection, p[0], p[1], p[2], centre_p);
1834 if (start_p > 0.0f && end_p < 1.0f && !d2d_geometry_intersections_add(intersections,
1835 idx_p, centre_p, intersection))
1836 return FALSE;
1837 if (start_q > 0.0f && end_q < 1.0f && !d2d_geometry_intersections_add(intersections,
1838 idx_q, centre_q, intersection))
1839 return FALSE;
1840 return TRUE;
1843 if (!d2d_geometry_intersect_bezier_bezier(geometry, intersections,
1844 idx_p, start_p, centre_p, idx_q, start_q, centre_q))
1845 return FALSE;
1846 if (!d2d_geometry_intersect_bezier_bezier(geometry, intersections,
1847 idx_p, start_p, centre_p, idx_q, centre_q, end_q))
1848 return FALSE;
1849 if (!d2d_geometry_intersect_bezier_bezier(geometry, intersections,
1850 idx_p, centre_p, end_p, idx_q, start_q, centre_q))
1851 return FALSE;
1852 if (!d2d_geometry_intersect_bezier_bezier(geometry, intersections,
1853 idx_p, centre_p, end_p, idx_q, centre_q, end_q))
1854 return FALSE;
1856 return TRUE;
1859 static BOOL d2d_geometry_apply_intersections(struct d2d_geometry *geometry,
1860 struct d2d_geometry_intersections *intersections)
1862 size_t vertex_offset, control_offset, next, i;
1863 struct d2d_geometry_intersection *inter;
1864 enum d2d_vertex_type vertex_type;
1865 const D2D1_POINT_2F *p[3];
1866 struct d2d_figure *figure;
1867 D2D1_POINT_2F q[2];
1868 float t, t_prev;
1870 for (i = 0; i < intersections->intersection_count; ++i)
1872 inter = &intersections->intersections[i];
1873 if (!i || inter->figure_idx != intersections->intersections[i - 1].figure_idx)
1874 vertex_offset = control_offset = 0;
1876 figure = &geometry->u.path.figures[inter->figure_idx];
1877 vertex_type = figure->vertex_types[inter->vertex_idx + vertex_offset];
1878 if (vertex_type != D2D_VERTEX_TYPE_BEZIER && vertex_type != D2D_VERTEX_TYPE_SPLIT_BEZIER)
1880 if (!d2d_figure_insert_vertex(&geometry->u.path.figures[inter->figure_idx],
1881 inter->vertex_idx + vertex_offset + 1, inter->p))
1882 return FALSE;
1883 ++vertex_offset;
1884 continue;
1887 t = inter->t;
1888 if (i && inter->figure_idx == intersections->intersections[i - 1].figure_idx
1889 && inter->vertex_idx == intersections->intersections[i - 1].vertex_idx)
1891 t_prev = intersections->intersections[i - 1].t;
1892 if (t - t_prev < 1e-3f)
1894 inter->t = intersections->intersections[i - 1].t;
1895 continue;
1897 t = (t - t_prev) / (1.0f - t_prev);
1900 p[0] = &figure->vertices[inter->vertex_idx + vertex_offset];
1901 p[1] = &figure->bezier_controls[inter->control_idx + control_offset];
1902 next = inter->vertex_idx + vertex_offset + 1;
1903 if (next == figure->vertex_count)
1904 next = 0;
1905 p[2] = &figure->vertices[next];
1907 d2d_point_lerp(&q[0], p[0], p[1], t);
1908 d2d_point_lerp(&q[1], p[1], p[2], t);
1910 figure->bezier_controls[inter->control_idx + control_offset] = q[0];
1911 if (!(d2d_figure_insert_bezier_control(figure, inter->control_idx + control_offset + 1, &q[1])))
1912 return FALSE;
1913 ++control_offset;
1915 if (!(d2d_figure_insert_vertex(figure, inter->vertex_idx + vertex_offset + 1, inter->p)))
1916 return FALSE;
1917 figure->vertex_types[inter->vertex_idx + vertex_offset + 1] = D2D_VERTEX_TYPE_SPLIT_BEZIER;
1918 ++vertex_offset;
1921 return TRUE;
1924 /* Intersect the geometry's segments with themselves. This uses the
1925 * straightforward approach of testing everything against everything, but
1926 * there certainly exist more scalable algorithms for this. */
1927 static BOOL d2d_geometry_intersect_self(struct d2d_geometry *geometry)
1929 struct d2d_geometry_intersections intersections = {0};
1930 const struct d2d_figure *figure_p, *figure_q;
1931 struct d2d_segment_idx idx_p, idx_q;
1932 enum d2d_vertex_type type_p, type_q;
1933 BOOL ret = FALSE;
1934 size_t max_q;
1936 if (!geometry->u.path.figure_count)
1937 return TRUE;
1939 for (idx_p.figure_idx = 0; idx_p.figure_idx < geometry->u.path.figure_count; ++idx_p.figure_idx)
1941 figure_p = &geometry->u.path.figures[idx_p.figure_idx];
1942 idx_p.control_idx = 0;
1943 for (idx_p.vertex_idx = 0; idx_p.vertex_idx < figure_p->vertex_count; ++idx_p.vertex_idx)
1945 type_p = figure_p->vertex_types[idx_p.vertex_idx];
1946 for (idx_q.figure_idx = 0; idx_q.figure_idx <= idx_p.figure_idx; ++idx_q.figure_idx)
1948 figure_q = &geometry->u.path.figures[idx_q.figure_idx];
1949 if (idx_q.figure_idx != idx_p.figure_idx)
1951 if (!d2d_rect_check_overlap(&figure_p->bounds, &figure_q->bounds))
1952 continue;
1953 max_q = figure_q->vertex_count;
1955 else
1957 max_q = idx_p.vertex_idx;
1960 idx_q.control_idx = 0;
1961 for (idx_q.vertex_idx = 0; idx_q.vertex_idx < max_q; ++idx_q.vertex_idx)
1963 type_q = figure_q->vertex_types[idx_q.vertex_idx];
1964 if (type_q == D2D_VERTEX_TYPE_BEZIER)
1966 if (type_p == D2D_VERTEX_TYPE_BEZIER)
1968 if (!d2d_geometry_intersect_bezier_bezier(geometry, &intersections,
1969 &idx_p, 0.0f, 1.0f, &idx_q, 0.0f, 1.0f))
1970 goto done;
1972 else
1974 if (!d2d_geometry_intersect_bezier_line(geometry, &intersections, &idx_q, &idx_p))
1975 goto done;
1977 ++idx_q.control_idx;
1979 else
1981 if (type_p == D2D_VERTEX_TYPE_BEZIER)
1983 if (!d2d_geometry_intersect_bezier_line(geometry, &intersections, &idx_p, &idx_q))
1984 goto done;
1986 else
1988 if (!d2d_geometry_intersect_line_line(geometry, &intersections, &idx_p, &idx_q))
1989 goto done;
1994 if (type_p == D2D_VERTEX_TYPE_BEZIER)
1995 ++idx_p.control_idx;
1999 qsort(intersections.intersections, intersections.intersection_count,
2000 sizeof(*intersections.intersections), d2d_geometry_intersections_compare);
2001 ret = d2d_geometry_apply_intersections(geometry, &intersections);
2003 done:
2004 heap_free(intersections.intersections);
2005 return ret;
2008 static HRESULT d2d_path_geometry_triangulate(struct d2d_geometry *geometry)
2010 struct d2d_cdt_edge_ref left_edge, right_edge;
2011 size_t vertex_count, i, j;
2012 struct d2d_cdt cdt = {0};
2013 D2D1_POINT_2F *vertices;
2015 for (i = 0, vertex_count = 0; i < geometry->u.path.figure_count; ++i)
2017 if (geometry->u.path.figures[i].flags & D2D_FIGURE_FLAG_HOLLOW)
2018 continue;
2019 vertex_count += geometry->u.path.figures[i].vertex_count;
2022 if (vertex_count < 3)
2024 WARN("Geometry has %lu vertices.\n", (long)vertex_count);
2025 return S_OK;
2028 if (!(vertices = heap_calloc(vertex_count, sizeof(*vertices))))
2029 return E_OUTOFMEMORY;
2031 for (i = 0, j = 0; i < geometry->u.path.figure_count; ++i)
2033 if (geometry->u.path.figures[i].flags & D2D_FIGURE_FLAG_HOLLOW)
2034 continue;
2035 memcpy(&vertices[j], geometry->u.path.figures[i].vertices,
2036 geometry->u.path.figures[i].vertex_count * sizeof(*vertices));
2037 j += geometry->u.path.figures[i].vertex_count;
2040 /* Sort vertices, eliminate duplicates. */
2041 qsort(vertices, vertex_count, sizeof(*vertices), d2d_cdt_compare_vertices);
2042 for (i = 1; i < vertex_count; ++i)
2044 if (!memcmp(&vertices[i - 1], &vertices[i], sizeof(*vertices)))
2046 --vertex_count;
2047 memmove(&vertices[i], &vertices[i + 1], (vertex_count - i) * sizeof(*vertices));
2048 --i;
2052 geometry->fill.vertices = vertices;
2053 geometry->fill.vertex_count = vertex_count;
2055 cdt.free_edge = ~0u;
2056 cdt.vertices = vertices;
2057 if (!d2d_cdt_triangulate(&cdt, 0, vertex_count, &left_edge, &right_edge))
2058 goto fail;
2059 if (!d2d_cdt_insert_segments(&cdt, geometry))
2060 goto fail;
2061 if (!d2d_cdt_generate_faces(&cdt, geometry))
2062 goto fail;
2064 heap_free(cdt.edges);
2065 return S_OK;
2067 fail:
2068 geometry->fill.vertices = NULL;
2069 geometry->fill.vertex_count = 0;
2070 heap_free(vertices);
2071 heap_free(cdt.edges);
2072 return E_FAIL;
2075 static BOOL d2d_path_geometry_add_figure(struct d2d_geometry *geometry)
2077 struct d2d_figure *figure;
2079 if (!d2d_array_reserve((void **)&geometry->u.path.figures, &geometry->u.path.figures_size,
2080 geometry->u.path.figure_count + 1, sizeof(*geometry->u.path.figures)))
2082 ERR("Failed to grow figures array.\n");
2083 return FALSE;
2086 figure = &geometry->u.path.figures[geometry->u.path.figure_count];
2087 memset(figure, 0, sizeof(*figure));
2088 figure->bounds.left = FLT_MAX;
2089 figure->bounds.top = FLT_MAX;
2090 figure->bounds.right = -FLT_MAX;
2091 figure->bounds.bottom = -FLT_MAX;
2093 ++geometry->u.path.figure_count;
2094 return TRUE;
2097 static BOOL d2d_geometry_outline_add_join(struct d2d_geometry *geometry,
2098 const D2D1_POINT_2F *prev, const D2D1_POINT_2F *p0, const D2D1_POINT_2F *next)
2100 static const D2D1_POINT_2F origin = {0.0f, 0.0f};
2101 struct d2d_outline_vertex *v;
2102 struct d2d_face *f;
2103 size_t base_idx;
2104 float ccw;
2106 if (!d2d_array_reserve((void **)&geometry->outline.vertices, &geometry->outline.vertices_size,
2107 geometry->outline.vertex_count + 4, sizeof(*geometry->outline.vertices)))
2109 ERR("Failed to grow outline vertices array.\n");
2110 return FALSE;
2112 base_idx = geometry->outline.vertex_count;
2113 v = &geometry->outline.vertices[base_idx];
2115 if (!d2d_array_reserve((void **)&geometry->outline.faces, &geometry->outline.faces_size,
2116 geometry->outline.face_count + 2, sizeof(*geometry->outline.faces)))
2118 ERR("Failed to grow outline faces array.\n");
2119 return FALSE;
2121 f = &geometry->outline.faces[geometry->outline.face_count];
2123 ccw = d2d_point_ccw(&origin, prev, next);
2124 if (ccw == 0.0f)
2126 d2d_outline_vertex_set(&v[0], p0->x, p0->y, -prev->x, -prev->y, -prev->x, -prev->y);
2127 d2d_outline_vertex_set(&v[1], p0->x, p0->y, prev->x, prev->y, prev->x, prev->y);
2128 d2d_outline_vertex_set(&v[2], p0->x + 25.0f * -prev->x, p0->y + 25.0f * -prev->y,
2129 prev->x, prev->y, prev->x, prev->y);
2130 d2d_outline_vertex_set(&v[3], p0->x + 25.0f * -prev->x, p0->y + 25.0f * -prev->y,
2131 -prev->x, -prev->y, -prev->x, -prev->y);
2133 else if (ccw < 0.0f)
2135 d2d_outline_vertex_set(&v[0], p0->x, p0->y, next->x, next->y, -prev->x, -prev->y);
2136 d2d_outline_vertex_set(&v[1], p0->x, p0->y, -next->x, -next->y, -next->x, -next->y);
2137 d2d_outline_vertex_set(&v[2], p0->x, p0->y, -next->x, -next->y, prev->x, prev->y);
2138 d2d_outline_vertex_set(&v[3], p0->x, p0->y, prev->x, prev->y, prev->x, prev->y);
2140 else
2142 d2d_outline_vertex_set(&v[0], p0->x, p0->y, prev->x, prev->y, -next->x, -next->y);
2143 d2d_outline_vertex_set(&v[1], p0->x, p0->y, -prev->x, -prev->y, -prev->x, -prev->y);
2144 d2d_outline_vertex_set(&v[2], p0->x, p0->y, -prev->x, -prev->y, next->x, next->y);
2145 d2d_outline_vertex_set(&v[3], p0->x, p0->y, next->x, next->y, next->x, next->y);
2147 geometry->outline.vertex_count += 4;
2149 d2d_face_set(&f[0], base_idx + 1, base_idx + 0, base_idx + 2);
2150 d2d_face_set(&f[1], base_idx + 2, base_idx + 0, base_idx + 3);
2151 geometry->outline.face_count += 2;
2153 return TRUE;
2156 static BOOL d2d_geometry_outline_add_line_segment(struct d2d_geometry *geometry,
2157 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *next)
2159 struct d2d_outline_vertex *v;
2160 D2D1_POINT_2F q_next;
2161 struct d2d_face *f;
2162 size_t base_idx;
2164 if (!d2d_array_reserve((void **)&geometry->outline.vertices, &geometry->outline.vertices_size,
2165 geometry->outline.vertex_count + 4, sizeof(*geometry->outline.vertices)))
2167 ERR("Failed to grow outline vertices array.\n");
2168 return FALSE;
2170 base_idx = geometry->outline.vertex_count;
2171 v = &geometry->outline.vertices[base_idx];
2173 if (!d2d_array_reserve((void **)&geometry->outline.faces, &geometry->outline.faces_size,
2174 geometry->outline.face_count + 2, sizeof(*geometry->outline.faces)))
2176 ERR("Failed to grow outline faces array.\n");
2177 return FALSE;
2179 f = &geometry->outline.faces[geometry->outline.face_count];
2181 d2d_point_subtract(&q_next, next, p0);
2182 d2d_point_normalise(&q_next);
2184 d2d_outline_vertex_set(&v[0], p0->x, p0->y, q_next.x, q_next.y, q_next.x, q_next.y);
2185 d2d_outline_vertex_set(&v[1], p0->x, p0->y, -q_next.x, -q_next.y, -q_next.x, -q_next.y);
2186 d2d_outline_vertex_set(&v[2], next->x, next->y, q_next.x, q_next.y, q_next.x, q_next.y);
2187 d2d_outline_vertex_set(&v[3], next->x, next->y, -q_next.x, -q_next.y, -q_next.x, -q_next.y);
2188 geometry->outline.vertex_count += 4;
2190 d2d_face_set(&f[0], base_idx + 0, base_idx + 1, base_idx + 2);
2191 d2d_face_set(&f[1], base_idx + 2, base_idx + 1, base_idx + 3);
2192 geometry->outline.face_count += 2;
2194 return TRUE;
2197 static BOOL d2d_geometry_outline_add_bezier_segment(struct d2d_geometry *geometry,
2198 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2)
2200 struct d2d_curve_outline_vertex *b;
2201 D2D1_POINT_2F r0, r1, r2;
2202 D2D1_POINT_2F q0, q1, q2;
2203 struct d2d_face *f;
2204 size_t base_idx;
2206 if (!d2d_array_reserve((void **)&geometry->outline.beziers, &geometry->outline.beziers_size,
2207 geometry->outline.bezier_count + 7, sizeof(*geometry->outline.beziers)))
2209 ERR("Failed to grow outline beziers array.\n");
2210 return FALSE;
2212 base_idx = geometry->outline.bezier_count;
2213 b = &geometry->outline.beziers[base_idx];
2215 if (!d2d_array_reserve((void **)&geometry->outline.bezier_faces, &geometry->outline.bezier_faces_size,
2216 geometry->outline.bezier_face_count + 5, sizeof(*geometry->outline.bezier_faces)))
2218 ERR("Failed to grow outline faces array.\n");
2219 return FALSE;
2221 f = &geometry->outline.bezier_faces[geometry->outline.bezier_face_count];
2223 d2d_point_lerp(&q0, p0, p1, 0.5f);
2224 d2d_point_lerp(&q1, p1, p2, 0.5f);
2225 d2d_point_lerp(&q2, &q0, &q1, 0.5f);
2227 d2d_point_subtract(&r0, &q0, p0);
2228 d2d_point_subtract(&r1, &q1, &q0);
2229 d2d_point_subtract(&r2, p2, &q1);
2231 d2d_point_normalise(&r0);
2232 d2d_point_normalise(&r1);
2233 d2d_point_normalise(&r2);
2235 if (d2d_point_ccw(p0, p1, p2) > 0.0f)
2237 d2d_point_scale(&r0, -1.0f);
2238 d2d_point_scale(&r1, -1.0f);
2239 d2d_point_scale(&r2, -1.0f);
2242 d2d_curve_outline_vertex_set(&b[0], p0, p0, p1, p2, r0.x, r0.y, r0.x, r0.y);
2243 d2d_curve_outline_vertex_set(&b[1], p0, p0, p1, p2, -r0.x, -r0.y, -r0.x, -r0.y);
2244 d2d_curve_outline_vertex_set(&b[2], &q0, p0, p1, p2, r0.x, r0.y, r1.x, r1.y);
2245 d2d_curve_outline_vertex_set(&b[3], &q2, p0, p1, p2, -r1.x, -r1.y, -r1.x, -r1.y);
2246 d2d_curve_outline_vertex_set(&b[4], &q1, p0, p1, p2, r1.x, r1.y, r2.x, r2.y);
2247 d2d_curve_outline_vertex_set(&b[5], p2, p0, p1, p2, -r2.x, -r2.y, -r2.x, -r2.y);
2248 d2d_curve_outline_vertex_set(&b[6], p2, p0, p1, p2, r2.x, r2.y, r2.x, r2.y);
2249 geometry->outline.bezier_count += 7;
2251 d2d_face_set(&f[0], base_idx + 0, base_idx + 1, base_idx + 2);
2252 d2d_face_set(&f[1], base_idx + 2, base_idx + 1, base_idx + 3);
2253 d2d_face_set(&f[2], base_idx + 3, base_idx + 4, base_idx + 2);
2254 d2d_face_set(&f[3], base_idx + 5, base_idx + 4, base_idx + 3);
2255 d2d_face_set(&f[4], base_idx + 5, base_idx + 6, base_idx + 4);
2256 geometry->outline.bezier_face_count += 5;
2258 return TRUE;
2261 static BOOL d2d_geometry_outline_add_arc_quadrant(struct d2d_geometry *geometry,
2262 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2)
2264 struct d2d_curve_outline_vertex *a;
2265 D2D1_POINT_2F r0, r1;
2266 struct d2d_face *f;
2267 size_t base_idx;
2269 if (!d2d_array_reserve((void **)&geometry->outline.arcs, &geometry->outline.arcs_size,
2270 geometry->outline.arc_count + 5, sizeof(*geometry->outline.arcs)))
2272 ERR("Failed to grow outline arcs array.\n");
2273 return FALSE;
2275 base_idx = geometry->outline.arc_count;
2276 a = &geometry->outline.arcs[base_idx];
2278 if (!d2d_array_reserve((void **)&geometry->outline.arc_faces, &geometry->outline.arc_faces_size,
2279 geometry->outline.arc_face_count + 3, sizeof(*geometry->outline.arc_faces)))
2281 ERR("Failed to grow outline faces array.\n");
2282 return FALSE;
2284 f = &geometry->outline.arc_faces[geometry->outline.arc_face_count];
2286 d2d_point_subtract(&r0, p1, p0);
2287 d2d_point_subtract(&r1, p2, p1);
2289 d2d_point_normalise(&r0);
2290 d2d_point_normalise(&r1);
2292 if (d2d_point_ccw(p0, p1, p2) > 0.0f)
2294 d2d_point_scale(&r0, -1.0f);
2295 d2d_point_scale(&r1, -1.0f);
2298 d2d_curve_outline_vertex_set(&a[0], p0, p0, p1, p2, r0.x, r0.y, r0.x, r0.y);
2299 d2d_curve_outline_vertex_set(&a[1], p0, p0, p1, p2, -r0.x, -r0.y, -r0.x, -r0.y);
2300 d2d_curve_outline_vertex_set(&a[2], p1, p0, p1, p2, r0.x, r0.y, r1.x, r1.y);
2301 d2d_curve_outline_vertex_set(&a[3], p2, p0, p1, p2, -r1.x, -r1.y, -r1.x, -r1.y);
2302 d2d_curve_outline_vertex_set(&a[4], p2, p0, p1, p2, r1.x, r1.y, r1.x, r1.y);
2303 geometry->outline.arc_count += 5;
2305 d2d_face_set(&f[0], base_idx + 0, base_idx + 1, base_idx + 2);
2306 d2d_face_set(&f[1], base_idx + 2, base_idx + 1, base_idx + 3);
2307 d2d_face_set(&f[2], base_idx + 2, base_idx + 4, base_idx + 3);
2308 geometry->outline.arc_face_count += 3;
2310 return TRUE;
2313 static BOOL d2d_geometry_add_figure_outline(struct d2d_geometry *geometry,
2314 struct d2d_figure *figure, D2D1_FIGURE_END figure_end)
2316 const D2D1_POINT_2F *prev, *p0, *next;
2317 enum d2d_vertex_type prev_type, type;
2318 size_t bezier_idx, i;
2320 for (i = 0, bezier_idx = 0; i < figure->vertex_count; ++i)
2322 type = figure->vertex_types[i];
2323 if (type == D2D_VERTEX_TYPE_NONE)
2324 continue;
2326 p0 = &figure->vertices[i];
2328 if (!i)
2330 prev_type = figure->vertex_types[figure->vertex_count - 1];
2331 if (prev_type == D2D_VERTEX_TYPE_BEZIER)
2332 prev = &figure->bezier_controls[figure->bezier_control_count - 1];
2333 else
2334 prev = &figure->vertices[figure->vertex_count - 1];
2336 else
2338 prev_type = figure->vertex_types[i - 1];
2339 if (prev_type == D2D_VERTEX_TYPE_BEZIER)
2340 prev = &figure->bezier_controls[bezier_idx - 1];
2341 else
2342 prev = &figure->vertices[i - 1];
2345 if (type == D2D_VERTEX_TYPE_BEZIER)
2346 next = &figure->bezier_controls[bezier_idx++];
2347 else if (i == figure->vertex_count - 1)
2348 next = &figure->vertices[0];
2349 else
2350 next = &figure->vertices[i + 1];
2352 if (figure_end == D2D1_FIGURE_END_CLOSED || (i && i < figure->vertex_count - 1))
2354 D2D1_POINT_2F q_next, q_prev;
2356 d2d_point_subtract(&q_prev, prev, p0);
2357 d2d_point_subtract(&q_next, next, p0);
2359 d2d_point_normalise(&q_prev);
2360 d2d_point_normalise(&q_next);
2362 if (!d2d_geometry_outline_add_join(geometry, &q_prev, p0, &q_next))
2364 ERR("Failed to add join.\n");
2365 return FALSE;
2369 if (type == D2D_VERTEX_TYPE_LINE && (figure_end == D2D1_FIGURE_END_CLOSED || i < figure->vertex_count - 1)
2370 && !d2d_geometry_outline_add_line_segment(geometry, p0, next))
2372 ERR("Failed to add line segment.\n");
2373 return FALSE;
2375 else if (type == D2D_VERTEX_TYPE_BEZIER)
2377 const D2D1_POINT_2F *p2;
2379 if (i == figure->vertex_count - 1)
2380 p2 = &figure->vertices[0];
2381 else
2382 p2 = &figure->vertices[i + 1];
2384 if (!d2d_geometry_outline_add_bezier_segment(geometry, p0, next, p2))
2386 ERR("Failed to add bezier segment.\n");
2387 return FALSE;
2392 return TRUE;
2395 static BOOL d2d_geometry_fill_add_arc_triangle(struct d2d_geometry *geometry,
2396 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2)
2398 struct d2d_curve_vertex *a;
2400 if (!d2d_array_reserve((void **)&geometry->fill.arc_vertices, &geometry->fill.arc_vertices_size,
2401 geometry->fill.arc_vertex_count + 3, sizeof(*geometry->fill.arc_vertices)))
2402 return FALSE;
2404 a = &geometry->fill.arc_vertices[geometry->fill.arc_vertex_count];
2405 d2d_curve_vertex_set(&a[0], p0, 0.0f, 1.0f, -1.0f);
2406 d2d_curve_vertex_set(&a[1], p1, 1.0f, 1.0f, -1.0f);
2407 d2d_curve_vertex_set(&a[2], p2, 1.0f, 0.0f, -1.0f);
2408 geometry->fill.arc_vertex_count += 3;
2410 return TRUE;
2413 static void d2d_geometry_cleanup(struct d2d_geometry *geometry)
2415 heap_free(geometry->outline.arc_faces);
2416 heap_free(geometry->outline.arcs);
2417 heap_free(geometry->outline.bezier_faces);
2418 heap_free(geometry->outline.beziers);
2419 heap_free(geometry->outline.faces);
2420 heap_free(geometry->outline.vertices);
2421 heap_free(geometry->fill.arc_vertices);
2422 heap_free(geometry->fill.bezier_vertices);
2423 heap_free(geometry->fill.faces);
2424 heap_free(geometry->fill.vertices);
2425 ID2D1Factory_Release(geometry->factory);
2428 static void d2d_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
2429 const D2D1_MATRIX_3X2_F *transform, const struct ID2D1GeometryVtbl *vtbl)
2431 geometry->ID2D1Geometry_iface.lpVtbl = vtbl;
2432 geometry->refcount = 1;
2433 ID2D1Factory_AddRef(geometry->factory = factory);
2434 geometry->transform = *transform;
2437 static inline struct d2d_geometry *impl_from_ID2D1GeometrySink(ID2D1GeometrySink *iface)
2439 return CONTAINING_RECORD(iface, struct d2d_geometry, u.path.ID2D1GeometrySink_iface);
2442 static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_QueryInterface(ID2D1GeometrySink *iface, REFIID iid, void **out)
2444 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
2446 if (IsEqualGUID(iid, &IID_ID2D1GeometrySink)
2447 || IsEqualGUID(iid, &IID_ID2D1SimplifiedGeometrySink)
2448 || IsEqualGUID(iid, &IID_IUnknown))
2450 ID2D1GeometrySink_AddRef(iface);
2451 *out = iface;
2452 return S_OK;
2455 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
2457 *out = NULL;
2458 return E_NOINTERFACE;
2461 static ULONG STDMETHODCALLTYPE d2d_geometry_sink_AddRef(ID2D1GeometrySink *iface)
2463 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2465 TRACE("iface %p.\n", iface);
2467 return ID2D1Geometry_AddRef(&geometry->ID2D1Geometry_iface);
2470 static ULONG STDMETHODCALLTYPE d2d_geometry_sink_Release(ID2D1GeometrySink *iface)
2472 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2474 TRACE("iface %p.\n", iface);
2476 return ID2D1Geometry_Release(&geometry->ID2D1Geometry_iface);
2479 static void STDMETHODCALLTYPE d2d_geometry_sink_SetFillMode(ID2D1GeometrySink *iface, D2D1_FILL_MODE mode)
2481 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2483 TRACE("iface %p, mode %#x.\n", iface, mode);
2485 if (geometry->u.path.state == D2D_GEOMETRY_STATE_CLOSED)
2486 return;
2487 geometry->u.path.fill_mode = mode;
2490 static void STDMETHODCALLTYPE d2d_geometry_sink_SetSegmentFlags(ID2D1GeometrySink *iface, D2D1_PATH_SEGMENT flags)
2492 FIXME("iface %p, flags %#x stub!\n", iface, flags);
2495 static void STDMETHODCALLTYPE d2d_geometry_sink_BeginFigure(ID2D1GeometrySink *iface,
2496 D2D1_POINT_2F start_point, D2D1_FIGURE_BEGIN figure_begin)
2498 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2499 struct d2d_figure *figure;
2501 TRACE("iface %p, start_point %s, figure_begin %#x.\n",
2502 iface, debug_d2d_point_2f(&start_point), figure_begin);
2504 if (geometry->u.path.state != D2D_GEOMETRY_STATE_OPEN)
2506 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2507 return;
2510 if (!d2d_path_geometry_add_figure(geometry))
2512 ERR("Failed to add figure.\n");
2513 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2514 return;
2517 figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2518 if (figure_begin == D2D1_FIGURE_BEGIN_HOLLOW)
2519 figure->flags |= D2D_FIGURE_FLAG_HOLLOW;
2521 if (!d2d_figure_add_vertex(figure, start_point))
2523 ERR("Failed to add vertex.\n");
2524 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2525 return;
2528 geometry->u.path.state = D2D_GEOMETRY_STATE_FIGURE;
2531 static void STDMETHODCALLTYPE d2d_geometry_sink_AddLines(ID2D1GeometrySink *iface,
2532 const D2D1_POINT_2F *points, UINT32 count)
2534 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2535 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2536 unsigned int i;
2538 TRACE("iface %p, points %p, count %u.\n", iface, points, count);
2540 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2542 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2543 return;
2546 for (i = 0; i < count; ++i)
2548 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_LINE;
2549 if (!d2d_figure_add_vertex(figure, points[i]))
2551 ERR("Failed to add vertex.\n");
2552 return;
2556 geometry->u.path.segment_count += count;
2559 static void STDMETHODCALLTYPE d2d_geometry_sink_AddBeziers(ID2D1GeometrySink *iface,
2560 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
2562 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2563 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2564 D2D1_POINT_2F p;
2565 unsigned int i;
2567 TRACE("iface %p, beziers %p, count %u.\n", iface, beziers, count);
2569 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2571 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2572 return;
2575 for (i = 0; i < count; ++i)
2577 D2D1_RECT_F bezier_bounds;
2579 /* FIXME: This tries to approximate a cubic bezier with a quadratic one. */
2580 p.x = (beziers[i].point1.x + beziers[i].point2.x) * 0.75f;
2581 p.y = (beziers[i].point1.y + beziers[i].point2.y) * 0.75f;
2582 p.x -= (figure->vertices[figure->vertex_count - 1].x + beziers[i].point3.x) * 0.25f;
2583 p.y -= (figure->vertices[figure->vertex_count - 1].y + beziers[i].point3.y) * 0.25f;
2584 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_BEZIER;
2586 d2d_rect_get_bezier_bounds(&bezier_bounds, &figure->vertices[figure->vertex_count - 1],
2587 &p, &beziers[i].point3);
2589 if (!d2d_figure_add_bezier_control(figure, &p))
2591 ERR("Failed to add bezier control.\n");
2592 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2593 return;
2596 if (!d2d_figure_add_vertex(figure, beziers[i].point3))
2598 ERR("Failed to add bezier vertex.\n");
2599 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2600 return;
2603 d2d_rect_union(&figure->bounds, &bezier_bounds);
2606 geometry->u.path.segment_count += count;
2609 static void STDMETHODCALLTYPE d2d_geometry_sink_EndFigure(ID2D1GeometrySink *iface, D2D1_FIGURE_END figure_end)
2611 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2612 struct d2d_figure *figure;
2614 TRACE("iface %p, figure_end %#x.\n", iface, figure_end);
2616 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2618 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2619 return;
2622 figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2623 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_LINE;
2624 if (figure_end == D2D1_FIGURE_END_CLOSED)
2626 ++geometry->u.path.segment_count;
2627 figure->flags |= D2D_FIGURE_FLAG_CLOSED;
2628 if (!memcmp(&figure->vertices[0], &figure->vertices[figure->vertex_count - 1], sizeof(*figure->vertices)))
2629 --figure->vertex_count;
2632 if (!d2d_geometry_add_figure_outline(geometry, figure, figure_end))
2634 ERR("Failed to add figure outline.\n");
2635 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2636 return;
2639 geometry->u.path.state = D2D_GEOMETRY_STATE_OPEN;
2642 static void d2d_path_geometry_free_figures(struct d2d_geometry *geometry)
2644 size_t i;
2646 if (!geometry->u.path.figures)
2647 return;
2649 for (i = 0; i < geometry->u.path.figure_count; ++i)
2651 heap_free(geometry->u.path.figures[i].bezier_controls);
2652 heap_free(geometry->u.path.figures[i].original_bezier_controls);
2653 heap_free(geometry->u.path.figures[i].vertices);
2655 heap_free(geometry->u.path.figures);
2656 geometry->u.path.figures = NULL;
2657 geometry->u.path.figures_size = 0;
2660 static BOOL d2d_geometry_get_bezier_segment_idx(struct d2d_geometry *geometry, struct d2d_segment_idx *idx, BOOL next)
2662 if (next)
2664 ++idx->vertex_idx;
2665 ++idx->control_idx;
2668 for (; idx->figure_idx < geometry->u.path.figure_count; ++idx->figure_idx, idx->vertex_idx = idx->control_idx = 0)
2670 struct d2d_figure *figure = &geometry->u.path.figures[idx->figure_idx];
2672 if (!figure->bezier_control_count || figure->flags & D2D_FIGURE_FLAG_HOLLOW)
2673 continue;
2675 for (; idx->vertex_idx < figure->vertex_count; ++idx->vertex_idx)
2677 if (figure->vertex_types[idx->vertex_idx] == D2D_VERTEX_TYPE_BEZIER
2678 || figure->vertex_types[idx->vertex_idx] == D2D_VERTEX_TYPE_SPLIT_BEZIER)
2679 return TRUE;
2683 return FALSE;
2686 static BOOL d2d_geometry_get_first_bezier_segment_idx(struct d2d_geometry *geometry, struct d2d_segment_idx *idx)
2688 memset(idx, 0, sizeof(*idx));
2690 return d2d_geometry_get_bezier_segment_idx(geometry, idx, FALSE);
2693 static BOOL d2d_geometry_get_next_bezier_segment_idx(struct d2d_geometry *geometry, struct d2d_segment_idx *idx)
2695 return d2d_geometry_get_bezier_segment_idx(geometry, idx, TRUE);
2698 static BOOL d2d_geometry_check_bezier_overlap(struct d2d_geometry *geometry,
2699 const struct d2d_segment_idx *idx_p, const struct d2d_segment_idx *idx_q)
2701 const D2D1_POINT_2F *a[3], *b[3], *p[2], *q;
2702 const struct d2d_figure *figure;
2703 D2D1_POINT_2F v_q[3], v_p, v_qp;
2704 unsigned int i, j, score;
2705 float det, t;
2707 figure = &geometry->u.path.figures[idx_p->figure_idx];
2708 a[0] = &figure->vertices[idx_p->vertex_idx];
2709 a[1] = &figure->bezier_controls[idx_p->control_idx];
2710 if (idx_p->vertex_idx == figure->vertex_count - 1)
2711 a[2] = &figure->vertices[0];
2712 else
2713 a[2] = &figure->vertices[idx_p->vertex_idx + 1];
2715 figure = &geometry->u.path.figures[idx_q->figure_idx];
2716 b[0] = &figure->vertices[idx_q->vertex_idx];
2717 b[1] = &figure->bezier_controls[idx_q->control_idx];
2718 if (idx_q->vertex_idx == figure->vertex_count - 1)
2719 b[2] = &figure->vertices[0];
2720 else
2721 b[2] = &figure->vertices[idx_q->vertex_idx + 1];
2723 if (d2d_point_ccw(a[0], a[1], a[2]) == 0.0f || d2d_point_ccw(b[0], b[1], b[2]) == 0.0f)
2724 return FALSE;
2726 d2d_point_subtract(&v_q[0], b[1], b[0]);
2727 d2d_point_subtract(&v_q[1], b[2], b[0]);
2728 d2d_point_subtract(&v_q[2], b[1], b[2]);
2730 /* Check for intersections between the edges. Strictly speaking we'd only
2731 * need to check 8 of the 9 possible intersections, since if there's any
2732 * intersection there has to be a second intersection as well. */
2733 for (i = 0; i < 3; ++i)
2735 d2d_point_subtract(&v_p, a[(i & 1) + 1], a[i & 2]);
2736 for (j = 0; j < 3; ++j)
2738 det = v_p.x * v_q[j].y - v_p.y * v_q[j].x;
2739 if (det == 0.0f)
2740 continue;
2742 d2d_point_subtract(&v_qp, a[i & 2], b[j & 2]);
2743 t = (v_q[j].x * v_qp.y - v_q[j].y * v_qp.x) / det;
2744 if (t <= 0.0f || t >= 1.0f)
2745 continue;
2747 t = (v_p.x * v_qp.y - v_p.y * v_qp.x) / det;
2748 if (t <= 0.0f || t >= 1.0f)
2749 continue;
2751 return TRUE;
2755 /* Check if one triangle is contained within the other. */
2756 for (j = 0, score = 0, q = a[1], p[0] = b[2]; j < 3; ++j)
2758 p[1] = b[j];
2759 d2d_point_subtract(&v_p, p[1], p[0]);
2760 d2d_point_subtract(&v_qp, q, p[0]);
2762 if ((q->y < p[0]->y) != (q->y < p[1]->y) && v_qp.x < v_p.x * (v_qp.y / v_p.y))
2763 ++score;
2765 p[0] = p[1];
2768 if (score & 1)
2769 return TRUE;
2771 for (j = 0, score = 0, q = b[1], p[0] = a[2]; j < 3; ++j)
2773 p[1] = a[j];
2774 d2d_point_subtract(&v_p, p[1], p[0]);
2775 d2d_point_subtract(&v_qp, q, p[0]);
2777 if ((q->y < p[0]->y) != (q->y < p[1]->y) && v_qp.x < v_p.x * (v_qp.y / v_p.y))
2778 ++score;
2780 p[0] = p[1];
2783 return score & 1;
2786 static float d2d_geometry_bezier_ccw(struct d2d_geometry *geometry, const struct d2d_segment_idx *idx)
2788 const struct d2d_figure *figure = &geometry->u.path.figures[idx->figure_idx];
2789 size_t next = idx->vertex_idx + 1;
2791 if (next == figure->vertex_count)
2792 next = 0;
2794 return d2d_point_ccw(&figure->vertices[idx->vertex_idx],
2795 &figure->bezier_controls[idx->control_idx], &figure->vertices[next]);
2798 static BOOL d2d_geometry_split_bezier(struct d2d_geometry *geometry, const struct d2d_segment_idx *idx)
2800 const D2D1_POINT_2F *p[3];
2801 struct d2d_figure *figure;
2802 D2D1_POINT_2F q[3];
2803 size_t next;
2805 figure = &geometry->u.path.figures[idx->figure_idx];
2806 p[0] = &figure->vertices[idx->vertex_idx];
2807 p[1] = &figure->bezier_controls[idx->control_idx];
2808 next = idx->vertex_idx + 1;
2809 if (next == figure->vertex_count)
2810 next = 0;
2811 p[2] = &figure->vertices[next];
2813 d2d_point_lerp(&q[0], p[0], p[1], 0.5f);
2814 d2d_point_lerp(&q[1], p[1], p[2], 0.5f);
2815 d2d_point_lerp(&q[2], &q[0], &q[1], 0.5f);
2817 figure->bezier_controls[idx->control_idx] = q[0];
2818 if (!(d2d_figure_insert_bezier_control(figure, idx->control_idx + 1, &q[1])))
2819 return FALSE;
2820 if (!(d2d_figure_insert_vertex(figure, idx->vertex_idx + 1, q[2])))
2821 return FALSE;
2822 figure->vertex_types[idx->vertex_idx + 1] = D2D_VERTEX_TYPE_SPLIT_BEZIER;
2824 return TRUE;
2827 static HRESULT d2d_geometry_resolve_beziers(struct d2d_geometry *geometry)
2829 struct d2d_segment_idx idx_p, idx_q;
2830 struct d2d_curve_vertex *b;
2831 const D2D1_POINT_2F *p[3];
2832 struct d2d_figure *figure;
2833 size_t bezier_idx, i;
2835 if (!d2d_geometry_get_first_bezier_segment_idx(geometry, &idx_p))
2836 return S_OK;
2838 /* Split overlapping bezier control triangles. */
2839 while (d2d_geometry_get_next_bezier_segment_idx(geometry, &idx_p))
2841 d2d_geometry_get_first_bezier_segment_idx(geometry, &idx_q);
2842 while (idx_q.figure_idx < idx_p.figure_idx || idx_q.vertex_idx < idx_p.vertex_idx)
2844 while (d2d_geometry_check_bezier_overlap(geometry, &idx_p, &idx_q))
2846 if (fabsf(d2d_geometry_bezier_ccw(geometry, &idx_q)) > fabsf(d2d_geometry_bezier_ccw(geometry, &idx_p)))
2848 if (!d2d_geometry_split_bezier(geometry, &idx_q))
2849 return E_OUTOFMEMORY;
2850 if (idx_p.figure_idx == idx_q.figure_idx)
2852 ++idx_p.vertex_idx;
2853 ++idx_p.control_idx;
2856 else
2858 if (!d2d_geometry_split_bezier(geometry, &idx_p))
2859 return E_OUTOFMEMORY;
2862 d2d_geometry_get_next_bezier_segment_idx(geometry, &idx_q);
2866 for (i = 0; i < geometry->u.path.figure_count; ++i)
2868 if (geometry->u.path.figures[i].flags & D2D_FIGURE_FLAG_HOLLOW)
2869 continue;
2870 geometry->fill.bezier_vertex_count += 3 * geometry->u.path.figures[i].bezier_control_count;
2873 if (!(geometry->fill.bezier_vertices = heap_calloc(geometry->fill.bezier_vertex_count,
2874 sizeof(*geometry->fill.bezier_vertices))))
2876 ERR("Failed to allocate bezier vertices array.\n");
2877 geometry->fill.bezier_vertex_count = 0;
2878 return E_OUTOFMEMORY;
2881 bezier_idx = 0;
2882 d2d_geometry_get_first_bezier_segment_idx(geometry, &idx_p);
2883 for (;;)
2885 float sign = -1.0f;
2887 figure = &geometry->u.path.figures[idx_p.figure_idx];
2888 p[0] = &figure->vertices[idx_p.vertex_idx];
2889 p[1] = &figure->bezier_controls[idx_p.control_idx];
2891 i = idx_p.vertex_idx + 1;
2892 if (d2d_path_geometry_point_inside(geometry, p[1], FALSE))
2894 sign = 1.0f;
2895 d2d_figure_insert_vertex(figure, i, *p[1]);
2896 /* Inserting a vertex potentially invalidates p[0]. */
2897 p[0] = &figure->vertices[idx_p.vertex_idx];
2898 ++i;
2901 if (i == figure->vertex_count)
2902 i = 0;
2903 p[2] = &figure->vertices[i];
2905 b = &geometry->fill.bezier_vertices[bezier_idx * 3];
2906 d2d_curve_vertex_set(&b[0], p[0], 0.0f, 0.0f, sign);
2907 d2d_curve_vertex_set(&b[1], p[1], 0.5f, 0.0f, sign);
2908 d2d_curve_vertex_set(&b[2], p[2], 1.0f, 1.0f, sign);
2910 if (!d2d_geometry_get_next_bezier_segment_idx(geometry, &idx_p))
2911 break;
2912 ++bezier_idx;
2915 return S_OK;
2918 static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_Close(ID2D1GeometrySink *iface)
2920 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2921 HRESULT hr = E_FAIL;
2922 size_t i;
2924 TRACE("iface %p.\n", iface);
2926 if (geometry->u.path.state != D2D_GEOMETRY_STATE_OPEN)
2928 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
2929 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2930 return D2DERR_WRONG_STATE;
2932 geometry->u.path.state = D2D_GEOMETRY_STATE_CLOSED;
2934 for (i = 0; i < geometry->u.path.figure_count; ++i)
2936 struct d2d_figure *figure = &geometry->u.path.figures[i];
2937 size_t size = figure->bezier_control_count * sizeof(*figure->original_bezier_controls);
2938 if (!(figure->original_bezier_controls = heap_alloc(size)))
2939 goto done;
2940 memcpy(figure->original_bezier_controls, figure->bezier_controls, size);
2943 if (!d2d_geometry_intersect_self(geometry))
2944 goto done;
2945 if (FAILED(hr = d2d_geometry_resolve_beziers(geometry)))
2946 goto done;
2947 if (FAILED(hr = d2d_path_geometry_triangulate(geometry)))
2948 goto done;
2950 done:
2951 if (FAILED(hr))
2953 heap_free(geometry->fill.bezier_vertices);
2954 geometry->fill.bezier_vertex_count = 0;
2955 d2d_path_geometry_free_figures(geometry);
2956 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2958 return hr;
2961 static void STDMETHODCALLTYPE d2d_geometry_sink_AddLine(ID2D1GeometrySink *iface, D2D1_POINT_2F point)
2963 TRACE("iface %p, point %s.\n", iface, debug_d2d_point_2f(&point));
2965 d2d_geometry_sink_AddLines(iface, &point, 1);
2968 static void STDMETHODCALLTYPE d2d_geometry_sink_AddBezier(ID2D1GeometrySink *iface, const D2D1_BEZIER_SEGMENT *bezier)
2970 TRACE("iface %p, bezier %p.\n", iface, bezier);
2972 d2d_geometry_sink_AddBeziers(iface, bezier, 1);
2975 static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBezier(ID2D1GeometrySink *iface,
2976 const D2D1_QUADRATIC_BEZIER_SEGMENT *bezier)
2978 TRACE("iface %p, bezier %p.\n", iface, bezier);
2980 ID2D1GeometrySink_AddQuadraticBeziers(iface, bezier, 1);
2983 static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBeziers(ID2D1GeometrySink *iface,
2984 const D2D1_QUADRATIC_BEZIER_SEGMENT *beziers, UINT32 bezier_count)
2986 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2987 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2988 unsigned int i;
2990 TRACE("iface %p, beziers %p, bezier_count %u.\n", iface, beziers, bezier_count);
2992 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2994 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2995 return;
2998 for (i = 0; i < bezier_count; ++i)
3000 D2D1_RECT_F bezier_bounds;
3002 d2d_rect_get_bezier_bounds(&bezier_bounds, &figure->vertices[figure->vertex_count - 1],
3003 &beziers[i].point1, &beziers[i].point2);
3005 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_BEZIER;
3006 if (!d2d_figure_add_bezier_control(figure, &beziers[i].point1))
3008 ERR("Failed to add bezier.\n");
3009 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3010 return;
3013 if (!d2d_figure_add_vertex(figure, beziers[i].point2))
3015 ERR("Failed to add bezier vertex.\n");
3016 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3017 return;
3020 d2d_rect_union(&figure->bounds, &bezier_bounds);
3023 geometry->u.path.segment_count += bezier_count;
3026 static void STDMETHODCALLTYPE d2d_geometry_sink_AddArc(ID2D1GeometrySink *iface, const D2D1_ARC_SEGMENT *arc)
3028 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
3030 FIXME("iface %p, arc %p stub!\n", iface, arc);
3032 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
3034 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3035 return;
3038 if (!d2d_figure_add_vertex(&geometry->u.path.figures[geometry->u.path.figure_count - 1], arc->point))
3040 ERR("Failed to add vertex.\n");
3041 return;
3044 ++geometry->u.path.segment_count;
3047 static const struct ID2D1GeometrySinkVtbl d2d_geometry_sink_vtbl =
3049 d2d_geometry_sink_QueryInterface,
3050 d2d_geometry_sink_AddRef,
3051 d2d_geometry_sink_Release,
3052 d2d_geometry_sink_SetFillMode,
3053 d2d_geometry_sink_SetSegmentFlags,
3054 d2d_geometry_sink_BeginFigure,
3055 d2d_geometry_sink_AddLines,
3056 d2d_geometry_sink_AddBeziers,
3057 d2d_geometry_sink_EndFigure,
3058 d2d_geometry_sink_Close,
3059 d2d_geometry_sink_AddLine,
3060 d2d_geometry_sink_AddBezier,
3061 d2d_geometry_sink_AddQuadraticBezier,
3062 d2d_geometry_sink_AddQuadraticBeziers,
3063 d2d_geometry_sink_AddArc,
3066 static inline struct d2d_geometry *impl_from_ID2D1PathGeometry(ID2D1PathGeometry *iface)
3068 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
3071 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_QueryInterface(ID2D1PathGeometry *iface, REFIID iid, void **out)
3073 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
3075 if (IsEqualGUID(iid, &IID_ID2D1PathGeometry)
3076 || IsEqualGUID(iid, &IID_ID2D1Geometry)
3077 || IsEqualGUID(iid, &IID_ID2D1Resource)
3078 || IsEqualGUID(iid, &IID_IUnknown))
3080 ID2D1PathGeometry_AddRef(iface);
3081 *out = iface;
3082 return S_OK;
3085 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
3087 *out = NULL;
3088 return E_NOINTERFACE;
3091 static ULONG STDMETHODCALLTYPE d2d_path_geometry_AddRef(ID2D1PathGeometry *iface)
3093 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3094 ULONG refcount = InterlockedIncrement(&geometry->refcount);
3096 TRACE("%p increasing refcount to %u.\n", iface, refcount);
3098 return refcount;
3101 static ULONG STDMETHODCALLTYPE d2d_path_geometry_Release(ID2D1PathGeometry *iface)
3103 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3104 ULONG refcount = InterlockedDecrement(&geometry->refcount);
3106 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
3108 if (!refcount)
3110 d2d_path_geometry_free_figures(geometry);
3111 d2d_geometry_cleanup(geometry);
3112 heap_free(geometry);
3115 return refcount;
3118 static void STDMETHODCALLTYPE d2d_path_geometry_GetFactory(ID2D1PathGeometry *iface, ID2D1Factory **factory)
3120 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3122 TRACE("iface %p, factory %p.\n", iface, factory);
3124 ID2D1Factory_AddRef(*factory = geometry->factory);
3127 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetBounds(ID2D1PathGeometry *iface,
3128 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
3130 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3131 size_t i;
3133 TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
3135 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
3136 return D2DERR_WRONG_STATE;
3138 bounds->left = FLT_MAX;
3139 bounds->top = FLT_MAX;
3140 bounds->right = -FLT_MAX;
3141 bounds->bottom = -FLT_MAX;
3143 if (!transform)
3145 if (geometry->u.path.bounds.left > geometry->u.path.bounds.right
3146 && !isinf(geometry->u.path.bounds.left))
3148 for (i = 0; i < geometry->u.path.figure_count; ++i)
3150 if (geometry->u.path.figures[i].flags & D2D_FIGURE_FLAG_HOLLOW)
3151 continue;
3152 d2d_rect_union(&geometry->u.path.bounds, &geometry->u.path.figures[i].bounds);
3154 if (geometry->u.path.bounds.left > geometry->u.path.bounds.right)
3156 geometry->u.path.bounds.left = INFINITY;
3157 geometry->u.path.bounds.right = FLT_MAX;
3158 geometry->u.path.bounds.top = INFINITY;
3159 geometry->u.path.bounds.bottom = FLT_MAX;
3163 *bounds = geometry->u.path.bounds;
3164 return S_OK;
3167 for (i = 0; i < geometry->u.path.figure_count; ++i)
3169 const struct d2d_figure *figure = &geometry->u.path.figures[i];
3170 enum d2d_vertex_type type = D2D_VERTEX_TYPE_NONE;
3171 D2D1_RECT_F bezier_bounds;
3172 D2D1_POINT_2F p, p1, p2;
3173 size_t j, bezier_idx;
3175 if (figure->flags & D2D_FIGURE_FLAG_HOLLOW)
3176 continue;
3178 /* Single vertex figures are reduced by CloseFigure(). */
3179 if (figure->vertex_count == 0)
3181 d2d_point_transform(&p, transform, figure->bounds.left, figure->bounds.top);
3182 d2d_rect_expand(bounds, &p);
3183 continue;
3186 for (j = 0; j < figure->vertex_count; ++j)
3188 if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
3189 continue;
3191 p = figure->vertices[j];
3192 type = figure->vertex_types[j];
3193 d2d_point_transform(&p, transform, p.x, p.y);
3194 d2d_rect_expand(bounds, &p);
3195 break;
3198 for (bezier_idx = 0, ++j; j < figure->vertex_count; ++j)
3200 if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE
3201 || figure->vertex_types[j] == D2D_VERTEX_TYPE_SPLIT_BEZIER)
3202 continue;
3204 switch (type)
3206 case D2D_VERTEX_TYPE_LINE:
3207 p = figure->vertices[j];
3208 d2d_point_transform(&p, transform, p.x, p.y);
3209 d2d_rect_expand(bounds, &p);
3210 break;
3212 case D2D_VERTEX_TYPE_BEZIER:
3213 p1 = figure->original_bezier_controls[bezier_idx++];
3214 d2d_point_transform(&p1, transform, p1.x, p1.y);
3215 p2 = figure->vertices[j];
3216 d2d_point_transform(&p2, transform, p2.x, p2.y);
3217 d2d_rect_get_bezier_bounds(&bezier_bounds, &p, &p1, &p2);
3218 d2d_rect_union(bounds, &bezier_bounds);
3219 p = p2;
3220 break;
3222 default:
3223 FIXME("Unhandled vertex type %#x.\n", type);
3224 p = figure->vertices[j];
3225 d2d_point_transform(&p, transform, p.x, p.y);
3226 d2d_rect_expand(bounds, &p);
3227 break;
3230 type = figure->vertex_types[j];
3233 if (type == D2D_VERTEX_TYPE_BEZIER)
3235 p1 = figure->original_bezier_controls[bezier_idx++];
3236 d2d_point_transform(&p1, transform, p1.x, p1.y);
3237 p2 = figure->vertices[0];
3238 d2d_point_transform(&p2, transform, p2.x, p2.y);
3239 d2d_rect_get_bezier_bounds(&bezier_bounds, &p, &p1, &p2);
3240 d2d_rect_union(bounds, &bezier_bounds);
3244 if (bounds->left > bounds->right)
3246 bounds->left = INFINITY;
3247 bounds->right = FLT_MAX;
3248 bounds->top = INFINITY;
3249 bounds->bottom = FLT_MAX;
3252 return S_OK;
3255 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetWidenedBounds(ID2D1PathGeometry *iface, float stroke_width,
3256 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_RECT_F *bounds)
3258 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
3259 iface, stroke_width, stroke_style, transform, tolerance, bounds);
3261 return E_NOTIMPL;
3264 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_StrokeContainsPoint(ID2D1PathGeometry *iface,
3265 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
3266 float tolerance, BOOL *contains)
3268 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, "
3269 "transform %p, tolerance %.8e, contains %p stub!\n",
3270 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
3272 return E_NOTIMPL;
3275 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_FillContainsPoint(ID2D1PathGeometry *iface,
3276 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
3278 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3279 D2D1_MATRIX_3X2_F g_i;
3281 TRACE("iface %p, point %s, transform %p, tolerance %.8e, contains %p.\n",
3282 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
3284 if (transform)
3286 if (!d2d_matrix_invert(&g_i, transform))
3287 return D2DERR_UNSUPPORTED_OPERATION;
3288 d2d_point_transform(&point, &g_i, point.x, point.y);
3291 *contains = !!d2d_path_geometry_point_inside(geometry, &point, FALSE);
3293 TRACE("-> %#x.\n", *contains);
3295 return S_OK;
3298 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_CompareWithGeometry(ID2D1PathGeometry *iface,
3299 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
3301 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
3302 iface, geometry, transform, tolerance, relation);
3304 return E_NOTIMPL;
3307 static void d2d_geometry_flatten_cubic(ID2D1SimplifiedGeometrySink *sink, const D2D1_POINT_2F *p0,
3308 const D2D1_BEZIER_SEGMENT *b, float tolerance)
3310 D2D1_BEZIER_SEGMENT b0, b1;
3311 D2D1_POINT_2F q;
3312 float d;
3314 /* It's certainly possible to calculate the maximum deviation of the
3315 * approximation from the curve, but it's a little involved. Instead, note
3316 * that if the control points were evenly spaced and collinear, p1 would
3317 * be exactly between p0 and p2, and p2 would be exactly between p1 and
3318 * p3. The deviation is a decent enough approximation, and much easier to
3319 * calculate.
3321 * p1' = (p0 + p2) / 2
3322 * p2' = (p1 + p3) / 2
3323 * d = ‖p1 - p1'‖₁ + ‖p2 - p2'‖₁ */
3324 d2d_point_lerp(&q, p0, &b->point2, 0.5f);
3325 d2d_point_subtract(&q, &b->point1, &q);
3326 d = fabsf(q.x) + fabsf(q.y);
3327 d2d_point_lerp(&q, &b->point1, &b->point3, 0.5f);
3328 d2d_point_subtract(&q, &b->point2, &q);
3329 d += fabsf(q.x) + fabsf(q.y);
3330 if (d < tolerance)
3332 ID2D1SimplifiedGeometrySink_AddLines(sink, &b->point3, 1);
3333 return;
3336 d2d_point_lerp(&q, &b->point1, &b->point2, 0.5f);
3338 b1.point3 = b->point3;
3339 d2d_point_lerp(&b1.point2, &b1.point3, &b->point2, 0.5f);
3340 d2d_point_lerp(&b1.point1, &b1.point2, &q, 0.5f);
3342 d2d_point_lerp(&b0.point1, p0, &b->point1, 0.5f);
3343 d2d_point_lerp(&b0.point2, &b0.point1, &q, 0.5f);
3344 d2d_point_lerp(&b0.point3, &b0.point2, &b1.point1, 0.5f);
3346 d2d_geometry_flatten_cubic(sink, p0, &b0, tolerance);
3347 ID2D1SimplifiedGeometrySink_SetSegmentFlags(sink, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN);
3348 d2d_geometry_flatten_cubic(sink, &b0.point3, &b1, tolerance);
3349 ID2D1SimplifiedGeometrySink_SetSegmentFlags(sink, D2D1_PATH_SEGMENT_NONE);
3352 static void d2d_geometry_simplify_quadratic(ID2D1SimplifiedGeometrySink *sink,
3353 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_POINT_2F *p0,
3354 const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2, float tolerance)
3356 D2D1_BEZIER_SEGMENT b;
3358 d2d_point_lerp(&b.point1, p0, p1, 2.0f / 3.0f);
3359 d2d_point_lerp(&b.point2, p2, p1, 2.0f / 3.0f);
3360 b.point3 = *p2;
3362 if (option == D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES)
3363 d2d_geometry_flatten_cubic(sink, p0, &b, tolerance);
3364 else
3365 ID2D1SimplifiedGeometrySink_AddBeziers(sink, &b, 1);
3368 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *iface,
3369 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
3370 ID2D1SimplifiedGeometrySink *sink)
3372 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3373 enum d2d_vertex_type type = D2D_VERTEX_TYPE_NONE;
3374 unsigned int i, j, bezier_idx;
3375 D2D1_FIGURE_BEGIN begin;
3376 D2D1_POINT_2F p, p1, p2;
3377 D2D1_FIGURE_END end;
3379 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
3380 iface, option, transform, tolerance, sink);
3382 ID2D1SimplifiedGeometrySink_SetFillMode(sink, geometry->u.path.fill_mode);
3383 for (i = 0; i < geometry->u.path.figure_count; ++i)
3385 const struct d2d_figure *figure = &geometry->u.path.figures[i];
3387 for (j = 0; j < figure->vertex_count; ++j)
3389 if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
3390 continue;
3392 p = figure->vertices[j];
3393 if (transform)
3394 d2d_point_transform(&p, transform, p.x, p.y);
3395 begin = figure->flags & D2D_FIGURE_FLAG_HOLLOW ? D2D1_FIGURE_BEGIN_HOLLOW : D2D1_FIGURE_BEGIN_FILLED;
3396 ID2D1SimplifiedGeometrySink_BeginFigure(sink, p, begin);
3397 type = figure->vertex_types[j];
3398 break;
3401 for (bezier_idx = 0, ++j; j < figure->vertex_count; ++j)
3403 if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE
3404 || figure->vertex_types[j] == D2D_VERTEX_TYPE_SPLIT_BEZIER)
3405 continue;
3407 switch (type)
3409 case D2D_VERTEX_TYPE_LINE:
3410 p = figure->vertices[j];
3411 if (transform)
3412 d2d_point_transform(&p, transform, p.x, p.y);
3413 ID2D1SimplifiedGeometrySink_AddLines(sink, &p, 1);
3414 break;
3416 case D2D_VERTEX_TYPE_BEZIER:
3417 p1 = figure->original_bezier_controls[bezier_idx++];
3418 if (transform)
3419 d2d_point_transform(&p1, transform, p1.x, p1.y);
3420 p2 = figure->vertices[j];
3421 if (transform)
3422 d2d_point_transform(&p2, transform, p2.x, p2.y);
3423 d2d_geometry_simplify_quadratic(sink, option, &p, &p1, &p2, tolerance);
3424 p = p2;
3425 break;
3427 default:
3428 FIXME("Unhandled vertex type %#x.\n", type);
3429 p = figure->vertices[j];
3430 if (transform)
3431 d2d_point_transform(&p, transform, p.x, p.y);
3432 ID2D1SimplifiedGeometrySink_AddLines(sink, &p, 1);
3433 break;
3436 type = figure->vertex_types[j];
3439 if (type == D2D_VERTEX_TYPE_BEZIER)
3441 p1 = figure->original_bezier_controls[bezier_idx++];
3442 if (transform)
3443 d2d_point_transform(&p1, transform, p1.x, p1.y);
3444 p2 = figure->vertices[0];
3445 if (transform)
3446 d2d_point_transform(&p2, transform, p2.x, p2.y);
3447 d2d_geometry_simplify_quadratic(sink, option, &p, &p1, &p2, tolerance);
3450 end = figure->flags & D2D_FIGURE_FLAG_CLOSED ? D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN;
3451 ID2D1SimplifiedGeometrySink_EndFigure(sink, end);
3454 return S_OK;
3457 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Tessellate(ID2D1PathGeometry *iface,
3458 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
3460 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
3462 return E_NOTIMPL;
3465 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_CombineWithGeometry(ID2D1PathGeometry *iface,
3466 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
3467 float tolerance, ID2D1SimplifiedGeometrySink *sink)
3469 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
3470 iface, geometry, combine_mode, transform, tolerance, sink);
3472 return E_NOTIMPL;
3475 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Outline(ID2D1PathGeometry *iface,
3476 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
3478 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
3480 return E_NOTIMPL;
3483 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeArea(ID2D1PathGeometry *iface,
3484 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
3486 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
3488 return E_NOTIMPL;
3491 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeLength(ID2D1PathGeometry *iface,
3492 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
3494 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
3496 return E_NOTIMPL;
3499 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputePointAtLength(ID2D1PathGeometry *iface, float length,
3500 const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point, D2D1_POINT_2F *tangent)
3502 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
3503 iface, length, transform, tolerance, point, tangent);
3505 return E_NOTIMPL;
3508 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Widen(ID2D1PathGeometry *iface, float stroke_width,
3509 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
3510 ID2D1SimplifiedGeometrySink *sink)
3512 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
3513 iface, stroke_width, stroke_style, transform, tolerance, sink);
3515 return E_NOTIMPL;
3518 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Open(ID2D1PathGeometry *iface, ID2D1GeometrySink **sink)
3520 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3522 TRACE("iface %p, sink %p.\n", iface, sink);
3524 if (geometry->u.path.state != D2D_GEOMETRY_STATE_INITIAL)
3525 return D2DERR_WRONG_STATE;
3527 *sink = &geometry->u.path.ID2D1GeometrySink_iface;
3528 ID2D1GeometrySink_AddRef(*sink);
3530 geometry->u.path.state = D2D_GEOMETRY_STATE_OPEN;
3532 return S_OK;
3535 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Stream(ID2D1PathGeometry *iface, ID2D1GeometrySink *sink)
3537 FIXME("iface %p, sink %p stub!\n", iface, sink);
3539 return E_NOTIMPL;
3542 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetSegmentCount(ID2D1PathGeometry *iface, UINT32 *count)
3544 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3546 TRACE("iface %p, count %p.\n", iface, count);
3548 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
3549 return D2DERR_WRONG_STATE;
3551 *count = geometry->u.path.segment_count;
3553 return S_OK;
3556 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetFigureCount(ID2D1PathGeometry *iface, UINT32 *count)
3558 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3560 TRACE("iface %p, count %p.\n", iface, count);
3562 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
3563 return D2DERR_WRONG_STATE;
3565 *count = geometry->u.path.figure_count;
3567 return S_OK;
3570 static const struct ID2D1PathGeometryVtbl d2d_path_geometry_vtbl =
3572 d2d_path_geometry_QueryInterface,
3573 d2d_path_geometry_AddRef,
3574 d2d_path_geometry_Release,
3575 d2d_path_geometry_GetFactory,
3576 d2d_path_geometry_GetBounds,
3577 d2d_path_geometry_GetWidenedBounds,
3578 d2d_path_geometry_StrokeContainsPoint,
3579 d2d_path_geometry_FillContainsPoint,
3580 d2d_path_geometry_CompareWithGeometry,
3581 d2d_path_geometry_Simplify,
3582 d2d_path_geometry_Tessellate,
3583 d2d_path_geometry_CombineWithGeometry,
3584 d2d_path_geometry_Outline,
3585 d2d_path_geometry_ComputeArea,
3586 d2d_path_geometry_ComputeLength,
3587 d2d_path_geometry_ComputePointAtLength,
3588 d2d_path_geometry_Widen,
3589 d2d_path_geometry_Open,
3590 d2d_path_geometry_Stream,
3591 d2d_path_geometry_GetSegmentCount,
3592 d2d_path_geometry_GetFigureCount,
3595 void d2d_path_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory)
3597 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl);
3598 geometry->u.path.ID2D1GeometrySink_iface.lpVtbl = &d2d_geometry_sink_vtbl;
3599 geometry->u.path.bounds.left = FLT_MAX;
3600 geometry->u.path.bounds.right = -FLT_MAX;
3601 geometry->u.path.bounds.top = FLT_MAX;
3602 geometry->u.path.bounds.bottom = -FLT_MAX;
3605 static inline struct d2d_geometry *impl_from_ID2D1EllipseGeometry(ID2D1EllipseGeometry *iface)
3607 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
3610 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_QueryInterface(ID2D1EllipseGeometry *iface,
3611 REFIID iid, void **out)
3613 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
3615 if (IsEqualGUID(iid, &IID_ID2D1EllipseGeometry)
3616 || IsEqualGUID(iid, &IID_ID2D1Geometry)
3617 || IsEqualGUID(iid, &IID_ID2D1Resource)
3618 || IsEqualGUID(iid, &IID_IUnknown))
3620 ID2D1EllipseGeometry_AddRef(iface);
3621 *out = iface;
3622 return S_OK;
3625 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
3627 *out = NULL;
3628 return E_NOINTERFACE;
3631 static ULONG STDMETHODCALLTYPE d2d_ellipse_geometry_AddRef(ID2D1EllipseGeometry *iface)
3633 struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface);
3634 ULONG refcount = InterlockedIncrement(&geometry->refcount);
3636 TRACE("%p increasing refcount to %u.\n", iface, refcount);
3638 return refcount;
3641 static ULONG STDMETHODCALLTYPE d2d_ellipse_geometry_Release(ID2D1EllipseGeometry *iface)
3643 struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface);
3644 ULONG refcount = InterlockedDecrement(&geometry->refcount);
3646 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
3648 if (!refcount)
3650 d2d_geometry_cleanup(geometry);
3651 heap_free(geometry);
3654 return refcount;
3657 static void STDMETHODCALLTYPE d2d_ellipse_geometry_GetFactory(ID2D1EllipseGeometry *iface, ID2D1Factory **factory)
3659 struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface);
3661 TRACE("iface %p, factory %p.\n", iface, factory);
3663 ID2D1Factory_AddRef(*factory = geometry->factory);
3666 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_GetBounds(ID2D1EllipseGeometry *iface,
3667 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
3669 FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
3671 return E_NOTIMPL;
3674 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_GetWidenedBounds(ID2D1EllipseGeometry *iface,
3675 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
3676 float tolerance, D2D1_RECT_F *bounds)
3678 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
3679 iface, stroke_width, stroke_style, transform, tolerance, bounds);
3681 return E_NOTIMPL;
3684 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_StrokeContainsPoint(ID2D1EllipseGeometry *iface,
3685 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
3686 float tolerance, BOOL *contains)
3688 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p stub!\n",
3689 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
3691 return E_NOTIMPL;
3694 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_FillContainsPoint(ID2D1EllipseGeometry *iface,
3695 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
3697 FIXME("iface %p, point %s, transform %p, tolerance %.8e, contains %p stub!\n",
3698 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
3700 return E_NOTIMPL;
3703 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_CompareWithGeometry(ID2D1EllipseGeometry *iface,
3704 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
3706 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
3707 iface, geometry, transform, tolerance, relation);
3709 return E_NOTIMPL;
3712 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Simplify(ID2D1EllipseGeometry *iface,
3713 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
3714 ID2D1SimplifiedGeometrySink *sink)
3716 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
3717 iface, option, transform, tolerance, sink);
3719 return E_NOTIMPL;
3722 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Tessellate(ID2D1EllipseGeometry *iface,
3723 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
3725 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
3727 return E_NOTIMPL;
3730 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_CombineWithGeometry(ID2D1EllipseGeometry *iface,
3731 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
3732 float tolerance, ID2D1SimplifiedGeometrySink *sink)
3734 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
3735 iface, geometry, combine_mode, transform, tolerance, sink);
3737 return E_NOTIMPL;
3740 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Outline(ID2D1EllipseGeometry *iface,
3741 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
3743 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
3745 return E_NOTIMPL;
3748 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_ComputeArea(ID2D1EllipseGeometry *iface,
3749 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
3751 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
3753 return E_NOTIMPL;
3756 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_ComputeLength(ID2D1EllipseGeometry *iface,
3757 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
3759 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
3761 return E_NOTIMPL;
3764 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_ComputePointAtLength(ID2D1EllipseGeometry *iface,
3765 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
3766 D2D1_POINT_2F *tangent)
3768 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
3769 iface, length, transform, tolerance, point, tangent);
3771 return E_NOTIMPL;
3774 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Widen(ID2D1EllipseGeometry *iface, float stroke_width,
3775 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
3776 ID2D1SimplifiedGeometrySink *sink)
3778 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
3779 iface, stroke_width, stroke_style, transform, tolerance, sink);
3781 return E_NOTIMPL;
3784 static void STDMETHODCALLTYPE d2d_ellipse_geometry_GetEllipse(ID2D1EllipseGeometry *iface, D2D1_ELLIPSE *ellipse)
3786 struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface);
3788 TRACE("iface %p, ellipse %p.\n", iface, ellipse);
3790 *ellipse = geometry->u.ellipse.ellipse;
3793 static const struct ID2D1EllipseGeometryVtbl d2d_ellipse_geometry_vtbl =
3795 d2d_ellipse_geometry_QueryInterface,
3796 d2d_ellipse_geometry_AddRef,
3797 d2d_ellipse_geometry_Release,
3798 d2d_ellipse_geometry_GetFactory,
3799 d2d_ellipse_geometry_GetBounds,
3800 d2d_ellipse_geometry_GetWidenedBounds,
3801 d2d_ellipse_geometry_StrokeContainsPoint,
3802 d2d_ellipse_geometry_FillContainsPoint,
3803 d2d_ellipse_geometry_CompareWithGeometry,
3804 d2d_ellipse_geometry_Simplify,
3805 d2d_ellipse_geometry_Tessellate,
3806 d2d_ellipse_geometry_CombineWithGeometry,
3807 d2d_ellipse_geometry_Outline,
3808 d2d_ellipse_geometry_ComputeArea,
3809 d2d_ellipse_geometry_ComputeLength,
3810 d2d_ellipse_geometry_ComputePointAtLength,
3811 d2d_ellipse_geometry_Widen,
3812 d2d_ellipse_geometry_GetEllipse,
3815 HRESULT d2d_ellipse_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_ELLIPSE *ellipse)
3817 D2D1_POINT_2F *v, v1, v2, v3, v4;
3818 struct d2d_face *f;
3819 float l, r, t, b;
3821 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_ellipse_geometry_vtbl);
3822 geometry->u.ellipse.ellipse = *ellipse;
3824 if (!(geometry->fill.vertices = heap_alloc(4 * sizeof(*geometry->fill.vertices))))
3825 goto fail;
3826 if (!d2d_array_reserve((void **)&geometry->fill.faces,
3827 &geometry->fill.faces_size, 2, sizeof(*geometry->fill.faces)))
3828 goto fail;
3830 l = ellipse->point.x - ellipse->radiusX;
3831 r = ellipse->point.x + ellipse->radiusX;
3832 t = ellipse->point.y - ellipse->radiusY;
3833 b = ellipse->point.y + ellipse->radiusY;
3835 d2d_point_set(&v1, r, t);
3836 d2d_point_set(&v2, r, b);
3837 d2d_point_set(&v3, l, b);
3838 d2d_point_set(&v4, l, t);
3840 v = geometry->fill.vertices;
3841 d2d_point_set(&v[0], ellipse->point.x, t);
3842 d2d_point_set(&v[1], r, ellipse->point.y);
3843 d2d_point_set(&v[2], ellipse->point.x, b);
3844 d2d_point_set(&v[3], l, ellipse->point.y);
3845 geometry->fill.vertex_count = 4;
3847 f = geometry->fill.faces;
3848 d2d_face_set(&f[0], 0, 3, 2);
3849 d2d_face_set(&f[1], 0, 2, 1);
3850 geometry->fill.face_count = 2;
3852 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[0], &v1, &v[1]))
3853 goto fail;
3854 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[1], &v2, &v[2]))
3855 goto fail;
3856 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[2], &v3, &v[3]))
3857 goto fail;
3858 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[3], &v4, &v[0]))
3859 goto fail;
3861 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[0], &v1, &v[1]))
3862 goto fail;
3863 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[1], &v2, &v[2]))
3864 goto fail;
3865 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[2], &v3, &v[3]))
3866 goto fail;
3867 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[3], &v4, &v[0]))
3868 goto fail;
3870 return S_OK;
3872 fail:
3873 d2d_geometry_cleanup(geometry);
3874 return E_OUTOFMEMORY;
3877 static inline struct d2d_geometry *impl_from_ID2D1RectangleGeometry(ID2D1RectangleGeometry *iface)
3879 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
3882 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_QueryInterface(ID2D1RectangleGeometry *iface,
3883 REFIID iid, void **out)
3885 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
3887 if (IsEqualGUID(iid, &IID_ID2D1RectangleGeometry)
3888 || IsEqualGUID(iid, &IID_ID2D1Geometry)
3889 || IsEqualGUID(iid, &IID_ID2D1Resource)
3890 || IsEqualGUID(iid, &IID_IUnknown))
3892 ID2D1RectangleGeometry_AddRef(iface);
3893 *out = iface;
3894 return S_OK;
3897 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
3899 *out = NULL;
3900 return E_NOINTERFACE;
3903 static ULONG STDMETHODCALLTYPE d2d_rectangle_geometry_AddRef(ID2D1RectangleGeometry *iface)
3905 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
3906 ULONG refcount = InterlockedIncrement(&geometry->refcount);
3908 TRACE("%p increasing refcount to %u.\n", iface, refcount);
3910 return refcount;
3913 static ULONG STDMETHODCALLTYPE d2d_rectangle_geometry_Release(ID2D1RectangleGeometry *iface)
3915 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
3916 ULONG refcount = InterlockedDecrement(&geometry->refcount);
3918 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
3920 if (!refcount)
3922 d2d_geometry_cleanup(geometry);
3923 heap_free(geometry);
3926 return refcount;
3929 static void STDMETHODCALLTYPE d2d_rectangle_geometry_GetFactory(ID2D1RectangleGeometry *iface, ID2D1Factory **factory)
3931 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
3933 TRACE("iface %p, factory %p.\n", iface, factory);
3935 ID2D1Factory_AddRef(*factory = geometry->factory);
3938 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_GetBounds(ID2D1RectangleGeometry *iface,
3939 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
3941 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
3942 D2D1_RECT_F *rect;
3943 D2D1_POINT_2F p;
3945 TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
3947 rect = &geometry->u.rectangle.rect;
3948 if (!transform)
3950 *bounds = *rect;
3951 return S_OK;
3954 bounds->left = FLT_MAX;
3955 bounds->top = FLT_MAX;
3956 bounds->right = -FLT_MAX;
3957 bounds->bottom = -FLT_MAX;
3959 d2d_point_transform(&p, transform, rect->left, rect->top);
3960 d2d_rect_expand(bounds, &p);
3961 d2d_point_transform(&p, transform, rect->left, rect->bottom);
3962 d2d_rect_expand(bounds, &p);
3963 d2d_point_transform(&p, transform, rect->right, rect->bottom);
3964 d2d_rect_expand(bounds, &p);
3965 d2d_point_transform(&p, transform, rect->right, rect->top);
3966 d2d_rect_expand(bounds, &p);
3968 return S_OK;
3971 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_GetWidenedBounds(ID2D1RectangleGeometry *iface,
3972 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
3973 float tolerance, D2D1_RECT_F *bounds)
3975 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
3976 iface, stroke_width, stroke_style, transform, tolerance, bounds);
3978 return E_NOTIMPL;
3981 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_StrokeContainsPoint(ID2D1RectangleGeometry *iface,
3982 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
3983 float tolerance, BOOL *contains)
3985 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p stub!\n",
3986 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
3988 return E_NOTIMPL;
3991 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_FillContainsPoint(ID2D1RectangleGeometry *iface,
3992 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
3994 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
3995 D2D1_RECT_F *rect = &geometry->u.rectangle.rect;
3996 float dx, dy;
3998 TRACE("iface %p, point %s, transform %p, tolerance %.8e, contains %p.\n",
3999 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
4001 if (transform)
4003 D2D1_MATRIX_3X2_F g_i;
4005 if (!d2d_matrix_invert(&g_i, transform))
4006 return D2DERR_UNSUPPORTED_OPERATION;
4007 d2d_point_transform(&point, &g_i, point.x, point.y);
4010 if (tolerance == 0.0f)
4011 tolerance = D2D1_DEFAULT_FLATTENING_TOLERANCE;
4013 dx = max(fabsf((rect->right + rect->left) / 2.0f - point.x) - (rect->right - rect->left) / 2.0f, 0.0f);
4014 dy = max(fabsf((rect->bottom + rect->top) / 2.0f - point.y) - (rect->bottom - rect->top) / 2.0f, 0.0f);
4016 *contains = tolerance * tolerance > (dx * dx + dy * dy);
4017 return S_OK;
4020 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_CompareWithGeometry(ID2D1RectangleGeometry *iface,
4021 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
4023 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
4024 iface, geometry, transform, tolerance, relation);
4026 return E_NOTIMPL;
4029 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Simplify(ID2D1RectangleGeometry *iface,
4030 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4031 ID2D1SimplifiedGeometrySink *sink)
4033 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4034 D2D1_RECT_F *rect = &geometry->u.rectangle.rect;
4035 D2D1_POINT_2F p[4];
4036 unsigned int i;
4038 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
4039 iface, option, transform, tolerance, sink);
4041 d2d_point_set(&p[0], rect->left, rect->top);
4042 d2d_point_set(&p[1], rect->right, rect->top);
4043 d2d_point_set(&p[2], rect->right, rect->bottom);
4044 d2d_point_set(&p[3], rect->left, rect->bottom);
4046 if (transform)
4048 for (i = 0; i < ARRAY_SIZE(p); ++i)
4050 d2d_point_transform(&p[i], transform, p[i].x, p[i].y);
4054 ID2D1SimplifiedGeometrySink_SetFillMode(sink, D2D1_FILL_MODE_ALTERNATE);
4055 ID2D1SimplifiedGeometrySink_BeginFigure(sink, p[0], D2D1_FIGURE_BEGIN_FILLED);
4056 ID2D1SimplifiedGeometrySink_AddLines(sink, &p[1], 3);
4057 ID2D1SimplifiedGeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
4059 return S_OK;
4062 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Tessellate(ID2D1RectangleGeometry *iface,
4063 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
4065 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4067 return E_NOTIMPL;
4070 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_CombineWithGeometry(ID2D1RectangleGeometry *iface,
4071 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
4072 float tolerance, ID2D1SimplifiedGeometrySink *sink)
4074 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4075 iface, geometry, combine_mode, transform, tolerance, sink);
4077 return E_NOTIMPL;
4080 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Outline(ID2D1RectangleGeometry *iface,
4081 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
4083 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4085 return E_NOTIMPL;
4088 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputeArea(ID2D1RectangleGeometry *iface,
4089 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
4091 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
4093 return E_NOTIMPL;
4096 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputeLength(ID2D1RectangleGeometry *iface,
4097 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
4099 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
4101 return E_NOTIMPL;
4104 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputePointAtLength(ID2D1RectangleGeometry *iface,
4105 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
4106 D2D1_POINT_2F *tangent)
4108 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
4109 iface, length, transform, tolerance, point, tangent);
4111 return E_NOTIMPL;
4114 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Widen(ID2D1RectangleGeometry *iface, float stroke_width,
4115 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4116 ID2D1SimplifiedGeometrySink *sink)
4118 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
4119 iface, stroke_width, stroke_style, transform, tolerance, sink);
4121 return E_NOTIMPL;
4124 static void STDMETHODCALLTYPE d2d_rectangle_geometry_GetRect(ID2D1RectangleGeometry *iface, D2D1_RECT_F *rect)
4126 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4128 TRACE("iface %p, rect %p.\n", iface, rect);
4130 *rect = geometry->u.rectangle.rect;
4133 static const struct ID2D1RectangleGeometryVtbl d2d_rectangle_geometry_vtbl =
4135 d2d_rectangle_geometry_QueryInterface,
4136 d2d_rectangle_geometry_AddRef,
4137 d2d_rectangle_geometry_Release,
4138 d2d_rectangle_geometry_GetFactory,
4139 d2d_rectangle_geometry_GetBounds,
4140 d2d_rectangle_geometry_GetWidenedBounds,
4141 d2d_rectangle_geometry_StrokeContainsPoint,
4142 d2d_rectangle_geometry_FillContainsPoint,
4143 d2d_rectangle_geometry_CompareWithGeometry,
4144 d2d_rectangle_geometry_Simplify,
4145 d2d_rectangle_geometry_Tessellate,
4146 d2d_rectangle_geometry_CombineWithGeometry,
4147 d2d_rectangle_geometry_Outline,
4148 d2d_rectangle_geometry_ComputeArea,
4149 d2d_rectangle_geometry_ComputeLength,
4150 d2d_rectangle_geometry_ComputePointAtLength,
4151 d2d_rectangle_geometry_Widen,
4152 d2d_rectangle_geometry_GetRect,
4155 HRESULT d2d_rectangle_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_RECT_F *rect)
4157 struct d2d_face *f;
4158 D2D1_POINT_2F *v;
4159 float l, r, t, b;
4161 static const D2D1_POINT_2F prev[] =
4163 { 1.0f, 0.0f},
4164 { 0.0f, -1.0f},
4165 {-1.0f, 0.0f},
4166 { 0.0f, 1.0f},
4168 static const D2D1_POINT_2F next[] =
4170 { 0.0f, 1.0f},
4171 { 1.0f, 0.0f},
4172 { 0.0f, -1.0f},
4173 {-1.0f, 0.0f},
4176 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl);
4177 geometry->u.rectangle.rect = *rect;
4179 if (!(geometry->fill.vertices = heap_alloc(4 * sizeof(*geometry->fill.vertices))))
4180 goto fail;
4181 if (!d2d_array_reserve((void **)&geometry->fill.faces,
4182 &geometry->fill.faces_size, 2, sizeof(*geometry->fill.faces)))
4183 goto fail;
4185 l = min(rect->left, rect->right);
4186 r = max(rect->left, rect->right);
4187 t = min(rect->top, rect->bottom);
4188 b = max(rect->top, rect->bottom);
4190 v = geometry->fill.vertices;
4191 d2d_point_set(&v[0], l, t);
4192 d2d_point_set(&v[1], l, b);
4193 d2d_point_set(&v[2], r, b);
4194 d2d_point_set(&v[3], r, t);
4195 geometry->fill.vertex_count = 4;
4197 f = geometry->fill.faces;
4198 d2d_face_set(&f[0], 1, 2, 0);
4199 d2d_face_set(&f[1], 0, 2, 3);
4200 geometry->fill.face_count = 2;
4202 if (!d2d_geometry_outline_add_line_segment(geometry, &v[0], &v[1]))
4203 goto fail;
4204 if (!d2d_geometry_outline_add_line_segment(geometry, &v[1], &v[2]))
4205 goto fail;
4206 if (!d2d_geometry_outline_add_line_segment(geometry, &v[2], &v[3]))
4207 goto fail;
4208 if (!d2d_geometry_outline_add_line_segment(geometry, &v[3], &v[0]))
4209 goto fail;
4211 if (!d2d_geometry_outline_add_join(geometry, &prev[0], &v[0], &next[0]))
4212 goto fail;
4213 if (!d2d_geometry_outline_add_join(geometry, &prev[1], &v[1], &next[1]))
4214 goto fail;
4215 if (!d2d_geometry_outline_add_join(geometry, &prev[2], &v[2], &next[2]))
4216 goto fail;
4217 if (!d2d_geometry_outline_add_join(geometry, &prev[3], &v[3], &next[3]))
4218 goto fail;
4220 return S_OK;
4222 fail:
4223 d2d_geometry_cleanup(geometry);
4224 return E_OUTOFMEMORY;
4227 static inline struct d2d_geometry *impl_from_ID2D1RoundedRectangleGeometry(ID2D1RoundedRectangleGeometry *iface)
4229 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
4232 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_QueryInterface(ID2D1RoundedRectangleGeometry *iface,
4233 REFIID iid, void **out)
4235 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
4237 if (IsEqualGUID(iid, &IID_ID2D1RoundedRectangleGeometry)
4238 || IsEqualGUID(iid, &IID_ID2D1Geometry)
4239 || IsEqualGUID(iid, &IID_ID2D1Resource)
4240 || IsEqualGUID(iid, &IID_IUnknown))
4242 ID2D1RoundedRectangleGeometry_AddRef(iface);
4243 *out = iface;
4244 return S_OK;
4247 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
4249 *out = NULL;
4250 return E_NOINTERFACE;
4253 static ULONG STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_AddRef(ID2D1RoundedRectangleGeometry *iface)
4255 struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface);
4256 ULONG refcount = InterlockedIncrement(&geometry->refcount);
4258 TRACE("%p increasing refcount to %u.\n", iface, refcount);
4260 return refcount;
4263 static ULONG STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Release(ID2D1RoundedRectangleGeometry *iface)
4265 struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface);
4266 ULONG refcount = InterlockedDecrement(&geometry->refcount);
4268 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
4270 if (!refcount)
4272 d2d_geometry_cleanup(geometry);
4273 heap_free(geometry);
4276 return refcount;
4279 static void STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetFactory(ID2D1RoundedRectangleGeometry *iface,
4280 ID2D1Factory **factory)
4282 struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface);
4284 TRACE("iface %p, factory %p.\n", iface, factory);
4286 ID2D1Factory_AddRef(*factory = geometry->factory);
4289 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetBounds(ID2D1RoundedRectangleGeometry *iface,
4290 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
4292 FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
4294 return E_NOTIMPL;
4297 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetWidenedBounds(ID2D1RoundedRectangleGeometry *iface,
4298 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4299 float tolerance, D2D1_RECT_F *bounds)
4301 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
4302 iface, stroke_width, stroke_style, transform, tolerance, bounds);
4304 return E_NOTIMPL;
4307 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_StrokeContainsPoint(
4308 ID2D1RoundedRectangleGeometry *iface, D2D1_POINT_2F point, float stroke_width,
4309 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
4311 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p stub!\n",
4312 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
4314 return E_NOTIMPL;
4317 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_FillContainsPoint(ID2D1RoundedRectangleGeometry *iface,
4318 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
4320 FIXME("iface %p, point %s, transform %p, tolerance %.8e, contains %p stub!\n",
4321 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
4323 return E_NOTIMPL;
4326 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_CompareWithGeometry(
4327 ID2D1RoundedRectangleGeometry *iface, ID2D1Geometry *geometry,
4328 const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
4330 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
4331 iface, geometry, transform, tolerance, relation);
4333 return E_NOTIMPL;
4336 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Simplify(ID2D1RoundedRectangleGeometry *iface,
4337 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4338 ID2D1SimplifiedGeometrySink *sink)
4340 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4341 iface, option, transform, tolerance, sink);
4343 return E_NOTIMPL;
4346 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Tessellate(ID2D1RoundedRectangleGeometry *iface,
4347 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
4349 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4351 return E_NOTIMPL;
4354 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_CombineWithGeometry(
4355 ID2D1RoundedRectangleGeometry *iface, ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode,
4356 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
4358 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4359 iface, geometry, combine_mode, transform, tolerance, sink);
4361 return E_NOTIMPL;
4364 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Outline(ID2D1RoundedRectangleGeometry *iface,
4365 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
4367 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4369 return E_NOTIMPL;
4372 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_ComputeArea(ID2D1RoundedRectangleGeometry *iface,
4373 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
4375 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
4377 return E_NOTIMPL;
4380 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_ComputeLength(ID2D1RoundedRectangleGeometry *iface,
4381 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
4383 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
4385 return E_NOTIMPL;
4388 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_ComputePointAtLength(
4389 ID2D1RoundedRectangleGeometry *iface, float length, const D2D1_MATRIX_3X2_F *transform,
4390 float tolerance, D2D1_POINT_2F *point, D2D1_POINT_2F *tangent)
4392 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
4393 iface, length, transform, tolerance, point, tangent);
4395 return E_NOTIMPL;
4398 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Widen(ID2D1RoundedRectangleGeometry *iface,
4399 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4400 float tolerance, ID2D1SimplifiedGeometrySink *sink)
4402 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
4403 iface, stroke_width, stroke_style, transform, tolerance, sink);
4405 return E_NOTIMPL;
4408 static void STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetRoundedRect(ID2D1RoundedRectangleGeometry *iface,
4409 D2D1_ROUNDED_RECT *rounded_rect)
4411 struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface);
4413 TRACE("iface %p, rounded_rect %p.\n", iface, rounded_rect);
4415 *rounded_rect = geometry->u.rounded_rectangle.rounded_rect;
4418 static const struct ID2D1RoundedRectangleGeometryVtbl d2d_rounded_rectangle_geometry_vtbl =
4420 d2d_rounded_rectangle_geometry_QueryInterface,
4421 d2d_rounded_rectangle_geometry_AddRef,
4422 d2d_rounded_rectangle_geometry_Release,
4423 d2d_rounded_rectangle_geometry_GetFactory,
4424 d2d_rounded_rectangle_geometry_GetBounds,
4425 d2d_rounded_rectangle_geometry_GetWidenedBounds,
4426 d2d_rounded_rectangle_geometry_StrokeContainsPoint,
4427 d2d_rounded_rectangle_geometry_FillContainsPoint,
4428 d2d_rounded_rectangle_geometry_CompareWithGeometry,
4429 d2d_rounded_rectangle_geometry_Simplify,
4430 d2d_rounded_rectangle_geometry_Tessellate,
4431 d2d_rounded_rectangle_geometry_CombineWithGeometry,
4432 d2d_rounded_rectangle_geometry_Outline,
4433 d2d_rounded_rectangle_geometry_ComputeArea,
4434 d2d_rounded_rectangle_geometry_ComputeLength,
4435 d2d_rounded_rectangle_geometry_ComputePointAtLength,
4436 d2d_rounded_rectangle_geometry_Widen,
4437 d2d_rounded_rectangle_geometry_GetRoundedRect,
4440 HRESULT d2d_rounded_rectangle_geometry_init(struct d2d_geometry *geometry,
4441 ID2D1Factory *factory, const D2D1_ROUNDED_RECT *rounded_rect)
4443 D2D1_POINT_2F *v, v1, v2, v3, v4;
4444 struct d2d_face *f;
4445 float l, r, t, b;
4446 float rx, ry;
4448 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rounded_rectangle_geometry_vtbl);
4449 geometry->u.rounded_rectangle.rounded_rect = *rounded_rect;
4451 if (!(geometry->fill.vertices = heap_alloc(8 * sizeof(*geometry->fill.vertices))))
4452 goto fail;
4453 if (!d2d_array_reserve((void **)&geometry->fill.faces,
4454 &geometry->fill.faces_size, 6, sizeof(*geometry->fill.faces)))
4455 goto fail;
4457 l = min(rounded_rect->rect.left, rounded_rect->rect.right);
4458 r = max(rounded_rect->rect.left, rounded_rect->rect.right);
4459 t = min(rounded_rect->rect.top, rounded_rect->rect.bottom);
4460 b = max(rounded_rect->rect.top, rounded_rect->rect.bottom);
4462 rx = min(rounded_rect->radiusX, 0.5f * (r - l));
4463 ry = min(rounded_rect->radiusY, 0.5f * (b - t));
4465 d2d_point_set(&v1, r, t);
4466 d2d_point_set(&v2, r, b);
4467 d2d_point_set(&v3, l, b);
4468 d2d_point_set(&v4, l, t);
4470 v = geometry->fill.vertices;
4471 d2d_point_set(&v[0], l + rx, t);
4472 d2d_point_set(&v[1], r - rx, t);
4473 d2d_point_set(&v[2], r, t + ry);
4474 d2d_point_set(&v[3], r, b - ry);
4475 d2d_point_set(&v[4], r - rx, b);
4476 d2d_point_set(&v[5], l + rx, b);
4477 d2d_point_set(&v[6], l, b - ry);
4478 d2d_point_set(&v[7], l, t + ry);
4479 geometry->fill.vertex_count = 8;
4481 f = geometry->fill.faces;
4482 d2d_face_set(&f[0], 0, 7, 6);
4483 d2d_face_set(&f[1], 0, 6, 5);
4484 d2d_face_set(&f[2], 0, 5, 4);
4485 d2d_face_set(&f[3], 0, 4, 1);
4486 d2d_face_set(&f[4], 1, 4, 3);
4487 d2d_face_set(&f[5], 1, 3, 2);
4488 geometry->fill.face_count = 6;
4490 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[1], &v1, &v[2]))
4491 goto fail;
4492 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[3], &v2, &v[4]))
4493 goto fail;
4494 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[5], &v3, &v[6]))
4495 goto fail;
4496 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[7], &v4, &v[0]))
4497 goto fail;
4499 if (!d2d_geometry_outline_add_line_segment(geometry, &v[0], &v[1]))
4500 goto fail;
4501 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[1], &v1, &v[2]))
4502 goto fail;
4503 if (!d2d_geometry_outline_add_line_segment(geometry, &v[2], &v[3]))
4504 goto fail;
4505 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[3], &v2, &v[4]))
4506 goto fail;
4507 if (!d2d_geometry_outline_add_line_segment(geometry, &v[4], &v[5]))
4508 goto fail;
4509 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[5], &v3, &v[6]))
4510 goto fail;
4511 if (!d2d_geometry_outline_add_line_segment(geometry, &v[6], &v[7]))
4512 goto fail;
4513 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[7], &v4, &v[0]))
4514 goto fail;
4516 return S_OK;
4518 fail:
4519 d2d_geometry_cleanup(geometry);
4520 return E_OUTOFMEMORY;
4523 static inline struct d2d_geometry *impl_from_ID2D1TransformedGeometry(ID2D1TransformedGeometry *iface)
4525 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
4528 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_QueryInterface(ID2D1TransformedGeometry *iface,
4529 REFIID iid, void **out)
4531 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
4533 if (IsEqualGUID(iid, &IID_ID2D1TransformedGeometry)
4534 || IsEqualGUID(iid, &IID_ID2D1Geometry)
4535 || IsEqualGUID(iid, &IID_ID2D1Resource)
4536 || IsEqualGUID(iid, &IID_IUnknown))
4538 ID2D1TransformedGeometry_AddRef(iface);
4539 *out = iface;
4540 return S_OK;
4543 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
4545 *out = NULL;
4546 return E_NOINTERFACE;
4549 static ULONG STDMETHODCALLTYPE d2d_transformed_geometry_AddRef(ID2D1TransformedGeometry *iface)
4551 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4552 ULONG refcount = InterlockedIncrement(&geometry->refcount);
4554 TRACE("%p increasing refcount to %u.\n", iface, refcount);
4556 return refcount;
4559 static ULONG STDMETHODCALLTYPE d2d_transformed_geometry_Release(ID2D1TransformedGeometry *iface)
4561 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4562 ULONG refcount = InterlockedDecrement(&geometry->refcount);
4564 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
4566 if (!refcount)
4568 geometry->outline.arc_faces = NULL;
4569 geometry->outline.arcs = NULL;
4570 geometry->outline.bezier_faces = NULL;
4571 geometry->outline.beziers = NULL;
4572 geometry->outline.faces = NULL;
4573 geometry->outline.vertices = NULL;
4574 geometry->fill.arc_vertices = NULL;
4575 geometry->fill.bezier_vertices = NULL;
4576 geometry->fill.faces = NULL;
4577 geometry->fill.vertices = NULL;
4578 ID2D1Geometry_Release(geometry->u.transformed.src_geometry);
4579 d2d_geometry_cleanup(geometry);
4580 heap_free(geometry);
4583 return refcount;
4586 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetFactory(ID2D1TransformedGeometry *iface,
4587 ID2D1Factory **factory)
4589 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4591 TRACE("iface %p, factory %p.\n", iface, factory);
4593 ID2D1Factory_AddRef(*factory = geometry->factory);
4596 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_GetBounds(ID2D1TransformedGeometry *iface,
4597 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
4599 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4600 D2D1_MATRIX_3X2_F g;
4602 TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
4604 g = geometry->transform;
4605 if (transform)
4606 d2d_matrix_multiply(&g, transform);
4608 return ID2D1Geometry_GetBounds(geometry->u.transformed.src_geometry, &g, bounds);
4611 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_GetWidenedBounds(ID2D1TransformedGeometry *iface,
4612 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4613 float tolerance, D2D1_RECT_F *bounds)
4615 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
4616 iface, stroke_width, stroke_style, transform, tolerance, bounds);
4618 return E_NOTIMPL;
4621 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_StrokeContainsPoint(ID2D1TransformedGeometry *iface,
4622 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4623 float tolerance, BOOL *contains)
4625 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4626 D2D1_MATRIX_3X2_F g;
4628 TRACE("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p.\n",
4629 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
4631 g = geometry->transform;
4632 if (transform)
4633 d2d_matrix_multiply(&g, transform);
4635 return ID2D1Geometry_StrokeContainsPoint(geometry->u.transformed.src_geometry, point, stroke_width, stroke_style,
4636 &g, tolerance, contains);
4639 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_FillContainsPoint(ID2D1TransformedGeometry *iface,
4640 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
4642 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4643 D2D1_MATRIX_3X2_F g;
4645 TRACE("iface %p, point %s, transform %p, tolerance %.8e, contains %p.\n",
4646 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
4648 g = geometry->transform;
4649 if (transform)
4650 d2d_matrix_multiply(&g, transform);
4652 return ID2D1Geometry_FillContainsPoint(geometry->u.transformed.src_geometry, point, &g, tolerance, contains);
4655 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_CompareWithGeometry(ID2D1TransformedGeometry *iface,
4656 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
4658 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
4659 iface, geometry, transform, tolerance, relation);
4661 return E_NOTIMPL;
4664 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Simplify(ID2D1TransformedGeometry *iface,
4665 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4666 ID2D1SimplifiedGeometrySink *sink)
4668 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4669 D2D1_MATRIX_3X2_F g;
4671 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
4672 iface, option, transform, tolerance, sink);
4674 g = geometry->transform;
4675 if (transform)
4676 d2d_matrix_multiply(&g, transform);
4678 return ID2D1Geometry_Simplify(geometry->u.transformed.src_geometry, option, &g, tolerance, sink);
4681 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Tessellate(ID2D1TransformedGeometry *iface,
4682 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
4684 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4686 return E_NOTIMPL;
4689 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_CombineWithGeometry(ID2D1TransformedGeometry *iface,
4690 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
4691 float tolerance, ID2D1SimplifiedGeometrySink *sink)
4693 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4694 iface, geometry, combine_mode, transform, tolerance, sink);
4696 return E_NOTIMPL;
4699 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Outline(ID2D1TransformedGeometry *iface,
4700 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
4702 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4704 return E_NOTIMPL;
4707 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputeArea(ID2D1TransformedGeometry *iface,
4708 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
4710 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
4712 return E_NOTIMPL;
4715 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputeLength(ID2D1TransformedGeometry *iface,
4716 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
4718 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
4720 return E_NOTIMPL;
4723 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputePointAtLength(ID2D1TransformedGeometry *iface,
4724 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
4725 D2D1_POINT_2F *tangent)
4727 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
4728 iface, length, transform, tolerance, point, tangent);
4730 return E_NOTIMPL;
4733 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Widen(ID2D1TransformedGeometry *iface, float stroke_width,
4734 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4735 ID2D1SimplifiedGeometrySink *sink)
4737 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
4738 iface, stroke_width, stroke_style, transform, tolerance, sink);
4740 return E_NOTIMPL;
4743 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetSourceGeometry(ID2D1TransformedGeometry *iface,
4744 ID2D1Geometry **src_geometry)
4746 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4748 TRACE("iface %p, src_geometry %p.\n", iface, src_geometry);
4750 ID2D1Geometry_AddRef(*src_geometry = geometry->u.transformed.src_geometry);
4753 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetTransform(ID2D1TransformedGeometry *iface,
4754 D2D1_MATRIX_3X2_F *transform)
4756 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4758 TRACE("iface %p, transform %p.\n", iface, transform);
4760 *transform = geometry->u.transformed.transform;
4763 static const struct ID2D1TransformedGeometryVtbl d2d_transformed_geometry_vtbl =
4765 d2d_transformed_geometry_QueryInterface,
4766 d2d_transformed_geometry_AddRef,
4767 d2d_transformed_geometry_Release,
4768 d2d_transformed_geometry_GetFactory,
4769 d2d_transformed_geometry_GetBounds,
4770 d2d_transformed_geometry_GetWidenedBounds,
4771 d2d_transformed_geometry_StrokeContainsPoint,
4772 d2d_transformed_geometry_FillContainsPoint,
4773 d2d_transformed_geometry_CompareWithGeometry,
4774 d2d_transformed_geometry_Simplify,
4775 d2d_transformed_geometry_Tessellate,
4776 d2d_transformed_geometry_CombineWithGeometry,
4777 d2d_transformed_geometry_Outline,
4778 d2d_transformed_geometry_ComputeArea,
4779 d2d_transformed_geometry_ComputeLength,
4780 d2d_transformed_geometry_ComputePointAtLength,
4781 d2d_transformed_geometry_Widen,
4782 d2d_transformed_geometry_GetSourceGeometry,
4783 d2d_transformed_geometry_GetTransform,
4786 void d2d_transformed_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
4787 ID2D1Geometry *src_geometry, const D2D_MATRIX_3X2_F *transform)
4789 struct d2d_geometry *src_impl;
4790 D2D_MATRIX_3X2_F g;
4792 src_impl = unsafe_impl_from_ID2D1Geometry(src_geometry);
4794 g = src_impl->transform;
4795 d2d_matrix_multiply(&g, transform);
4796 d2d_geometry_init(geometry, factory, &g, (ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl);
4797 ID2D1Geometry_AddRef(geometry->u.transformed.src_geometry = src_geometry);
4798 geometry->u.transformed.transform = *transform;
4799 geometry->fill = src_impl->fill;
4800 geometry->outline = src_impl->outline;
4803 static inline struct d2d_geometry *impl_from_ID2D1GeometryGroup(ID2D1GeometryGroup *iface)
4805 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
4808 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_QueryInterface(ID2D1GeometryGroup *iface,
4809 REFIID iid, void **out)
4811 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
4813 if (IsEqualGUID(iid, &IID_ID2D1GeometryGroup)
4814 || IsEqualGUID(iid, &IID_ID2D1Geometry)
4815 || IsEqualGUID(iid, &IID_ID2D1Resource)
4816 || IsEqualGUID(iid, &IID_IUnknown))
4818 ID2D1GeometryGroup_AddRef(iface);
4819 *out = iface;
4820 return S_OK;
4823 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
4825 *out = NULL;
4826 return E_NOINTERFACE;
4829 static ULONG STDMETHODCALLTYPE d2d_geometry_group_AddRef(ID2D1GeometryGroup *iface)
4831 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
4832 ULONG refcount = InterlockedIncrement(&geometry->refcount);
4834 TRACE("%p increasing refcount to %u.\n", iface, refcount);
4836 return refcount;
4839 static ULONG STDMETHODCALLTYPE d2d_geometry_group_Release(ID2D1GeometryGroup *iface)
4841 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
4842 ULONG refcount = InterlockedDecrement(&geometry->refcount);
4843 unsigned int i;
4845 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
4847 if (!refcount)
4849 for (i = 0; i < geometry->u.group.geometry_count; ++i)
4850 ID2D1Geometry_Release(geometry->u.group.src_geometries[i]);
4851 heap_free(geometry->u.group.src_geometries);
4852 d2d_geometry_cleanup(geometry);
4853 heap_free(geometry);
4856 return refcount;
4859 static void STDMETHODCALLTYPE d2d_geometry_group_GetFactory(ID2D1GeometryGroup *iface,
4860 ID2D1Factory **factory)
4862 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
4864 TRACE("iface %p, factory %p.\n", iface, factory);
4866 ID2D1Factory_AddRef(*factory = geometry->factory);
4869 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_GetBounds(ID2D1GeometryGroup *iface,
4870 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
4872 FIXME("iface %p, transform %p, bounds %p stub!.\n", iface, transform, bounds);
4874 return E_NOTIMPL;
4877 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_GetWidenedBounds(ID2D1GeometryGroup *iface,
4878 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4879 float tolerance, D2D1_RECT_F *bounds)
4881 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
4882 iface, stroke_width, stroke_style, transform, tolerance, bounds);
4884 return E_NOTIMPL;
4887 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_StrokeContainsPoint(ID2D1GeometryGroup *iface,
4888 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4889 float tolerance, BOOL *contains)
4891 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p.\n",
4892 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
4894 return E_NOTIMPL;
4897 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_FillContainsPoint(ID2D1GeometryGroup *iface,
4898 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
4900 FIXME("iface %p, point %s, transform %p, tolerance %.8e, contains %p stub!.\n",
4901 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
4903 return E_NOTIMPL;
4906 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_CompareWithGeometry(ID2D1GeometryGroup *iface,
4907 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
4909 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
4910 iface, geometry, transform, tolerance, relation);
4912 return E_NOTIMPL;
4915 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_Simplify(ID2D1GeometryGroup *iface,
4916 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4917 ID2D1SimplifiedGeometrySink *sink)
4919 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!.\n",
4920 iface, option, transform, tolerance, sink);
4922 return E_NOTIMPL;
4925 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_Tessellate(ID2D1GeometryGroup *iface,
4926 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
4928 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4930 return E_NOTIMPL;
4933 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_CombineWithGeometry(ID2D1GeometryGroup *iface,
4934 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
4935 float tolerance, ID2D1SimplifiedGeometrySink *sink)
4937 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4938 iface, geometry, combine_mode, transform, tolerance, sink);
4940 return E_NOTIMPL;
4943 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_Outline(ID2D1GeometryGroup *iface,
4944 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
4946 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4948 return E_NOTIMPL;
4951 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_ComputeArea(ID2D1GeometryGroup *iface,
4952 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
4954 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
4956 return E_NOTIMPL;
4959 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_ComputeLength(ID2D1GeometryGroup *iface,
4960 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
4962 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
4964 return E_NOTIMPL;
4967 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_ComputePointAtLength(ID2D1GeometryGroup *iface,
4968 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
4969 D2D1_POINT_2F *tangent)
4971 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
4972 iface, length, transform, tolerance, point, tangent);
4974 return E_NOTIMPL;
4977 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_Widen(ID2D1GeometryGroup *iface, float stroke_width,
4978 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4979 ID2D1SimplifiedGeometrySink *sink)
4981 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
4982 iface, stroke_width, stroke_style, transform, tolerance, sink);
4984 return E_NOTIMPL;
4987 static D2D1_FILL_MODE STDMETHODCALLTYPE d2d_geometry_group_GetFillMode(ID2D1GeometryGroup *iface)
4989 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
4991 TRACE("iface %p.\n", iface);
4993 return geometry->u.group.fill_mode;
4996 static UINT32 STDMETHODCALLTYPE d2d_geometry_group_GetSourceGeometryCount(ID2D1GeometryGroup *iface)
4998 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5000 TRACE("iface %p.\n", iface);
5002 return geometry->u.group.geometry_count;
5005 static void STDMETHODCALLTYPE d2d_geometry_group_GetSourceGeometries(ID2D1GeometryGroup *iface,
5006 ID2D1Geometry **geometries, UINT32 geometry_count)
5008 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5009 unsigned int i;
5011 TRACE("iface %p, geometries %p, geometry_count %u.\n", iface, geometries, geometry_count);
5013 geometry_count = min(geometry_count, geometry->u.group.geometry_count);
5014 for (i = 0; i < geometry_count; ++i)
5015 ID2D1Geometry_AddRef(geometries[i] = geometry->u.group.src_geometries[i]);
5018 static const struct ID2D1GeometryGroupVtbl d2d_geometry_group_vtbl =
5020 d2d_geometry_group_QueryInterface,
5021 d2d_geometry_group_AddRef,
5022 d2d_geometry_group_Release,
5023 d2d_geometry_group_GetFactory,
5024 d2d_geometry_group_GetBounds,
5025 d2d_geometry_group_GetWidenedBounds,
5026 d2d_geometry_group_StrokeContainsPoint,
5027 d2d_geometry_group_FillContainsPoint,
5028 d2d_geometry_group_CompareWithGeometry,
5029 d2d_geometry_group_Simplify,
5030 d2d_geometry_group_Tessellate,
5031 d2d_geometry_group_CombineWithGeometry,
5032 d2d_geometry_group_Outline,
5033 d2d_geometry_group_ComputeArea,
5034 d2d_geometry_group_ComputeLength,
5035 d2d_geometry_group_ComputePointAtLength,
5036 d2d_geometry_group_Widen,
5037 d2d_geometry_group_GetFillMode,
5038 d2d_geometry_group_GetSourceGeometryCount,
5039 d2d_geometry_group_GetSourceGeometries,
5042 HRESULT d2d_geometry_group_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
5043 D2D1_FILL_MODE fill_mode, ID2D1Geometry **geometries, unsigned int geometry_count)
5045 unsigned int i;
5047 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_geometry_group_vtbl);
5049 if (!(geometry->u.group.src_geometries = heap_calloc(geometry_count, sizeof(*geometries))))
5051 d2d_geometry_cleanup(geometry);
5052 return E_OUTOFMEMORY;
5055 for (i = 0; i < geometry_count; ++i)
5057 ID2D1Geometry_AddRef(geometry->u.group.src_geometries[i] = geometries[i]);
5059 geometry->u.group.geometry_count = geometry_count;
5060 geometry->u.group.fill_mode = fill_mode;
5062 return S_OK;
5065 struct d2d_geometry *unsafe_impl_from_ID2D1Geometry(ID2D1Geometry *iface)
5067 if (!iface)
5068 return NULL;
5069 assert(iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_ellipse_geometry_vtbl
5070 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl
5071 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl
5072 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_rounded_rectangle_geometry_vtbl
5073 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl
5074 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_geometry_group_vtbl);
5075 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);