d2d1: Check the vertex count again after duplicate removal in d2d_path_geometry_trian...
[wine.git] / dlls / d2d1 / geometry.c
blobc7d0d94f1adc295aefae80761b9e0fa1dd92f82a
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 =
33 {{{
34 1.0f, 0.0f,
35 0.0f, 1.0f,
36 0.0f, 0.0f,
37 }}};
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 static BOOL d2d_vertex_type_is_bezier(enum d2d_vertex_type t)
414 return (t == D2D_VERTEX_TYPE_BEZIER || t == D2D_VERTEX_TYPE_SPLIT_BEZIER);
417 static BOOL d2d_vertex_type_is_split_bezier(enum d2d_vertex_type t)
419 return t == D2D_VERTEX_TYPE_SPLIT_BEZIER;
422 /* This implementation is based on the paper "Adaptive Precision
423 * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
424 * associated (Public Domain) code by Jonathan Richard Shewchuk. */
425 static float d2d_point_ccw(const D2D1_POINT_2F *a, const D2D1_POINT_2F *b, const D2D1_POINT_2F *c)
427 static const float err_bound_result = (3.0f + 8.0f * D2D_FP_EPS) * D2D_FP_EPS;
428 static const float err_bound_a = (3.0f + 16.0f * D2D_FP_EPS) * D2D_FP_EPS;
429 static const float err_bound_b = (2.0f + 12.0f * D2D_FP_EPS) * D2D_FP_EPS;
430 static const float err_bound_c = (9.0f + 64.0f * D2D_FP_EPS) * D2D_FP_EPS * D2D_FP_EPS;
431 float det_d[16], det_c2[12], det_c1[8], det_b[4], temp4[4], temp2a[2], temp2b[2], abxacy[2], abyacx[2];
432 size_t det_d_len, det_c2_len, det_c1_len;
433 float det, det_sum, err_bound;
434 struct d2d_fp_two_vec2 ab, ac;
436 ab.x[1] = b->x - a->x;
437 ab.y[1] = b->y - a->y;
438 ac.x[1] = c->x - a->x;
439 ac.y[1] = c->y - a->y;
441 abxacy[1] = ab.x[1] * ac.y[1];
442 abyacx[1] = ab.y[1] * ac.x[1];
443 det = abxacy[1] - abyacx[1];
445 if (abxacy[1] > 0.0f)
447 if (abyacx[1] <= 0.0f)
448 return det;
449 det_sum = abxacy[1] + abyacx[1];
451 else if (abxacy[1] < 0.0f)
453 if (abyacx[1] >= 0.0f)
454 return det;
455 det_sum = -abxacy[1] - abyacx[1];
457 else
459 return det;
462 err_bound = err_bound_a * det_sum;
463 if (det >= err_bound || -det >= err_bound)
464 return det;
466 d2d_fp_two_product(abxacy, ab.x[1], ac.y[1]);
467 d2d_fp_two_product(abyacx, ab.y[1], ac.x[1]);
468 d2d_fp_two_two_diff(det_b, abxacy, abyacx);
470 det = d2d_fp_estimate(det_b, 4);
471 err_bound = err_bound_b * det_sum;
472 if (det >= err_bound || -det >= err_bound)
473 return det;
475 d2d_fp_two_diff_tail(&ab.x[0], b->x, a->x, ab.x[1]);
476 d2d_fp_two_diff_tail(&ab.y[0], b->y, a->y, ab.y[1]);
477 d2d_fp_two_diff_tail(&ac.x[0], c->x, a->x, ac.x[1]);
478 d2d_fp_two_diff_tail(&ac.y[0], c->y, a->y, ac.y[1]);
480 if (ab.x[0] == 0.0f && ab.y[0] == 0.0f && ac.x[0] == 0.0f && ac.y[0] == 0.0f)
481 return det;
483 err_bound = err_bound_c * det_sum + err_bound_result * fabsf(det);
484 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]);
485 if (det >= err_bound || -det >= err_bound)
486 return det;
488 d2d_fp_two_product(temp2a, ab.x[0], ac.y[1]);
489 d2d_fp_two_product(temp2b, ab.y[0], ac.x[1]);
490 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
491 d2d_fp_fast_expansion_sum_zeroelim(det_c1, &det_c1_len, det_b, 4, temp4, 4);
493 d2d_fp_two_product(temp2a, ab.x[1], ac.y[0]);
494 d2d_fp_two_product(temp2b, ab.y[1], ac.x[0]);
495 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
496 d2d_fp_fast_expansion_sum_zeroelim(det_c2, &det_c2_len, det_c1, det_c1_len, temp4, 4);
498 d2d_fp_two_product(temp2a, ab.x[0], ac.y[0]);
499 d2d_fp_two_product(temp2b, ab.y[0], ac.x[0]);
500 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
501 d2d_fp_fast_expansion_sum_zeroelim(det_d, &det_d_len, det_c2, det_c2_len, temp4, 4);
503 return det_d[det_d_len - 1];
506 static void d2d_rect_union(D2D1_RECT_F *l, const D2D1_RECT_F *r)
508 l->left = min(l->left, r->left);
509 l->top = min(l->top, r->top);
510 l->right = max(l->right, r->right);
511 l->bottom = max(l->bottom, r->bottom);
514 static BOOL d2d_rect_check_overlap(const D2D_RECT_F *p, const D2D_RECT_F *q)
516 return p->left < q->right && p->top < q->bottom && p->right > q->left && p->bottom > q->top;
519 static void d2d_rect_get_bezier_bounds(D2D_RECT_F *bounds, const D2D1_POINT_2F *p0,
520 const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2)
522 D2D1_POINT_2F p;
523 float root;
525 bounds->left = p0->x;
526 bounds->top = p0->y;
527 bounds->right = p0->x;
528 bounds->bottom = p0->y;
530 d2d_rect_expand(bounds, p2);
532 /* f(t) = (1 - t)²P₀ + 2(1 - t)tP₁ + t²P₂
533 * f'(t) = 2(1 - t)(P₁ - P₀) + 2t(P₂ - P₁)
534 * = 2(P₂ - 2P₁ + P₀)t + 2(P₁ - P₀)
536 * f'(t) = 0
537 * t = (P₀ - P₁) / (P₂ - 2P₁ + P₀) */
538 root = (p0->x - p1->x) / (p2->x - 2.0f * p1->x + p0->x);
539 if (root > 0.0f && root < 1.0f)
541 d2d_point_calculate_bezier(&p, p0, p1, p2, root);
542 d2d_rect_expand(bounds, &p);
545 root = (p0->y - p1->y) / (p2->y - 2.0f * p1->y + p0->y);
546 if (root > 0.0f && root < 1.0f)
548 d2d_point_calculate_bezier(&p, p0, p1, p2, root);
549 d2d_rect_expand(bounds, &p);
553 static void d2d_rect_get_bezier_segment_bounds(D2D_RECT_F *bounds, const D2D1_POINT_2F *p0,
554 const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2, float start, float end)
556 D2D1_POINT_2F q[3], r[2];
558 d2d_point_lerp(&r[0], p0, p1, start);
559 d2d_point_lerp(&r[1], p1, p2, start);
560 d2d_point_lerp(&q[0], &r[0], &r[1], start);
562 end = (end - start) / (1.0f - start);
563 d2d_point_lerp(&q[1], &q[0], &r[1], end);
564 d2d_point_lerp(&r[0], &r[1], p2, end);
565 d2d_point_lerp(&q[2], &q[1], &r[0], end);
567 d2d_rect_get_bezier_bounds(bounds, &q[0], &q[1], &q[2]);
570 static BOOL d2d_figure_insert_vertex(struct d2d_figure *figure, size_t idx, D2D1_POINT_2F vertex)
572 if (!d2d_array_reserve((void **)&figure->vertices, &figure->vertices_size,
573 figure->vertex_count + 1, sizeof(*figure->vertices)))
575 ERR("Failed to grow vertices array.\n");
576 return FALSE;
579 if (!d2d_array_reserve((void **)&figure->vertex_types, &figure->vertex_types_size,
580 figure->vertex_count + 1, sizeof(*figure->vertex_types)))
582 ERR("Failed to grow vertex types array.\n");
583 return FALSE;
586 memmove(&figure->vertices[idx + 1], &figure->vertices[idx],
587 (figure->vertex_count - idx) * sizeof(*figure->vertices));
588 memmove(&figure->vertex_types[idx + 1], &figure->vertex_types[idx],
589 (figure->vertex_count - idx) * sizeof(*figure->vertex_types));
590 figure->vertices[idx] = vertex;
591 figure->vertex_types[idx] = D2D_VERTEX_TYPE_NONE;
592 d2d_rect_expand(&figure->bounds, &vertex);
593 ++figure->vertex_count;
594 return TRUE;
597 static BOOL d2d_figure_add_vertex(struct d2d_figure *figure, D2D1_POINT_2F vertex)
599 size_t last = figure->vertex_count - 1;
601 if (figure->vertex_count && figure->vertex_types[last] == D2D_VERTEX_TYPE_LINE
602 && !memcmp(&figure->vertices[last], &vertex, sizeof(vertex)))
603 return TRUE;
605 if (!d2d_array_reserve((void **)&figure->vertices, &figure->vertices_size,
606 figure->vertex_count + 1, sizeof(*figure->vertices)))
608 ERR("Failed to grow vertices array.\n");
609 return FALSE;
612 if (!d2d_array_reserve((void **)&figure->vertex_types, &figure->vertex_types_size,
613 figure->vertex_count + 1, sizeof(*figure->vertex_types)))
615 ERR("Failed to grow vertex types array.\n");
616 return FALSE;
619 figure->vertices[figure->vertex_count] = vertex;
620 figure->vertex_types[figure->vertex_count] = D2D_VERTEX_TYPE_NONE;
621 d2d_rect_expand(&figure->bounds, &vertex);
622 ++figure->vertex_count;
623 return TRUE;
626 static BOOL d2d_figure_insert_bezier_controls(struct d2d_figure *figure,
627 size_t idx, size_t count, const D2D1_POINT_2F *p)
629 if (!d2d_array_reserve((void **)&figure->bezier_controls, &figure->bezier_controls_size,
630 figure->bezier_control_count + count, sizeof(*figure->bezier_controls)))
632 ERR("Failed to grow bezier controls array.\n");
633 return FALSE;
636 memmove(&figure->bezier_controls[idx + count], &figure->bezier_controls[idx],
637 (figure->bezier_control_count - idx) * sizeof(*figure->bezier_controls));
638 memcpy(&figure->bezier_controls[idx], p, count * sizeof(*figure->bezier_controls));
639 figure->bezier_control_count += count;
641 return TRUE;
644 static BOOL d2d_figure_add_bezier_controls(struct d2d_figure *figure, size_t count, const D2D1_POINT_2F *p)
646 if (!d2d_array_reserve((void **)&figure->bezier_controls, &figure->bezier_controls_size,
647 figure->bezier_control_count + count, sizeof(*figure->bezier_controls)))
649 ERR("Failed to grow bezier controls array.\n");
650 return FALSE;
653 memcpy(&figure->bezier_controls[figure->bezier_control_count], p, count * sizeof(*figure->bezier_controls));
654 figure->bezier_control_count += count;
656 return TRUE;
659 static void d2d_cdt_edge_rot(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_ROT) & 3;
665 static void d2d_cdt_edge_sym(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
667 dst->idx = src->idx;
668 dst->r = (src->r + D2D_EDGE_NEXT_SYM) & 3;
671 static void d2d_cdt_edge_tor(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
673 dst->idx = src->idx;
674 dst->r = (src->r + D2D_EDGE_NEXT_TOR) & 3;
677 static void d2d_cdt_edge_next_left(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_TOR) & 3]);
683 static void d2d_cdt_edge_next_origin(const struct d2d_cdt *cdt,
684 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
686 *dst = cdt->edges[src->idx].next[src->r];
689 static void d2d_cdt_edge_prev_origin(const struct d2d_cdt *cdt,
690 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
692 d2d_cdt_edge_rot(dst, &cdt->edges[src->idx].next[(src->r + D2D_EDGE_NEXT_ROT) & 3]);
695 static size_t d2d_cdt_edge_origin(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
697 return cdt->edges[e->idx].vertex[e->r >> 1];
700 static size_t d2d_cdt_edge_destination(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
702 return cdt->edges[e->idx].vertex[!(e->r >> 1)];
705 static void d2d_cdt_edge_set_origin(const struct d2d_cdt *cdt,
706 const struct d2d_cdt_edge_ref *e, size_t vertex)
708 cdt->edges[e->idx].vertex[e->r >> 1] = vertex;
711 static void d2d_cdt_edge_set_destination(const struct d2d_cdt *cdt,
712 const struct d2d_cdt_edge_ref *e, size_t vertex)
714 cdt->edges[e->idx].vertex[!(e->r >> 1)] = vertex;
717 static float d2d_cdt_ccw(const struct d2d_cdt *cdt, size_t a, size_t b, size_t c)
719 return d2d_point_ccw(&cdt->vertices[a], &cdt->vertices[b], &cdt->vertices[c]);
722 static BOOL d2d_cdt_rightof(const struct d2d_cdt *cdt, size_t p, const struct d2d_cdt_edge_ref *e)
724 return d2d_cdt_ccw(cdt, p, d2d_cdt_edge_destination(cdt, e), d2d_cdt_edge_origin(cdt, e)) > 0.0f;
727 static BOOL d2d_cdt_leftof(const struct d2d_cdt *cdt, size_t p, const struct d2d_cdt_edge_ref *e)
729 return d2d_cdt_ccw(cdt, p, d2d_cdt_edge_origin(cdt, e), d2d_cdt_edge_destination(cdt, e)) > 0.0f;
732 /* |ax ay|
733 * |bx by| */
734 static void d2d_fp_four_det2x2(float *out, float ax, float ay, float bx, float by)
736 float axby[2], aybx[2];
738 d2d_fp_two_product(axby, ax, by);
739 d2d_fp_two_product(aybx, ay, bx);
740 d2d_fp_two_two_diff(out, axby, aybx);
743 /* (a->x² + a->y²) * det2x2 */
744 static void d2d_fp_sub_det3x3(float *out, size_t *out_len, const struct d2d_fp_two_vec2 *a, const float *det2x2)
746 size_t axd_len, ayd_len, axxd_len, ayyd_len;
747 float axd[8], ayd[8], axxd[16], ayyd[16];
749 d2d_fp_scale_expansion_zeroelim(axd, &axd_len, det2x2, 4, a->x[1]);
750 d2d_fp_scale_expansion_zeroelim(axxd, &axxd_len, axd, axd_len, a->x[1]);
751 d2d_fp_scale_expansion_zeroelim(ayd, &ayd_len, det2x2, 4, a->y[1]);
752 d2d_fp_scale_expansion_zeroelim(ayyd, &ayyd_len, ayd, ayd_len, a->y[1]);
753 d2d_fp_fast_expansion_sum_zeroelim(out, out_len, axxd, axxd_len, ayyd, ayyd_len);
756 /* det_abt = det_ab * c[0]
757 * fin += c[0] * (az * b - bz * a + c[1] * det_ab * 2.0f) */
758 static void d2d_cdt_incircle_refine1(struct d2d_fp_fin *fin, float *det_abt, size_t *det_abt_len,
759 const float *det_ab, float a, const float *az, float b, const float *bz, const float *c)
761 size_t temp48_len, temp32_len, temp16a_len, temp16b_len, temp16c_len, temp8_len;
762 float temp48[48], temp32[32], temp16a[16], temp16b[16], temp16c[16], temp8[8];
763 float *swap;
765 d2d_fp_scale_expansion_zeroelim(det_abt, det_abt_len, det_ab, 4, c[0]);
766 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, det_abt, *det_abt_len, 2.0f * c[1]);
767 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, az, 4, c[0]);
768 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, temp8, temp8_len, b);
769 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, bz, 4, c[0]);
770 d2d_fp_scale_expansion_zeroelim(temp16c, &temp16c_len, temp8, temp8_len, -a);
771 d2d_fp_fast_expansion_sum_zeroelim(temp32, &temp32_len, temp16a, temp16a_len, temp16b, temp16b_len);
772 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16c, temp16c_len, temp32, temp32_len);
773 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
774 swap = fin->now; fin->now = fin->other; fin->other = swap;
777 static void d2d_cdt_incircle_refine2(struct d2d_fp_fin *fin, const struct d2d_fp_two_vec2 *a,
778 const struct d2d_fp_two_vec2 *b, const float *bz, const struct d2d_fp_two_vec2 *c, const float *cz,
779 const float *axt_det_bc, size_t axt_det_bc_len, const float *ayt_det_bc, size_t ayt_det_bc_len)
781 size_t temp64_len, temp48_len, temp32a_len, temp32b_len, temp16a_len, temp16b_len, temp8_len;
782 float temp64[64], temp48[48], temp32a[32], temp32b[32], temp16a[16], temp16b[16], temp8[8];
783 float bct[8], bctt[4], temp4a[4], temp4b[4], temp2a[2], temp2b[2];
784 size_t bct_len, bctt_len;
785 float *swap;
787 /* 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]) */
788 /* bctt = b->x[0] * c->y[0] + c->x[0] * b->y[0] */
789 if (b->x[0] != 0.0f || b->y[0] != 0.0f || c->x[0] != 0.0f || c->y[0] != 0.0f)
791 d2d_fp_two_product(temp2a, b->x[0], c->y[1]);
792 d2d_fp_two_product(temp2b, b->x[1], c->y[0]);
793 d2d_fp_two_two_sum(temp4a, temp2a, temp2b);
794 d2d_fp_two_product(temp2a, c->x[0], -b->y[1]);
795 d2d_fp_two_product(temp2b, c->x[1], -b->y[0]);
796 d2d_fp_two_two_sum(temp4b, temp2a, temp2b);
797 d2d_fp_fast_expansion_sum_zeroelim(bct, &bct_len, temp4a, 4, temp4b, 4);
799 d2d_fp_two_product(temp2a, b->x[0], c->y[0]);
800 d2d_fp_two_product(temp2b, c->x[0], b->y[0]);
801 d2d_fp_two_two_diff(bctt, temp2a, temp2b);
802 bctt_len = 4;
804 else
806 bct[0] = 0.0f;
807 bct_len = 1;
808 bctt[0] = 0.0f;
809 bctt_len = 1;
812 if (a->x[0] != 0.0f)
814 size_t axt_bct_len, axt_bctt_len;
815 float axt_bct[16], axt_bctt[8];
817 /* fin += a->x[0] * (axt_det_bc + bct * 2.0f * a->x[1]) */
818 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, axt_det_bc, axt_det_bc_len, a->x[0]);
819 d2d_fp_scale_expansion_zeroelim(axt_bct, &axt_bct_len, bct, bct_len, a->x[0]);
820 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, axt_bct, axt_bct_len, 2.0f * a->x[1]);
821 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16a, temp16a_len, temp32a, temp32a_len);
822 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
823 swap = fin->now; fin->now = fin->other; fin->other = swap;
825 if (b->y[0] != 0.0f)
827 /* fin += a->x[0] * cz * b->y[0] */
828 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, cz, 4, a->x[0]);
829 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, temp8, temp8_len, b->y[0]);
830 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp16a, temp16a_len);
831 swap = fin->now; fin->now = fin->other; fin->other = swap;
834 if (c->y[0] != 0.0f)
836 /* fin -= a->x[0] * bz * c->y[0] */
837 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, bz, 4, -a->x[0]);
838 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, temp8, temp8_len, c->y[0]);
839 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp16a, temp16a_len);
840 swap = fin->now; fin->now = fin->other; fin->other = swap;
843 /* fin += a->x[0] * (bct * a->x[0] + bctt * (2.0f * a->x[1] + a->x[0])) */
844 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, axt_bct, axt_bct_len, a->x[0]);
845 d2d_fp_scale_expansion_zeroelim(axt_bctt, &axt_bctt_len, bctt, bctt_len, a->x[0]);
846 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, axt_bctt, axt_bctt_len, 2.0f * a->x[1]);
847 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, axt_bctt, axt_bctt_len, a->x[0]);
848 d2d_fp_fast_expansion_sum_zeroelim(temp32b, &temp32b_len, temp16a, temp16a_len, temp16b, temp16b_len);
849 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, temp32a, temp32a_len, temp32b, temp32b_len);
850 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp64, temp64_len);
851 swap = fin->now; fin->now = fin->other; fin->other = swap;
854 if (a->y[0] != 0.0f)
856 size_t ayt_bct_len, ayt_bctt_len;
857 float ayt_bct[16], ayt_bctt[8];
859 /* fin += a->y[0] * (ayt_det_bc + bct * 2.0f * a->y[1]) */
860 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, ayt_det_bc, ayt_det_bc_len, a->y[0]);
861 d2d_fp_scale_expansion_zeroelim(ayt_bct, &ayt_bct_len, bct, bct_len, a->y[0]);
862 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, ayt_bct, ayt_bct_len, 2.0f * a->y[1]);
863 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16a, temp16a_len, temp32a, temp32a_len);
864 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
865 swap = fin->now; fin->now = fin->other; fin->other = swap;
867 /* fin += a->y[0] * (bct * a->y[0] + bctt * (2.0f * a->y[1] + a->y[0])) */
868 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, ayt_bct, ayt_bct_len, a->y[0]);
869 d2d_fp_scale_expansion_zeroelim(ayt_bctt, &ayt_bctt_len, bctt, bctt_len, a->y[0]);
870 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, ayt_bctt, ayt_bctt_len, 2.0f * a->y[1]);
871 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, ayt_bctt, ayt_bctt_len, a->y[0]);
872 d2d_fp_fast_expansion_sum_zeroelim(temp32b, &temp32b_len, temp16a, temp16a_len, temp16b, temp16b_len);
873 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, temp32a, temp32a_len, temp32b, temp32b_len);
874 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp64, temp64_len);
875 swap = fin->now; fin->now = fin->other; fin->other = swap;
879 /* Determine if point D is inside or outside the circle defined by points A,
880 * B, C. As explained in the paper by Guibas and Stolfi, this is equivalent to
881 * calculating the signed volume of the tetrahedron defined by projecting the
882 * points onto the paraboloid of revolution x = x² + y²,
883 * λ:(x, y) → (x, y, x² + y²). I.e., D is inside the cirlce if
885 * |λ(A) 1|
886 * |λ(B) 1| > 0
887 * |λ(C) 1|
888 * |λ(D) 1|
890 * After translating D to the origin, that becomes:
892 * |λ(A-D)|
893 * |λ(B-D)| > 0
894 * |λ(C-D)|
896 * This implementation is based on the paper "Adaptive Precision
897 * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
898 * associated (Public Domain) code by Jonathan Richard Shewchuk. */
899 static BOOL d2d_cdt_incircle(const struct d2d_cdt *cdt, size_t a, size_t b, size_t c, size_t d)
901 static const float err_bound_result = (3.0f + 8.0f * D2D_FP_EPS) * D2D_FP_EPS;
902 static const float err_bound_a = (10.0f + 96.0f * D2D_FP_EPS) * D2D_FP_EPS;
903 static const float err_bound_b = (4.0f + 48.0f * D2D_FP_EPS) * D2D_FP_EPS;
904 static const float err_bound_c = (44.0f + 576.0f * D2D_FP_EPS) * D2D_FP_EPS * D2D_FP_EPS;
906 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;
907 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];
908 float fin1[1152], fin2[1152], temp64[64], sub_det_a[32], sub_det_b[32], sub_det_c[32];
909 float det_bc[4], det_ca[4], det_ab[4], daz[4], dbz[4], dcz[4], temp2a[2], temp2b[2];
910 size_t temp64_len, sub_det_a_len, sub_det_b_len, sub_det_c_len;
911 float dbxdcy, dbydcx, dcxday, dcydax, daxdby, daydbx;
912 const D2D1_POINT_2F *p = cdt->vertices;
913 struct d2d_fp_two_vec2 da, db, dc;
914 float permanent, err_bound, det;
915 struct d2d_fp_fin fin;
917 da.x[1] = p[a].x - p[d].x;
918 da.y[1] = p[a].y - p[d].y;
919 db.x[1] = p[b].x - p[d].x;
920 db.y[1] = p[b].y - p[d].y;
921 dc.x[1] = p[c].x - p[d].x;
922 dc.y[1] = p[c].y - p[d].y;
924 daz[3] = da.x[1] * da.x[1] + da.y[1] * da.y[1];
925 dbxdcy = db.x[1] * dc.y[1];
926 dbydcx = db.y[1] * dc.x[1];
928 dbz[3] = db.x[1] * db.x[1] + db.y[1] * db.y[1];
929 dcxday = dc.x[1] * da.y[1];
930 dcydax = dc.y[1] * da.x[1];
932 dcz[3] = dc.x[1] * dc.x[1] + dc.y[1] * dc.y[1];
933 daxdby = da.x[1] * db.y[1];
934 daydbx = da.y[1] * db.x[1];
936 det = daz[3] * (dbxdcy - dbydcx) + dbz[3] * (dcxday - dcydax) + dcz[3] * (daxdby - daydbx);
937 permanent = daz[3] * (fabsf(dbxdcy) + fabsf(dbydcx))
938 + dbz[3] * (fabsf(dcxday) + fabsf(dcydax))
939 + dcz[3] * (fabsf(daxdby) + fabsf(daydbx));
940 err_bound = err_bound_a * permanent;
941 if (det > err_bound || -det > err_bound)
942 return det > 0.0f;
944 fin.now = fin1;
945 fin.other = fin2;
947 d2d_fp_four_det2x2(det_bc, db.x[1], db.y[1], dc.x[1], dc.y[1]);
948 d2d_fp_sub_det3x3(sub_det_a, &sub_det_a_len, &da, det_bc);
950 d2d_fp_four_det2x2(det_ca, dc.x[1], dc.y[1], da.x[1], da.y[1]);
951 d2d_fp_sub_det3x3(sub_det_b, &sub_det_b_len, &db, det_ca);
953 d2d_fp_four_det2x2(det_ab, da.x[1], da.y[1], db.x[1], db.y[1]);
954 d2d_fp_sub_det3x3(sub_det_c, &sub_det_c_len, &dc, det_ab);
956 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, sub_det_a, sub_det_a_len, sub_det_b, sub_det_b_len);
957 d2d_fp_fast_expansion_sum_zeroelim(fin.now, &fin.length, temp64, temp64_len, sub_det_c, sub_det_c_len);
958 det = d2d_fp_estimate(fin.now, fin.length);
959 err_bound = err_bound_b * permanent;
960 if (det >= err_bound || -det >= err_bound)
961 return det > 0.0f;
963 d2d_fp_two_diff_tail(&da.x[0], p[a].x, p[d].x, da.x[1]);
964 d2d_fp_two_diff_tail(&da.y[0], p[a].y, p[d].y, da.y[1]);
965 d2d_fp_two_diff_tail(&db.x[0], p[b].x, p[d].x, db.x[1]);
966 d2d_fp_two_diff_tail(&db.y[0], p[b].y, p[d].y, db.y[1]);
967 d2d_fp_two_diff_tail(&dc.x[0], p[c].x, p[d].x, dc.x[1]);
968 d2d_fp_two_diff_tail(&dc.y[0], p[c].y, p[d].y, dc.y[1]);
969 if (da.x[0] == 0.0f && db.x[0] == 0.0f && dc.x[0] == 0.0f
970 && da.y[0] == 0.0f && db.y[0] == 0.0f && dc.y[0] == 0.0f)
971 return det > 0.0f;
973 err_bound = err_bound_c * permanent + err_bound_result * fabsf(det);
974 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]))
975 + 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]))
976 + (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]))
977 + 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]))
978 + (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]))
979 + 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]));
980 if (det >= err_bound || -det >= err_bound)
981 return det > 0.0f;
983 if (db.x[0] != 0.0f || db.y[0] != 0.0f || dc.x[0] != 0.0f || dc.y[0] != 0.0f)
985 d2d_fp_square(temp2a, da.x[1]);
986 d2d_fp_square(temp2b, da.y[1]);
987 d2d_fp_two_two_sum(daz, temp2a, temp2b);
989 if (dc.x[0] != 0.0f || dc.y[0] != 0.0f || da.x[0] != 0.0f || da.y[0] != 0.0f)
991 d2d_fp_square(temp2a, db.x[1]);
992 d2d_fp_square(temp2b, db.y[1]);
993 d2d_fp_two_two_sum(dbz, temp2a, temp2b);
995 if (da.x[0] != 0.0f || da.y[0] != 0.0f || db.x[0] != 0.0f || db.y[0] != 0.0f)
997 d2d_fp_square(temp2a, dc.x[1]);
998 d2d_fp_square(temp2b, dc.y[1]);
999 d2d_fp_two_two_sum(dcz, temp2a, temp2b);
1002 if (da.x[0] != 0.0f)
1003 d2d_cdt_incircle_refine1(&fin, axt_det_bc, &axt_det_bc_len, det_bc, dc.y[1], dcz, db.y[1], dbz, da.x);
1004 if (da.y[0] != 0.0f)
1005 d2d_cdt_incircle_refine1(&fin, ayt_det_bc, &ayt_det_bc_len, det_bc, db.x[1], dbz, dc.x[1], dcz, da.y);
1006 if (db.x[0] != 0.0f)
1007 d2d_cdt_incircle_refine1(&fin, bxt_det_ca, &bxt_det_ca_len, det_ca, da.y[1], daz, dc.y[1], dcz, db.x);
1008 if (db.y[0] != 0.0f)
1009 d2d_cdt_incircle_refine1(&fin, byt_det_ca, &byt_det_ca_len, det_ca, dc.x[1], dcz, da.x[1], daz, db.y);
1010 if (dc.x[0] != 0.0f)
1011 d2d_cdt_incircle_refine1(&fin, cxt_det_ab, &cxt_det_ab_len, det_ab, db.y[1], dbz, da.y[1], daz, dc.x);
1012 if (dc.y[0] != 0.0f)
1013 d2d_cdt_incircle_refine1(&fin, cyt_det_ab, &cyt_det_ab_len, det_ab, da.x[1], daz, db.x[1], dbz, dc.y);
1015 if (da.x[0] != 0.0f || da.y[0] != 0.0f)
1016 d2d_cdt_incircle_refine2(&fin, &da, &db, dbz, &dc, dcz,
1017 axt_det_bc, axt_det_bc_len, ayt_det_bc, ayt_det_bc_len);
1018 if (db.x[0] != 0.0f || db.y[0] != 0.0f)
1019 d2d_cdt_incircle_refine2(&fin, &db, &dc, dcz, &da, daz,
1020 bxt_det_ca, bxt_det_ca_len, byt_det_ca, byt_det_ca_len);
1021 if (dc.x[0] != 0.0f || dc.y[0] != 0.0f)
1022 d2d_cdt_incircle_refine2(&fin, &dc, &da, daz, &db, dbz,
1023 cxt_det_ab, cxt_det_ab_len, cyt_det_ab, cyt_det_ab_len);
1025 return fin.now[fin.length - 1] > 0.0f;
1028 static void d2d_cdt_splice(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *a,
1029 const struct d2d_cdt_edge_ref *b)
1031 struct d2d_cdt_edge_ref ta, tb, alpha, beta;
1033 ta = cdt->edges[a->idx].next[a->r];
1034 tb = cdt->edges[b->idx].next[b->r];
1035 cdt->edges[a->idx].next[a->r] = tb;
1036 cdt->edges[b->idx].next[b->r] = ta;
1038 d2d_cdt_edge_rot(&alpha, &ta);
1039 d2d_cdt_edge_rot(&beta, &tb);
1041 ta = cdt->edges[alpha.idx].next[alpha.r];
1042 tb = cdt->edges[beta.idx].next[beta.r];
1043 cdt->edges[alpha.idx].next[alpha.r] = tb;
1044 cdt->edges[beta.idx].next[beta.r] = ta;
1047 static BOOL d2d_cdt_create_edge(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *e)
1049 struct d2d_cdt_edge *edge;
1051 if (cdt->free_edge != ~0u)
1053 e->idx = cdt->free_edge;
1054 cdt->free_edge = cdt->edges[e->idx].next[D2D_EDGE_NEXT_ORIGIN].idx;
1056 else
1058 if (!d2d_array_reserve((void **)&cdt->edges, &cdt->edges_size, cdt->edge_count + 1, sizeof(*cdt->edges)))
1060 ERR("Failed to grow edges array.\n");
1061 return FALSE;
1063 e->idx = cdt->edge_count++;
1065 e->r = 0;
1067 edge = &cdt->edges[e->idx];
1068 edge->next[D2D_EDGE_NEXT_ORIGIN] = *e;
1069 d2d_cdt_edge_tor(&edge->next[D2D_EDGE_NEXT_ROT], e);
1070 d2d_cdt_edge_sym(&edge->next[D2D_EDGE_NEXT_SYM], e);
1071 d2d_cdt_edge_rot(&edge->next[D2D_EDGE_NEXT_TOR], e);
1072 edge->flags = 0;
1074 return TRUE;
1077 static void d2d_cdt_destroy_edge(struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
1079 struct d2d_cdt_edge_ref next, sym, prev;
1081 d2d_cdt_edge_next_origin(cdt, &next, e);
1082 if (next.idx != e->idx || next.r != e->r)
1084 d2d_cdt_edge_prev_origin(cdt, &prev, e);
1085 d2d_cdt_splice(cdt, e, &prev);
1088 d2d_cdt_edge_sym(&sym, e);
1090 d2d_cdt_edge_next_origin(cdt, &next, &sym);
1091 if (next.idx != sym.idx || next.r != sym.r)
1093 d2d_cdt_edge_prev_origin(cdt, &prev, &sym);
1094 d2d_cdt_splice(cdt, &sym, &prev);
1097 cdt->edges[e->idx].flags |= D2D_CDT_EDGE_FLAG_FREED;
1098 cdt->edges[e->idx].next[D2D_EDGE_NEXT_ORIGIN].idx = cdt->free_edge;
1099 cdt->free_edge = e->idx;
1102 static BOOL d2d_cdt_connect(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *e,
1103 const struct d2d_cdt_edge_ref *a, const struct d2d_cdt_edge_ref *b)
1105 struct d2d_cdt_edge_ref tmp;
1107 if (!d2d_cdt_create_edge(cdt, e))
1108 return FALSE;
1109 d2d_cdt_edge_set_origin(cdt, e, d2d_cdt_edge_destination(cdt, a));
1110 d2d_cdt_edge_set_destination(cdt, e, d2d_cdt_edge_origin(cdt, b));
1111 d2d_cdt_edge_next_left(cdt, &tmp, a);
1112 d2d_cdt_splice(cdt, e, &tmp);
1113 d2d_cdt_edge_sym(&tmp, e);
1114 d2d_cdt_splice(cdt, &tmp, b);
1116 return TRUE;
1119 static BOOL d2d_cdt_merge(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *left_outer,
1120 struct d2d_cdt_edge_ref *left_inner, struct d2d_cdt_edge_ref *right_inner,
1121 struct d2d_cdt_edge_ref *right_outer)
1123 struct d2d_cdt_edge_ref base_edge, tmp;
1125 /* Create the base edge between both parts. */
1126 for (;;)
1128 if (d2d_cdt_leftof(cdt, d2d_cdt_edge_origin(cdt, right_inner), left_inner))
1130 d2d_cdt_edge_next_left(cdt, left_inner, left_inner);
1132 else if (d2d_cdt_rightof(cdt, d2d_cdt_edge_origin(cdt, left_inner), right_inner))
1134 d2d_cdt_edge_sym(&tmp, right_inner);
1135 d2d_cdt_edge_next_origin(cdt, right_inner, &tmp);
1137 else
1139 break;
1143 d2d_cdt_edge_sym(&tmp, right_inner);
1144 if (!d2d_cdt_connect(cdt, &base_edge, &tmp, left_inner))
1145 return FALSE;
1146 if (d2d_cdt_edge_origin(cdt, left_inner) == d2d_cdt_edge_origin(cdt, left_outer))
1147 d2d_cdt_edge_sym(left_outer, &base_edge);
1148 if (d2d_cdt_edge_origin(cdt, right_inner) == d2d_cdt_edge_origin(cdt, right_outer))
1149 *right_outer = base_edge;
1151 for (;;)
1153 struct d2d_cdt_edge_ref left_candidate, right_candidate, sym_base_edge;
1154 BOOL left_valid, right_valid;
1156 /* Find the left candidate. */
1157 d2d_cdt_edge_sym(&sym_base_edge, &base_edge);
1158 d2d_cdt_edge_next_origin(cdt, &left_candidate, &sym_base_edge);
1159 if ((left_valid = d2d_cdt_leftof(cdt, d2d_cdt_edge_destination(cdt, &left_candidate), &sym_base_edge)))
1161 d2d_cdt_edge_next_origin(cdt, &tmp, &left_candidate);
1162 while (d2d_cdt_edge_destination(cdt, &tmp) != d2d_cdt_edge_destination(cdt, &sym_base_edge)
1163 && d2d_cdt_incircle(cdt,
1164 d2d_cdt_edge_origin(cdt, &sym_base_edge), d2d_cdt_edge_destination(cdt, &sym_base_edge),
1165 d2d_cdt_edge_destination(cdt, &left_candidate), d2d_cdt_edge_destination(cdt, &tmp)))
1167 d2d_cdt_destroy_edge(cdt, &left_candidate);
1168 left_candidate = tmp;
1169 d2d_cdt_edge_next_origin(cdt, &tmp, &left_candidate);
1172 d2d_cdt_edge_sym(&left_candidate, &left_candidate);
1174 /* Find the right candidate. */
1175 d2d_cdt_edge_prev_origin(cdt, &right_candidate, &base_edge);
1176 if ((right_valid = d2d_cdt_rightof(cdt, d2d_cdt_edge_destination(cdt, &right_candidate), &base_edge)))
1178 d2d_cdt_edge_prev_origin(cdt, &tmp, &right_candidate);
1179 while (d2d_cdt_edge_destination(cdt, &tmp) != d2d_cdt_edge_destination(cdt, &base_edge)
1180 && d2d_cdt_incircle(cdt,
1181 d2d_cdt_edge_origin(cdt, &sym_base_edge), d2d_cdt_edge_destination(cdt, &sym_base_edge),
1182 d2d_cdt_edge_destination(cdt, &right_candidate), d2d_cdt_edge_destination(cdt, &tmp)))
1184 d2d_cdt_destroy_edge(cdt, &right_candidate);
1185 right_candidate = tmp;
1186 d2d_cdt_edge_prev_origin(cdt, &tmp, &right_candidate);
1190 if (!left_valid && !right_valid)
1191 break;
1193 /* Connect the appropriate candidate with the base edge. */
1194 if (!left_valid || (right_valid && d2d_cdt_incircle(cdt,
1195 d2d_cdt_edge_origin(cdt, &left_candidate), d2d_cdt_edge_destination(cdt, &left_candidate),
1196 d2d_cdt_edge_origin(cdt, &right_candidate), d2d_cdt_edge_destination(cdt, &right_candidate))))
1198 if (!d2d_cdt_connect(cdt, &base_edge, &right_candidate, &sym_base_edge))
1199 return FALSE;
1201 else
1203 if (!d2d_cdt_connect(cdt, &base_edge, &sym_base_edge, &left_candidate))
1204 return FALSE;
1208 return TRUE;
1211 /* Create a Delaunay triangulation from a set of vertices. This is an
1212 * implementation of the divide-and-conquer algorithm described by Guibas and
1213 * Stolfi. Should be called with at least two vertices. */
1214 static BOOL d2d_cdt_triangulate(struct d2d_cdt *cdt, size_t start_vertex, size_t vertex_count,
1215 struct d2d_cdt_edge_ref *left_edge, struct d2d_cdt_edge_ref *right_edge)
1217 struct d2d_cdt_edge_ref left_inner, left_outer, right_inner, right_outer, tmp;
1218 size_t cut;
1220 /* Only two vertices, create a single edge. */
1221 if (vertex_count == 2)
1223 struct d2d_cdt_edge_ref a;
1225 if (!d2d_cdt_create_edge(cdt, &a))
1226 return FALSE;
1227 d2d_cdt_edge_set_origin(cdt, &a, start_vertex);
1228 d2d_cdt_edge_set_destination(cdt, &a, start_vertex + 1);
1230 *left_edge = a;
1231 d2d_cdt_edge_sym(right_edge, &a);
1233 return TRUE;
1236 /* Three vertices, create a triangle. */
1237 if (vertex_count == 3)
1239 struct d2d_cdt_edge_ref a, b, c;
1240 float det;
1242 if (!d2d_cdt_create_edge(cdt, &a))
1243 return FALSE;
1244 if (!d2d_cdt_create_edge(cdt, &b))
1245 return FALSE;
1246 d2d_cdt_edge_sym(&tmp, &a);
1247 d2d_cdt_splice(cdt, &tmp, &b);
1249 d2d_cdt_edge_set_origin(cdt, &a, start_vertex);
1250 d2d_cdt_edge_set_destination(cdt, &a, start_vertex + 1);
1251 d2d_cdt_edge_set_origin(cdt, &b, start_vertex + 1);
1252 d2d_cdt_edge_set_destination(cdt, &b, start_vertex + 2);
1254 det = d2d_cdt_ccw(cdt, start_vertex, start_vertex + 1, start_vertex + 2);
1255 if (det != 0.0f && !d2d_cdt_connect(cdt, &c, &b, &a))
1256 return FALSE;
1258 if (det < 0.0f)
1260 d2d_cdt_edge_sym(left_edge, &c);
1261 *right_edge = c;
1263 else
1265 *left_edge = a;
1266 d2d_cdt_edge_sym(right_edge, &b);
1269 return TRUE;
1272 /* More than tree vertices, divide. */
1273 cut = vertex_count / 2;
1274 if (!d2d_cdt_triangulate(cdt, start_vertex, cut, &left_outer, &left_inner))
1275 return FALSE;
1276 if (!d2d_cdt_triangulate(cdt, start_vertex + cut, vertex_count - cut, &right_inner, &right_outer))
1277 return FALSE;
1278 /* Merge the left and right parts. */
1279 if (!d2d_cdt_merge(cdt, &left_outer, &left_inner, &right_inner, &right_outer))
1280 return FALSE;
1282 *left_edge = left_outer;
1283 *right_edge = right_outer;
1284 return TRUE;
1287 static int __cdecl d2d_cdt_compare_vertices(const void *a, const void *b)
1289 const D2D1_POINT_2F *p0 = a;
1290 const D2D1_POINT_2F *p1 = b;
1291 float diff = p0->x - p1->x;
1293 if (diff == 0.0f)
1294 diff = p0->y - p1->y;
1296 return diff == 0.0f ? 0 : (diff > 0.0f ? 1 : -1);
1299 /* Determine whether a given point is inside the geometry, using the current
1300 * fill mode rule. */
1301 static BOOL d2d_path_geometry_point_inside(const struct d2d_geometry *geometry,
1302 const D2D1_POINT_2F *probe, BOOL triangles_only)
1304 const D2D1_POINT_2F *p0, *p1;
1305 D2D1_POINT_2F v_p, v_probe;
1306 unsigned int score;
1307 size_t i, j, last;
1309 for (i = 0, score = 0; i < geometry->u.path.figure_count; ++i)
1311 const struct d2d_figure *figure = &geometry->u.path.figures[i];
1313 if (probe->x < figure->bounds.left || probe->x > figure->bounds.right
1314 || probe->y < figure->bounds.top || probe->y > figure->bounds.bottom)
1315 continue;
1317 last = figure->vertex_count - 1;
1318 if (!triangles_only)
1320 while (last && figure->vertex_types[last] == D2D_VERTEX_TYPE_NONE)
1321 --last;
1323 p0 = &figure->vertices[last];
1324 for (j = 0; j <= last; ++j)
1326 if (!triangles_only && figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
1327 continue;
1329 p1 = &figure->vertices[j];
1330 d2d_point_subtract(&v_p, p1, p0);
1331 d2d_point_subtract(&v_probe, probe, p0);
1333 if ((probe->y < p0->y) != (probe->y < p1->y) && v_probe.x < v_p.x * (v_probe.y / v_p.y))
1335 if (geometry->u.path.fill_mode == D2D1_FILL_MODE_ALTERNATE || (probe->y < p0->y))
1336 ++score;
1337 else
1338 --score;
1341 p0 = p1;
1345 return geometry->u.path.fill_mode == D2D1_FILL_MODE_ALTERNATE ? score & 1 : score;
1348 static BOOL d2d_path_geometry_add_fill_face(struct d2d_geometry *geometry, const struct d2d_cdt *cdt,
1349 const struct d2d_cdt_edge_ref *base_edge)
1351 struct d2d_cdt_edge_ref tmp;
1352 struct d2d_face *face;
1353 D2D1_POINT_2F probe;
1355 if (cdt->edges[base_edge->idx].flags & D2D_CDT_EDGE_FLAG_VISITED(base_edge->r))
1356 return TRUE;
1358 if (!d2d_array_reserve((void **)&geometry->fill.faces, &geometry->fill.faces_size,
1359 geometry->fill.face_count + 1, sizeof(*geometry->fill.faces)))
1361 ERR("Failed to grow faces array.\n");
1362 return FALSE;
1365 face = &geometry->fill.faces[geometry->fill.face_count];
1367 /* It may seem tempting to use the center of the face as probe origin, but
1368 * multiplying by powers of two works much better for preserving accuracy. */
1370 tmp = *base_edge;
1371 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1372 face->v[0] = d2d_cdt_edge_origin(cdt, &tmp);
1373 probe.x = cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.25f;
1374 probe.y = cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.25f;
1376 d2d_cdt_edge_next_left(cdt, &tmp, &tmp);
1377 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1378 face->v[1] = d2d_cdt_edge_origin(cdt, &tmp);
1379 probe.x += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.25f;
1380 probe.y += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.25f;
1382 d2d_cdt_edge_next_left(cdt, &tmp, &tmp);
1383 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1384 face->v[2] = d2d_cdt_edge_origin(cdt, &tmp);
1385 probe.x += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.50f;
1386 probe.y += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.50f;
1388 if (d2d_cdt_leftof(cdt, face->v[2], base_edge) && d2d_path_geometry_point_inside(geometry, &probe, TRUE))
1389 ++geometry->fill.face_count;
1391 return TRUE;
1394 static BOOL d2d_cdt_generate_faces(const struct d2d_cdt *cdt, struct d2d_geometry *geometry)
1396 struct d2d_cdt_edge_ref base_edge;
1397 size_t i;
1399 for (i = 0; i < cdt->edge_count; ++i)
1401 if (cdt->edges[i].flags & D2D_CDT_EDGE_FLAG_FREED)
1402 continue;
1404 base_edge.idx = i;
1405 base_edge.r = 0;
1406 if (!d2d_path_geometry_add_fill_face(geometry, cdt, &base_edge))
1407 goto fail;
1408 d2d_cdt_edge_sym(&base_edge, &base_edge);
1409 if (!d2d_path_geometry_add_fill_face(geometry, cdt, &base_edge))
1410 goto fail;
1413 return TRUE;
1415 fail:
1416 heap_free(geometry->fill.faces);
1417 geometry->fill.faces = NULL;
1418 geometry->fill.faces_size = 0;
1419 geometry->fill.face_count = 0;
1420 return FALSE;
1423 static BOOL d2d_cdt_fixup(struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *base_edge)
1425 struct d2d_cdt_edge_ref candidate, next, new_base;
1426 unsigned int count = 0;
1428 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1429 if (next.idx == base_edge->idx)
1431 ERR("Degenerate face.\n");
1432 return FALSE;
1435 candidate = next;
1436 while (d2d_cdt_edge_destination(cdt, &next) != d2d_cdt_edge_origin(cdt, base_edge))
1438 if (d2d_cdt_incircle(cdt, d2d_cdt_edge_origin(cdt, base_edge), d2d_cdt_edge_destination(cdt, base_edge),
1439 d2d_cdt_edge_destination(cdt, &candidate), d2d_cdt_edge_destination(cdt, &next)))
1440 candidate = next;
1441 d2d_cdt_edge_next_left(cdt, &next, &next);
1442 ++count;
1445 if (count > 1)
1447 d2d_cdt_edge_next_left(cdt, &next, &candidate);
1448 if (d2d_cdt_edge_destination(cdt, &next) == d2d_cdt_edge_origin(cdt, base_edge))
1449 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1450 else
1451 next = *base_edge;
1452 if (!d2d_cdt_connect(cdt, &new_base, &candidate, &next))
1453 return FALSE;
1454 if (!d2d_cdt_fixup(cdt, &new_base))
1455 return FALSE;
1456 d2d_cdt_edge_sym(&new_base, &new_base);
1457 if (!d2d_cdt_fixup(cdt, &new_base))
1458 return FALSE;
1461 return TRUE;
1464 static void d2d_cdt_cut_edges(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *end_edge,
1465 const struct d2d_cdt_edge_ref *base_edge, size_t start_vertex, size_t end_vertex)
1467 struct d2d_cdt_edge_ref next;
1468 float ccw;
1470 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1471 if (d2d_cdt_edge_destination(cdt, &next) == end_vertex)
1473 *end_edge = next;
1474 return;
1477 ccw = d2d_cdt_ccw(cdt, d2d_cdt_edge_destination(cdt, &next), end_vertex, start_vertex);
1478 if (ccw == 0.0f)
1480 *end_edge = next;
1481 return;
1484 if (ccw > 0.0f)
1485 d2d_cdt_edge_next_left(cdt, &next, &next);
1487 d2d_cdt_edge_sym(&next, &next);
1488 d2d_cdt_cut_edges(cdt, end_edge, &next, start_vertex, end_vertex);
1489 d2d_cdt_destroy_edge(cdt, &next);
1492 static BOOL d2d_cdt_insert_segment(struct d2d_cdt *cdt, struct d2d_geometry *geometry,
1493 const struct d2d_cdt_edge_ref *origin, struct d2d_cdt_edge_ref *edge, size_t end_vertex)
1495 struct d2d_cdt_edge_ref base_edge, current, new_origin, next, target;
1496 size_t current_destination, current_origin;
1498 for (current = *origin;; current = next)
1500 d2d_cdt_edge_next_origin(cdt, &next, &current);
1502 current_destination = d2d_cdt_edge_destination(cdt, &current);
1503 if (current_destination == end_vertex)
1505 d2d_cdt_edge_sym(edge, &current);
1506 return TRUE;
1509 current_origin = d2d_cdt_edge_origin(cdt, &current);
1510 if (d2d_cdt_ccw(cdt, end_vertex, current_origin, current_destination) == 0.0f
1511 && (cdt->vertices[current_destination].x > cdt->vertices[current_origin].x)
1512 == (cdt->vertices[end_vertex].x > cdt->vertices[current_origin].x)
1513 && (cdt->vertices[current_destination].y > cdt->vertices[current_origin].y)
1514 == (cdt->vertices[end_vertex].y > cdt->vertices[current_origin].y))
1516 d2d_cdt_edge_sym(&new_origin, &current);
1517 return d2d_cdt_insert_segment(cdt, geometry, &new_origin, edge, end_vertex);
1520 if (d2d_cdt_rightof(cdt, end_vertex, &next) && d2d_cdt_leftof(cdt, end_vertex, &current))
1522 d2d_cdt_edge_next_left(cdt, &base_edge, &current);
1524 d2d_cdt_edge_sym(&base_edge, &base_edge);
1525 d2d_cdt_cut_edges(cdt, &target, &base_edge, d2d_cdt_edge_origin(cdt, origin), end_vertex);
1526 d2d_cdt_destroy_edge(cdt, &base_edge);
1528 if (!d2d_cdt_connect(cdt, &base_edge, &target, &current))
1529 return FALSE;
1530 *edge = base_edge;
1531 if (!d2d_cdt_fixup(cdt, &base_edge))
1532 return FALSE;
1533 d2d_cdt_edge_sym(&base_edge, &base_edge);
1534 if (!d2d_cdt_fixup(cdt, &base_edge))
1535 return FALSE;
1537 if (d2d_cdt_edge_origin(cdt, edge) == end_vertex)
1538 return TRUE;
1539 new_origin = *edge;
1540 return d2d_cdt_insert_segment(cdt, geometry, &new_origin, edge, end_vertex);
1543 if (next.idx == origin->idx)
1545 ERR("Triangle not found.\n");
1546 return FALSE;
1551 static BOOL d2d_cdt_insert_segments(struct d2d_cdt *cdt, struct d2d_geometry *geometry)
1553 size_t start_vertex, end_vertex, i, j, k;
1554 struct d2d_cdt_edge_ref edge, new_edge;
1555 const struct d2d_figure *figure;
1556 const D2D1_POINT_2F *p;
1557 BOOL found;
1559 for (i = 0; i < geometry->u.path.figure_count; ++i)
1561 figure = &geometry->u.path.figures[i];
1563 if (figure->flags & D2D_FIGURE_FLAG_HOLLOW)
1564 continue;
1566 /* Degenerate figure. */
1567 if (figure->vertex_count < 2)
1568 continue;
1570 p = bsearch(&figure->vertices[figure->vertex_count - 1], cdt->vertices,
1571 geometry->fill.vertex_count, sizeof(*p), d2d_cdt_compare_vertices);
1572 start_vertex = p - cdt->vertices;
1574 for (k = 0, found = FALSE; k < cdt->edge_count; ++k)
1576 if (cdt->edges[k].flags & D2D_CDT_EDGE_FLAG_FREED)
1577 continue;
1579 edge.idx = k;
1580 edge.r = 0;
1582 if (d2d_cdt_edge_origin(cdt, &edge) == start_vertex)
1584 found = TRUE;
1585 break;
1587 d2d_cdt_edge_sym(&edge, &edge);
1588 if (d2d_cdt_edge_origin(cdt, &edge) == start_vertex)
1590 found = TRUE;
1591 break;
1595 if (!found)
1597 ERR("Edge not found.\n");
1598 return FALSE;
1601 for (j = 0; j < figure->vertex_count; start_vertex = end_vertex, ++j)
1603 p = bsearch(&figure->vertices[j], cdt->vertices,
1604 geometry->fill.vertex_count, sizeof(*p), d2d_cdt_compare_vertices);
1605 end_vertex = p - cdt->vertices;
1607 if (start_vertex == end_vertex)
1608 continue;
1610 if (!d2d_cdt_insert_segment(cdt, geometry, &edge, &new_edge, end_vertex))
1611 return FALSE;
1612 edge = new_edge;
1616 return TRUE;
1619 static BOOL d2d_geometry_intersections_add(struct d2d_geometry_intersections *i,
1620 const struct d2d_segment_idx *segment_idx, float t, D2D1_POINT_2F p)
1622 struct d2d_geometry_intersection *intersection;
1624 if (!d2d_array_reserve((void **)&i->intersections, &i->intersections_size,
1625 i->intersection_count + 1, sizeof(*i->intersections)))
1627 ERR("Failed to grow intersections array.\n");
1628 return FALSE;
1631 intersection = &i->intersections[i->intersection_count++];
1632 intersection->figure_idx = segment_idx->figure_idx;
1633 intersection->vertex_idx = segment_idx->vertex_idx;
1634 intersection->control_idx = segment_idx->control_idx;
1635 intersection->t = t;
1636 intersection->p = p;
1638 return TRUE;
1641 static int __cdecl d2d_geometry_intersections_compare(const void *a, const void *b)
1643 const struct d2d_geometry_intersection *i0 = a;
1644 const struct d2d_geometry_intersection *i1 = b;
1646 if (i0->figure_idx != i1->figure_idx)
1647 return i0->figure_idx - i1->figure_idx;
1648 if (i0->vertex_idx != i1->vertex_idx)
1649 return i0->vertex_idx - i1->vertex_idx;
1650 if (i0->t != i1->t)
1651 return i0->t > i1->t ? 1 : -1;
1652 return 0;
1655 static BOOL d2d_geometry_intersect_line_line(struct d2d_geometry *geometry,
1656 struct d2d_geometry_intersections *intersections, const struct d2d_segment_idx *idx_p,
1657 const struct d2d_segment_idx *idx_q)
1659 D2D1_POINT_2F v_p, v_q, v_qp, intersection;
1660 const D2D1_POINT_2F *p[2], *q[2];
1661 const struct d2d_figure *figure;
1662 float s, t, det;
1663 size_t next;
1665 figure = &geometry->u.path.figures[idx_p->figure_idx];
1666 p[0] = &figure->vertices[idx_p->vertex_idx];
1667 next = idx_p->vertex_idx + 1;
1668 if (next == figure->vertex_count)
1669 next = 0;
1670 p[1] = &figure->vertices[next];
1672 figure = &geometry->u.path.figures[idx_q->figure_idx];
1673 q[0] = &figure->vertices[idx_q->vertex_idx];
1674 next = idx_q->vertex_idx + 1;
1675 if (next == figure->vertex_count)
1676 next = 0;
1677 q[1] = &figure->vertices[next];
1679 d2d_point_subtract(&v_p, p[1], p[0]);
1680 d2d_point_subtract(&v_q, q[1], q[0]);
1681 d2d_point_subtract(&v_qp, p[0], q[0]);
1683 det = v_p.x * v_q.y - v_p.y * v_q.x;
1684 if (det == 0.0f)
1685 return TRUE;
1687 s = (v_q.x * v_qp.y - v_q.y * v_qp.x) / det;
1688 t = (v_p.x * v_qp.y - v_p.y * v_qp.x) / det;
1690 if (s < 0.0f || s > 1.0f || t < 0.0f || t > 1.0f)
1691 return TRUE;
1693 intersection.x = p[0]->x + v_p.x * s;
1694 intersection.y = p[0]->y + v_p.y * s;
1696 if (s > 0.0f && s < 1.0f && !d2d_geometry_intersections_add(intersections, idx_p, s, intersection))
1697 return FALSE;
1699 if (t > 0.0f && t < 1.0f && !d2d_geometry_intersections_add(intersections, idx_q, t, intersection))
1700 return FALSE;
1702 return TRUE;
1705 static BOOL d2d_geometry_add_bezier_line_intersections(struct d2d_geometry *geometry,
1706 struct d2d_geometry_intersections *intersections, const struct d2d_segment_idx *idx_p,
1707 const D2D1_POINT_2F **p, const struct d2d_segment_idx *idx_q, const D2D1_POINT_2F **q, float s)
1709 D2D1_POINT_2F intersection;
1710 float t;
1712 d2d_point_calculate_bezier(&intersection, p[0], p[1], p[2], s);
1713 if (fabsf(q[1]->x - q[0]->x) > fabsf(q[1]->y - q[0]->y))
1714 t = (intersection.x - q[0]->x) / (q[1]->x - q[0]->x);
1715 else
1716 t = (intersection.y - q[0]->y) / (q[1]->y - q[0]->y);
1717 if (t < 0.0f || t > 1.0f)
1718 return TRUE;
1720 d2d_point_lerp(&intersection, q[0], q[1], t);
1722 if (s > 0.0f && s < 1.0f && !d2d_geometry_intersections_add(intersections, idx_p, s, intersection))
1723 return FALSE;
1725 if (t > 0.0f && t < 1.0f && !d2d_geometry_intersections_add(intersections, idx_q, t, intersection))
1726 return FALSE;
1728 return TRUE;
1731 static BOOL d2d_geometry_intersect_bezier_line(struct d2d_geometry *geometry,
1732 struct d2d_geometry_intersections *intersections,
1733 const struct d2d_segment_idx *idx_p, const struct d2d_segment_idx *idx_q)
1735 const D2D1_POINT_2F *p[3], *q[2];
1736 const struct d2d_figure *figure;
1737 float y[3], root, theta, d, e;
1738 size_t next;
1740 figure = &geometry->u.path.figures[idx_p->figure_idx];
1741 p[0] = &figure->vertices[idx_p->vertex_idx];
1742 p[1] = &figure->bezier_controls[idx_p->control_idx];
1743 next = idx_p->vertex_idx + 1;
1744 if (next == figure->vertex_count)
1745 next = 0;
1746 p[2] = &figure->vertices[next];
1748 figure = &geometry->u.path.figures[idx_q->figure_idx];
1749 q[0] = &figure->vertices[idx_q->vertex_idx];
1750 next = idx_q->vertex_idx + 1;
1751 if (next == figure->vertex_count)
1752 next = 0;
1753 q[1] = &figure->vertices[next];
1755 /* Align the line with x-axis. */
1756 theta = -atan2f(q[1]->y - q[0]->y, q[1]->x - q[0]->x);
1757 y[0] = (p[0]->x - q[0]->x) * sinf(theta) + (p[0]->y - q[0]->y) * cosf(theta);
1758 y[1] = (p[1]->x - q[0]->x) * sinf(theta) + (p[1]->y - q[0]->y) * cosf(theta);
1759 y[2] = (p[2]->x - q[0]->x) * sinf(theta) + (p[2]->y - q[0]->y) * cosf(theta);
1761 /* Intersect the transformed curve with the x-axis.
1763 * f(t) = (1 - t)²P₀ + 2(1 - t)tP₁ + t²P₂
1764 * = (P₀ - 2P₁ + P₂)t² + 2(P₁ - P₀)t + P₀
1766 * a = P₀ - 2P₁ + P₂
1767 * b = 2(P₁ - P₀)
1768 * c = P₀
1770 * f(t) = 0
1771 * t = (-b ± √(b² - 4ac)) / 2a
1772 * = (-2(P₁ - P₀) ± √((2(P₁ - P₀))² - 4((P₀ - 2P₁ + P₂)P₀))) / 2(P₀ - 2P₁ + P₂)
1773 * = (2P₀ - 2P₁ ± √(4P₀² + 4P₁² - 8P₀P₁ - 4P₀² + 8P₀P₁ - 4P₀P₂)) / (2P₀ - 4P₁ + 2P₂)
1774 * = (P₀ - P₁ ± √(P₁² - P₀P₂)) / (P₀ - 2P₁ + P₂) */
1776 d = y[0] - 2 * y[1] + y[2];
1777 if (d == 0.0f)
1779 /* P₀ - 2P₁ + P₂ = 0
1780 * f(t) = (P₀ - 2P₁ + P₂)t² + 2(P₁ - P₀)t + P₀ = 0
1781 * t = -P₀ / 2(P₁ - P₀) */
1782 root = -y[0] / (2.0f * (y[1] - y[0]));
1783 if (root < 0.0f || root > 1.0f)
1784 return TRUE;
1786 return d2d_geometry_add_bezier_line_intersections(geometry, intersections, idx_p, p, idx_q, q, root);
1789 e = y[1] * y[1] - y[0] * y[2];
1790 if (e < 0.0f)
1791 return TRUE;
1793 root = (y[0] - y[1] + sqrtf(e)) / d;
1794 if (root >= 0.0f && root <= 1.0f && !d2d_geometry_add_bezier_line_intersections(geometry,
1795 intersections, idx_p, p, idx_q, q, root))
1796 return FALSE;
1798 root = (y[0] - y[1] - sqrtf(e)) / d;
1799 if (root >= 0.0f && root <= 1.0f && !d2d_geometry_add_bezier_line_intersections(geometry,
1800 intersections, idx_p, p, idx_q, q, root))
1801 return FALSE;
1803 return TRUE;
1806 static BOOL d2d_geometry_intersect_bezier_bezier(struct d2d_geometry *geometry,
1807 struct d2d_geometry_intersections *intersections,
1808 const struct d2d_segment_idx *idx_p, float start_p, float end_p,
1809 const struct d2d_segment_idx *idx_q, float start_q, float end_q)
1811 const D2D1_POINT_2F *p[3], *q[3];
1812 const struct d2d_figure *figure;
1813 D2D_RECT_F p_bounds, q_bounds;
1814 D2D1_POINT_2F intersection;
1815 float centre_p, centre_q;
1816 size_t next;
1818 figure = &geometry->u.path.figures[idx_p->figure_idx];
1819 p[0] = &figure->vertices[idx_p->vertex_idx];
1820 p[1] = &figure->bezier_controls[idx_p->control_idx];
1821 next = idx_p->vertex_idx + 1;
1822 if (next == figure->vertex_count)
1823 next = 0;
1824 p[2] = &figure->vertices[next];
1826 figure = &geometry->u.path.figures[idx_q->figure_idx];
1827 q[0] = &figure->vertices[idx_q->vertex_idx];
1828 q[1] = &figure->bezier_controls[idx_q->control_idx];
1829 next = idx_q->vertex_idx + 1;
1830 if (next == figure->vertex_count)
1831 next = 0;
1832 q[2] = &figure->vertices[next];
1834 d2d_rect_get_bezier_segment_bounds(&p_bounds, p[0], p[1], p[2], start_p, end_p);
1835 d2d_rect_get_bezier_segment_bounds(&q_bounds, q[0], q[1], q[2], start_q, end_q);
1837 if (!d2d_rect_check_overlap(&p_bounds, &q_bounds))
1838 return TRUE;
1840 centre_p = (start_p + end_p) / 2.0f;
1841 centre_q = (start_q + end_q) / 2.0f;
1843 if (end_p - start_p < 1e-3f)
1845 d2d_point_calculate_bezier(&intersection, p[0], p[1], p[2], centre_p);
1846 if (start_p > 0.0f && end_p < 1.0f && !d2d_geometry_intersections_add(intersections,
1847 idx_p, centre_p, intersection))
1848 return FALSE;
1849 if (start_q > 0.0f && end_q < 1.0f && !d2d_geometry_intersections_add(intersections,
1850 idx_q, centre_q, intersection))
1851 return FALSE;
1852 return TRUE;
1855 if (!d2d_geometry_intersect_bezier_bezier(geometry, intersections,
1856 idx_p, start_p, centre_p, idx_q, start_q, centre_q))
1857 return FALSE;
1858 if (!d2d_geometry_intersect_bezier_bezier(geometry, intersections,
1859 idx_p, start_p, centre_p, idx_q, centre_q, end_q))
1860 return FALSE;
1861 if (!d2d_geometry_intersect_bezier_bezier(geometry, intersections,
1862 idx_p, centre_p, end_p, idx_q, start_q, centre_q))
1863 return FALSE;
1864 if (!d2d_geometry_intersect_bezier_bezier(geometry, intersections,
1865 idx_p, centre_p, end_p, idx_q, centre_q, end_q))
1866 return FALSE;
1868 return TRUE;
1871 static BOOL d2d_geometry_apply_intersections(struct d2d_geometry *geometry,
1872 struct d2d_geometry_intersections *intersections)
1874 size_t vertex_offset, control_offset, next, i;
1875 struct d2d_geometry_intersection *inter;
1876 enum d2d_vertex_type vertex_type;
1877 const D2D1_POINT_2F *p[3];
1878 struct d2d_figure *figure;
1879 D2D1_POINT_2F q[2];
1880 float t, t_prev;
1882 for (i = 0; i < intersections->intersection_count; ++i)
1884 inter = &intersections->intersections[i];
1885 if (!i || inter->figure_idx != intersections->intersections[i - 1].figure_idx)
1886 vertex_offset = control_offset = 0;
1888 figure = &geometry->u.path.figures[inter->figure_idx];
1889 vertex_type = figure->vertex_types[inter->vertex_idx + vertex_offset];
1890 if (!d2d_vertex_type_is_bezier(vertex_type))
1892 if (!d2d_figure_insert_vertex(&geometry->u.path.figures[inter->figure_idx],
1893 inter->vertex_idx + vertex_offset + 1, inter->p))
1894 return FALSE;
1895 ++vertex_offset;
1896 continue;
1899 t = inter->t;
1900 if (i && inter->figure_idx == intersections->intersections[i - 1].figure_idx
1901 && inter->vertex_idx == intersections->intersections[i - 1].vertex_idx)
1903 t_prev = intersections->intersections[i - 1].t;
1904 if (t - t_prev < 1e-3f)
1906 inter->t = intersections->intersections[i - 1].t;
1907 continue;
1909 t = (t - t_prev) / (1.0f - t_prev);
1912 p[0] = &figure->vertices[inter->vertex_idx + vertex_offset];
1913 p[1] = &figure->bezier_controls[inter->control_idx + control_offset];
1914 next = inter->vertex_idx + vertex_offset + 1;
1915 if (next == figure->vertex_count)
1916 next = 0;
1917 p[2] = &figure->vertices[next];
1919 d2d_point_lerp(&q[0], p[0], p[1], t);
1920 d2d_point_lerp(&q[1], p[1], p[2], t);
1922 figure->bezier_controls[inter->control_idx + control_offset] = q[0];
1923 if (!(d2d_figure_insert_bezier_controls(figure, inter->control_idx + control_offset + 1, 1, &q[1])))
1924 return FALSE;
1925 ++control_offset;
1927 if (!(d2d_figure_insert_vertex(figure, inter->vertex_idx + vertex_offset + 1, inter->p)))
1928 return FALSE;
1929 figure->vertex_types[inter->vertex_idx + vertex_offset + 1] = D2D_VERTEX_TYPE_SPLIT_BEZIER;
1930 ++vertex_offset;
1933 return TRUE;
1936 /* Intersect the geometry's segments with themselves. This uses the
1937 * straightforward approach of testing everything against everything, but
1938 * there certainly exist more scalable algorithms for this. */
1939 static BOOL d2d_geometry_intersect_self(struct d2d_geometry *geometry)
1941 struct d2d_geometry_intersections intersections = {0};
1942 const struct d2d_figure *figure_p, *figure_q;
1943 struct d2d_segment_idx idx_p, idx_q;
1944 enum d2d_vertex_type type_p, type_q;
1945 BOOL ret = FALSE;
1946 size_t max_q;
1948 if (!geometry->u.path.figure_count)
1949 return TRUE;
1951 for (idx_p.figure_idx = 0; idx_p.figure_idx < geometry->u.path.figure_count; ++idx_p.figure_idx)
1953 figure_p = &geometry->u.path.figures[idx_p.figure_idx];
1954 idx_p.control_idx = 0;
1955 for (idx_p.vertex_idx = 0; idx_p.vertex_idx < figure_p->vertex_count; ++idx_p.vertex_idx)
1957 type_p = figure_p->vertex_types[idx_p.vertex_idx];
1958 for (idx_q.figure_idx = 0; idx_q.figure_idx <= idx_p.figure_idx; ++idx_q.figure_idx)
1960 figure_q = &geometry->u.path.figures[idx_q.figure_idx];
1961 if (idx_q.figure_idx != idx_p.figure_idx)
1963 if (!d2d_rect_check_overlap(&figure_p->bounds, &figure_q->bounds))
1964 continue;
1965 max_q = figure_q->vertex_count;
1967 else
1969 max_q = idx_p.vertex_idx;
1972 idx_q.control_idx = 0;
1973 for (idx_q.vertex_idx = 0; idx_q.vertex_idx < max_q; ++idx_q.vertex_idx)
1975 type_q = figure_q->vertex_types[idx_q.vertex_idx];
1976 if (d2d_vertex_type_is_bezier(type_q))
1978 if (d2d_vertex_type_is_bezier(type_p))
1980 if (!d2d_geometry_intersect_bezier_bezier(geometry, &intersections,
1981 &idx_p, 0.0f, 1.0f, &idx_q, 0.0f, 1.0f))
1982 goto done;
1984 else
1986 if (!d2d_geometry_intersect_bezier_line(geometry, &intersections, &idx_q, &idx_p))
1987 goto done;
1989 ++idx_q.control_idx;
1991 else
1993 if (d2d_vertex_type_is_bezier(type_p))
1995 if (!d2d_geometry_intersect_bezier_line(geometry, &intersections, &idx_p, &idx_q))
1996 goto done;
1998 else
2000 if (!d2d_geometry_intersect_line_line(geometry, &intersections, &idx_p, &idx_q))
2001 goto done;
2006 if (d2d_vertex_type_is_bezier(type_p))
2007 ++idx_p.control_idx;
2011 qsort(intersections.intersections, intersections.intersection_count,
2012 sizeof(*intersections.intersections), d2d_geometry_intersections_compare);
2013 ret = d2d_geometry_apply_intersections(geometry, &intersections);
2015 done:
2016 heap_free(intersections.intersections);
2017 return ret;
2020 static HRESULT d2d_path_geometry_triangulate(struct d2d_geometry *geometry)
2022 struct d2d_cdt_edge_ref left_edge, right_edge;
2023 size_t vertex_count, i, j;
2024 struct d2d_cdt cdt = {0};
2025 D2D1_POINT_2F *vertices;
2027 for (i = 0, vertex_count = 0; i < geometry->u.path.figure_count; ++i)
2029 if (geometry->u.path.figures[i].flags & D2D_FIGURE_FLAG_HOLLOW)
2030 continue;
2031 vertex_count += geometry->u.path.figures[i].vertex_count;
2034 if (vertex_count < 3)
2036 WARN("Geometry has %lu vertices.\n", (long)vertex_count);
2037 return S_OK;
2040 if (!(vertices = heap_calloc(vertex_count, sizeof(*vertices))))
2041 return E_OUTOFMEMORY;
2043 for (i = 0, j = 0; i < geometry->u.path.figure_count; ++i)
2045 if (geometry->u.path.figures[i].flags & D2D_FIGURE_FLAG_HOLLOW)
2046 continue;
2047 memcpy(&vertices[j], geometry->u.path.figures[i].vertices,
2048 geometry->u.path.figures[i].vertex_count * sizeof(*vertices));
2049 j += geometry->u.path.figures[i].vertex_count;
2052 /* Sort vertices, eliminate duplicates. */
2053 qsort(vertices, vertex_count, sizeof(*vertices), d2d_cdt_compare_vertices);
2054 for (i = 1; i < vertex_count; ++i)
2056 if (!memcmp(&vertices[i - 1], &vertices[i], sizeof(*vertices)))
2058 --vertex_count;
2059 memmove(&vertices[i], &vertices[i + 1], (vertex_count - i) * sizeof(*vertices));
2060 --i;
2064 if (vertex_count < 3)
2066 WARN("Geometry has %lu vertices after eliminating duplicates.\n", (long)vertex_count);
2067 heap_free(vertices);
2068 return S_OK;
2071 geometry->fill.vertices = vertices;
2072 geometry->fill.vertex_count = vertex_count;
2074 cdt.free_edge = ~0u;
2075 cdt.vertices = vertices;
2076 if (!d2d_cdt_triangulate(&cdt, 0, vertex_count, &left_edge, &right_edge))
2077 goto fail;
2078 if (!d2d_cdt_insert_segments(&cdt, geometry))
2079 goto fail;
2080 if (!d2d_cdt_generate_faces(&cdt, geometry))
2081 goto fail;
2083 heap_free(cdt.edges);
2084 return S_OK;
2086 fail:
2087 geometry->fill.vertices = NULL;
2088 geometry->fill.vertex_count = 0;
2089 heap_free(vertices);
2090 heap_free(cdt.edges);
2091 return E_FAIL;
2094 static BOOL d2d_path_geometry_add_figure(struct d2d_geometry *geometry)
2096 struct d2d_figure *figure;
2098 if (!d2d_array_reserve((void **)&geometry->u.path.figures, &geometry->u.path.figures_size,
2099 geometry->u.path.figure_count + 1, sizeof(*geometry->u.path.figures)))
2101 ERR("Failed to grow figures array.\n");
2102 return FALSE;
2105 figure = &geometry->u.path.figures[geometry->u.path.figure_count];
2106 memset(figure, 0, sizeof(*figure));
2107 figure->bounds.left = FLT_MAX;
2108 figure->bounds.top = FLT_MAX;
2109 figure->bounds.right = -FLT_MAX;
2110 figure->bounds.bottom = -FLT_MAX;
2112 ++geometry->u.path.figure_count;
2113 return TRUE;
2116 static BOOL d2d_geometry_outline_add_join(struct d2d_geometry *geometry,
2117 const D2D1_POINT_2F *prev, const D2D1_POINT_2F *p0, const D2D1_POINT_2F *next)
2119 static const D2D1_POINT_2F origin = {0.0f, 0.0f};
2120 struct d2d_outline_vertex *v;
2121 struct d2d_face *f;
2122 size_t base_idx;
2123 float ccw;
2125 if (!d2d_array_reserve((void **)&geometry->outline.vertices, &geometry->outline.vertices_size,
2126 geometry->outline.vertex_count + 4, sizeof(*geometry->outline.vertices)))
2128 ERR("Failed to grow outline vertices array.\n");
2129 return FALSE;
2131 base_idx = geometry->outline.vertex_count;
2132 v = &geometry->outline.vertices[base_idx];
2134 if (!d2d_array_reserve((void **)&geometry->outline.faces, &geometry->outline.faces_size,
2135 geometry->outline.face_count + 2, sizeof(*geometry->outline.faces)))
2137 ERR("Failed to grow outline faces array.\n");
2138 return FALSE;
2140 f = &geometry->outline.faces[geometry->outline.face_count];
2142 ccw = d2d_point_ccw(&origin, prev, next);
2143 if (ccw == 0.0f)
2145 d2d_outline_vertex_set(&v[0], p0->x, p0->y, -prev->x, -prev->y, -prev->x, -prev->y);
2146 d2d_outline_vertex_set(&v[1], p0->x, p0->y, prev->x, prev->y, prev->x, prev->y);
2147 d2d_outline_vertex_set(&v[2], p0->x + 25.0f * -prev->x, p0->y + 25.0f * -prev->y,
2148 prev->x, prev->y, prev->x, prev->y);
2149 d2d_outline_vertex_set(&v[3], p0->x + 25.0f * -prev->x, p0->y + 25.0f * -prev->y,
2150 -prev->x, -prev->y, -prev->x, -prev->y);
2152 else if (ccw < 0.0f)
2154 d2d_outline_vertex_set(&v[0], p0->x, p0->y, next->x, next->y, -prev->x, -prev->y);
2155 d2d_outline_vertex_set(&v[1], p0->x, p0->y, -next->x, -next->y, -next->x, -next->y);
2156 d2d_outline_vertex_set(&v[2], p0->x, p0->y, -next->x, -next->y, prev->x, prev->y);
2157 d2d_outline_vertex_set(&v[3], p0->x, p0->y, prev->x, prev->y, prev->x, prev->y);
2159 else
2161 d2d_outline_vertex_set(&v[0], p0->x, p0->y, prev->x, prev->y, -next->x, -next->y);
2162 d2d_outline_vertex_set(&v[1], p0->x, p0->y, -prev->x, -prev->y, -prev->x, -prev->y);
2163 d2d_outline_vertex_set(&v[2], p0->x, p0->y, -prev->x, -prev->y, next->x, next->y);
2164 d2d_outline_vertex_set(&v[3], p0->x, p0->y, next->x, next->y, next->x, next->y);
2166 geometry->outline.vertex_count += 4;
2168 d2d_face_set(&f[0], base_idx + 1, base_idx + 0, base_idx + 2);
2169 d2d_face_set(&f[1], base_idx + 2, base_idx + 0, base_idx + 3);
2170 geometry->outline.face_count += 2;
2172 return TRUE;
2175 static BOOL d2d_geometry_outline_add_line_segment(struct d2d_geometry *geometry,
2176 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *next)
2178 struct d2d_outline_vertex *v;
2179 D2D1_POINT_2F q_next;
2180 struct d2d_face *f;
2181 size_t base_idx;
2183 if (!d2d_array_reserve((void **)&geometry->outline.vertices, &geometry->outline.vertices_size,
2184 geometry->outline.vertex_count + 4, sizeof(*geometry->outline.vertices)))
2186 ERR("Failed to grow outline vertices array.\n");
2187 return FALSE;
2189 base_idx = geometry->outline.vertex_count;
2190 v = &geometry->outline.vertices[base_idx];
2192 if (!d2d_array_reserve((void **)&geometry->outline.faces, &geometry->outline.faces_size,
2193 geometry->outline.face_count + 2, sizeof(*geometry->outline.faces)))
2195 ERR("Failed to grow outline faces array.\n");
2196 return FALSE;
2198 f = &geometry->outline.faces[geometry->outline.face_count];
2200 d2d_point_subtract(&q_next, next, p0);
2201 d2d_point_normalise(&q_next);
2203 d2d_outline_vertex_set(&v[0], p0->x, p0->y, q_next.x, q_next.y, q_next.x, q_next.y);
2204 d2d_outline_vertex_set(&v[1], p0->x, p0->y, -q_next.x, -q_next.y, -q_next.x, -q_next.y);
2205 d2d_outline_vertex_set(&v[2], next->x, next->y, q_next.x, q_next.y, q_next.x, q_next.y);
2206 d2d_outline_vertex_set(&v[3], next->x, next->y, -q_next.x, -q_next.y, -q_next.x, -q_next.y);
2207 geometry->outline.vertex_count += 4;
2209 d2d_face_set(&f[0], base_idx + 0, base_idx + 1, base_idx + 2);
2210 d2d_face_set(&f[1], base_idx + 2, base_idx + 1, base_idx + 3);
2211 geometry->outline.face_count += 2;
2213 return TRUE;
2216 static BOOL d2d_geometry_outline_add_bezier_segment(struct d2d_geometry *geometry,
2217 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2)
2219 struct d2d_curve_outline_vertex *b;
2220 D2D1_POINT_2F r0, r1, r2;
2221 D2D1_POINT_2F q0, q1, q2;
2222 struct d2d_face *f;
2223 size_t base_idx;
2225 if (!d2d_array_reserve((void **)&geometry->outline.beziers, &geometry->outline.beziers_size,
2226 geometry->outline.bezier_count + 7, sizeof(*geometry->outline.beziers)))
2228 ERR("Failed to grow outline beziers array.\n");
2229 return FALSE;
2231 base_idx = geometry->outline.bezier_count;
2232 b = &geometry->outline.beziers[base_idx];
2234 if (!d2d_array_reserve((void **)&geometry->outline.bezier_faces, &geometry->outline.bezier_faces_size,
2235 geometry->outline.bezier_face_count + 5, sizeof(*geometry->outline.bezier_faces)))
2237 ERR("Failed to grow outline faces array.\n");
2238 return FALSE;
2240 f = &geometry->outline.bezier_faces[geometry->outline.bezier_face_count];
2242 d2d_point_lerp(&q0, p0, p1, 0.5f);
2243 d2d_point_lerp(&q1, p1, p2, 0.5f);
2244 d2d_point_lerp(&q2, &q0, &q1, 0.5f);
2246 d2d_point_subtract(&r0, &q0, p0);
2247 d2d_point_subtract(&r1, &q1, &q0);
2248 d2d_point_subtract(&r2, p2, &q1);
2250 d2d_point_normalise(&r0);
2251 d2d_point_normalise(&r1);
2252 d2d_point_normalise(&r2);
2254 if (d2d_point_ccw(p0, p1, p2) > 0.0f)
2256 d2d_point_scale(&r0, -1.0f);
2257 d2d_point_scale(&r1, -1.0f);
2258 d2d_point_scale(&r2, -1.0f);
2261 d2d_curve_outline_vertex_set(&b[0], p0, p0, p1, p2, r0.x, r0.y, r0.x, r0.y);
2262 d2d_curve_outline_vertex_set(&b[1], p0, p0, p1, p2, -r0.x, -r0.y, -r0.x, -r0.y);
2263 d2d_curve_outline_vertex_set(&b[2], &q0, p0, p1, p2, r0.x, r0.y, r1.x, r1.y);
2264 d2d_curve_outline_vertex_set(&b[3], &q2, p0, p1, p2, -r1.x, -r1.y, -r1.x, -r1.y);
2265 d2d_curve_outline_vertex_set(&b[4], &q1, p0, p1, p2, r1.x, r1.y, r2.x, r2.y);
2266 d2d_curve_outline_vertex_set(&b[5], p2, p0, p1, p2, -r2.x, -r2.y, -r2.x, -r2.y);
2267 d2d_curve_outline_vertex_set(&b[6], p2, p0, p1, p2, r2.x, r2.y, r2.x, r2.y);
2268 geometry->outline.bezier_count += 7;
2270 d2d_face_set(&f[0], base_idx + 0, base_idx + 1, base_idx + 2);
2271 d2d_face_set(&f[1], base_idx + 2, base_idx + 1, base_idx + 3);
2272 d2d_face_set(&f[2], base_idx + 3, base_idx + 4, base_idx + 2);
2273 d2d_face_set(&f[3], base_idx + 5, base_idx + 4, base_idx + 3);
2274 d2d_face_set(&f[4], base_idx + 5, base_idx + 6, base_idx + 4);
2275 geometry->outline.bezier_face_count += 5;
2277 return TRUE;
2280 static BOOL d2d_geometry_outline_add_arc_quadrant(struct d2d_geometry *geometry,
2281 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2)
2283 struct d2d_curve_outline_vertex *a;
2284 D2D1_POINT_2F r0, r1;
2285 struct d2d_face *f;
2286 size_t base_idx;
2288 if (!d2d_array_reserve((void **)&geometry->outline.arcs, &geometry->outline.arcs_size,
2289 geometry->outline.arc_count + 5, sizeof(*geometry->outline.arcs)))
2291 ERR("Failed to grow outline arcs array.\n");
2292 return FALSE;
2294 base_idx = geometry->outline.arc_count;
2295 a = &geometry->outline.arcs[base_idx];
2297 if (!d2d_array_reserve((void **)&geometry->outline.arc_faces, &geometry->outline.arc_faces_size,
2298 geometry->outline.arc_face_count + 3, sizeof(*geometry->outline.arc_faces)))
2300 ERR("Failed to grow outline faces array.\n");
2301 return FALSE;
2303 f = &geometry->outline.arc_faces[geometry->outline.arc_face_count];
2305 d2d_point_subtract(&r0, p1, p0);
2306 d2d_point_subtract(&r1, p2, p1);
2308 d2d_point_normalise(&r0);
2309 d2d_point_normalise(&r1);
2311 if (d2d_point_ccw(p0, p1, p2) > 0.0f)
2313 d2d_point_scale(&r0, -1.0f);
2314 d2d_point_scale(&r1, -1.0f);
2317 d2d_curve_outline_vertex_set(&a[0], p0, p0, p1, p2, r0.x, r0.y, r0.x, r0.y);
2318 d2d_curve_outline_vertex_set(&a[1], p0, p0, p1, p2, -r0.x, -r0.y, -r0.x, -r0.y);
2319 d2d_curve_outline_vertex_set(&a[2], p1, p0, p1, p2, r0.x, r0.y, r1.x, r1.y);
2320 d2d_curve_outline_vertex_set(&a[3], p2, p0, p1, p2, -r1.x, -r1.y, -r1.x, -r1.y);
2321 d2d_curve_outline_vertex_set(&a[4], p2, p0, p1, p2, r1.x, r1.y, r1.x, r1.y);
2322 geometry->outline.arc_count += 5;
2324 d2d_face_set(&f[0], base_idx + 0, base_idx + 1, base_idx + 2);
2325 d2d_face_set(&f[1], base_idx + 2, base_idx + 1, base_idx + 3);
2326 d2d_face_set(&f[2], base_idx + 2, base_idx + 4, base_idx + 3);
2327 geometry->outline.arc_face_count += 3;
2329 return TRUE;
2332 static BOOL d2d_geometry_add_figure_outline(struct d2d_geometry *geometry,
2333 struct d2d_figure *figure, D2D1_FIGURE_END figure_end)
2335 const D2D1_POINT_2F *prev, *p0, *next;
2336 enum d2d_vertex_type prev_type, type;
2337 size_t bezier_idx, i;
2339 for (i = 0, bezier_idx = 0; i < figure->vertex_count; ++i)
2341 type = figure->vertex_types[i];
2342 if (type == D2D_VERTEX_TYPE_NONE)
2343 continue;
2345 p0 = &figure->vertices[i];
2347 if (!i)
2349 prev_type = figure->vertex_types[figure->vertex_count - 1];
2350 if (d2d_vertex_type_is_bezier(prev_type))
2351 prev = &figure->bezier_controls[figure->bezier_control_count - 1];
2352 else
2353 prev = &figure->vertices[figure->vertex_count - 1];
2355 else
2357 prev_type = figure->vertex_types[i - 1];
2358 if (d2d_vertex_type_is_bezier(prev_type))
2359 prev = &figure->bezier_controls[bezier_idx - 1];
2360 else
2361 prev = &figure->vertices[i - 1];
2364 if (d2d_vertex_type_is_bezier(type))
2365 next = &figure->bezier_controls[bezier_idx++];
2366 else if (i == figure->vertex_count - 1)
2367 next = &figure->vertices[0];
2368 else
2369 next = &figure->vertices[i + 1];
2371 if (figure_end == D2D1_FIGURE_END_CLOSED || (i && i < figure->vertex_count - 1))
2373 D2D1_POINT_2F q_next, q_prev;
2375 d2d_point_subtract(&q_prev, prev, p0);
2376 d2d_point_subtract(&q_next, next, p0);
2378 d2d_point_normalise(&q_prev);
2379 d2d_point_normalise(&q_next);
2381 if (!d2d_geometry_outline_add_join(geometry, &q_prev, p0, &q_next))
2383 ERR("Failed to add join.\n");
2384 return FALSE;
2388 if (type == D2D_VERTEX_TYPE_LINE && (figure_end == D2D1_FIGURE_END_CLOSED || i < figure->vertex_count - 1)
2389 && !d2d_geometry_outline_add_line_segment(geometry, p0, next))
2391 ERR("Failed to add line segment.\n");
2392 return FALSE;
2394 else if (d2d_vertex_type_is_bezier(type))
2396 const D2D1_POINT_2F *p2;
2398 if (i == figure->vertex_count - 1)
2399 p2 = &figure->vertices[0];
2400 else
2401 p2 = &figure->vertices[i + 1];
2403 if (!d2d_geometry_outline_add_bezier_segment(geometry, p0, next, p2))
2405 ERR("Failed to add bezier segment.\n");
2406 return FALSE;
2411 return TRUE;
2414 static BOOL d2d_geometry_fill_add_arc_triangle(struct d2d_geometry *geometry,
2415 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2)
2417 struct d2d_curve_vertex *a;
2419 if (!d2d_array_reserve((void **)&geometry->fill.arc_vertices, &geometry->fill.arc_vertices_size,
2420 geometry->fill.arc_vertex_count + 3, sizeof(*geometry->fill.arc_vertices)))
2421 return FALSE;
2423 a = &geometry->fill.arc_vertices[geometry->fill.arc_vertex_count];
2424 d2d_curve_vertex_set(&a[0], p0, 0.0f, 1.0f, -1.0f);
2425 d2d_curve_vertex_set(&a[1], p1, 1.0f, 1.0f, -1.0f);
2426 d2d_curve_vertex_set(&a[2], p2, 1.0f, 0.0f, -1.0f);
2427 geometry->fill.arc_vertex_count += 3;
2429 return TRUE;
2432 static void d2d_geometry_cleanup(struct d2d_geometry *geometry)
2434 heap_free(geometry->outline.arc_faces);
2435 heap_free(geometry->outline.arcs);
2436 heap_free(geometry->outline.bezier_faces);
2437 heap_free(geometry->outline.beziers);
2438 heap_free(geometry->outline.faces);
2439 heap_free(geometry->outline.vertices);
2440 heap_free(geometry->fill.arc_vertices);
2441 heap_free(geometry->fill.bezier_vertices);
2442 heap_free(geometry->fill.faces);
2443 heap_free(geometry->fill.vertices);
2444 ID2D1Factory_Release(geometry->factory);
2447 static void d2d_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
2448 const D2D1_MATRIX_3X2_F *transform, const struct ID2D1GeometryVtbl *vtbl)
2450 geometry->ID2D1Geometry_iface.lpVtbl = vtbl;
2451 geometry->refcount = 1;
2452 ID2D1Factory_AddRef(geometry->factory = factory);
2453 geometry->transform = *transform;
2456 static inline struct d2d_geometry *impl_from_ID2D1GeometrySink(ID2D1GeometrySink *iface)
2458 return CONTAINING_RECORD(iface, struct d2d_geometry, u.path.ID2D1GeometrySink_iface);
2461 static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_QueryInterface(ID2D1GeometrySink *iface, REFIID iid, void **out)
2463 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
2465 if (IsEqualGUID(iid, &IID_ID2D1GeometrySink)
2466 || IsEqualGUID(iid, &IID_ID2D1SimplifiedGeometrySink)
2467 || IsEqualGUID(iid, &IID_IUnknown))
2469 ID2D1GeometrySink_AddRef(iface);
2470 *out = iface;
2471 return S_OK;
2474 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
2476 *out = NULL;
2477 return E_NOINTERFACE;
2480 static ULONG STDMETHODCALLTYPE d2d_geometry_sink_AddRef(ID2D1GeometrySink *iface)
2482 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2484 TRACE("iface %p.\n", iface);
2486 return ID2D1Geometry_AddRef(&geometry->ID2D1Geometry_iface);
2489 static ULONG STDMETHODCALLTYPE d2d_geometry_sink_Release(ID2D1GeometrySink *iface)
2491 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2493 TRACE("iface %p.\n", iface);
2495 return ID2D1Geometry_Release(&geometry->ID2D1Geometry_iface);
2498 static void STDMETHODCALLTYPE d2d_geometry_sink_SetFillMode(ID2D1GeometrySink *iface, D2D1_FILL_MODE mode)
2500 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2502 TRACE("iface %p, mode %#x.\n", iface, mode);
2504 if (geometry->u.path.state == D2D_GEOMETRY_STATE_CLOSED)
2505 return;
2506 geometry->u.path.fill_mode = mode;
2509 static void STDMETHODCALLTYPE d2d_geometry_sink_SetSegmentFlags(ID2D1GeometrySink *iface, D2D1_PATH_SEGMENT flags)
2511 FIXME("iface %p, flags %#x stub!\n", iface, flags);
2514 static void STDMETHODCALLTYPE d2d_geometry_sink_BeginFigure(ID2D1GeometrySink *iface,
2515 D2D1_POINT_2F start_point, D2D1_FIGURE_BEGIN figure_begin)
2517 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2518 struct d2d_figure *figure;
2520 TRACE("iface %p, start_point %s, figure_begin %#x.\n",
2521 iface, debug_d2d_point_2f(&start_point), figure_begin);
2523 if (geometry->u.path.state != D2D_GEOMETRY_STATE_OPEN)
2525 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2526 return;
2529 if (!d2d_path_geometry_add_figure(geometry))
2531 ERR("Failed to add figure.\n");
2532 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2533 return;
2536 figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2537 if (figure_begin == D2D1_FIGURE_BEGIN_HOLLOW)
2538 figure->flags |= D2D_FIGURE_FLAG_HOLLOW;
2540 if (!d2d_figure_add_vertex(figure, start_point))
2542 ERR("Failed to add vertex.\n");
2543 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2544 return;
2547 geometry->u.path.state = D2D_GEOMETRY_STATE_FIGURE;
2550 static void STDMETHODCALLTYPE d2d_geometry_sink_AddLines(ID2D1GeometrySink *iface,
2551 const D2D1_POINT_2F *points, UINT32 count)
2553 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2554 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2555 unsigned int i;
2557 TRACE("iface %p, points %p, count %u.\n", iface, points, count);
2559 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2561 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2562 return;
2565 for (i = 0; i < count; ++i)
2567 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_LINE;
2568 if (!d2d_figure_add_vertex(figure, points[i]))
2570 ERR("Failed to add vertex.\n");
2571 return;
2575 geometry->u.path.segment_count += count;
2578 static void STDMETHODCALLTYPE d2d_geometry_sink_AddBeziers(ID2D1GeometrySink *iface,
2579 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
2581 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2582 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2583 D2D1_POINT_2F p;
2584 unsigned int i;
2586 TRACE("iface %p, beziers %p, count %u.\n", iface, beziers, count);
2588 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2590 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2591 return;
2594 for (i = 0; i < count; ++i)
2596 D2D1_RECT_F bezier_bounds;
2598 /* FIXME: This tries to approximate a cubic bezier with a quadratic one. */
2599 p.x = (beziers[i].point1.x + beziers[i].point2.x) * 0.75f;
2600 p.y = (beziers[i].point1.y + beziers[i].point2.y) * 0.75f;
2601 p.x -= (figure->vertices[figure->vertex_count - 1].x + beziers[i].point3.x) * 0.25f;
2602 p.y -= (figure->vertices[figure->vertex_count - 1].y + beziers[i].point3.y) * 0.25f;
2603 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_BEZIER;
2605 d2d_rect_get_bezier_bounds(&bezier_bounds, &figure->vertices[figure->vertex_count - 1],
2606 &p, &beziers[i].point3);
2608 if (!d2d_figure_add_bezier_controls(figure, 1, &p))
2610 ERR("Failed to add bezier control.\n");
2611 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2612 return;
2615 if (!d2d_figure_add_vertex(figure, beziers[i].point3))
2617 ERR("Failed to add bezier vertex.\n");
2618 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2619 return;
2622 d2d_rect_union(&figure->bounds, &bezier_bounds);
2625 geometry->u.path.segment_count += count;
2628 static void STDMETHODCALLTYPE d2d_geometry_sink_EndFigure(ID2D1GeometrySink *iface, D2D1_FIGURE_END figure_end)
2630 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2631 struct d2d_figure *figure;
2633 TRACE("iface %p, figure_end %#x.\n", iface, figure_end);
2635 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2637 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2638 return;
2641 figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2642 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_LINE;
2643 if (figure_end == D2D1_FIGURE_END_CLOSED)
2645 ++geometry->u.path.segment_count;
2646 figure->flags |= D2D_FIGURE_FLAG_CLOSED;
2647 if (!memcmp(&figure->vertices[0], &figure->vertices[figure->vertex_count - 1], sizeof(*figure->vertices)))
2648 --figure->vertex_count;
2651 if (!d2d_geometry_add_figure_outline(geometry, figure, figure_end))
2653 ERR("Failed to add figure outline.\n");
2654 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2655 return;
2658 geometry->u.path.state = D2D_GEOMETRY_STATE_OPEN;
2661 static void d2d_path_geometry_free_figures(struct d2d_geometry *geometry)
2663 size_t i;
2665 if (!geometry->u.path.figures)
2666 return;
2668 for (i = 0; i < geometry->u.path.figure_count; ++i)
2670 heap_free(geometry->u.path.figures[i].bezier_controls);
2671 heap_free(geometry->u.path.figures[i].original_bezier_controls);
2672 heap_free(geometry->u.path.figures[i].vertices);
2674 heap_free(geometry->u.path.figures);
2675 geometry->u.path.figures = NULL;
2676 geometry->u.path.figures_size = 0;
2679 static BOOL d2d_geometry_get_bezier_segment_idx(struct d2d_geometry *geometry, struct d2d_segment_idx *idx, BOOL next)
2681 if (next)
2683 ++idx->vertex_idx;
2684 ++idx->control_idx;
2687 for (; idx->figure_idx < geometry->u.path.figure_count; ++idx->figure_idx, idx->vertex_idx = idx->control_idx = 0)
2689 struct d2d_figure *figure = &geometry->u.path.figures[idx->figure_idx];
2691 if (!figure->bezier_control_count || figure->flags & D2D_FIGURE_FLAG_HOLLOW)
2692 continue;
2694 for (; idx->vertex_idx < figure->vertex_count; ++idx->vertex_idx)
2696 if (d2d_vertex_type_is_bezier(figure->vertex_types[idx->vertex_idx]))
2697 return TRUE;
2701 return FALSE;
2704 static BOOL d2d_geometry_get_first_bezier_segment_idx(struct d2d_geometry *geometry, struct d2d_segment_idx *idx)
2706 memset(idx, 0, sizeof(*idx));
2708 return d2d_geometry_get_bezier_segment_idx(geometry, idx, FALSE);
2711 static BOOL d2d_geometry_get_next_bezier_segment_idx(struct d2d_geometry *geometry, struct d2d_segment_idx *idx)
2713 return d2d_geometry_get_bezier_segment_idx(geometry, idx, TRUE);
2716 static BOOL d2d_geometry_check_bezier_overlap(struct d2d_geometry *geometry,
2717 const struct d2d_segment_idx *idx_p, const struct d2d_segment_idx *idx_q)
2719 const D2D1_POINT_2F *a[3], *b[3], *p[2], *q;
2720 const struct d2d_figure *figure;
2721 D2D1_POINT_2F v_q[3], v_p, v_qp;
2722 unsigned int i, j, score;
2723 float det, t;
2725 figure = &geometry->u.path.figures[idx_p->figure_idx];
2726 a[0] = &figure->vertices[idx_p->vertex_idx];
2727 a[1] = &figure->bezier_controls[idx_p->control_idx];
2728 if (idx_p->vertex_idx == figure->vertex_count - 1)
2729 a[2] = &figure->vertices[0];
2730 else
2731 a[2] = &figure->vertices[idx_p->vertex_idx + 1];
2733 figure = &geometry->u.path.figures[idx_q->figure_idx];
2734 b[0] = &figure->vertices[idx_q->vertex_idx];
2735 b[1] = &figure->bezier_controls[idx_q->control_idx];
2736 if (idx_q->vertex_idx == figure->vertex_count - 1)
2737 b[2] = &figure->vertices[0];
2738 else
2739 b[2] = &figure->vertices[idx_q->vertex_idx + 1];
2741 if (d2d_point_ccw(a[0], a[1], a[2]) == 0.0f || d2d_point_ccw(b[0], b[1], b[2]) == 0.0f)
2742 return FALSE;
2744 d2d_point_subtract(&v_q[0], b[1], b[0]);
2745 d2d_point_subtract(&v_q[1], b[2], b[0]);
2746 d2d_point_subtract(&v_q[2], b[1], b[2]);
2748 /* Check for intersections between the edges. Strictly speaking we'd only
2749 * need to check 8 of the 9 possible intersections, since if there's any
2750 * intersection there has to be a second intersection as well. */
2751 for (i = 0; i < 3; ++i)
2753 d2d_point_subtract(&v_p, a[(i & 1) + 1], a[i & 2]);
2754 for (j = 0; j < 3; ++j)
2756 det = v_p.x * v_q[j].y - v_p.y * v_q[j].x;
2757 if (det == 0.0f)
2758 continue;
2760 d2d_point_subtract(&v_qp, a[i & 2], b[j & 2]);
2761 t = (v_q[j].x * v_qp.y - v_q[j].y * v_qp.x) / det;
2762 if (t <= 0.0f || t >= 1.0f)
2763 continue;
2765 t = (v_p.x * v_qp.y - v_p.y * v_qp.x) / det;
2766 if (t <= 0.0f || t >= 1.0f)
2767 continue;
2769 return TRUE;
2773 /* Check if one triangle is contained within the other. */
2774 for (j = 0, score = 0, q = a[1], p[0] = b[2]; j < 3; ++j)
2776 p[1] = b[j];
2777 d2d_point_subtract(&v_p, p[1], p[0]);
2778 d2d_point_subtract(&v_qp, q, p[0]);
2780 if ((q->y < p[0]->y) != (q->y < p[1]->y) && v_qp.x < v_p.x * (v_qp.y / v_p.y))
2781 ++score;
2783 p[0] = p[1];
2786 if (score & 1)
2787 return TRUE;
2789 for (j = 0, score = 0, q = b[1], p[0] = a[2]; j < 3; ++j)
2791 p[1] = a[j];
2792 d2d_point_subtract(&v_p, p[1], p[0]);
2793 d2d_point_subtract(&v_qp, q, p[0]);
2795 if ((q->y < p[0]->y) != (q->y < p[1]->y) && v_qp.x < v_p.x * (v_qp.y / v_p.y))
2796 ++score;
2798 p[0] = p[1];
2801 return score & 1;
2804 static float d2d_geometry_bezier_ccw(struct d2d_geometry *geometry, const struct d2d_segment_idx *idx)
2806 const struct d2d_figure *figure = &geometry->u.path.figures[idx->figure_idx];
2807 size_t next = idx->vertex_idx + 1;
2809 if (next == figure->vertex_count)
2810 next = 0;
2812 return d2d_point_ccw(&figure->vertices[idx->vertex_idx],
2813 &figure->bezier_controls[idx->control_idx], &figure->vertices[next]);
2816 static BOOL d2d_geometry_split_bezier(struct d2d_geometry *geometry, const struct d2d_segment_idx *idx)
2818 const D2D1_POINT_2F *p[3];
2819 struct d2d_figure *figure;
2820 D2D1_POINT_2F q[3];
2821 size_t next;
2823 figure = &geometry->u.path.figures[idx->figure_idx];
2824 p[0] = &figure->vertices[idx->vertex_idx];
2825 p[1] = &figure->bezier_controls[idx->control_idx];
2826 next = idx->vertex_idx + 1;
2827 if (next == figure->vertex_count)
2828 next = 0;
2829 p[2] = &figure->vertices[next];
2831 d2d_point_lerp(&q[0], p[0], p[1], 0.5f);
2832 d2d_point_lerp(&q[1], p[1], p[2], 0.5f);
2833 d2d_point_lerp(&q[2], &q[0], &q[1], 0.5f);
2835 figure->bezier_controls[idx->control_idx] = q[0];
2836 if (!(d2d_figure_insert_bezier_controls(figure, idx->control_idx + 1, 1, &q[1])))
2837 return FALSE;
2838 if (!(d2d_figure_insert_vertex(figure, idx->vertex_idx + 1, q[2])))
2839 return FALSE;
2840 figure->vertex_types[idx->vertex_idx + 1] = D2D_VERTEX_TYPE_SPLIT_BEZIER;
2842 return TRUE;
2845 static HRESULT d2d_geometry_resolve_beziers(struct d2d_geometry *geometry)
2847 struct d2d_segment_idx idx_p, idx_q;
2848 struct d2d_curve_vertex *b;
2849 const D2D1_POINT_2F *p[3];
2850 struct d2d_figure *figure;
2851 size_t bezier_idx, i;
2853 if (!d2d_geometry_get_first_bezier_segment_idx(geometry, &idx_p))
2854 return S_OK;
2856 /* Split overlapping bezier control triangles. */
2857 while (d2d_geometry_get_next_bezier_segment_idx(geometry, &idx_p))
2859 d2d_geometry_get_first_bezier_segment_idx(geometry, &idx_q);
2860 while (idx_q.figure_idx < idx_p.figure_idx || idx_q.vertex_idx < idx_p.vertex_idx)
2862 while (d2d_geometry_check_bezier_overlap(geometry, &idx_p, &idx_q))
2864 if (fabsf(d2d_geometry_bezier_ccw(geometry, &idx_q)) > fabsf(d2d_geometry_bezier_ccw(geometry, &idx_p)))
2866 if (!d2d_geometry_split_bezier(geometry, &idx_q))
2867 return E_OUTOFMEMORY;
2868 if (idx_p.figure_idx == idx_q.figure_idx)
2870 ++idx_p.vertex_idx;
2871 ++idx_p.control_idx;
2874 else
2876 if (!d2d_geometry_split_bezier(geometry, &idx_p))
2877 return E_OUTOFMEMORY;
2880 d2d_geometry_get_next_bezier_segment_idx(geometry, &idx_q);
2884 for (i = 0; i < geometry->u.path.figure_count; ++i)
2886 if (geometry->u.path.figures[i].flags & D2D_FIGURE_FLAG_HOLLOW)
2887 continue;
2888 geometry->fill.bezier_vertex_count += 3 * geometry->u.path.figures[i].bezier_control_count;
2891 if (!(geometry->fill.bezier_vertices = heap_calloc(geometry->fill.bezier_vertex_count,
2892 sizeof(*geometry->fill.bezier_vertices))))
2894 ERR("Failed to allocate bezier vertices array.\n");
2895 geometry->fill.bezier_vertex_count = 0;
2896 return E_OUTOFMEMORY;
2899 bezier_idx = 0;
2900 d2d_geometry_get_first_bezier_segment_idx(geometry, &idx_p);
2901 for (;;)
2903 float sign = -1.0f;
2905 figure = &geometry->u.path.figures[idx_p.figure_idx];
2906 p[0] = &figure->vertices[idx_p.vertex_idx];
2907 p[1] = &figure->bezier_controls[idx_p.control_idx];
2909 i = idx_p.vertex_idx + 1;
2910 if (d2d_path_geometry_point_inside(geometry, p[1], FALSE))
2912 sign = 1.0f;
2913 d2d_figure_insert_vertex(figure, i, *p[1]);
2914 /* Inserting a vertex potentially invalidates p[0]. */
2915 p[0] = &figure->vertices[idx_p.vertex_idx];
2916 ++i;
2919 if (i == figure->vertex_count)
2920 i = 0;
2921 p[2] = &figure->vertices[i];
2923 b = &geometry->fill.bezier_vertices[bezier_idx * 3];
2924 d2d_curve_vertex_set(&b[0], p[0], 0.0f, 0.0f, sign);
2925 d2d_curve_vertex_set(&b[1], p[1], 0.5f, 0.0f, sign);
2926 d2d_curve_vertex_set(&b[2], p[2], 1.0f, 1.0f, sign);
2928 if (!d2d_geometry_get_next_bezier_segment_idx(geometry, &idx_p))
2929 break;
2930 ++bezier_idx;
2933 return S_OK;
2936 static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_Close(ID2D1GeometrySink *iface)
2938 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2939 HRESULT hr = E_FAIL;
2940 size_t i;
2942 TRACE("iface %p.\n", iface);
2944 if (geometry->u.path.state != D2D_GEOMETRY_STATE_OPEN)
2946 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
2947 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2948 return D2DERR_WRONG_STATE;
2950 geometry->u.path.state = D2D_GEOMETRY_STATE_CLOSED;
2952 for (i = 0; i < geometry->u.path.figure_count; ++i)
2954 struct d2d_figure *figure = &geometry->u.path.figures[i];
2955 size_t size = figure->bezier_control_count * sizeof(*figure->original_bezier_controls);
2956 if (!(figure->original_bezier_controls = heap_alloc(size)))
2957 goto done;
2958 memcpy(figure->original_bezier_controls, figure->bezier_controls, size);
2961 if (!d2d_geometry_intersect_self(geometry))
2962 goto done;
2963 if (FAILED(hr = d2d_geometry_resolve_beziers(geometry)))
2964 goto done;
2965 if (FAILED(hr = d2d_path_geometry_triangulate(geometry)))
2966 goto done;
2968 done:
2969 if (FAILED(hr))
2971 heap_free(geometry->fill.bezier_vertices);
2972 geometry->fill.bezier_vertex_count = 0;
2973 d2d_path_geometry_free_figures(geometry);
2974 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2976 return hr;
2979 static void STDMETHODCALLTYPE d2d_geometry_sink_AddLine(ID2D1GeometrySink *iface, D2D1_POINT_2F point)
2981 TRACE("iface %p, point %s.\n", iface, debug_d2d_point_2f(&point));
2983 d2d_geometry_sink_AddLines(iface, &point, 1);
2986 static void STDMETHODCALLTYPE d2d_geometry_sink_AddBezier(ID2D1GeometrySink *iface, const D2D1_BEZIER_SEGMENT *bezier)
2988 TRACE("iface %p, bezier %p.\n", iface, bezier);
2990 d2d_geometry_sink_AddBeziers(iface, bezier, 1);
2993 static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBezier(ID2D1GeometrySink *iface,
2994 const D2D1_QUADRATIC_BEZIER_SEGMENT *bezier)
2996 TRACE("iface %p, bezier %p.\n", iface, bezier);
2998 ID2D1GeometrySink_AddQuadraticBeziers(iface, bezier, 1);
3001 static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBeziers(ID2D1GeometrySink *iface,
3002 const D2D1_QUADRATIC_BEZIER_SEGMENT *beziers, UINT32 bezier_count)
3004 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
3005 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
3006 unsigned int i;
3008 TRACE("iface %p, beziers %p, bezier_count %u.\n", iface, beziers, bezier_count);
3010 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
3012 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3013 return;
3016 for (i = 0; i < bezier_count; ++i)
3018 D2D1_RECT_F bezier_bounds;
3020 d2d_rect_get_bezier_bounds(&bezier_bounds, &figure->vertices[figure->vertex_count - 1],
3021 &beziers[i].point1, &beziers[i].point2);
3023 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_BEZIER;
3024 if (!d2d_figure_add_bezier_controls(figure, 1, &beziers[i].point1))
3026 ERR("Failed to add bezier.\n");
3027 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3028 return;
3031 if (!d2d_figure_add_vertex(figure, beziers[i].point2))
3033 ERR("Failed to add bezier vertex.\n");
3034 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3035 return;
3038 d2d_rect_union(&figure->bounds, &bezier_bounds);
3041 geometry->u.path.segment_count += bezier_count;
3044 static void STDMETHODCALLTYPE d2d_geometry_sink_AddArc(ID2D1GeometrySink *iface, const D2D1_ARC_SEGMENT *arc)
3046 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
3048 FIXME("iface %p, arc %p stub!\n", iface, arc);
3050 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
3052 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3053 return;
3056 if (!d2d_figure_add_vertex(&geometry->u.path.figures[geometry->u.path.figure_count - 1], arc->point))
3058 ERR("Failed to add vertex.\n");
3059 return;
3062 ++geometry->u.path.segment_count;
3065 static const struct ID2D1GeometrySinkVtbl d2d_geometry_sink_vtbl =
3067 d2d_geometry_sink_QueryInterface,
3068 d2d_geometry_sink_AddRef,
3069 d2d_geometry_sink_Release,
3070 d2d_geometry_sink_SetFillMode,
3071 d2d_geometry_sink_SetSegmentFlags,
3072 d2d_geometry_sink_BeginFigure,
3073 d2d_geometry_sink_AddLines,
3074 d2d_geometry_sink_AddBeziers,
3075 d2d_geometry_sink_EndFigure,
3076 d2d_geometry_sink_Close,
3077 d2d_geometry_sink_AddLine,
3078 d2d_geometry_sink_AddBezier,
3079 d2d_geometry_sink_AddQuadraticBezier,
3080 d2d_geometry_sink_AddQuadraticBeziers,
3081 d2d_geometry_sink_AddArc,
3084 static inline struct d2d_geometry *impl_from_ID2D1PathGeometry(ID2D1PathGeometry *iface)
3086 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
3089 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_QueryInterface(ID2D1PathGeometry *iface, REFIID iid, void **out)
3091 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
3093 if (IsEqualGUID(iid, &IID_ID2D1PathGeometry)
3094 || IsEqualGUID(iid, &IID_ID2D1Geometry)
3095 || IsEqualGUID(iid, &IID_ID2D1Resource)
3096 || IsEqualGUID(iid, &IID_IUnknown))
3098 ID2D1PathGeometry_AddRef(iface);
3099 *out = iface;
3100 return S_OK;
3103 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
3105 *out = NULL;
3106 return E_NOINTERFACE;
3109 static ULONG STDMETHODCALLTYPE d2d_path_geometry_AddRef(ID2D1PathGeometry *iface)
3111 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3112 ULONG refcount = InterlockedIncrement(&geometry->refcount);
3114 TRACE("%p increasing refcount to %u.\n", iface, refcount);
3116 return refcount;
3119 static ULONG STDMETHODCALLTYPE d2d_path_geometry_Release(ID2D1PathGeometry *iface)
3121 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3122 ULONG refcount = InterlockedDecrement(&geometry->refcount);
3124 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
3126 if (!refcount)
3128 d2d_path_geometry_free_figures(geometry);
3129 d2d_geometry_cleanup(geometry);
3130 heap_free(geometry);
3133 return refcount;
3136 static void STDMETHODCALLTYPE d2d_path_geometry_GetFactory(ID2D1PathGeometry *iface, ID2D1Factory **factory)
3138 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3140 TRACE("iface %p, factory %p.\n", iface, factory);
3142 ID2D1Factory_AddRef(*factory = geometry->factory);
3145 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetBounds(ID2D1PathGeometry *iface,
3146 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
3148 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3149 size_t i;
3151 TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
3153 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
3154 return D2DERR_WRONG_STATE;
3156 bounds->left = FLT_MAX;
3157 bounds->top = FLT_MAX;
3158 bounds->right = -FLT_MAX;
3159 bounds->bottom = -FLT_MAX;
3161 if (!transform)
3163 if (geometry->u.path.bounds.left > geometry->u.path.bounds.right
3164 && !isinf(geometry->u.path.bounds.left))
3166 for (i = 0; i < geometry->u.path.figure_count; ++i)
3168 if (geometry->u.path.figures[i].flags & D2D_FIGURE_FLAG_HOLLOW)
3169 continue;
3170 d2d_rect_union(&geometry->u.path.bounds, &geometry->u.path.figures[i].bounds);
3172 if (geometry->u.path.bounds.left > geometry->u.path.bounds.right)
3174 geometry->u.path.bounds.left = INFINITY;
3175 geometry->u.path.bounds.right = FLT_MAX;
3176 geometry->u.path.bounds.top = INFINITY;
3177 geometry->u.path.bounds.bottom = FLT_MAX;
3181 *bounds = geometry->u.path.bounds;
3182 return S_OK;
3185 for (i = 0; i < geometry->u.path.figure_count; ++i)
3187 const struct d2d_figure *figure = &geometry->u.path.figures[i];
3188 enum d2d_vertex_type type = D2D_VERTEX_TYPE_NONE;
3189 D2D1_RECT_F bezier_bounds;
3190 D2D1_POINT_2F p, p1, p2;
3191 size_t j, bezier_idx;
3193 if (figure->flags & D2D_FIGURE_FLAG_HOLLOW)
3194 continue;
3196 /* Single vertex figures are reduced by CloseFigure(). */
3197 if (figure->vertex_count == 0)
3199 d2d_point_transform(&p, transform, figure->bounds.left, figure->bounds.top);
3200 d2d_rect_expand(bounds, &p);
3201 continue;
3204 for (j = 0; j < figure->vertex_count; ++j)
3206 if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
3207 continue;
3209 p = figure->vertices[j];
3210 type = figure->vertex_types[j];
3211 d2d_point_transform(&p, transform, p.x, p.y);
3212 d2d_rect_expand(bounds, &p);
3213 break;
3216 for (bezier_idx = 0, ++j; j < figure->vertex_count; ++j)
3218 if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE
3219 || d2d_vertex_type_is_split_bezier(figure->vertex_types[j]))
3220 continue;
3222 switch (type)
3224 case D2D_VERTEX_TYPE_LINE:
3225 p = figure->vertices[j];
3226 d2d_point_transform(&p, transform, p.x, p.y);
3227 d2d_rect_expand(bounds, &p);
3228 break;
3230 case D2D_VERTEX_TYPE_BEZIER:
3231 p1 = figure->original_bezier_controls[bezier_idx++];
3232 d2d_point_transform(&p1, transform, p1.x, p1.y);
3233 p2 = figure->vertices[j];
3234 d2d_point_transform(&p2, transform, p2.x, p2.y);
3235 d2d_rect_get_bezier_bounds(&bezier_bounds, &p, &p1, &p2);
3236 d2d_rect_union(bounds, &bezier_bounds);
3237 p = p2;
3238 break;
3240 default:
3241 FIXME("Unhandled vertex type %#x.\n", type);
3242 p = figure->vertices[j];
3243 d2d_point_transform(&p, transform, p.x, p.y);
3244 d2d_rect_expand(bounds, &p);
3245 break;
3248 type = figure->vertex_types[j];
3251 if (d2d_vertex_type_is_bezier(type))
3253 p1 = figure->original_bezier_controls[bezier_idx++];
3254 d2d_point_transform(&p1, transform, p1.x, p1.y);
3255 p2 = figure->vertices[0];
3256 d2d_point_transform(&p2, transform, p2.x, p2.y);
3257 d2d_rect_get_bezier_bounds(&bezier_bounds, &p, &p1, &p2);
3258 d2d_rect_union(bounds, &bezier_bounds);
3262 if (bounds->left > bounds->right)
3264 bounds->left = INFINITY;
3265 bounds->right = FLT_MAX;
3266 bounds->top = INFINITY;
3267 bounds->bottom = FLT_MAX;
3270 return S_OK;
3273 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetWidenedBounds(ID2D1PathGeometry *iface, float stroke_width,
3274 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_RECT_F *bounds)
3276 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
3277 iface, stroke_width, stroke_style, transform, tolerance, bounds);
3279 return E_NOTIMPL;
3282 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_StrokeContainsPoint(ID2D1PathGeometry *iface,
3283 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
3284 float tolerance, BOOL *contains)
3286 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, "
3287 "transform %p, tolerance %.8e, contains %p stub!\n",
3288 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
3290 return E_NOTIMPL;
3293 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_FillContainsPoint(ID2D1PathGeometry *iface,
3294 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
3296 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3297 D2D1_MATRIX_3X2_F g_i;
3299 TRACE("iface %p, point %s, transform %p, tolerance %.8e, contains %p.\n",
3300 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
3302 if (transform)
3304 if (!d2d_matrix_invert(&g_i, transform))
3305 return D2DERR_UNSUPPORTED_OPERATION;
3306 d2d_point_transform(&point, &g_i, point.x, point.y);
3309 *contains = !!d2d_path_geometry_point_inside(geometry, &point, FALSE);
3311 TRACE("-> %#x.\n", *contains);
3313 return S_OK;
3316 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_CompareWithGeometry(ID2D1PathGeometry *iface,
3317 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
3319 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
3320 iface, geometry, transform, tolerance, relation);
3322 return E_NOTIMPL;
3325 static void d2d_geometry_flatten_cubic(ID2D1SimplifiedGeometrySink *sink, const D2D1_POINT_2F *p0,
3326 const D2D1_BEZIER_SEGMENT *b, float tolerance)
3328 D2D1_BEZIER_SEGMENT b0, b1;
3329 D2D1_POINT_2F q;
3330 float d;
3332 /* It's certainly possible to calculate the maximum deviation of the
3333 * approximation from the curve, but it's a little involved. Instead, note
3334 * that if the control points were evenly spaced and collinear, p1 would
3335 * be exactly between p0 and p2, and p2 would be exactly between p1 and
3336 * p3. The deviation is a decent enough approximation, and much easier to
3337 * calculate.
3339 * p1' = (p0 + p2) / 2
3340 * p2' = (p1 + p3) / 2
3341 * d = ‖p1 - p1'‖₁ + ‖p2 - p2'‖₁ */
3342 d2d_point_lerp(&q, p0, &b->point2, 0.5f);
3343 d2d_point_subtract(&q, &b->point1, &q);
3344 d = fabsf(q.x) + fabsf(q.y);
3345 d2d_point_lerp(&q, &b->point1, &b->point3, 0.5f);
3346 d2d_point_subtract(&q, &b->point2, &q);
3347 d += fabsf(q.x) + fabsf(q.y);
3348 if (d < tolerance)
3350 ID2D1SimplifiedGeometrySink_AddLines(sink, &b->point3, 1);
3351 return;
3354 d2d_point_lerp(&q, &b->point1, &b->point2, 0.5f);
3356 b1.point3 = b->point3;
3357 d2d_point_lerp(&b1.point2, &b1.point3, &b->point2, 0.5f);
3358 d2d_point_lerp(&b1.point1, &b1.point2, &q, 0.5f);
3360 d2d_point_lerp(&b0.point1, p0, &b->point1, 0.5f);
3361 d2d_point_lerp(&b0.point2, &b0.point1, &q, 0.5f);
3362 d2d_point_lerp(&b0.point3, &b0.point2, &b1.point1, 0.5f);
3364 d2d_geometry_flatten_cubic(sink, p0, &b0, tolerance);
3365 ID2D1SimplifiedGeometrySink_SetSegmentFlags(sink, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN);
3366 d2d_geometry_flatten_cubic(sink, &b0.point3, &b1, tolerance);
3367 ID2D1SimplifiedGeometrySink_SetSegmentFlags(sink, D2D1_PATH_SEGMENT_NONE);
3370 static void d2d_geometry_simplify_quadratic(ID2D1SimplifiedGeometrySink *sink,
3371 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_POINT_2F *p0,
3372 const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2, float tolerance)
3374 D2D1_BEZIER_SEGMENT b;
3376 d2d_point_lerp(&b.point1, p0, p1, 2.0f / 3.0f);
3377 d2d_point_lerp(&b.point2, p2, p1, 2.0f / 3.0f);
3378 b.point3 = *p2;
3380 if (option == D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES)
3381 d2d_geometry_flatten_cubic(sink, p0, &b, tolerance);
3382 else
3383 ID2D1SimplifiedGeometrySink_AddBeziers(sink, &b, 1);
3386 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *iface,
3387 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
3388 ID2D1SimplifiedGeometrySink *sink)
3390 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3391 enum d2d_vertex_type type = D2D_VERTEX_TYPE_NONE;
3392 unsigned int i, j, bezier_idx;
3393 D2D1_FIGURE_BEGIN begin;
3394 D2D1_POINT_2F p, p1, p2;
3395 D2D1_FIGURE_END end;
3397 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
3398 iface, option, transform, tolerance, sink);
3400 ID2D1SimplifiedGeometrySink_SetFillMode(sink, geometry->u.path.fill_mode);
3401 for (i = 0; i < geometry->u.path.figure_count; ++i)
3403 const struct d2d_figure *figure = &geometry->u.path.figures[i];
3405 for (j = 0; j < figure->vertex_count; ++j)
3407 if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
3408 continue;
3410 p = figure->vertices[j];
3411 if (transform)
3412 d2d_point_transform(&p, transform, p.x, p.y);
3413 begin = figure->flags & D2D_FIGURE_FLAG_HOLLOW ? D2D1_FIGURE_BEGIN_HOLLOW : D2D1_FIGURE_BEGIN_FILLED;
3414 ID2D1SimplifiedGeometrySink_BeginFigure(sink, p, begin);
3415 type = figure->vertex_types[j];
3416 break;
3419 for (bezier_idx = 0, ++j; j < figure->vertex_count; ++j)
3421 if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE
3422 || d2d_vertex_type_is_split_bezier(figure->vertex_types[j]))
3423 continue;
3425 switch (type)
3427 case D2D_VERTEX_TYPE_LINE:
3428 p = figure->vertices[j];
3429 if (transform)
3430 d2d_point_transform(&p, transform, p.x, p.y);
3431 ID2D1SimplifiedGeometrySink_AddLines(sink, &p, 1);
3432 break;
3434 case D2D_VERTEX_TYPE_BEZIER:
3435 p1 = figure->original_bezier_controls[bezier_idx++];
3436 if (transform)
3437 d2d_point_transform(&p1, transform, p1.x, p1.y);
3438 p2 = figure->vertices[j];
3439 if (transform)
3440 d2d_point_transform(&p2, transform, p2.x, p2.y);
3441 d2d_geometry_simplify_quadratic(sink, option, &p, &p1, &p2, tolerance);
3442 p = p2;
3443 break;
3445 default:
3446 FIXME("Unhandled vertex type %#x.\n", type);
3447 p = figure->vertices[j];
3448 if (transform)
3449 d2d_point_transform(&p, transform, p.x, p.y);
3450 ID2D1SimplifiedGeometrySink_AddLines(sink, &p, 1);
3451 break;
3454 type = figure->vertex_types[j];
3457 if (d2d_vertex_type_is_bezier(type))
3459 p1 = figure->original_bezier_controls[bezier_idx++];
3460 if (transform)
3461 d2d_point_transform(&p1, transform, p1.x, p1.y);
3462 p2 = figure->vertices[0];
3463 if (transform)
3464 d2d_point_transform(&p2, transform, p2.x, p2.y);
3465 d2d_geometry_simplify_quadratic(sink, option, &p, &p1, &p2, tolerance);
3468 end = figure->flags & D2D_FIGURE_FLAG_CLOSED ? D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN;
3469 ID2D1SimplifiedGeometrySink_EndFigure(sink, end);
3472 return S_OK;
3475 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Tessellate(ID2D1PathGeometry *iface,
3476 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *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_CombineWithGeometry(ID2D1PathGeometry *iface,
3484 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
3485 float tolerance, ID2D1SimplifiedGeometrySink *sink)
3487 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
3488 iface, geometry, combine_mode, transform, tolerance, sink);
3490 return E_NOTIMPL;
3493 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Outline(ID2D1PathGeometry *iface,
3494 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
3496 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
3498 return E_NOTIMPL;
3501 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeArea(ID2D1PathGeometry *iface,
3502 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
3504 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
3506 return E_NOTIMPL;
3509 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeLength(ID2D1PathGeometry *iface,
3510 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
3512 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
3514 return E_NOTIMPL;
3517 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputePointAtLength(ID2D1PathGeometry *iface, float length,
3518 const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point, D2D1_POINT_2F *tangent)
3520 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
3521 iface, length, transform, tolerance, point, tangent);
3523 return E_NOTIMPL;
3526 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Widen(ID2D1PathGeometry *iface, float stroke_width,
3527 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
3528 ID2D1SimplifiedGeometrySink *sink)
3530 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
3531 iface, stroke_width, stroke_style, transform, tolerance, sink);
3533 return E_NOTIMPL;
3536 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Open(ID2D1PathGeometry *iface, ID2D1GeometrySink **sink)
3538 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3540 TRACE("iface %p, sink %p.\n", iface, sink);
3542 if (geometry->u.path.state != D2D_GEOMETRY_STATE_INITIAL)
3543 return D2DERR_WRONG_STATE;
3545 *sink = &geometry->u.path.ID2D1GeometrySink_iface;
3546 ID2D1GeometrySink_AddRef(*sink);
3548 geometry->u.path.state = D2D_GEOMETRY_STATE_OPEN;
3550 return S_OK;
3553 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Stream(ID2D1PathGeometry *iface, ID2D1GeometrySink *sink)
3555 FIXME("iface %p, sink %p stub!\n", iface, sink);
3557 return E_NOTIMPL;
3560 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetSegmentCount(ID2D1PathGeometry *iface, UINT32 *count)
3562 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3564 TRACE("iface %p, count %p.\n", iface, count);
3566 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
3567 return D2DERR_WRONG_STATE;
3569 *count = geometry->u.path.segment_count;
3571 return S_OK;
3574 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetFigureCount(ID2D1PathGeometry *iface, UINT32 *count)
3576 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3578 TRACE("iface %p, count %p.\n", iface, count);
3580 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
3581 return D2DERR_WRONG_STATE;
3583 *count = geometry->u.path.figure_count;
3585 return S_OK;
3588 static const struct ID2D1PathGeometryVtbl d2d_path_geometry_vtbl =
3590 d2d_path_geometry_QueryInterface,
3591 d2d_path_geometry_AddRef,
3592 d2d_path_geometry_Release,
3593 d2d_path_geometry_GetFactory,
3594 d2d_path_geometry_GetBounds,
3595 d2d_path_geometry_GetWidenedBounds,
3596 d2d_path_geometry_StrokeContainsPoint,
3597 d2d_path_geometry_FillContainsPoint,
3598 d2d_path_geometry_CompareWithGeometry,
3599 d2d_path_geometry_Simplify,
3600 d2d_path_geometry_Tessellate,
3601 d2d_path_geometry_CombineWithGeometry,
3602 d2d_path_geometry_Outline,
3603 d2d_path_geometry_ComputeArea,
3604 d2d_path_geometry_ComputeLength,
3605 d2d_path_geometry_ComputePointAtLength,
3606 d2d_path_geometry_Widen,
3607 d2d_path_geometry_Open,
3608 d2d_path_geometry_Stream,
3609 d2d_path_geometry_GetSegmentCount,
3610 d2d_path_geometry_GetFigureCount,
3613 void d2d_path_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory)
3615 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl);
3616 geometry->u.path.ID2D1GeometrySink_iface.lpVtbl = &d2d_geometry_sink_vtbl;
3617 geometry->u.path.bounds.left = FLT_MAX;
3618 geometry->u.path.bounds.right = -FLT_MAX;
3619 geometry->u.path.bounds.top = FLT_MAX;
3620 geometry->u.path.bounds.bottom = -FLT_MAX;
3623 static inline struct d2d_geometry *impl_from_ID2D1EllipseGeometry(ID2D1EllipseGeometry *iface)
3625 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
3628 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_QueryInterface(ID2D1EllipseGeometry *iface,
3629 REFIID iid, void **out)
3631 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
3633 if (IsEqualGUID(iid, &IID_ID2D1EllipseGeometry)
3634 || IsEqualGUID(iid, &IID_ID2D1Geometry)
3635 || IsEqualGUID(iid, &IID_ID2D1Resource)
3636 || IsEqualGUID(iid, &IID_IUnknown))
3638 ID2D1EllipseGeometry_AddRef(iface);
3639 *out = iface;
3640 return S_OK;
3643 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
3645 *out = NULL;
3646 return E_NOINTERFACE;
3649 static ULONG STDMETHODCALLTYPE d2d_ellipse_geometry_AddRef(ID2D1EllipseGeometry *iface)
3651 struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface);
3652 ULONG refcount = InterlockedIncrement(&geometry->refcount);
3654 TRACE("%p increasing refcount to %u.\n", iface, refcount);
3656 return refcount;
3659 static ULONG STDMETHODCALLTYPE d2d_ellipse_geometry_Release(ID2D1EllipseGeometry *iface)
3661 struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface);
3662 ULONG refcount = InterlockedDecrement(&geometry->refcount);
3664 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
3666 if (!refcount)
3668 d2d_geometry_cleanup(geometry);
3669 heap_free(geometry);
3672 return refcount;
3675 static void STDMETHODCALLTYPE d2d_ellipse_geometry_GetFactory(ID2D1EllipseGeometry *iface, ID2D1Factory **factory)
3677 struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface);
3679 TRACE("iface %p, factory %p.\n", iface, factory);
3681 ID2D1Factory_AddRef(*factory = geometry->factory);
3684 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_GetBounds(ID2D1EllipseGeometry *iface,
3685 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
3687 FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
3689 return E_NOTIMPL;
3692 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_GetWidenedBounds(ID2D1EllipseGeometry *iface,
3693 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
3694 float tolerance, D2D1_RECT_F *bounds)
3696 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
3697 iface, stroke_width, stroke_style, transform, tolerance, bounds);
3699 return E_NOTIMPL;
3702 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_StrokeContainsPoint(ID2D1EllipseGeometry *iface,
3703 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
3704 float tolerance, BOOL *contains)
3706 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p stub!\n",
3707 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
3709 return E_NOTIMPL;
3712 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_FillContainsPoint(ID2D1EllipseGeometry *iface,
3713 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
3715 FIXME("iface %p, point %s, transform %p, tolerance %.8e, contains %p stub!\n",
3716 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
3718 return E_NOTIMPL;
3721 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_CompareWithGeometry(ID2D1EllipseGeometry *iface,
3722 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
3724 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
3725 iface, geometry, transform, tolerance, relation);
3727 return E_NOTIMPL;
3730 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Simplify(ID2D1EllipseGeometry *iface,
3731 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
3732 ID2D1SimplifiedGeometrySink *sink)
3734 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
3735 iface, option, transform, tolerance, sink);
3737 return E_NOTIMPL;
3740 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Tessellate(ID2D1EllipseGeometry *iface,
3741 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *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_CombineWithGeometry(ID2D1EllipseGeometry *iface,
3749 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
3750 float tolerance, ID2D1SimplifiedGeometrySink *sink)
3752 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
3753 iface, geometry, combine_mode, transform, tolerance, sink);
3755 return E_NOTIMPL;
3758 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Outline(ID2D1EllipseGeometry *iface,
3759 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
3761 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
3763 return E_NOTIMPL;
3766 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_ComputeArea(ID2D1EllipseGeometry *iface,
3767 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
3769 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
3771 return E_NOTIMPL;
3774 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_ComputeLength(ID2D1EllipseGeometry *iface,
3775 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
3777 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
3779 return E_NOTIMPL;
3782 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_ComputePointAtLength(ID2D1EllipseGeometry *iface,
3783 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
3784 D2D1_POINT_2F *tangent)
3786 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
3787 iface, length, transform, tolerance, point, tangent);
3789 return E_NOTIMPL;
3792 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Widen(ID2D1EllipseGeometry *iface, float stroke_width,
3793 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
3794 ID2D1SimplifiedGeometrySink *sink)
3796 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
3797 iface, stroke_width, stroke_style, transform, tolerance, sink);
3799 return E_NOTIMPL;
3802 static void STDMETHODCALLTYPE d2d_ellipse_geometry_GetEllipse(ID2D1EllipseGeometry *iface, D2D1_ELLIPSE *ellipse)
3804 struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface);
3806 TRACE("iface %p, ellipse %p.\n", iface, ellipse);
3808 *ellipse = geometry->u.ellipse.ellipse;
3811 static const struct ID2D1EllipseGeometryVtbl d2d_ellipse_geometry_vtbl =
3813 d2d_ellipse_geometry_QueryInterface,
3814 d2d_ellipse_geometry_AddRef,
3815 d2d_ellipse_geometry_Release,
3816 d2d_ellipse_geometry_GetFactory,
3817 d2d_ellipse_geometry_GetBounds,
3818 d2d_ellipse_geometry_GetWidenedBounds,
3819 d2d_ellipse_geometry_StrokeContainsPoint,
3820 d2d_ellipse_geometry_FillContainsPoint,
3821 d2d_ellipse_geometry_CompareWithGeometry,
3822 d2d_ellipse_geometry_Simplify,
3823 d2d_ellipse_geometry_Tessellate,
3824 d2d_ellipse_geometry_CombineWithGeometry,
3825 d2d_ellipse_geometry_Outline,
3826 d2d_ellipse_geometry_ComputeArea,
3827 d2d_ellipse_geometry_ComputeLength,
3828 d2d_ellipse_geometry_ComputePointAtLength,
3829 d2d_ellipse_geometry_Widen,
3830 d2d_ellipse_geometry_GetEllipse,
3833 HRESULT d2d_ellipse_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_ELLIPSE *ellipse)
3835 D2D1_POINT_2F *v, v1, v2, v3, v4;
3836 struct d2d_face *f;
3837 float l, r, t, b;
3839 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_ellipse_geometry_vtbl);
3840 geometry->u.ellipse.ellipse = *ellipse;
3842 if (!(geometry->fill.vertices = heap_alloc(4 * sizeof(*geometry->fill.vertices))))
3843 goto fail;
3844 if (!d2d_array_reserve((void **)&geometry->fill.faces,
3845 &geometry->fill.faces_size, 2, sizeof(*geometry->fill.faces)))
3846 goto fail;
3848 l = ellipse->point.x - ellipse->radiusX;
3849 r = ellipse->point.x + ellipse->radiusX;
3850 t = ellipse->point.y - ellipse->radiusY;
3851 b = ellipse->point.y + ellipse->radiusY;
3853 d2d_point_set(&v1, r, t);
3854 d2d_point_set(&v2, r, b);
3855 d2d_point_set(&v3, l, b);
3856 d2d_point_set(&v4, l, t);
3858 v = geometry->fill.vertices;
3859 d2d_point_set(&v[0], ellipse->point.x, t);
3860 d2d_point_set(&v[1], r, ellipse->point.y);
3861 d2d_point_set(&v[2], ellipse->point.x, b);
3862 d2d_point_set(&v[3], l, ellipse->point.y);
3863 geometry->fill.vertex_count = 4;
3865 f = geometry->fill.faces;
3866 d2d_face_set(&f[0], 0, 3, 2);
3867 d2d_face_set(&f[1], 0, 2, 1);
3868 geometry->fill.face_count = 2;
3870 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[0], &v1, &v[1]))
3871 goto fail;
3872 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[1], &v2, &v[2]))
3873 goto fail;
3874 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[2], &v3, &v[3]))
3875 goto fail;
3876 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[3], &v4, &v[0]))
3877 goto fail;
3879 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[0], &v1, &v[1]))
3880 goto fail;
3881 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[1], &v2, &v[2]))
3882 goto fail;
3883 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[2], &v3, &v[3]))
3884 goto fail;
3885 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[3], &v4, &v[0]))
3886 goto fail;
3888 return S_OK;
3890 fail:
3891 d2d_geometry_cleanup(geometry);
3892 return E_OUTOFMEMORY;
3895 static inline struct d2d_geometry *impl_from_ID2D1RectangleGeometry(ID2D1RectangleGeometry *iface)
3897 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
3900 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_QueryInterface(ID2D1RectangleGeometry *iface,
3901 REFIID iid, void **out)
3903 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
3905 if (IsEqualGUID(iid, &IID_ID2D1RectangleGeometry)
3906 || IsEqualGUID(iid, &IID_ID2D1Geometry)
3907 || IsEqualGUID(iid, &IID_ID2D1Resource)
3908 || IsEqualGUID(iid, &IID_IUnknown))
3910 ID2D1RectangleGeometry_AddRef(iface);
3911 *out = iface;
3912 return S_OK;
3915 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
3917 *out = NULL;
3918 return E_NOINTERFACE;
3921 static ULONG STDMETHODCALLTYPE d2d_rectangle_geometry_AddRef(ID2D1RectangleGeometry *iface)
3923 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
3924 ULONG refcount = InterlockedIncrement(&geometry->refcount);
3926 TRACE("%p increasing refcount to %u.\n", iface, refcount);
3928 return refcount;
3931 static ULONG STDMETHODCALLTYPE d2d_rectangle_geometry_Release(ID2D1RectangleGeometry *iface)
3933 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
3934 ULONG refcount = InterlockedDecrement(&geometry->refcount);
3936 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
3938 if (!refcount)
3940 d2d_geometry_cleanup(geometry);
3941 heap_free(geometry);
3944 return refcount;
3947 static void STDMETHODCALLTYPE d2d_rectangle_geometry_GetFactory(ID2D1RectangleGeometry *iface, ID2D1Factory **factory)
3949 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
3951 TRACE("iface %p, factory %p.\n", iface, factory);
3953 ID2D1Factory_AddRef(*factory = geometry->factory);
3956 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_GetBounds(ID2D1RectangleGeometry *iface,
3957 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
3959 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
3960 D2D1_RECT_F *rect;
3961 D2D1_POINT_2F p;
3963 TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
3965 rect = &geometry->u.rectangle.rect;
3966 if (!transform)
3968 *bounds = *rect;
3969 return S_OK;
3972 bounds->left = FLT_MAX;
3973 bounds->top = FLT_MAX;
3974 bounds->right = -FLT_MAX;
3975 bounds->bottom = -FLT_MAX;
3977 d2d_point_transform(&p, transform, rect->left, rect->top);
3978 d2d_rect_expand(bounds, &p);
3979 d2d_point_transform(&p, transform, rect->left, rect->bottom);
3980 d2d_rect_expand(bounds, &p);
3981 d2d_point_transform(&p, transform, rect->right, rect->bottom);
3982 d2d_rect_expand(bounds, &p);
3983 d2d_point_transform(&p, transform, rect->right, rect->top);
3984 d2d_rect_expand(bounds, &p);
3986 return S_OK;
3989 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_GetWidenedBounds(ID2D1RectangleGeometry *iface,
3990 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
3991 float tolerance, D2D1_RECT_F *bounds)
3993 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
3994 iface, stroke_width, stroke_style, transform, tolerance, bounds);
3996 return E_NOTIMPL;
3999 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_StrokeContainsPoint(ID2D1RectangleGeometry *iface,
4000 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4001 float tolerance, BOOL *contains)
4003 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p stub!\n",
4004 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
4006 return E_NOTIMPL;
4009 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_FillContainsPoint(ID2D1RectangleGeometry *iface,
4010 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
4012 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4013 D2D1_RECT_F *rect = &geometry->u.rectangle.rect;
4014 float dx, dy;
4016 TRACE("iface %p, point %s, transform %p, tolerance %.8e, contains %p.\n",
4017 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
4019 if (transform)
4021 D2D1_MATRIX_3X2_F g_i;
4023 if (!d2d_matrix_invert(&g_i, transform))
4024 return D2DERR_UNSUPPORTED_OPERATION;
4025 d2d_point_transform(&point, &g_i, point.x, point.y);
4028 if (tolerance == 0.0f)
4029 tolerance = D2D1_DEFAULT_FLATTENING_TOLERANCE;
4031 dx = max(fabsf((rect->right + rect->left) / 2.0f - point.x) - (rect->right - rect->left) / 2.0f, 0.0f);
4032 dy = max(fabsf((rect->bottom + rect->top) / 2.0f - point.y) - (rect->bottom - rect->top) / 2.0f, 0.0f);
4034 *contains = tolerance * tolerance > (dx * dx + dy * dy);
4035 return S_OK;
4038 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_CompareWithGeometry(ID2D1RectangleGeometry *iface,
4039 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
4041 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
4042 iface, geometry, transform, tolerance, relation);
4044 return E_NOTIMPL;
4047 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Simplify(ID2D1RectangleGeometry *iface,
4048 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4049 ID2D1SimplifiedGeometrySink *sink)
4051 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4052 D2D1_RECT_F *rect = &geometry->u.rectangle.rect;
4053 D2D1_POINT_2F p[4];
4054 unsigned int i;
4056 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
4057 iface, option, transform, tolerance, sink);
4059 d2d_point_set(&p[0], rect->left, rect->top);
4060 d2d_point_set(&p[1], rect->right, rect->top);
4061 d2d_point_set(&p[2], rect->right, rect->bottom);
4062 d2d_point_set(&p[3], rect->left, rect->bottom);
4064 if (transform)
4066 for (i = 0; i < ARRAY_SIZE(p); ++i)
4068 d2d_point_transform(&p[i], transform, p[i].x, p[i].y);
4072 ID2D1SimplifiedGeometrySink_SetFillMode(sink, D2D1_FILL_MODE_ALTERNATE);
4073 ID2D1SimplifiedGeometrySink_BeginFigure(sink, p[0], D2D1_FIGURE_BEGIN_FILLED);
4074 ID2D1SimplifiedGeometrySink_AddLines(sink, &p[1], 3);
4075 ID2D1SimplifiedGeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
4077 return S_OK;
4080 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Tessellate(ID2D1RectangleGeometry *iface,
4081 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *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_CombineWithGeometry(ID2D1RectangleGeometry *iface,
4089 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
4090 float tolerance, ID2D1SimplifiedGeometrySink *sink)
4092 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4093 iface, geometry, combine_mode, transform, tolerance, sink);
4095 return E_NOTIMPL;
4098 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Outline(ID2D1RectangleGeometry *iface,
4099 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
4101 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4103 return E_NOTIMPL;
4106 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputeArea(ID2D1RectangleGeometry *iface,
4107 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
4109 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
4111 return E_NOTIMPL;
4114 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputeLength(ID2D1RectangleGeometry *iface,
4115 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
4117 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
4119 return E_NOTIMPL;
4122 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputePointAtLength(ID2D1RectangleGeometry *iface,
4123 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
4124 D2D1_POINT_2F *tangent)
4126 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
4127 iface, length, transform, tolerance, point, tangent);
4129 return E_NOTIMPL;
4132 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Widen(ID2D1RectangleGeometry *iface, float stroke_width,
4133 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4134 ID2D1SimplifiedGeometrySink *sink)
4136 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
4137 iface, stroke_width, stroke_style, transform, tolerance, sink);
4139 return E_NOTIMPL;
4142 static void STDMETHODCALLTYPE d2d_rectangle_geometry_GetRect(ID2D1RectangleGeometry *iface, D2D1_RECT_F *rect)
4144 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4146 TRACE("iface %p, rect %p.\n", iface, rect);
4148 *rect = geometry->u.rectangle.rect;
4151 static const struct ID2D1RectangleGeometryVtbl d2d_rectangle_geometry_vtbl =
4153 d2d_rectangle_geometry_QueryInterface,
4154 d2d_rectangle_geometry_AddRef,
4155 d2d_rectangle_geometry_Release,
4156 d2d_rectangle_geometry_GetFactory,
4157 d2d_rectangle_geometry_GetBounds,
4158 d2d_rectangle_geometry_GetWidenedBounds,
4159 d2d_rectangle_geometry_StrokeContainsPoint,
4160 d2d_rectangle_geometry_FillContainsPoint,
4161 d2d_rectangle_geometry_CompareWithGeometry,
4162 d2d_rectangle_geometry_Simplify,
4163 d2d_rectangle_geometry_Tessellate,
4164 d2d_rectangle_geometry_CombineWithGeometry,
4165 d2d_rectangle_geometry_Outline,
4166 d2d_rectangle_geometry_ComputeArea,
4167 d2d_rectangle_geometry_ComputeLength,
4168 d2d_rectangle_geometry_ComputePointAtLength,
4169 d2d_rectangle_geometry_Widen,
4170 d2d_rectangle_geometry_GetRect,
4173 HRESULT d2d_rectangle_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_RECT_F *rect)
4175 struct d2d_face *f;
4176 D2D1_POINT_2F *v;
4177 float l, r, t, b;
4179 static const D2D1_POINT_2F prev[] =
4181 { 1.0f, 0.0f},
4182 { 0.0f, -1.0f},
4183 {-1.0f, 0.0f},
4184 { 0.0f, 1.0f},
4186 static const D2D1_POINT_2F next[] =
4188 { 0.0f, 1.0f},
4189 { 1.0f, 0.0f},
4190 { 0.0f, -1.0f},
4191 {-1.0f, 0.0f},
4194 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl);
4195 geometry->u.rectangle.rect = *rect;
4197 if (!(geometry->fill.vertices = heap_alloc(4 * sizeof(*geometry->fill.vertices))))
4198 goto fail;
4199 if (!d2d_array_reserve((void **)&geometry->fill.faces,
4200 &geometry->fill.faces_size, 2, sizeof(*geometry->fill.faces)))
4201 goto fail;
4203 l = min(rect->left, rect->right);
4204 r = max(rect->left, rect->right);
4205 t = min(rect->top, rect->bottom);
4206 b = max(rect->top, rect->bottom);
4208 v = geometry->fill.vertices;
4209 d2d_point_set(&v[0], l, t);
4210 d2d_point_set(&v[1], l, b);
4211 d2d_point_set(&v[2], r, b);
4212 d2d_point_set(&v[3], r, t);
4213 geometry->fill.vertex_count = 4;
4215 f = geometry->fill.faces;
4216 d2d_face_set(&f[0], 1, 2, 0);
4217 d2d_face_set(&f[1], 0, 2, 3);
4218 geometry->fill.face_count = 2;
4220 if (!d2d_geometry_outline_add_line_segment(geometry, &v[0], &v[1]))
4221 goto fail;
4222 if (!d2d_geometry_outline_add_line_segment(geometry, &v[1], &v[2]))
4223 goto fail;
4224 if (!d2d_geometry_outline_add_line_segment(geometry, &v[2], &v[3]))
4225 goto fail;
4226 if (!d2d_geometry_outline_add_line_segment(geometry, &v[3], &v[0]))
4227 goto fail;
4229 if (!d2d_geometry_outline_add_join(geometry, &prev[0], &v[0], &next[0]))
4230 goto fail;
4231 if (!d2d_geometry_outline_add_join(geometry, &prev[1], &v[1], &next[1]))
4232 goto fail;
4233 if (!d2d_geometry_outline_add_join(geometry, &prev[2], &v[2], &next[2]))
4234 goto fail;
4235 if (!d2d_geometry_outline_add_join(geometry, &prev[3], &v[3], &next[3]))
4236 goto fail;
4238 return S_OK;
4240 fail:
4241 d2d_geometry_cleanup(geometry);
4242 return E_OUTOFMEMORY;
4245 static inline struct d2d_geometry *impl_from_ID2D1RoundedRectangleGeometry(ID2D1RoundedRectangleGeometry *iface)
4247 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
4250 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_QueryInterface(ID2D1RoundedRectangleGeometry *iface,
4251 REFIID iid, void **out)
4253 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
4255 if (IsEqualGUID(iid, &IID_ID2D1RoundedRectangleGeometry)
4256 || IsEqualGUID(iid, &IID_ID2D1Geometry)
4257 || IsEqualGUID(iid, &IID_ID2D1Resource)
4258 || IsEqualGUID(iid, &IID_IUnknown))
4260 ID2D1RoundedRectangleGeometry_AddRef(iface);
4261 *out = iface;
4262 return S_OK;
4265 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
4267 *out = NULL;
4268 return E_NOINTERFACE;
4271 static ULONG STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_AddRef(ID2D1RoundedRectangleGeometry *iface)
4273 struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface);
4274 ULONG refcount = InterlockedIncrement(&geometry->refcount);
4276 TRACE("%p increasing refcount to %u.\n", iface, refcount);
4278 return refcount;
4281 static ULONG STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Release(ID2D1RoundedRectangleGeometry *iface)
4283 struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface);
4284 ULONG refcount = InterlockedDecrement(&geometry->refcount);
4286 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
4288 if (!refcount)
4290 d2d_geometry_cleanup(geometry);
4291 heap_free(geometry);
4294 return refcount;
4297 static void STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetFactory(ID2D1RoundedRectangleGeometry *iface,
4298 ID2D1Factory **factory)
4300 struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface);
4302 TRACE("iface %p, factory %p.\n", iface, factory);
4304 ID2D1Factory_AddRef(*factory = geometry->factory);
4307 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetBounds(ID2D1RoundedRectangleGeometry *iface,
4308 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
4310 FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
4312 return E_NOTIMPL;
4315 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetWidenedBounds(ID2D1RoundedRectangleGeometry *iface,
4316 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4317 float tolerance, D2D1_RECT_F *bounds)
4319 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
4320 iface, stroke_width, stroke_style, transform, tolerance, bounds);
4322 return E_NOTIMPL;
4325 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_StrokeContainsPoint(
4326 ID2D1RoundedRectangleGeometry *iface, D2D1_POINT_2F point, float stroke_width,
4327 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
4329 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p stub!\n",
4330 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
4332 return E_NOTIMPL;
4335 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_FillContainsPoint(ID2D1RoundedRectangleGeometry *iface,
4336 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
4338 FIXME("iface %p, point %s, transform %p, tolerance %.8e, contains %p stub!\n",
4339 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
4341 return E_NOTIMPL;
4344 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_CompareWithGeometry(
4345 ID2D1RoundedRectangleGeometry *iface, ID2D1Geometry *geometry,
4346 const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
4348 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
4349 iface, geometry, transform, tolerance, relation);
4351 return E_NOTIMPL;
4354 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Simplify(ID2D1RoundedRectangleGeometry *iface,
4355 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4356 ID2D1SimplifiedGeometrySink *sink)
4358 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4359 iface, option, transform, tolerance, sink);
4361 return E_NOTIMPL;
4364 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Tessellate(ID2D1RoundedRectangleGeometry *iface,
4365 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *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_CombineWithGeometry(
4373 ID2D1RoundedRectangleGeometry *iface, ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode,
4374 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
4376 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4377 iface, geometry, combine_mode, transform, tolerance, sink);
4379 return E_NOTIMPL;
4382 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Outline(ID2D1RoundedRectangleGeometry *iface,
4383 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
4385 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4387 return E_NOTIMPL;
4390 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_ComputeArea(ID2D1RoundedRectangleGeometry *iface,
4391 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
4393 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
4395 return E_NOTIMPL;
4398 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_ComputeLength(ID2D1RoundedRectangleGeometry *iface,
4399 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
4401 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
4403 return E_NOTIMPL;
4406 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_ComputePointAtLength(
4407 ID2D1RoundedRectangleGeometry *iface, float length, const D2D1_MATRIX_3X2_F *transform,
4408 float tolerance, D2D1_POINT_2F *point, D2D1_POINT_2F *tangent)
4410 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
4411 iface, length, transform, tolerance, point, tangent);
4413 return E_NOTIMPL;
4416 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Widen(ID2D1RoundedRectangleGeometry *iface,
4417 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4418 float tolerance, ID2D1SimplifiedGeometrySink *sink)
4420 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
4421 iface, stroke_width, stroke_style, transform, tolerance, sink);
4423 return E_NOTIMPL;
4426 static void STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetRoundedRect(ID2D1RoundedRectangleGeometry *iface,
4427 D2D1_ROUNDED_RECT *rounded_rect)
4429 struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface);
4431 TRACE("iface %p, rounded_rect %p.\n", iface, rounded_rect);
4433 *rounded_rect = geometry->u.rounded_rectangle.rounded_rect;
4436 static const struct ID2D1RoundedRectangleGeometryVtbl d2d_rounded_rectangle_geometry_vtbl =
4438 d2d_rounded_rectangle_geometry_QueryInterface,
4439 d2d_rounded_rectangle_geometry_AddRef,
4440 d2d_rounded_rectangle_geometry_Release,
4441 d2d_rounded_rectangle_geometry_GetFactory,
4442 d2d_rounded_rectangle_geometry_GetBounds,
4443 d2d_rounded_rectangle_geometry_GetWidenedBounds,
4444 d2d_rounded_rectangle_geometry_StrokeContainsPoint,
4445 d2d_rounded_rectangle_geometry_FillContainsPoint,
4446 d2d_rounded_rectangle_geometry_CompareWithGeometry,
4447 d2d_rounded_rectangle_geometry_Simplify,
4448 d2d_rounded_rectangle_geometry_Tessellate,
4449 d2d_rounded_rectangle_geometry_CombineWithGeometry,
4450 d2d_rounded_rectangle_geometry_Outline,
4451 d2d_rounded_rectangle_geometry_ComputeArea,
4452 d2d_rounded_rectangle_geometry_ComputeLength,
4453 d2d_rounded_rectangle_geometry_ComputePointAtLength,
4454 d2d_rounded_rectangle_geometry_Widen,
4455 d2d_rounded_rectangle_geometry_GetRoundedRect,
4458 HRESULT d2d_rounded_rectangle_geometry_init(struct d2d_geometry *geometry,
4459 ID2D1Factory *factory, const D2D1_ROUNDED_RECT *rounded_rect)
4461 D2D1_POINT_2F *v, v1, v2, v3, v4;
4462 struct d2d_face *f;
4463 float l, r, t, b;
4464 float rx, ry;
4466 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rounded_rectangle_geometry_vtbl);
4467 geometry->u.rounded_rectangle.rounded_rect = *rounded_rect;
4469 if (!(geometry->fill.vertices = heap_alloc(8 * sizeof(*geometry->fill.vertices))))
4470 goto fail;
4471 if (!d2d_array_reserve((void **)&geometry->fill.faces,
4472 &geometry->fill.faces_size, 6, sizeof(*geometry->fill.faces)))
4473 goto fail;
4475 l = min(rounded_rect->rect.left, rounded_rect->rect.right);
4476 r = max(rounded_rect->rect.left, rounded_rect->rect.right);
4477 t = min(rounded_rect->rect.top, rounded_rect->rect.bottom);
4478 b = max(rounded_rect->rect.top, rounded_rect->rect.bottom);
4480 rx = min(rounded_rect->radiusX, 0.5f * (r - l));
4481 ry = min(rounded_rect->radiusY, 0.5f * (b - t));
4483 d2d_point_set(&v1, r, t);
4484 d2d_point_set(&v2, r, b);
4485 d2d_point_set(&v3, l, b);
4486 d2d_point_set(&v4, l, t);
4488 v = geometry->fill.vertices;
4489 d2d_point_set(&v[0], l + rx, t);
4490 d2d_point_set(&v[1], r - rx, t);
4491 d2d_point_set(&v[2], r, t + ry);
4492 d2d_point_set(&v[3], r, b - ry);
4493 d2d_point_set(&v[4], r - rx, b);
4494 d2d_point_set(&v[5], l + rx, b);
4495 d2d_point_set(&v[6], l, b - ry);
4496 d2d_point_set(&v[7], l, t + ry);
4497 geometry->fill.vertex_count = 8;
4499 f = geometry->fill.faces;
4500 d2d_face_set(&f[0], 0, 7, 6);
4501 d2d_face_set(&f[1], 0, 6, 5);
4502 d2d_face_set(&f[2], 0, 5, 4);
4503 d2d_face_set(&f[3], 0, 4, 1);
4504 d2d_face_set(&f[4], 1, 4, 3);
4505 d2d_face_set(&f[5], 1, 3, 2);
4506 geometry->fill.face_count = 6;
4508 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[1], &v1, &v[2]))
4509 goto fail;
4510 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[3], &v2, &v[4]))
4511 goto fail;
4512 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[5], &v3, &v[6]))
4513 goto fail;
4514 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[7], &v4, &v[0]))
4515 goto fail;
4517 if (!d2d_geometry_outline_add_line_segment(geometry, &v[0], &v[1]))
4518 goto fail;
4519 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[1], &v1, &v[2]))
4520 goto fail;
4521 if (!d2d_geometry_outline_add_line_segment(geometry, &v[2], &v[3]))
4522 goto fail;
4523 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[3], &v2, &v[4]))
4524 goto fail;
4525 if (!d2d_geometry_outline_add_line_segment(geometry, &v[4], &v[5]))
4526 goto fail;
4527 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[5], &v3, &v[6]))
4528 goto fail;
4529 if (!d2d_geometry_outline_add_line_segment(geometry, &v[6], &v[7]))
4530 goto fail;
4531 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[7], &v4, &v[0]))
4532 goto fail;
4534 return S_OK;
4536 fail:
4537 d2d_geometry_cleanup(geometry);
4538 return E_OUTOFMEMORY;
4541 static inline struct d2d_geometry *impl_from_ID2D1TransformedGeometry(ID2D1TransformedGeometry *iface)
4543 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
4546 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_QueryInterface(ID2D1TransformedGeometry *iface,
4547 REFIID iid, void **out)
4549 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
4551 if (IsEqualGUID(iid, &IID_ID2D1TransformedGeometry)
4552 || IsEqualGUID(iid, &IID_ID2D1Geometry)
4553 || IsEqualGUID(iid, &IID_ID2D1Resource)
4554 || IsEqualGUID(iid, &IID_IUnknown))
4556 ID2D1TransformedGeometry_AddRef(iface);
4557 *out = iface;
4558 return S_OK;
4561 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
4563 *out = NULL;
4564 return E_NOINTERFACE;
4567 static ULONG STDMETHODCALLTYPE d2d_transformed_geometry_AddRef(ID2D1TransformedGeometry *iface)
4569 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4570 ULONG refcount = InterlockedIncrement(&geometry->refcount);
4572 TRACE("%p increasing refcount to %u.\n", iface, refcount);
4574 return refcount;
4577 static ULONG STDMETHODCALLTYPE d2d_transformed_geometry_Release(ID2D1TransformedGeometry *iface)
4579 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4580 ULONG refcount = InterlockedDecrement(&geometry->refcount);
4582 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
4584 if (!refcount)
4586 geometry->outline.arc_faces = NULL;
4587 geometry->outline.arcs = NULL;
4588 geometry->outline.bezier_faces = NULL;
4589 geometry->outline.beziers = NULL;
4590 geometry->outline.faces = NULL;
4591 geometry->outline.vertices = NULL;
4592 geometry->fill.arc_vertices = NULL;
4593 geometry->fill.bezier_vertices = NULL;
4594 geometry->fill.faces = NULL;
4595 geometry->fill.vertices = NULL;
4596 ID2D1Geometry_Release(geometry->u.transformed.src_geometry);
4597 d2d_geometry_cleanup(geometry);
4598 heap_free(geometry);
4601 return refcount;
4604 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetFactory(ID2D1TransformedGeometry *iface,
4605 ID2D1Factory **factory)
4607 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4609 TRACE("iface %p, factory %p.\n", iface, factory);
4611 ID2D1Factory_AddRef(*factory = geometry->factory);
4614 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_GetBounds(ID2D1TransformedGeometry *iface,
4615 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
4617 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4618 D2D1_MATRIX_3X2_F g;
4620 TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
4622 g = geometry->transform;
4623 if (transform)
4624 d2d_matrix_multiply(&g, transform);
4626 return ID2D1Geometry_GetBounds(geometry->u.transformed.src_geometry, &g, bounds);
4629 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_GetWidenedBounds(ID2D1TransformedGeometry *iface,
4630 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4631 float tolerance, D2D1_RECT_F *bounds)
4633 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
4634 iface, stroke_width, stroke_style, transform, tolerance, bounds);
4636 return E_NOTIMPL;
4639 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_StrokeContainsPoint(ID2D1TransformedGeometry *iface,
4640 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4641 float tolerance, BOOL *contains)
4643 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4644 D2D1_MATRIX_3X2_F g;
4646 TRACE("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p.\n",
4647 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
4649 g = geometry->transform;
4650 if (transform)
4651 d2d_matrix_multiply(&g, transform);
4653 return ID2D1Geometry_StrokeContainsPoint(geometry->u.transformed.src_geometry, point, stroke_width, stroke_style,
4654 &g, tolerance, contains);
4657 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_FillContainsPoint(ID2D1TransformedGeometry *iface,
4658 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
4660 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4661 D2D1_MATRIX_3X2_F g;
4663 TRACE("iface %p, point %s, transform %p, tolerance %.8e, contains %p.\n",
4664 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
4666 g = geometry->transform;
4667 if (transform)
4668 d2d_matrix_multiply(&g, transform);
4670 return ID2D1Geometry_FillContainsPoint(geometry->u.transformed.src_geometry, point, &g, tolerance, contains);
4673 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_CompareWithGeometry(ID2D1TransformedGeometry *iface,
4674 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
4676 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
4677 iface, geometry, transform, tolerance, relation);
4679 return E_NOTIMPL;
4682 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Simplify(ID2D1TransformedGeometry *iface,
4683 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4684 ID2D1SimplifiedGeometrySink *sink)
4686 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4687 D2D1_MATRIX_3X2_F g;
4689 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
4690 iface, option, transform, tolerance, sink);
4692 g = geometry->transform;
4693 if (transform)
4694 d2d_matrix_multiply(&g, transform);
4696 return ID2D1Geometry_Simplify(geometry->u.transformed.src_geometry, option, &g, tolerance, sink);
4699 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Tessellate(ID2D1TransformedGeometry *iface,
4700 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *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_CombineWithGeometry(ID2D1TransformedGeometry *iface,
4708 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
4709 float tolerance, ID2D1SimplifiedGeometrySink *sink)
4711 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4712 iface, geometry, combine_mode, transform, tolerance, sink);
4714 return E_NOTIMPL;
4717 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Outline(ID2D1TransformedGeometry *iface,
4718 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
4720 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4722 return E_NOTIMPL;
4725 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputeArea(ID2D1TransformedGeometry *iface,
4726 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
4728 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
4730 return E_NOTIMPL;
4733 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputeLength(ID2D1TransformedGeometry *iface,
4734 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
4736 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
4738 return E_NOTIMPL;
4741 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputePointAtLength(ID2D1TransformedGeometry *iface,
4742 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
4743 D2D1_POINT_2F *tangent)
4745 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
4746 iface, length, transform, tolerance, point, tangent);
4748 return E_NOTIMPL;
4751 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Widen(ID2D1TransformedGeometry *iface, float stroke_width,
4752 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4753 ID2D1SimplifiedGeometrySink *sink)
4755 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
4756 iface, stroke_width, stroke_style, transform, tolerance, sink);
4758 return E_NOTIMPL;
4761 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetSourceGeometry(ID2D1TransformedGeometry *iface,
4762 ID2D1Geometry **src_geometry)
4764 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4766 TRACE("iface %p, src_geometry %p.\n", iface, src_geometry);
4768 ID2D1Geometry_AddRef(*src_geometry = geometry->u.transformed.src_geometry);
4771 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetTransform(ID2D1TransformedGeometry *iface,
4772 D2D1_MATRIX_3X2_F *transform)
4774 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4776 TRACE("iface %p, transform %p.\n", iface, transform);
4778 *transform = geometry->u.transformed.transform;
4781 static const struct ID2D1TransformedGeometryVtbl d2d_transformed_geometry_vtbl =
4783 d2d_transformed_geometry_QueryInterface,
4784 d2d_transformed_geometry_AddRef,
4785 d2d_transformed_geometry_Release,
4786 d2d_transformed_geometry_GetFactory,
4787 d2d_transformed_geometry_GetBounds,
4788 d2d_transformed_geometry_GetWidenedBounds,
4789 d2d_transformed_geometry_StrokeContainsPoint,
4790 d2d_transformed_geometry_FillContainsPoint,
4791 d2d_transformed_geometry_CompareWithGeometry,
4792 d2d_transformed_geometry_Simplify,
4793 d2d_transformed_geometry_Tessellate,
4794 d2d_transformed_geometry_CombineWithGeometry,
4795 d2d_transformed_geometry_Outline,
4796 d2d_transformed_geometry_ComputeArea,
4797 d2d_transformed_geometry_ComputeLength,
4798 d2d_transformed_geometry_ComputePointAtLength,
4799 d2d_transformed_geometry_Widen,
4800 d2d_transformed_geometry_GetSourceGeometry,
4801 d2d_transformed_geometry_GetTransform,
4804 void d2d_transformed_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
4805 ID2D1Geometry *src_geometry, const D2D_MATRIX_3X2_F *transform)
4807 struct d2d_geometry *src_impl;
4808 D2D_MATRIX_3X2_F g;
4810 src_impl = unsafe_impl_from_ID2D1Geometry(src_geometry);
4812 g = src_impl->transform;
4813 d2d_matrix_multiply(&g, transform);
4814 d2d_geometry_init(geometry, factory, &g, (ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl);
4815 ID2D1Geometry_AddRef(geometry->u.transformed.src_geometry = src_geometry);
4816 geometry->u.transformed.transform = *transform;
4817 geometry->fill = src_impl->fill;
4818 geometry->outline = src_impl->outline;
4821 static inline struct d2d_geometry *impl_from_ID2D1GeometryGroup(ID2D1GeometryGroup *iface)
4823 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
4826 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_QueryInterface(ID2D1GeometryGroup *iface,
4827 REFIID iid, void **out)
4829 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
4831 if (IsEqualGUID(iid, &IID_ID2D1GeometryGroup)
4832 || IsEqualGUID(iid, &IID_ID2D1Geometry)
4833 || IsEqualGUID(iid, &IID_ID2D1Resource)
4834 || IsEqualGUID(iid, &IID_IUnknown))
4836 ID2D1GeometryGroup_AddRef(iface);
4837 *out = iface;
4838 return S_OK;
4841 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
4843 *out = NULL;
4844 return E_NOINTERFACE;
4847 static ULONG STDMETHODCALLTYPE d2d_geometry_group_AddRef(ID2D1GeometryGroup *iface)
4849 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
4850 ULONG refcount = InterlockedIncrement(&geometry->refcount);
4852 TRACE("%p increasing refcount to %u.\n", iface, refcount);
4854 return refcount;
4857 static ULONG STDMETHODCALLTYPE d2d_geometry_group_Release(ID2D1GeometryGroup *iface)
4859 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
4860 ULONG refcount = InterlockedDecrement(&geometry->refcount);
4861 unsigned int i;
4863 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
4865 if (!refcount)
4867 for (i = 0; i < geometry->u.group.geometry_count; ++i)
4868 ID2D1Geometry_Release(geometry->u.group.src_geometries[i]);
4869 heap_free(geometry->u.group.src_geometries);
4870 d2d_geometry_cleanup(geometry);
4871 heap_free(geometry);
4874 return refcount;
4877 static void STDMETHODCALLTYPE d2d_geometry_group_GetFactory(ID2D1GeometryGroup *iface,
4878 ID2D1Factory **factory)
4880 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
4882 TRACE("iface %p, factory %p.\n", iface, factory);
4884 ID2D1Factory_AddRef(*factory = geometry->factory);
4887 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_GetBounds(ID2D1GeometryGroup *iface,
4888 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
4890 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
4891 D2D1_RECT_F rect;
4892 unsigned int i;
4894 TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
4896 bounds->left = FLT_MAX;
4897 bounds->top = FLT_MAX;
4898 bounds->right = -FLT_MAX;
4899 bounds->bottom = -FLT_MAX;
4901 for (i = 0; i < geometry->u.group.geometry_count; ++i)
4903 if (SUCCEEDED(ID2D1Geometry_GetBounds(geometry->u.group.src_geometries[i], transform, &rect)))
4904 d2d_rect_union(bounds, &rect);
4907 return S_OK;
4910 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_GetWidenedBounds(ID2D1GeometryGroup *iface,
4911 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4912 float tolerance, D2D1_RECT_F *bounds)
4914 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
4915 iface, stroke_width, stroke_style, transform, tolerance, bounds);
4917 return E_NOTIMPL;
4920 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_StrokeContainsPoint(ID2D1GeometryGroup *iface,
4921 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4922 float tolerance, BOOL *contains)
4924 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p.\n",
4925 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
4927 return E_NOTIMPL;
4930 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_FillContainsPoint(ID2D1GeometryGroup *iface,
4931 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
4933 FIXME("iface %p, point %s, transform %p, tolerance %.8e, contains %p stub!.\n",
4934 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
4936 return E_NOTIMPL;
4939 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_CompareWithGeometry(ID2D1GeometryGroup *iface,
4940 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
4942 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
4943 iface, geometry, transform, tolerance, relation);
4945 return E_NOTIMPL;
4948 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_Simplify(ID2D1GeometryGroup *iface,
4949 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4950 ID2D1SimplifiedGeometrySink *sink)
4952 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!.\n",
4953 iface, option, transform, tolerance, sink);
4955 return E_NOTIMPL;
4958 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_Tessellate(ID2D1GeometryGroup *iface,
4959 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
4961 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4963 return E_NOTIMPL;
4966 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_CombineWithGeometry(ID2D1GeometryGroup *iface,
4967 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
4968 float tolerance, ID2D1SimplifiedGeometrySink *sink)
4970 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4971 iface, geometry, combine_mode, transform, tolerance, sink);
4973 return E_NOTIMPL;
4976 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_Outline(ID2D1GeometryGroup *iface,
4977 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
4979 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4981 return E_NOTIMPL;
4984 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_ComputeArea(ID2D1GeometryGroup *iface,
4985 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
4987 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
4989 return E_NOTIMPL;
4992 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_ComputeLength(ID2D1GeometryGroup *iface,
4993 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
4995 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
4997 return E_NOTIMPL;
5000 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_ComputePointAtLength(ID2D1GeometryGroup *iface,
5001 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
5002 D2D1_POINT_2F *tangent)
5004 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
5005 iface, length, transform, tolerance, point, tangent);
5007 return E_NOTIMPL;
5010 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_Widen(ID2D1GeometryGroup *iface, float stroke_width,
5011 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
5012 ID2D1SimplifiedGeometrySink *sink)
5014 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
5015 iface, stroke_width, stroke_style, transform, tolerance, sink);
5017 return E_NOTIMPL;
5020 static D2D1_FILL_MODE STDMETHODCALLTYPE d2d_geometry_group_GetFillMode(ID2D1GeometryGroup *iface)
5022 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5024 TRACE("iface %p.\n", iface);
5026 return geometry->u.group.fill_mode;
5029 static UINT32 STDMETHODCALLTYPE d2d_geometry_group_GetSourceGeometryCount(ID2D1GeometryGroup *iface)
5031 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5033 TRACE("iface %p.\n", iface);
5035 return geometry->u.group.geometry_count;
5038 static void STDMETHODCALLTYPE d2d_geometry_group_GetSourceGeometries(ID2D1GeometryGroup *iface,
5039 ID2D1Geometry **geometries, UINT32 geometry_count)
5041 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5042 unsigned int i;
5044 TRACE("iface %p, geometries %p, geometry_count %u.\n", iface, geometries, geometry_count);
5046 geometry_count = min(geometry_count, geometry->u.group.geometry_count);
5047 for (i = 0; i < geometry_count; ++i)
5048 ID2D1Geometry_AddRef(geometries[i] = geometry->u.group.src_geometries[i]);
5051 static const struct ID2D1GeometryGroupVtbl d2d_geometry_group_vtbl =
5053 d2d_geometry_group_QueryInterface,
5054 d2d_geometry_group_AddRef,
5055 d2d_geometry_group_Release,
5056 d2d_geometry_group_GetFactory,
5057 d2d_geometry_group_GetBounds,
5058 d2d_geometry_group_GetWidenedBounds,
5059 d2d_geometry_group_StrokeContainsPoint,
5060 d2d_geometry_group_FillContainsPoint,
5061 d2d_geometry_group_CompareWithGeometry,
5062 d2d_geometry_group_Simplify,
5063 d2d_geometry_group_Tessellate,
5064 d2d_geometry_group_CombineWithGeometry,
5065 d2d_geometry_group_Outline,
5066 d2d_geometry_group_ComputeArea,
5067 d2d_geometry_group_ComputeLength,
5068 d2d_geometry_group_ComputePointAtLength,
5069 d2d_geometry_group_Widen,
5070 d2d_geometry_group_GetFillMode,
5071 d2d_geometry_group_GetSourceGeometryCount,
5072 d2d_geometry_group_GetSourceGeometries,
5075 HRESULT d2d_geometry_group_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
5076 D2D1_FILL_MODE fill_mode, ID2D1Geometry **geometries, unsigned int geometry_count)
5078 unsigned int i;
5080 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_geometry_group_vtbl);
5082 if (!(geometry->u.group.src_geometries = heap_calloc(geometry_count, sizeof(*geometries))))
5084 d2d_geometry_cleanup(geometry);
5085 return E_OUTOFMEMORY;
5088 for (i = 0; i < geometry_count; ++i)
5090 ID2D1Geometry_AddRef(geometry->u.group.src_geometries[i] = geometries[i]);
5092 geometry->u.group.geometry_count = geometry_count;
5093 geometry->u.group.fill_mode = fill_mode;
5095 return S_OK;
5098 struct d2d_geometry *unsafe_impl_from_ID2D1Geometry(ID2D1Geometry *iface)
5100 if (!iface)
5101 return NULL;
5102 assert(iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_ellipse_geometry_vtbl
5103 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl
5104 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl
5105 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_rounded_rectangle_geometry_vtbl
5106 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl
5107 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_geometry_group_vtbl);
5108 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);