kernelbase: Ignore URL_PARTFLAG_KEEPSCHEME when used with URL_PART_SCHEME or URL_PART...
[wine.git] / dlls / d2d1 / geometry.c
blob7f02a63f284145d922342193d7a172f8685d7fc0
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,
53 D2D_VERTEX_TYPE_END,
56 struct d2d_segment_idx
58 size_t figure_idx;
59 size_t vertex_idx;
60 size_t control_idx;
63 struct d2d_figure
65 D2D1_POINT_2F *vertices;
66 size_t vertices_size;
67 enum d2d_vertex_type *vertex_types;
68 size_t vertex_types_size;
69 size_t vertex_count;
71 D2D1_POINT_2F *bezier_controls;
72 size_t bezier_controls_size;
73 size_t bezier_control_count;
75 D2D1_POINT_2F *original_bezier_controls;
76 size_t original_bezier_controls_size;
77 size_t original_bezier_control_count;
79 D2D1_RECT_F bounds;
80 unsigned int flags;
83 struct d2d_cdt_edge_ref
85 size_t idx;
86 enum d2d_cdt_edge_next r;
89 struct d2d_cdt_edge
91 struct d2d_cdt_edge_ref next[4];
92 size_t vertex[2];
93 unsigned int flags;
96 struct d2d_cdt
98 struct d2d_cdt_edge *edges;
99 size_t edges_size;
100 size_t edge_count;
101 size_t free_edge;
103 const D2D1_POINT_2F *vertices;
106 struct d2d_geometry_intersection
108 size_t figure_idx;
109 size_t vertex_idx;
110 size_t control_idx;
111 float t;
112 D2D1_POINT_2F p;
115 struct d2d_geometry_intersections
117 struct d2d_geometry_intersection *intersections;
118 size_t intersections_size;
119 size_t intersection_count;
122 struct d2d_fp_two_vec2
124 float x[2];
125 float y[2];
128 struct d2d_fp_fin
130 float *now, *other;
131 size_t length;
134 static void d2d_curve_vertex_set(struct d2d_curve_vertex *b,
135 const D2D1_POINT_2F *p, float u, float v, float sign)
137 b->position = *p;
138 b->texcoord.u = u;
139 b->texcoord.v = v;
140 b->texcoord.sign = sign;
143 static void d2d_face_set(struct d2d_face *f, UINT16 v0, UINT16 v1, UINT16 v2)
145 f->v[0] = v0;
146 f->v[1] = v1;
147 f->v[2] = v2;
150 static void d2d_outline_vertex_set(struct d2d_outline_vertex *v, float x, float y,
151 float prev_x, float prev_y, float next_x, float next_y)
153 d2d_point_set(&v->position, x, y);
154 d2d_point_set(&v->prev, prev_x, prev_y);
155 d2d_point_set(&v->next, next_x, next_y);
158 static void d2d_curve_outline_vertex_set(struct d2d_curve_outline_vertex *a, const D2D1_POINT_2F *position,
159 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2,
160 float prev_x, float prev_y, float next_x, float next_y)
162 a->position = *position;
163 a->p0 = *p0;
164 a->p1 = *p1;
165 a->p2 = *p2;
166 d2d_point_set(&a->prev, prev_x, prev_y);
167 d2d_point_set(&a->next, next_x, next_y);
170 static void d2d_fp_two_sum(float *out, float a, float b)
172 float a_virt, a_round, b_virt, b_round;
174 out[1] = a + b;
175 b_virt = out[1] - a;
176 a_virt = out[1] - b_virt;
177 b_round = b - b_virt;
178 a_round = a - a_virt;
179 out[0] = a_round + b_round;
182 static void d2d_fp_fast_two_sum(float *out, float a, float b)
184 float b_virt;
186 out[1] = a + b;
187 b_virt = out[1] - a;
188 out[0] = b - b_virt;
191 static void d2d_fp_two_two_sum(float *out, const float *a, const float *b)
193 float sum[2];
195 d2d_fp_two_sum(out, a[0], b[0]);
196 d2d_fp_two_sum(sum, a[1], out[1]);
197 d2d_fp_two_sum(&out[1], sum[0], b[1]);
198 d2d_fp_two_sum(&out[2], sum[1], out[2]);
201 static void d2d_fp_two_diff_tail(float *out, float a, float b, float x)
203 float a_virt, a_round, b_virt, b_round;
205 b_virt = a - x;
206 a_virt = x + b_virt;
207 b_round = b_virt - b;
208 a_round = a - a_virt;
209 *out = a_round + b_round;
212 static void d2d_fp_two_two_diff(float *out, const float *a, const float *b)
214 float sum[2], diff;
216 diff = a[0] - b[0];
217 d2d_fp_two_diff_tail(out, a[0], b[0], diff);
218 d2d_fp_two_sum(sum, a[1], diff);
219 diff = sum[0] - b[1];
220 d2d_fp_two_diff_tail(&out[1], sum[0], b[1], diff);
221 d2d_fp_two_sum(&out[2], sum[1], diff);
224 static void d2d_fp_split(float *out, float a)
226 float a_big, c;
228 c = a * ((1 << (FLT_MANT_DIG / 2)) + 1.0f);
229 a_big = c - a;
230 out[1] = c - a_big;
231 out[0] = a - out[1];
234 static void d2d_fp_two_product_presplit(float *out, float a, float b, const float *b_split)
236 float a_split[2], err1, err2, err3;
238 out[1] = a * b;
239 d2d_fp_split(a_split, a);
240 err1 = out[1] - (a_split[1] * b_split[1]);
241 err2 = err1 - (a_split[0] * b_split[1]);
242 err3 = err2 - (a_split[1] * b_split[0]);
243 out[0] = (a_split[0] * b_split[0]) - err3;
246 static void d2d_fp_two_product(float *out, float a, float b)
248 float b_split[2];
250 d2d_fp_split(b_split, b);
251 d2d_fp_two_product_presplit(out, a, b, b_split);
254 static void d2d_fp_square(float *out, float a)
256 float a_split[2], err1, err2;
258 out[1] = a * a;
259 d2d_fp_split(a_split, a);
260 err1 = out[1] - (a_split[1] * a_split[1]);
261 err2 = err1 - ((a_split[1] + a_split[1]) * a_split[0]);
262 out[0] = (a_split[0] * a_split[0]) - err2;
265 static float d2d_fp_estimate(float *a, size_t len)
267 float out = a[0];
268 size_t idx = 1;
270 while (idx < len)
271 out += a[idx++];
273 return out;
276 static void d2d_fp_fast_expansion_sum_zeroelim(float *out, size_t *out_len,
277 const float *a, size_t a_len, const float *b, size_t b_len)
279 float sum[2], q, a_curr, b_curr;
280 size_t a_idx, b_idx, out_idx;
282 a_curr = a[0];
283 b_curr = b[0];
284 a_idx = b_idx = 0;
285 if ((b_curr > a_curr) == (b_curr > -a_curr))
287 q = a_curr;
288 a_curr = a[++a_idx];
290 else
292 q = b_curr;
293 b_curr = b[++b_idx];
295 out_idx = 0;
296 if (a_idx < a_len && b_idx < b_len)
298 if ((b_curr > a_curr) == (b_curr > -a_curr))
300 d2d_fp_fast_two_sum(sum, a_curr, q);
301 a_curr = a[++a_idx];
303 else
305 d2d_fp_fast_two_sum(sum, b_curr, q);
306 b_curr = b[++b_idx];
308 if (sum[0] != 0.0f)
309 out[out_idx++] = sum[0];
310 q = sum[1];
311 while (a_idx < a_len && b_idx < b_len)
313 if ((b_curr > a_curr) == (b_curr > -a_curr))
315 d2d_fp_two_sum(sum, q, a_curr);
316 a_curr = a[++a_idx];
318 else
320 d2d_fp_two_sum(sum, q, b_curr);
321 b_curr = b[++b_idx];
323 if (sum[0] != 0.0f)
324 out[out_idx++] = sum[0];
325 q = sum[1];
328 while (a_idx < a_len)
330 d2d_fp_two_sum(sum, q, a_curr);
331 a_curr = a[++a_idx];
332 if (sum[0] != 0.0f)
333 out[out_idx++] = sum[0];
334 q = sum[1];
336 while (b_idx < b_len)
338 d2d_fp_two_sum(sum, q, b_curr);
339 b_curr = b[++b_idx];
340 if (sum[0] != 0.0f)
341 out[out_idx++] = sum[0];
342 q = sum[1];
344 if (q != 0.0f || !out_idx)
345 out[out_idx++] = q;
347 *out_len = out_idx;
350 static void d2d_fp_scale_expansion_zeroelim(float *out, size_t *out_len, const float *a, size_t a_len, float b)
352 float product[2], sum[2], b_split[2], q[2], a_curr;
353 size_t a_idx, out_idx;
355 d2d_fp_split(b_split, b);
356 d2d_fp_two_product_presplit(q, a[0], b, b_split);
357 out_idx = 0;
358 if (q[0] != 0.0f)
359 out[out_idx++] = q[0];
360 for (a_idx = 1; a_idx < a_len; ++a_idx)
362 a_curr = a[a_idx];
363 d2d_fp_two_product_presplit(product, a_curr, b, b_split);
364 d2d_fp_two_sum(sum, q[1], product[0]);
365 if (sum[0] != 0.0f)
366 out[out_idx++] = sum[0];
367 d2d_fp_fast_two_sum(q, product[1], sum[1]);
368 if (q[0] != 0.0f)
369 out[out_idx++] = q[0];
371 if (q[1] != 0.0f || !out_idx)
372 out[out_idx++] = q[1];
374 *out_len = out_idx;
377 static void d2d_point_subtract(D2D1_POINT_2F *out,
378 const D2D1_POINT_2F *a, const D2D1_POINT_2F *b)
380 out->x = a->x - b->x;
381 out->y = a->y - b->y;
384 static void d2d_point_scale(D2D1_POINT_2F *p, float scale)
386 p->x *= scale;
387 p->y *= scale;
390 static void d2d_point_lerp(D2D1_POINT_2F *out,
391 const D2D1_POINT_2F *a, const D2D1_POINT_2F *b, float t)
393 out->x = a->x * (1.0f - t) + b->x * t;
394 out->y = a->y * (1.0f - t) + b->y * t;
397 static void d2d_point_calculate_bezier(D2D1_POINT_2F *out, const D2D1_POINT_2F *p0,
398 const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2, float t)
400 float t_c = 1.0f - t;
402 out->x = t_c * (t_c * p0->x + t * p1->x) + t * (t_c * p1->x + t * p2->x);
403 out->y = t_c * (t_c * p0->y + t * p1->y) + t * (t_c * p1->y + t * p2->y);
406 static float d2d_point_length(const D2D1_POINT_2F *p)
408 return sqrtf(d2d_point_dot(p, p));
411 static void d2d_point_normalise(D2D1_POINT_2F *p)
413 float l;
415 if ((l = d2d_point_length(p)) != 0.0f)
416 d2d_point_scale(p, 1.0f / l);
419 static BOOL d2d_vertex_type_is_bezier(enum d2d_vertex_type t)
421 return (t == D2D_VERTEX_TYPE_BEZIER || t == D2D_VERTEX_TYPE_SPLIT_BEZIER);
424 static BOOL d2d_vertex_type_is_split_bezier(enum d2d_vertex_type t)
426 return t == D2D_VERTEX_TYPE_SPLIT_BEZIER;
429 /* This implementation is based on the paper "Adaptive Precision
430 * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
431 * associated (Public Domain) code by Jonathan Richard Shewchuk. */
432 static float d2d_point_ccw(const D2D1_POINT_2F *a, const D2D1_POINT_2F *b, const D2D1_POINT_2F *c)
434 static const float err_bound_result = (3.0f + 8.0f * D2D_FP_EPS) * D2D_FP_EPS;
435 static const float err_bound_a = (3.0f + 16.0f * D2D_FP_EPS) * D2D_FP_EPS;
436 static const float err_bound_b = (2.0f + 12.0f * D2D_FP_EPS) * D2D_FP_EPS;
437 static const float err_bound_c = (9.0f + 64.0f * D2D_FP_EPS) * D2D_FP_EPS * D2D_FP_EPS;
438 float det_d[16], det_c2[12], det_c1[8], det_b[4], temp4[4], temp2a[2], temp2b[2], abxacy[2], abyacx[2];
439 size_t det_d_len, det_c2_len, det_c1_len;
440 float det, det_sum, err_bound;
441 struct d2d_fp_two_vec2 ab, ac;
443 ab.x[1] = b->x - a->x;
444 ab.y[1] = b->y - a->y;
445 ac.x[1] = c->x - a->x;
446 ac.y[1] = c->y - a->y;
448 abxacy[1] = ab.x[1] * ac.y[1];
449 abyacx[1] = ab.y[1] * ac.x[1];
450 det = abxacy[1] - abyacx[1];
452 if (abxacy[1] > 0.0f)
454 if (abyacx[1] <= 0.0f)
455 return det;
456 det_sum = abxacy[1] + abyacx[1];
458 else if (abxacy[1] < 0.0f)
460 if (abyacx[1] >= 0.0f)
461 return det;
462 det_sum = -abxacy[1] - abyacx[1];
464 else
466 return det;
469 err_bound = err_bound_a * det_sum;
470 if (det >= err_bound || -det >= err_bound)
471 return det;
473 d2d_fp_two_product(abxacy, ab.x[1], ac.y[1]);
474 d2d_fp_two_product(abyacx, ab.y[1], ac.x[1]);
475 d2d_fp_two_two_diff(det_b, abxacy, abyacx);
477 det = d2d_fp_estimate(det_b, 4);
478 err_bound = err_bound_b * det_sum;
479 if (det >= err_bound || -det >= err_bound)
480 return det;
482 d2d_fp_two_diff_tail(&ab.x[0], b->x, a->x, ab.x[1]);
483 d2d_fp_two_diff_tail(&ab.y[0], b->y, a->y, ab.y[1]);
484 d2d_fp_two_diff_tail(&ac.x[0], c->x, a->x, ac.x[1]);
485 d2d_fp_two_diff_tail(&ac.y[0], c->y, a->y, ac.y[1]);
487 if (ab.x[0] == 0.0f && ab.y[0] == 0.0f && ac.x[0] == 0.0f && ac.y[0] == 0.0f)
488 return det;
490 err_bound = err_bound_c * det_sum + err_bound_result * fabsf(det);
491 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]);
492 if (det >= err_bound || -det >= err_bound)
493 return det;
495 d2d_fp_two_product(temp2a, ab.x[0], ac.y[1]);
496 d2d_fp_two_product(temp2b, ab.y[0], ac.x[1]);
497 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
498 d2d_fp_fast_expansion_sum_zeroelim(det_c1, &det_c1_len, det_b, 4, temp4, 4);
500 d2d_fp_two_product(temp2a, ab.x[1], ac.y[0]);
501 d2d_fp_two_product(temp2b, ab.y[1], ac.x[0]);
502 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
503 d2d_fp_fast_expansion_sum_zeroelim(det_c2, &det_c2_len, det_c1, det_c1_len, temp4, 4);
505 d2d_fp_two_product(temp2a, ab.x[0], ac.y[0]);
506 d2d_fp_two_product(temp2b, ab.y[0], ac.x[0]);
507 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
508 d2d_fp_fast_expansion_sum_zeroelim(det_d, &det_d_len, det_c2, det_c2_len, temp4, 4);
510 return det_d[det_d_len - 1];
513 /* Determine whether the point q is within the given tolerance of the line
514 * segment defined by p0 and p1, with the given stroke width and transform.
515 * Note that we don't care about the tolerance with respect to end-points or
516 * joins here; those are handled separately. */
517 static BOOL d2d_point_on_line_segment(const D2D1_POINT_2F *q, const D2D1_POINT_2F *p0,
518 const D2D1_POINT_2F *p1, const D2D1_MATRIX_3X2_F *transform, float stroke_width, float tolerance)
520 D2D1_POINT_2F v_n, v_p, v_q, v_r;
521 float l;
523 d2d_point_subtract(&v_p, p1, p0);
524 if ((l = d2d_point_length(&v_p)) == 0.0f)
525 return FALSE;
527 /* After (shear) transformation, the line segment is a parallelogram
528 * defined by p⃑' and n⃑':
530 * p⃑ = P₁ - P₀
531 * n⃑ = wp̂⟂
532 * p⃑' = p⃑T
533 * n⃑' = n⃑T */
534 l = stroke_width / l;
535 d2d_point_set(&v_r, transform->_31, transform->_32);
536 d2d_point_transform(&v_n, transform, -v_p.y * l, v_p.x * l);
537 d2d_point_subtract(&v_n, &v_n, &v_r);
538 d2d_point_transform(&v_p, transform, v_p.x, v_p.y);
539 d2d_point_subtract(&v_p, &v_p, &v_r);
541 /* Decompose the vector q⃑ = Q - P₀T into a linear combination of
542 * p⃑' and n⃑':
544 * lq⃑ = xp⃑' + yn⃑' */
545 d2d_point_transform(&v_q, transform, p0->x, p0->y);
546 d2d_point_subtract(&v_q, q, &v_q);
547 l = v_p.x * v_n.y - v_p.y * v_n.x;
548 v_r.x = v_q.x * v_n.y - v_q.y * v_n.x;
549 v_r.y = v_q.x * v_p.y - v_q.y * v_p.x;
551 if (l < 0.0f)
553 l *= -1.0f;
554 v_r.x *= -1.0f;
557 /* Check where Q projects onto p⃑'. */
558 if (v_r.x < 0.0f || v_r.x > l)
559 return FALSE;
561 /* Check where Q projects onto n⃑'. */
562 if (fabs(v_r.y) < l)
563 return TRUE;
565 /* Q lies outside the segment. Check whether the distance to the edge is
566 * within the tolerance.
568 * P₀' = P₀T + n⃑'
569 * q⃑' = Q - P₀'
570 * = q⃑ - n⃑'
572 * The distance is then q⃑' · p̂'⟂. */
574 if (v_r.y > 0.0f)
575 d2d_point_scale(&v_n, -1.0f);
576 d2d_point_subtract(&v_q, &v_q, &v_n);
578 /* Check where Q projects onto p⃑' + n⃑'. */
579 l = d2d_point_dot(&v_q, &v_p);
580 if (l < 0.0f || l > d2d_point_dot(&v_p, &v_p))
581 return FALSE;
583 v_n.x = -v_p.y;
584 v_n.y = v_p.x;
585 d2d_point_normalise(&v_n);
587 return fabsf(d2d_point_dot(&v_q, &v_n)) < tolerance;
590 /* Approximate the Bézier segment with a (wide) line segment. If the point
591 * lies outside the approximation, we're done. If the width of the
592 * approximation is less than the tolerance and the point lies inside, we're
593 * also done. If neither of those is the case, we subdivide the Bézier segment
594 * and try again. */
595 static BOOL d2d_point_on_bezier_segment(const D2D1_POINT_2F *q, const D2D1_POINT_2F *p0,
596 const D2D1_BEZIER_SEGMENT *b, const D2D1_MATRIX_3X2_F *transform, float stroke_width, float tolerance)
598 float d1, d2, d3, d4, d, l, m, w, w2;
599 D2D1_POINT_2F t[7], start, end, v_p;
600 D2D1_BEZIER_SEGMENT b0, b1;
602 m = 1.0f;
603 w = stroke_width * 0.5f;
605 d2d_point_subtract(&v_p, &b->point3, p0);
606 /* If the endpoints coincide, use the line through the control points as
607 * the direction vector. That choice is somewhat arbitrary; other choices
608 * with tighter error bounds exist. */
609 if ((l = d2d_point_dot(&v_p, &v_p)) == 0.0f)
611 d2d_point_subtract(&v_p, &b->point2, &b->point1);
612 /* If the control points also coincide, the curve is in fact a line. */
613 if ((l = d2d_point_dot(&v_p, &v_p)) == 0.0f)
615 d2d_point_subtract(&v_p, &b->point1, p0);
616 end.x = p0->x + 0.75f * v_p.x;
617 end.y = p0->y + 0.75f * v_p.y;
619 return d2d_point_on_line_segment(q, p0, &end, transform, w, tolerance);
621 m = 0.0f;
623 l = sqrtf(l);
624 d2d_point_scale(&v_p, 1.0f / l);
625 m *= l;
627 /* Calculate the width w2 of the approximation. */
629 end.x = p0->x + v_p.x;
630 end.y = p0->y + v_p.y;
631 /* Here, d1 and d2 are the maximum (signed) distance of the control points
632 * from the line through the start and end points. */
633 d1 = d2d_point_ccw(p0, &end, &b->point1);
634 d2 = d2d_point_ccw(p0, &end, &b->point2);
635 /* It can be shown that if the control points of a cubic Bézier curve lie
636 * on the same side of the line through the endpoints, the distance of the
637 * curve itself to that line will be within 3/4 of the distance of the
638 * control points to that line; if the control points lie on opposite
639 * sides, that distance will be within 4/9 of the distance of the
640 * corresponding control point. We're taking that as a given here. */
641 if (d1 * d2 > 0.0f)
643 d1 *= 0.75f;
644 d2 *= 0.75f;
646 else
648 d1 = (d1 * 4.0f) / 9.0f;
649 d2 = (d2 * 4.0f) / 9.0f;
651 w2 = max(fabsf(d1), fabsf(d2));
653 /* Project the control points onto the line through the endpoints of the
654 * curve. We will use these to calculate the endpoints of the
655 * approximation. */
656 d2d_point_subtract(&t[1], &b->point1, p0);
657 d1 = d2d_point_dot(&v_p, &t[1]);
658 d2d_point_subtract(&t[2], &b->point2, p0);
659 d2 = d2d_point_dot(&v_p, &t[2]);
661 /* Calculate the start point of the approximation. Like further above, the
662 * actual curve is somewhat closer to the endpoints than the control
663 * points are. */
664 d = min(min(d1, d2), 0);
665 if (d1 * d2 > 0.0f)
666 d *= 0.75f;
667 else
668 d = (d * 4.0f) / 9.0f;
669 /* Account for the stroke width and tolerance around the endpoints by
670 * adjusting the endpoints here. This matters because there are no joins
671 * in the original geometry for the places where we subdivide the original
672 * curve. We do this here because it's easy; alternatively we could
673 * explicitly test for this when subdividing the curve further below. */
674 d -= min(w + tolerance, w2);
675 start.x = p0->x + d * v_p.x;
676 start.y = p0->y + d * v_p.y;
678 /* Calculate the end point of the approximation. */
679 d1 -= m;
680 d2 -= m;
681 d = max(max(d1, d2), 0);
682 if (d1 * d2 > 0.0f)
683 d = m + d * 0.75f;
684 else
685 d = m + (d * 4.0f) / 9.0f;
686 d += min(w2, w + tolerance);
687 end.x = p0->x + d * v_p.x;
688 end.y = p0->y + d * v_p.y;
690 /* Calculate the error bounds of the approximation. We do this in
691 * transformed space because we need these to be relative to the given
692 * tolerance. */
694 d2d_point_transform(&t[0], transform, p0->x, p0->y);
695 d2d_point_transform(&t[1], transform, b->point1.x, b->point1.y);
696 d2d_point_transform(&t[2], transform, b->point2.x, b->point2.y);
697 d2d_point_transform(&t[3], transform, b->point3.x, b->point3.y);
698 d2d_point_transform(&t[4], transform, start.x, start.y);
699 d2d_point_transform(&t[5], transform, end.x, end.y);
701 d2d_point_subtract(&t[6], &t[5], &t[4]);
702 l = d2d_point_length(&t[6]);
703 /* Here, d1 and d2 are the maximum (signed) distance of the control points
704 * from the line through the start and end points. */
705 d1 = d2d_point_ccw(&t[4], &t[5], &t[1]) / l;
706 d2 = d2d_point_ccw(&t[4], &t[5], &t[2]) / l;
707 if (d1 * d2 > 0.0f)
709 d1 *= 0.75f;
710 d2 *= 0.75f;
712 else
714 d1 = (d1 * 4.0f) / 9.0f;
715 d2 = (d2 * 4.0f) / 9.0f;
717 l = max(max(d1, d2), 0) - min(min(d1, d2), 0);
719 /* d3 and d4 are the (unsigned) distance of the endpoints of the
720 * approximation from the original endpoints. */
721 d2d_point_subtract(&t[6], &t[4], &t[0]);
722 d3 = d2d_point_length(&t[6]);
723 d2d_point_subtract(&t[6], &t[5], &t[3]);
724 d4 = d2d_point_length(&t[6]);
725 l = max(max(d3, d4), l);
727 /* If the error of the approximation is less than the tolerance, and Q
728 * lies on the approximation, the distance of Q to the stroked curve is
729 * definitely within the tolerance. */
730 if (l <= tolerance && d2d_point_on_line_segment(q, &start, &end, transform, w, tolerance - l))
731 return TRUE;
732 /* On the other hand, if the distance of Q to the stroked curve is more
733 * than the sum of the tolerance and d, the distance of Q to the stroked
734 * curve can't possibly be within the tolerance. */
735 if (!d2d_point_on_line_segment(q, &start, &end, transform, w + w2, tolerance))
736 return FALSE;
738 /* Subdivide the curve. Note that simply splitting the segment in half
739 * here works and is easy, but may not be optimal. We could potentially
740 * reduce the number of iterations we need to do by splitting based on
741 * curvature or segment length. */
742 d2d_point_lerp(&t[0], &b->point1, &b->point2, 0.5f);
744 b1.point3 = b->point3;
745 d2d_point_lerp(&b1.point2, &b->point3, &b->point2, 0.5f);
746 d2d_point_lerp(&b1.point1, &t[0], &b1.point2, 0.5f);
748 d2d_point_lerp(&b0.point1, p0, &b->point1, 0.5f);
749 d2d_point_lerp(&b0.point2, &t[0], &b0.point1, 0.5f);
750 d2d_point_lerp(&b0.point3, &b0.point2, &b1.point1, 0.5f);
752 return d2d_point_on_bezier_segment(q, p0, &b0, transform, stroke_width, tolerance)
753 || d2d_point_on_bezier_segment(q, &b0.point3, &b1, transform, stroke_width, tolerance);
756 static void d2d_rect_union(D2D1_RECT_F *l, const D2D1_RECT_F *r)
758 l->left = min(l->left, r->left);
759 l->top = min(l->top, r->top);
760 l->right = max(l->right, r->right);
761 l->bottom = max(l->bottom, r->bottom);
764 static BOOL d2d_rect_check_overlap(const D2D_RECT_F *p, const D2D_RECT_F *q)
766 return p->left < q->right && p->top < q->bottom && p->right > q->left && p->bottom > q->top;
769 static void d2d_rect_get_bezier_bounds(D2D_RECT_F *bounds, const D2D1_POINT_2F *p0,
770 const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2)
772 D2D1_POINT_2F p;
773 float root;
775 bounds->left = p0->x;
776 bounds->top = p0->y;
777 bounds->right = p0->x;
778 bounds->bottom = p0->y;
780 d2d_rect_expand(bounds, p2);
782 /* f(t) = (1 - t)²P₀ + 2(1 - t)tP₁ + t²P₂
783 * f'(t) = 2(1 - t)(P₁ - P₀) + 2t(P₂ - P₁)
784 * = 2(P₂ - 2P₁ + P₀)t + 2(P₁ - P₀)
786 * f'(t) = 0
787 * t = (P₀ - P₁) / (P₂ - 2P₁ + P₀) */
788 root = (p0->x - p1->x) / (p2->x - 2.0f * p1->x + p0->x);
789 if (root > 0.0f && root < 1.0f)
791 d2d_point_calculate_bezier(&p, p0, p1, p2, root);
792 d2d_rect_expand(bounds, &p);
795 root = (p0->y - p1->y) / (p2->y - 2.0f * p1->y + p0->y);
796 if (root > 0.0f && root < 1.0f)
798 d2d_point_calculate_bezier(&p, p0, p1, p2, root);
799 d2d_rect_expand(bounds, &p);
803 static void d2d_rect_get_bezier_segment_bounds(D2D_RECT_F *bounds, const D2D1_POINT_2F *p0,
804 const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2, float start, float end)
806 D2D1_POINT_2F q[3], r[2];
808 d2d_point_lerp(&r[0], p0, p1, start);
809 d2d_point_lerp(&r[1], p1, p2, start);
810 d2d_point_lerp(&q[0], &r[0], &r[1], start);
812 end = (end - start) / (1.0f - start);
813 d2d_point_lerp(&q[1], &q[0], &r[1], end);
814 d2d_point_lerp(&r[0], &r[1], p2, end);
815 d2d_point_lerp(&q[2], &q[1], &r[0], end);
817 d2d_rect_get_bezier_bounds(bounds, &q[0], &q[1], &q[2]);
820 static BOOL d2d_figure_insert_vertex(struct d2d_figure *figure, size_t idx, D2D1_POINT_2F vertex)
822 if (!d2d_array_reserve((void **)&figure->vertices, &figure->vertices_size,
823 figure->vertex_count + 1, sizeof(*figure->vertices)))
825 ERR("Failed to grow vertices array.\n");
826 return FALSE;
829 if (!d2d_array_reserve((void **)&figure->vertex_types, &figure->vertex_types_size,
830 figure->vertex_count + 1, sizeof(*figure->vertex_types)))
832 ERR("Failed to grow vertex types array.\n");
833 return FALSE;
836 memmove(&figure->vertices[idx + 1], &figure->vertices[idx],
837 (figure->vertex_count - idx) * sizeof(*figure->vertices));
838 memmove(&figure->vertex_types[idx + 1], &figure->vertex_types[idx],
839 (figure->vertex_count - idx) * sizeof(*figure->vertex_types));
840 figure->vertices[idx] = vertex;
841 figure->vertex_types[idx] = D2D_VERTEX_TYPE_NONE;
842 d2d_rect_expand(&figure->bounds, &vertex);
843 ++figure->vertex_count;
844 return TRUE;
847 static BOOL d2d_figure_add_vertex(struct d2d_figure *figure, D2D1_POINT_2F vertex)
849 size_t last = figure->vertex_count - 1;
851 if (figure->vertex_count && figure->vertex_types[last] == D2D_VERTEX_TYPE_LINE
852 && !memcmp(&figure->vertices[last], &vertex, sizeof(vertex)))
853 return TRUE;
855 if (!d2d_array_reserve((void **)&figure->vertices, &figure->vertices_size,
856 figure->vertex_count + 1, sizeof(*figure->vertices)))
858 ERR("Failed to grow vertices array.\n");
859 return FALSE;
862 if (!d2d_array_reserve((void **)&figure->vertex_types, &figure->vertex_types_size,
863 figure->vertex_count + 1, sizeof(*figure->vertex_types)))
865 ERR("Failed to grow vertex types array.\n");
866 return FALSE;
869 figure->vertices[figure->vertex_count] = vertex;
870 figure->vertex_types[figure->vertex_count] = D2D_VERTEX_TYPE_NONE;
871 d2d_rect_expand(&figure->bounds, &vertex);
872 ++figure->vertex_count;
873 return TRUE;
876 static BOOL d2d_figure_insert_bezier_controls(struct d2d_figure *figure,
877 size_t idx, size_t count, const D2D1_POINT_2F *p)
879 if (!d2d_array_reserve((void **)&figure->bezier_controls, &figure->bezier_controls_size,
880 figure->bezier_control_count + count, sizeof(*figure->bezier_controls)))
882 ERR("Failed to grow bezier controls array.\n");
883 return FALSE;
886 memmove(&figure->bezier_controls[idx + count], &figure->bezier_controls[idx],
887 (figure->bezier_control_count - idx) * sizeof(*figure->bezier_controls));
888 memcpy(&figure->bezier_controls[idx], p, count * sizeof(*figure->bezier_controls));
889 figure->bezier_control_count += count;
891 return TRUE;
894 static BOOL d2d_figure_add_bezier_controls(struct d2d_figure *figure, size_t count, const D2D1_POINT_2F *p)
896 if (!d2d_array_reserve((void **)&figure->bezier_controls, &figure->bezier_controls_size,
897 figure->bezier_control_count + count, sizeof(*figure->bezier_controls)))
899 ERR("Failed to grow bezier controls array.\n");
900 return FALSE;
903 memcpy(&figure->bezier_controls[figure->bezier_control_count], p, count * sizeof(*figure->bezier_controls));
904 figure->bezier_control_count += count;
906 return TRUE;
909 static BOOL d2d_figure_add_original_bezier_controls(struct d2d_figure *figure, size_t count, const D2D1_POINT_2F *p)
911 if (!d2d_array_reserve((void **)&figure->original_bezier_controls, &figure->original_bezier_controls_size,
912 figure->original_bezier_control_count + count, sizeof(*figure->original_bezier_controls)))
914 ERR("Failed to grow cubic Bézier controls array.\n");
915 return FALSE;
918 memcpy(&figure->original_bezier_controls[figure->original_bezier_control_count],
919 p, count * sizeof(*figure->original_bezier_controls));
920 figure->original_bezier_control_count += count;
922 return TRUE;
925 static void d2d_cdt_edge_rot(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
927 dst->idx = src->idx;
928 dst->r = (src->r + D2D_EDGE_NEXT_ROT) & 3;
931 static void d2d_cdt_edge_sym(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
933 dst->idx = src->idx;
934 dst->r = (src->r + D2D_EDGE_NEXT_SYM) & 3;
937 static void d2d_cdt_edge_tor(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
939 dst->idx = src->idx;
940 dst->r = (src->r + D2D_EDGE_NEXT_TOR) & 3;
943 static void d2d_cdt_edge_next_left(const struct d2d_cdt *cdt,
944 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
946 d2d_cdt_edge_rot(dst, &cdt->edges[src->idx].next[(src->r + D2D_EDGE_NEXT_TOR) & 3]);
949 static void d2d_cdt_edge_next_origin(const struct d2d_cdt *cdt,
950 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
952 *dst = cdt->edges[src->idx].next[src->r];
955 static void d2d_cdt_edge_prev_origin(const struct d2d_cdt *cdt,
956 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
958 d2d_cdt_edge_rot(dst, &cdt->edges[src->idx].next[(src->r + D2D_EDGE_NEXT_ROT) & 3]);
961 static size_t d2d_cdt_edge_origin(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
963 return cdt->edges[e->idx].vertex[e->r >> 1];
966 static size_t d2d_cdt_edge_destination(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
968 return cdt->edges[e->idx].vertex[!(e->r >> 1)];
971 static void d2d_cdt_edge_set_origin(const struct d2d_cdt *cdt,
972 const struct d2d_cdt_edge_ref *e, size_t vertex)
974 cdt->edges[e->idx].vertex[e->r >> 1] = vertex;
977 static void d2d_cdt_edge_set_destination(const struct d2d_cdt *cdt,
978 const struct d2d_cdt_edge_ref *e, size_t vertex)
980 cdt->edges[e->idx].vertex[!(e->r >> 1)] = vertex;
983 static float d2d_cdt_ccw(const struct d2d_cdt *cdt, size_t a, size_t b, size_t c)
985 return d2d_point_ccw(&cdt->vertices[a], &cdt->vertices[b], &cdt->vertices[c]);
988 static BOOL d2d_cdt_rightof(const struct d2d_cdt *cdt, size_t p, const struct d2d_cdt_edge_ref *e)
990 return d2d_cdt_ccw(cdt, p, d2d_cdt_edge_destination(cdt, e), d2d_cdt_edge_origin(cdt, e)) > 0.0f;
993 static BOOL d2d_cdt_leftof(const struct d2d_cdt *cdt, size_t p, const struct d2d_cdt_edge_ref *e)
995 return d2d_cdt_ccw(cdt, p, d2d_cdt_edge_origin(cdt, e), d2d_cdt_edge_destination(cdt, e)) > 0.0f;
998 /* |ax ay|
999 * |bx by| */
1000 static void d2d_fp_four_det2x2(float *out, float ax, float ay, float bx, float by)
1002 float axby[2], aybx[2];
1004 d2d_fp_two_product(axby, ax, by);
1005 d2d_fp_two_product(aybx, ay, bx);
1006 d2d_fp_two_two_diff(out, axby, aybx);
1009 /* (a->x² + a->y²) * det2x2 */
1010 static void d2d_fp_sub_det3x3(float *out, size_t *out_len, const struct d2d_fp_two_vec2 *a, const float *det2x2)
1012 size_t axd_len, ayd_len, axxd_len, ayyd_len;
1013 float axd[8], ayd[8], axxd[16], ayyd[16];
1015 d2d_fp_scale_expansion_zeroelim(axd, &axd_len, det2x2, 4, a->x[1]);
1016 d2d_fp_scale_expansion_zeroelim(axxd, &axxd_len, axd, axd_len, a->x[1]);
1017 d2d_fp_scale_expansion_zeroelim(ayd, &ayd_len, det2x2, 4, a->y[1]);
1018 d2d_fp_scale_expansion_zeroelim(ayyd, &ayyd_len, ayd, ayd_len, a->y[1]);
1019 d2d_fp_fast_expansion_sum_zeroelim(out, out_len, axxd, axxd_len, ayyd, ayyd_len);
1022 /* det_abt = det_ab * c[0]
1023 * fin += c[0] * (az * b - bz * a + c[1] * det_ab * 2.0f) */
1024 static void d2d_cdt_incircle_refine1(struct d2d_fp_fin *fin, float *det_abt, size_t *det_abt_len,
1025 const float *det_ab, float a, const float *az, float b, const float *bz, const float *c)
1027 size_t temp48_len, temp32_len, temp16a_len, temp16b_len, temp16c_len, temp8_len;
1028 float temp48[48], temp32[32], temp16a[16], temp16b[16], temp16c[16], temp8[8];
1029 float *swap;
1031 d2d_fp_scale_expansion_zeroelim(det_abt, det_abt_len, det_ab, 4, c[0]);
1032 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, det_abt, *det_abt_len, 2.0f * c[1]);
1033 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, az, 4, c[0]);
1034 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, temp8, temp8_len, b);
1035 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, bz, 4, c[0]);
1036 d2d_fp_scale_expansion_zeroelim(temp16c, &temp16c_len, temp8, temp8_len, -a);
1037 d2d_fp_fast_expansion_sum_zeroelim(temp32, &temp32_len, temp16a, temp16a_len, temp16b, temp16b_len);
1038 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16c, temp16c_len, temp32, temp32_len);
1039 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
1040 swap = fin->now; fin->now = fin->other; fin->other = swap;
1043 static void d2d_cdt_incircle_refine2(struct d2d_fp_fin *fin, const struct d2d_fp_two_vec2 *a,
1044 const struct d2d_fp_two_vec2 *b, const float *bz, const struct d2d_fp_two_vec2 *c, const float *cz,
1045 const float *axt_det_bc, size_t axt_det_bc_len, const float *ayt_det_bc, size_t ayt_det_bc_len)
1047 size_t temp64_len, temp48_len, temp32a_len, temp32b_len, temp16a_len, temp16b_len, temp8_len;
1048 float temp64[64], temp48[48], temp32a[32], temp32b[32], temp16a[16], temp16b[16], temp8[8];
1049 float bct[8], bctt[4], temp4a[4], temp4b[4], temp2a[2], temp2b[2];
1050 size_t bct_len, bctt_len;
1051 float *swap;
1053 /* 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]) */
1054 /* bctt = b->x[0] * c->y[0] + c->x[0] * b->y[0] */
1055 if (b->x[0] != 0.0f || b->y[0] != 0.0f || c->x[0] != 0.0f || c->y[0] != 0.0f)
1057 d2d_fp_two_product(temp2a, b->x[0], c->y[1]);
1058 d2d_fp_two_product(temp2b, b->x[1], c->y[0]);
1059 d2d_fp_two_two_sum(temp4a, temp2a, temp2b);
1060 d2d_fp_two_product(temp2a, c->x[0], -b->y[1]);
1061 d2d_fp_two_product(temp2b, c->x[1], -b->y[0]);
1062 d2d_fp_two_two_sum(temp4b, temp2a, temp2b);
1063 d2d_fp_fast_expansion_sum_zeroelim(bct, &bct_len, temp4a, 4, temp4b, 4);
1065 d2d_fp_two_product(temp2a, b->x[0], c->y[0]);
1066 d2d_fp_two_product(temp2b, c->x[0], b->y[0]);
1067 d2d_fp_two_two_diff(bctt, temp2a, temp2b);
1068 bctt_len = 4;
1070 else
1072 bct[0] = 0.0f;
1073 bct_len = 1;
1074 bctt[0] = 0.0f;
1075 bctt_len = 1;
1078 if (a->x[0] != 0.0f)
1080 size_t axt_bct_len, axt_bctt_len;
1081 float axt_bct[16], axt_bctt[8];
1083 /* fin += a->x[0] * (axt_det_bc + bct * 2.0f * a->x[1]) */
1084 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, axt_det_bc, axt_det_bc_len, a->x[0]);
1085 d2d_fp_scale_expansion_zeroelim(axt_bct, &axt_bct_len, bct, bct_len, a->x[0]);
1086 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, axt_bct, axt_bct_len, 2.0f * a->x[1]);
1087 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16a, temp16a_len, temp32a, temp32a_len);
1088 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
1089 swap = fin->now; fin->now = fin->other; fin->other = swap;
1091 if (b->y[0] != 0.0f)
1093 /* fin += a->x[0] * cz * b->y[0] */
1094 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, cz, 4, a->x[0]);
1095 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, temp8, temp8_len, b->y[0]);
1096 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp16a, temp16a_len);
1097 swap = fin->now; fin->now = fin->other; fin->other = swap;
1100 if (c->y[0] != 0.0f)
1102 /* fin -= a->x[0] * bz * c->y[0] */
1103 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, bz, 4, -a->x[0]);
1104 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, temp8, temp8_len, c->y[0]);
1105 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp16a, temp16a_len);
1106 swap = fin->now; fin->now = fin->other; fin->other = swap;
1109 /* fin += a->x[0] * (bct * a->x[0] + bctt * (2.0f * a->x[1] + a->x[0])) */
1110 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, axt_bct, axt_bct_len, a->x[0]);
1111 d2d_fp_scale_expansion_zeroelim(axt_bctt, &axt_bctt_len, bctt, bctt_len, a->x[0]);
1112 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, axt_bctt, axt_bctt_len, 2.0f * a->x[1]);
1113 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, axt_bctt, axt_bctt_len, a->x[0]);
1114 d2d_fp_fast_expansion_sum_zeroelim(temp32b, &temp32b_len, temp16a, temp16a_len, temp16b, temp16b_len);
1115 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, temp32a, temp32a_len, temp32b, temp32b_len);
1116 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp64, temp64_len);
1117 swap = fin->now; fin->now = fin->other; fin->other = swap;
1120 if (a->y[0] != 0.0f)
1122 size_t ayt_bct_len, ayt_bctt_len;
1123 float ayt_bct[16], ayt_bctt[8];
1125 /* fin += a->y[0] * (ayt_det_bc + bct * 2.0f * a->y[1]) */
1126 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, ayt_det_bc, ayt_det_bc_len, a->y[0]);
1127 d2d_fp_scale_expansion_zeroelim(ayt_bct, &ayt_bct_len, bct, bct_len, a->y[0]);
1128 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, ayt_bct, ayt_bct_len, 2.0f * a->y[1]);
1129 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16a, temp16a_len, temp32a, temp32a_len);
1130 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
1131 swap = fin->now; fin->now = fin->other; fin->other = swap;
1133 /* fin += a->y[0] * (bct * a->y[0] + bctt * (2.0f * a->y[1] + a->y[0])) */
1134 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, ayt_bct, ayt_bct_len, a->y[0]);
1135 d2d_fp_scale_expansion_zeroelim(ayt_bctt, &ayt_bctt_len, bctt, bctt_len, a->y[0]);
1136 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, ayt_bctt, ayt_bctt_len, 2.0f * a->y[1]);
1137 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, ayt_bctt, ayt_bctt_len, a->y[0]);
1138 d2d_fp_fast_expansion_sum_zeroelim(temp32b, &temp32b_len, temp16a, temp16a_len, temp16b, temp16b_len);
1139 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, temp32a, temp32a_len, temp32b, temp32b_len);
1140 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp64, temp64_len);
1141 swap = fin->now; fin->now = fin->other; fin->other = swap;
1145 /* Determine if point D is inside or outside the circle defined by points A,
1146 * B, C. As explained in the paper by Guibas and Stolfi, this is equivalent to
1147 * calculating the signed volume of the tetrahedron defined by projecting the
1148 * points onto the paraboloid of revolution x = x² + y²,
1149 * λ:(x, y) → (x, y, x² + y²). I.e., D is inside the cirlce if
1151 * |λ(A) 1|
1152 * |λ(B) 1| > 0
1153 * |λ(C) 1|
1154 * |λ(D) 1|
1156 * After translating D to the origin, that becomes:
1158 * |λ(A-D)|
1159 * |λ(B-D)| > 0
1160 * |λ(C-D)|
1162 * This implementation is based on the paper "Adaptive Precision
1163 * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
1164 * associated (Public Domain) code by Jonathan Richard Shewchuk. */
1165 static BOOL d2d_cdt_incircle(const struct d2d_cdt *cdt, size_t a, size_t b, size_t c, size_t d)
1167 static const float err_bound_result = (3.0f + 8.0f * D2D_FP_EPS) * D2D_FP_EPS;
1168 static const float err_bound_a = (10.0f + 96.0f * D2D_FP_EPS) * D2D_FP_EPS;
1169 static const float err_bound_b = (4.0f + 48.0f * D2D_FP_EPS) * D2D_FP_EPS;
1170 static const float err_bound_c = (44.0f + 576.0f * D2D_FP_EPS) * D2D_FP_EPS * D2D_FP_EPS;
1172 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;
1173 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];
1174 float fin1[1152], fin2[1152], temp64[64], sub_det_a[32], sub_det_b[32], sub_det_c[32];
1175 float det_bc[4], det_ca[4], det_ab[4], daz[4], dbz[4], dcz[4], temp2a[2], temp2b[2];
1176 size_t temp64_len, sub_det_a_len, sub_det_b_len, sub_det_c_len;
1177 float dbxdcy, dbydcx, dcxday, dcydax, daxdby, daydbx;
1178 const D2D1_POINT_2F *p = cdt->vertices;
1179 struct d2d_fp_two_vec2 da, db, dc;
1180 float permanent, err_bound, det;
1181 struct d2d_fp_fin fin;
1183 da.x[1] = p[a].x - p[d].x;
1184 da.y[1] = p[a].y - p[d].y;
1185 db.x[1] = p[b].x - p[d].x;
1186 db.y[1] = p[b].y - p[d].y;
1187 dc.x[1] = p[c].x - p[d].x;
1188 dc.y[1] = p[c].y - p[d].y;
1190 daz[3] = da.x[1] * da.x[1] + da.y[1] * da.y[1];
1191 dbxdcy = db.x[1] * dc.y[1];
1192 dbydcx = db.y[1] * dc.x[1];
1194 dbz[3] = db.x[1] * db.x[1] + db.y[1] * db.y[1];
1195 dcxday = dc.x[1] * da.y[1];
1196 dcydax = dc.y[1] * da.x[1];
1198 dcz[3] = dc.x[1] * dc.x[1] + dc.y[1] * dc.y[1];
1199 daxdby = da.x[1] * db.y[1];
1200 daydbx = da.y[1] * db.x[1];
1202 det = daz[3] * (dbxdcy - dbydcx) + dbz[3] * (dcxday - dcydax) + dcz[3] * (daxdby - daydbx);
1203 permanent = daz[3] * (fabsf(dbxdcy) + fabsf(dbydcx))
1204 + dbz[3] * (fabsf(dcxday) + fabsf(dcydax))
1205 + dcz[3] * (fabsf(daxdby) + fabsf(daydbx));
1206 err_bound = err_bound_a * permanent;
1207 if (det > err_bound || -det > err_bound)
1208 return det > 0.0f;
1210 fin.now = fin1;
1211 fin.other = fin2;
1213 d2d_fp_four_det2x2(det_bc, db.x[1], db.y[1], dc.x[1], dc.y[1]);
1214 d2d_fp_sub_det3x3(sub_det_a, &sub_det_a_len, &da, det_bc);
1216 d2d_fp_four_det2x2(det_ca, dc.x[1], dc.y[1], da.x[1], da.y[1]);
1217 d2d_fp_sub_det3x3(sub_det_b, &sub_det_b_len, &db, det_ca);
1219 d2d_fp_four_det2x2(det_ab, da.x[1], da.y[1], db.x[1], db.y[1]);
1220 d2d_fp_sub_det3x3(sub_det_c, &sub_det_c_len, &dc, det_ab);
1222 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, sub_det_a, sub_det_a_len, sub_det_b, sub_det_b_len);
1223 d2d_fp_fast_expansion_sum_zeroelim(fin.now, &fin.length, temp64, temp64_len, sub_det_c, sub_det_c_len);
1224 det = d2d_fp_estimate(fin.now, fin.length);
1225 err_bound = err_bound_b * permanent;
1226 if (det >= err_bound || -det >= err_bound)
1227 return det > 0.0f;
1229 d2d_fp_two_diff_tail(&da.x[0], p[a].x, p[d].x, da.x[1]);
1230 d2d_fp_two_diff_tail(&da.y[0], p[a].y, p[d].y, da.y[1]);
1231 d2d_fp_two_diff_tail(&db.x[0], p[b].x, p[d].x, db.x[1]);
1232 d2d_fp_two_diff_tail(&db.y[0], p[b].y, p[d].y, db.y[1]);
1233 d2d_fp_two_diff_tail(&dc.x[0], p[c].x, p[d].x, dc.x[1]);
1234 d2d_fp_two_diff_tail(&dc.y[0], p[c].y, p[d].y, dc.y[1]);
1235 if (da.x[0] == 0.0f && db.x[0] == 0.0f && dc.x[0] == 0.0f
1236 && da.y[0] == 0.0f && db.y[0] == 0.0f && dc.y[0] == 0.0f)
1237 return det > 0.0f;
1239 err_bound = err_bound_c * permanent + err_bound_result * fabsf(det);
1240 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]))
1241 + 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]))
1242 + (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]))
1243 + 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]))
1244 + (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]))
1245 + 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]));
1246 if (det >= err_bound || -det >= err_bound)
1247 return det > 0.0f;
1249 if (db.x[0] != 0.0f || db.y[0] != 0.0f || dc.x[0] != 0.0f || dc.y[0] != 0.0f)
1251 d2d_fp_square(temp2a, da.x[1]);
1252 d2d_fp_square(temp2b, da.y[1]);
1253 d2d_fp_two_two_sum(daz, temp2a, temp2b);
1255 if (dc.x[0] != 0.0f || dc.y[0] != 0.0f || da.x[0] != 0.0f || da.y[0] != 0.0f)
1257 d2d_fp_square(temp2a, db.x[1]);
1258 d2d_fp_square(temp2b, db.y[1]);
1259 d2d_fp_two_two_sum(dbz, temp2a, temp2b);
1261 if (da.x[0] != 0.0f || da.y[0] != 0.0f || db.x[0] != 0.0f || db.y[0] != 0.0f)
1263 d2d_fp_square(temp2a, dc.x[1]);
1264 d2d_fp_square(temp2b, dc.y[1]);
1265 d2d_fp_two_two_sum(dcz, temp2a, temp2b);
1268 if (da.x[0] != 0.0f)
1269 d2d_cdt_incircle_refine1(&fin, axt_det_bc, &axt_det_bc_len, det_bc, dc.y[1], dcz, db.y[1], dbz, da.x);
1270 if (da.y[0] != 0.0f)
1271 d2d_cdt_incircle_refine1(&fin, ayt_det_bc, &ayt_det_bc_len, det_bc, db.x[1], dbz, dc.x[1], dcz, da.y);
1272 if (db.x[0] != 0.0f)
1273 d2d_cdt_incircle_refine1(&fin, bxt_det_ca, &bxt_det_ca_len, det_ca, da.y[1], daz, dc.y[1], dcz, db.x);
1274 if (db.y[0] != 0.0f)
1275 d2d_cdt_incircle_refine1(&fin, byt_det_ca, &byt_det_ca_len, det_ca, dc.x[1], dcz, da.x[1], daz, db.y);
1276 if (dc.x[0] != 0.0f)
1277 d2d_cdt_incircle_refine1(&fin, cxt_det_ab, &cxt_det_ab_len, det_ab, db.y[1], dbz, da.y[1], daz, dc.x);
1278 if (dc.y[0] != 0.0f)
1279 d2d_cdt_incircle_refine1(&fin, cyt_det_ab, &cyt_det_ab_len, det_ab, da.x[1], daz, db.x[1], dbz, dc.y);
1281 if (da.x[0] != 0.0f || da.y[0] != 0.0f)
1282 d2d_cdt_incircle_refine2(&fin, &da, &db, dbz, &dc, dcz,
1283 axt_det_bc, axt_det_bc_len, ayt_det_bc, ayt_det_bc_len);
1284 if (db.x[0] != 0.0f || db.y[0] != 0.0f)
1285 d2d_cdt_incircle_refine2(&fin, &db, &dc, dcz, &da, daz,
1286 bxt_det_ca, bxt_det_ca_len, byt_det_ca, byt_det_ca_len);
1287 if (dc.x[0] != 0.0f || dc.y[0] != 0.0f)
1288 d2d_cdt_incircle_refine2(&fin, &dc, &da, daz, &db, dbz,
1289 cxt_det_ab, cxt_det_ab_len, cyt_det_ab, cyt_det_ab_len);
1291 return fin.now[fin.length - 1] > 0.0f;
1294 static void d2d_cdt_splice(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *a,
1295 const struct d2d_cdt_edge_ref *b)
1297 struct d2d_cdt_edge_ref ta, tb, alpha, beta;
1299 ta = cdt->edges[a->idx].next[a->r];
1300 tb = cdt->edges[b->idx].next[b->r];
1301 cdt->edges[a->idx].next[a->r] = tb;
1302 cdt->edges[b->idx].next[b->r] = ta;
1304 d2d_cdt_edge_rot(&alpha, &ta);
1305 d2d_cdt_edge_rot(&beta, &tb);
1307 ta = cdt->edges[alpha.idx].next[alpha.r];
1308 tb = cdt->edges[beta.idx].next[beta.r];
1309 cdt->edges[alpha.idx].next[alpha.r] = tb;
1310 cdt->edges[beta.idx].next[beta.r] = ta;
1313 static BOOL d2d_cdt_create_edge(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *e)
1315 struct d2d_cdt_edge *edge;
1317 if (cdt->free_edge != ~0u)
1319 e->idx = cdt->free_edge;
1320 cdt->free_edge = cdt->edges[e->idx].next[D2D_EDGE_NEXT_ORIGIN].idx;
1322 else
1324 if (!d2d_array_reserve((void **)&cdt->edges, &cdt->edges_size, cdt->edge_count + 1, sizeof(*cdt->edges)))
1326 ERR("Failed to grow edges array.\n");
1327 return FALSE;
1329 e->idx = cdt->edge_count++;
1331 e->r = 0;
1333 edge = &cdt->edges[e->idx];
1334 edge->next[D2D_EDGE_NEXT_ORIGIN] = *e;
1335 d2d_cdt_edge_tor(&edge->next[D2D_EDGE_NEXT_ROT], e);
1336 d2d_cdt_edge_sym(&edge->next[D2D_EDGE_NEXT_SYM], e);
1337 d2d_cdt_edge_rot(&edge->next[D2D_EDGE_NEXT_TOR], e);
1338 edge->flags = 0;
1340 return TRUE;
1343 static void d2d_cdt_destroy_edge(struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
1345 struct d2d_cdt_edge_ref next, sym, prev;
1347 d2d_cdt_edge_next_origin(cdt, &next, e);
1348 if (next.idx != e->idx || next.r != e->r)
1350 d2d_cdt_edge_prev_origin(cdt, &prev, e);
1351 d2d_cdt_splice(cdt, e, &prev);
1354 d2d_cdt_edge_sym(&sym, e);
1356 d2d_cdt_edge_next_origin(cdt, &next, &sym);
1357 if (next.idx != sym.idx || next.r != sym.r)
1359 d2d_cdt_edge_prev_origin(cdt, &prev, &sym);
1360 d2d_cdt_splice(cdt, &sym, &prev);
1363 cdt->edges[e->idx].flags |= D2D_CDT_EDGE_FLAG_FREED;
1364 cdt->edges[e->idx].next[D2D_EDGE_NEXT_ORIGIN].idx = cdt->free_edge;
1365 cdt->free_edge = e->idx;
1368 static BOOL d2d_cdt_connect(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *e,
1369 const struct d2d_cdt_edge_ref *a, const struct d2d_cdt_edge_ref *b)
1371 struct d2d_cdt_edge_ref tmp;
1373 if (!d2d_cdt_create_edge(cdt, e))
1374 return FALSE;
1375 d2d_cdt_edge_set_origin(cdt, e, d2d_cdt_edge_destination(cdt, a));
1376 d2d_cdt_edge_set_destination(cdt, e, d2d_cdt_edge_origin(cdt, b));
1377 d2d_cdt_edge_next_left(cdt, &tmp, a);
1378 d2d_cdt_splice(cdt, e, &tmp);
1379 d2d_cdt_edge_sym(&tmp, e);
1380 d2d_cdt_splice(cdt, &tmp, b);
1382 return TRUE;
1385 static BOOL d2d_cdt_merge(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *left_outer,
1386 struct d2d_cdt_edge_ref *left_inner, struct d2d_cdt_edge_ref *right_inner,
1387 struct d2d_cdt_edge_ref *right_outer)
1389 struct d2d_cdt_edge_ref base_edge, tmp;
1391 /* Create the base edge between both parts. */
1392 for (;;)
1394 if (d2d_cdt_leftof(cdt, d2d_cdt_edge_origin(cdt, right_inner), left_inner))
1396 d2d_cdt_edge_next_left(cdt, left_inner, left_inner);
1398 else if (d2d_cdt_rightof(cdt, d2d_cdt_edge_origin(cdt, left_inner), right_inner))
1400 d2d_cdt_edge_sym(&tmp, right_inner);
1401 d2d_cdt_edge_next_origin(cdt, right_inner, &tmp);
1403 else
1405 break;
1409 d2d_cdt_edge_sym(&tmp, right_inner);
1410 if (!d2d_cdt_connect(cdt, &base_edge, &tmp, left_inner))
1411 return FALSE;
1412 if (d2d_cdt_edge_origin(cdt, left_inner) == d2d_cdt_edge_origin(cdt, left_outer))
1413 d2d_cdt_edge_sym(left_outer, &base_edge);
1414 if (d2d_cdt_edge_origin(cdt, right_inner) == d2d_cdt_edge_origin(cdt, right_outer))
1415 *right_outer = base_edge;
1417 for (;;)
1419 struct d2d_cdt_edge_ref left_candidate, right_candidate, sym_base_edge;
1420 BOOL left_valid, right_valid;
1422 /* Find the left candidate. */
1423 d2d_cdt_edge_sym(&sym_base_edge, &base_edge);
1424 d2d_cdt_edge_next_origin(cdt, &left_candidate, &sym_base_edge);
1425 if ((left_valid = d2d_cdt_leftof(cdt, d2d_cdt_edge_destination(cdt, &left_candidate), &sym_base_edge)))
1427 d2d_cdt_edge_next_origin(cdt, &tmp, &left_candidate);
1428 while (d2d_cdt_edge_destination(cdt, &tmp) != d2d_cdt_edge_destination(cdt, &sym_base_edge)
1429 && d2d_cdt_incircle(cdt,
1430 d2d_cdt_edge_origin(cdt, &sym_base_edge), d2d_cdt_edge_destination(cdt, &sym_base_edge),
1431 d2d_cdt_edge_destination(cdt, &left_candidate), d2d_cdt_edge_destination(cdt, &tmp)))
1433 d2d_cdt_destroy_edge(cdt, &left_candidate);
1434 left_candidate = tmp;
1435 d2d_cdt_edge_next_origin(cdt, &tmp, &left_candidate);
1438 d2d_cdt_edge_sym(&left_candidate, &left_candidate);
1440 /* Find the right candidate. */
1441 d2d_cdt_edge_prev_origin(cdt, &right_candidate, &base_edge);
1442 if ((right_valid = d2d_cdt_rightof(cdt, d2d_cdt_edge_destination(cdt, &right_candidate), &base_edge)))
1444 d2d_cdt_edge_prev_origin(cdt, &tmp, &right_candidate);
1445 while (d2d_cdt_edge_destination(cdt, &tmp) != d2d_cdt_edge_destination(cdt, &base_edge)
1446 && d2d_cdt_incircle(cdt,
1447 d2d_cdt_edge_origin(cdt, &sym_base_edge), d2d_cdt_edge_destination(cdt, &sym_base_edge),
1448 d2d_cdt_edge_destination(cdt, &right_candidate), d2d_cdt_edge_destination(cdt, &tmp)))
1450 d2d_cdt_destroy_edge(cdt, &right_candidate);
1451 right_candidate = tmp;
1452 d2d_cdt_edge_prev_origin(cdt, &tmp, &right_candidate);
1456 if (!left_valid && !right_valid)
1457 break;
1459 /* Connect the appropriate candidate with the base edge. */
1460 if (!left_valid || (right_valid && d2d_cdt_incircle(cdt,
1461 d2d_cdt_edge_origin(cdt, &left_candidate), d2d_cdt_edge_destination(cdt, &left_candidate),
1462 d2d_cdt_edge_origin(cdt, &right_candidate), d2d_cdt_edge_destination(cdt, &right_candidate))))
1464 if (!d2d_cdt_connect(cdt, &base_edge, &right_candidate, &sym_base_edge))
1465 return FALSE;
1467 else
1469 if (!d2d_cdt_connect(cdt, &base_edge, &sym_base_edge, &left_candidate))
1470 return FALSE;
1474 return TRUE;
1477 /* Create a Delaunay triangulation from a set of vertices. This is an
1478 * implementation of the divide-and-conquer algorithm described by Guibas and
1479 * Stolfi. Should be called with at least two vertices. */
1480 static BOOL d2d_cdt_triangulate(struct d2d_cdt *cdt, size_t start_vertex, size_t vertex_count,
1481 struct d2d_cdt_edge_ref *left_edge, struct d2d_cdt_edge_ref *right_edge)
1483 struct d2d_cdt_edge_ref left_inner, left_outer, right_inner, right_outer, tmp;
1484 size_t cut;
1486 /* Only two vertices, create a single edge. */
1487 if (vertex_count == 2)
1489 struct d2d_cdt_edge_ref a;
1491 if (!d2d_cdt_create_edge(cdt, &a))
1492 return FALSE;
1493 d2d_cdt_edge_set_origin(cdt, &a, start_vertex);
1494 d2d_cdt_edge_set_destination(cdt, &a, start_vertex + 1);
1496 *left_edge = a;
1497 d2d_cdt_edge_sym(right_edge, &a);
1499 return TRUE;
1502 /* Three vertices, create a triangle. */
1503 if (vertex_count == 3)
1505 struct d2d_cdt_edge_ref a, b, c;
1506 float det;
1508 if (!d2d_cdt_create_edge(cdt, &a))
1509 return FALSE;
1510 if (!d2d_cdt_create_edge(cdt, &b))
1511 return FALSE;
1512 d2d_cdt_edge_sym(&tmp, &a);
1513 d2d_cdt_splice(cdt, &tmp, &b);
1515 d2d_cdt_edge_set_origin(cdt, &a, start_vertex);
1516 d2d_cdt_edge_set_destination(cdt, &a, start_vertex + 1);
1517 d2d_cdt_edge_set_origin(cdt, &b, start_vertex + 1);
1518 d2d_cdt_edge_set_destination(cdt, &b, start_vertex + 2);
1520 det = d2d_cdt_ccw(cdt, start_vertex, start_vertex + 1, start_vertex + 2);
1521 if (det != 0.0f && !d2d_cdt_connect(cdt, &c, &b, &a))
1522 return FALSE;
1524 if (det < 0.0f)
1526 d2d_cdt_edge_sym(left_edge, &c);
1527 *right_edge = c;
1529 else
1531 *left_edge = a;
1532 d2d_cdt_edge_sym(right_edge, &b);
1535 return TRUE;
1538 /* More than tree vertices, divide. */
1539 cut = vertex_count / 2;
1540 if (!d2d_cdt_triangulate(cdt, start_vertex, cut, &left_outer, &left_inner))
1541 return FALSE;
1542 if (!d2d_cdt_triangulate(cdt, start_vertex + cut, vertex_count - cut, &right_inner, &right_outer))
1543 return FALSE;
1544 /* Merge the left and right parts. */
1545 if (!d2d_cdt_merge(cdt, &left_outer, &left_inner, &right_inner, &right_outer))
1546 return FALSE;
1548 *left_edge = left_outer;
1549 *right_edge = right_outer;
1550 return TRUE;
1553 static int __cdecl d2d_cdt_compare_vertices(const void *a, const void *b)
1555 const D2D1_POINT_2F *p0 = a;
1556 const D2D1_POINT_2F *p1 = b;
1557 float diff = p0->x - p1->x;
1559 if (diff == 0.0f)
1560 diff = p0->y - p1->y;
1562 return diff == 0.0f ? 0 : (diff > 0.0f ? 1 : -1);
1565 /* Determine whether a given point is inside the geometry, using the current
1566 * fill mode rule. */
1567 static BOOL d2d_path_geometry_point_inside(const struct d2d_geometry *geometry,
1568 const D2D1_POINT_2F *probe, BOOL triangles_only)
1570 const D2D1_POINT_2F *p0, *p1;
1571 D2D1_POINT_2F v_p, v_probe;
1572 unsigned int score;
1573 size_t i, j, last;
1575 for (i = 0, score = 0; i < geometry->u.path.figure_count; ++i)
1577 const struct d2d_figure *figure = &geometry->u.path.figures[i];
1579 if (probe->x < figure->bounds.left || probe->x > figure->bounds.right
1580 || probe->y < figure->bounds.top || probe->y > figure->bounds.bottom)
1581 continue;
1583 last = figure->vertex_count - 1;
1584 if (!triangles_only)
1586 while (last && figure->vertex_types[last] == D2D_VERTEX_TYPE_NONE)
1587 --last;
1589 p0 = &figure->vertices[last];
1590 for (j = 0; j <= last; ++j)
1592 if (!triangles_only && figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
1593 continue;
1595 p1 = &figure->vertices[j];
1596 d2d_point_subtract(&v_p, p1, p0);
1597 d2d_point_subtract(&v_probe, probe, p0);
1599 if ((probe->y < p0->y) != (probe->y < p1->y) && v_probe.x < v_p.x * (v_probe.y / v_p.y))
1601 if (geometry->u.path.fill_mode == D2D1_FILL_MODE_ALTERNATE || (probe->y < p0->y))
1602 ++score;
1603 else
1604 --score;
1607 p0 = p1;
1611 return geometry->u.path.fill_mode == D2D1_FILL_MODE_ALTERNATE ? score & 1 : score;
1614 static BOOL d2d_path_geometry_add_fill_face(struct d2d_geometry *geometry, const struct d2d_cdt *cdt,
1615 const struct d2d_cdt_edge_ref *base_edge)
1617 struct d2d_cdt_edge_ref tmp;
1618 struct d2d_face *face;
1619 D2D1_POINT_2F probe;
1621 if (cdt->edges[base_edge->idx].flags & D2D_CDT_EDGE_FLAG_VISITED(base_edge->r))
1622 return TRUE;
1624 if (!d2d_array_reserve((void **)&geometry->fill.faces, &geometry->fill.faces_size,
1625 geometry->fill.face_count + 1, sizeof(*geometry->fill.faces)))
1627 ERR("Failed to grow faces array.\n");
1628 return FALSE;
1631 face = &geometry->fill.faces[geometry->fill.face_count];
1633 /* It may seem tempting to use the center of the face as probe origin, but
1634 * multiplying by powers of two works much better for preserving accuracy. */
1636 tmp = *base_edge;
1637 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1638 face->v[0] = d2d_cdt_edge_origin(cdt, &tmp);
1639 probe.x = cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.25f;
1640 probe.y = cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.25f;
1642 d2d_cdt_edge_next_left(cdt, &tmp, &tmp);
1643 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1644 face->v[1] = d2d_cdt_edge_origin(cdt, &tmp);
1645 probe.x += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.25f;
1646 probe.y += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.25f;
1648 d2d_cdt_edge_next_left(cdt, &tmp, &tmp);
1649 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1650 face->v[2] = d2d_cdt_edge_origin(cdt, &tmp);
1651 probe.x += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.50f;
1652 probe.y += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.50f;
1654 if (d2d_cdt_leftof(cdt, face->v[2], base_edge) && d2d_path_geometry_point_inside(geometry, &probe, TRUE))
1655 ++geometry->fill.face_count;
1657 return TRUE;
1660 static BOOL d2d_cdt_generate_faces(const struct d2d_cdt *cdt, struct d2d_geometry *geometry)
1662 struct d2d_cdt_edge_ref base_edge;
1663 size_t i;
1665 for (i = 0; i < cdt->edge_count; ++i)
1667 if (cdt->edges[i].flags & D2D_CDT_EDGE_FLAG_FREED)
1668 continue;
1670 base_edge.idx = i;
1671 base_edge.r = 0;
1672 if (!d2d_path_geometry_add_fill_face(geometry, cdt, &base_edge))
1673 goto fail;
1674 d2d_cdt_edge_sym(&base_edge, &base_edge);
1675 if (!d2d_path_geometry_add_fill_face(geometry, cdt, &base_edge))
1676 goto fail;
1679 return TRUE;
1681 fail:
1682 heap_free(geometry->fill.faces);
1683 geometry->fill.faces = NULL;
1684 geometry->fill.faces_size = 0;
1685 geometry->fill.face_count = 0;
1686 return FALSE;
1689 static BOOL d2d_cdt_fixup(struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *base_edge)
1691 struct d2d_cdt_edge_ref candidate, next, new_base;
1692 unsigned int count = 0;
1694 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1695 if (next.idx == base_edge->idx)
1697 ERR("Degenerate face.\n");
1698 return FALSE;
1701 candidate = next;
1702 while (d2d_cdt_edge_destination(cdt, &next) != d2d_cdt_edge_origin(cdt, base_edge))
1704 if (d2d_cdt_incircle(cdt, d2d_cdt_edge_origin(cdt, base_edge), d2d_cdt_edge_destination(cdt, base_edge),
1705 d2d_cdt_edge_destination(cdt, &candidate), d2d_cdt_edge_destination(cdt, &next)))
1706 candidate = next;
1707 d2d_cdt_edge_next_left(cdt, &next, &next);
1708 ++count;
1711 if (count > 1)
1713 d2d_cdt_edge_next_left(cdt, &next, &candidate);
1714 if (d2d_cdt_edge_destination(cdt, &next) == d2d_cdt_edge_origin(cdt, base_edge))
1715 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1716 else
1717 next = *base_edge;
1718 if (!d2d_cdt_connect(cdt, &new_base, &candidate, &next))
1719 return FALSE;
1720 if (!d2d_cdt_fixup(cdt, &new_base))
1721 return FALSE;
1722 d2d_cdt_edge_sym(&new_base, &new_base);
1723 if (!d2d_cdt_fixup(cdt, &new_base))
1724 return FALSE;
1727 return TRUE;
1730 static void d2d_cdt_cut_edges(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *end_edge,
1731 const struct d2d_cdt_edge_ref *base_edge, size_t start_vertex, size_t end_vertex)
1733 struct d2d_cdt_edge_ref next;
1734 float ccw;
1736 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1737 if (d2d_cdt_edge_destination(cdt, &next) == end_vertex)
1739 *end_edge = next;
1740 return;
1743 ccw = d2d_cdt_ccw(cdt, d2d_cdt_edge_destination(cdt, &next), end_vertex, start_vertex);
1744 if (ccw == 0.0f)
1746 *end_edge = next;
1747 return;
1750 if (ccw > 0.0f)
1751 d2d_cdt_edge_next_left(cdt, &next, &next);
1753 d2d_cdt_edge_sym(&next, &next);
1754 d2d_cdt_cut_edges(cdt, end_edge, &next, start_vertex, end_vertex);
1755 d2d_cdt_destroy_edge(cdt, &next);
1758 static BOOL d2d_cdt_insert_segment(struct d2d_cdt *cdt, struct d2d_geometry *geometry,
1759 const struct d2d_cdt_edge_ref *origin, struct d2d_cdt_edge_ref *edge, size_t end_vertex)
1761 struct d2d_cdt_edge_ref base_edge, current, new_origin, next, target;
1762 size_t current_destination, current_origin;
1764 for (current = *origin;; current = next)
1766 d2d_cdt_edge_next_origin(cdt, &next, &current);
1768 current_destination = d2d_cdt_edge_destination(cdt, &current);
1769 if (current_destination == end_vertex)
1771 d2d_cdt_edge_sym(edge, &current);
1772 return TRUE;
1775 current_origin = d2d_cdt_edge_origin(cdt, &current);
1776 if (d2d_cdt_ccw(cdt, end_vertex, current_origin, current_destination) == 0.0f
1777 && (cdt->vertices[current_destination].x > cdt->vertices[current_origin].x)
1778 == (cdt->vertices[end_vertex].x > cdt->vertices[current_origin].x)
1779 && (cdt->vertices[current_destination].y > cdt->vertices[current_origin].y)
1780 == (cdt->vertices[end_vertex].y > cdt->vertices[current_origin].y))
1782 d2d_cdt_edge_sym(&new_origin, &current);
1783 return d2d_cdt_insert_segment(cdt, geometry, &new_origin, edge, end_vertex);
1786 if (d2d_cdt_rightof(cdt, end_vertex, &next) && d2d_cdt_leftof(cdt, end_vertex, &current))
1788 d2d_cdt_edge_next_left(cdt, &base_edge, &current);
1790 d2d_cdt_edge_sym(&base_edge, &base_edge);
1791 d2d_cdt_cut_edges(cdt, &target, &base_edge, d2d_cdt_edge_origin(cdt, origin), end_vertex);
1792 d2d_cdt_destroy_edge(cdt, &base_edge);
1794 if (!d2d_cdt_connect(cdt, &base_edge, &target, &current))
1795 return FALSE;
1796 *edge = base_edge;
1797 if (!d2d_cdt_fixup(cdt, &base_edge))
1798 return FALSE;
1799 d2d_cdt_edge_sym(&base_edge, &base_edge);
1800 if (!d2d_cdt_fixup(cdt, &base_edge))
1801 return FALSE;
1803 if (d2d_cdt_edge_origin(cdt, edge) == end_vertex)
1804 return TRUE;
1805 new_origin = *edge;
1806 return d2d_cdt_insert_segment(cdt, geometry, &new_origin, edge, end_vertex);
1809 if (next.idx == origin->idx)
1811 ERR("Triangle not found.\n");
1812 return FALSE;
1817 static BOOL d2d_cdt_insert_segments(struct d2d_cdt *cdt, struct d2d_geometry *geometry)
1819 size_t start_vertex, end_vertex, i, j, k;
1820 struct d2d_cdt_edge_ref edge, new_edge;
1821 const struct d2d_figure *figure;
1822 const D2D1_POINT_2F *p;
1823 BOOL found;
1825 for (i = 0; i < geometry->u.path.figure_count; ++i)
1827 figure = &geometry->u.path.figures[i];
1829 if (figure->flags & D2D_FIGURE_FLAG_HOLLOW)
1830 continue;
1832 /* Degenerate figure. */
1833 if (figure->vertex_count < 2)
1834 continue;
1836 p = bsearch(&figure->vertices[figure->vertex_count - 1], cdt->vertices,
1837 geometry->fill.vertex_count, sizeof(*p), d2d_cdt_compare_vertices);
1838 start_vertex = p - cdt->vertices;
1840 for (k = 0, found = FALSE; k < cdt->edge_count; ++k)
1842 if (cdt->edges[k].flags & D2D_CDT_EDGE_FLAG_FREED)
1843 continue;
1845 edge.idx = k;
1846 edge.r = 0;
1848 if (d2d_cdt_edge_origin(cdt, &edge) == start_vertex)
1850 found = TRUE;
1851 break;
1853 d2d_cdt_edge_sym(&edge, &edge);
1854 if (d2d_cdt_edge_origin(cdt, &edge) == start_vertex)
1856 found = TRUE;
1857 break;
1861 if (!found)
1863 ERR("Edge not found.\n");
1864 return FALSE;
1867 for (j = 0; j < figure->vertex_count; start_vertex = end_vertex, ++j)
1869 p = bsearch(&figure->vertices[j], cdt->vertices,
1870 geometry->fill.vertex_count, sizeof(*p), d2d_cdt_compare_vertices);
1871 end_vertex = p - cdt->vertices;
1873 if (start_vertex == end_vertex)
1874 continue;
1876 if (!d2d_cdt_insert_segment(cdt, geometry, &edge, &new_edge, end_vertex))
1877 return FALSE;
1878 edge = new_edge;
1882 return TRUE;
1885 static BOOL d2d_geometry_intersections_add(struct d2d_geometry_intersections *i,
1886 const struct d2d_segment_idx *segment_idx, float t, D2D1_POINT_2F p)
1888 struct d2d_geometry_intersection *intersection;
1890 if (!d2d_array_reserve((void **)&i->intersections, &i->intersections_size,
1891 i->intersection_count + 1, sizeof(*i->intersections)))
1893 ERR("Failed to grow intersections array.\n");
1894 return FALSE;
1897 intersection = &i->intersections[i->intersection_count++];
1898 intersection->figure_idx = segment_idx->figure_idx;
1899 intersection->vertex_idx = segment_idx->vertex_idx;
1900 intersection->control_idx = segment_idx->control_idx;
1901 intersection->t = t;
1902 intersection->p = p;
1904 return TRUE;
1907 static int __cdecl d2d_geometry_intersections_compare(const void *a, const void *b)
1909 const struct d2d_geometry_intersection *i0 = a;
1910 const struct d2d_geometry_intersection *i1 = b;
1912 if (i0->figure_idx != i1->figure_idx)
1913 return i0->figure_idx - i1->figure_idx;
1914 if (i0->vertex_idx != i1->vertex_idx)
1915 return i0->vertex_idx - i1->vertex_idx;
1916 if (i0->t != i1->t)
1917 return i0->t > i1->t ? 1 : -1;
1918 return 0;
1921 static BOOL d2d_geometry_intersect_line_line(struct d2d_geometry *geometry,
1922 struct d2d_geometry_intersections *intersections, const struct d2d_segment_idx *idx_p,
1923 const struct d2d_segment_idx *idx_q)
1925 D2D1_POINT_2F v_p, v_q, v_qp, intersection;
1926 const D2D1_POINT_2F *p[2], *q[2];
1927 const struct d2d_figure *figure;
1928 float s, t, det;
1929 size_t next;
1931 figure = &geometry->u.path.figures[idx_p->figure_idx];
1932 p[0] = &figure->vertices[idx_p->vertex_idx];
1933 next = idx_p->vertex_idx + 1;
1934 if (next == figure->vertex_count)
1935 next = 0;
1936 p[1] = &figure->vertices[next];
1938 figure = &geometry->u.path.figures[idx_q->figure_idx];
1939 q[0] = &figure->vertices[idx_q->vertex_idx];
1940 next = idx_q->vertex_idx + 1;
1941 if (next == figure->vertex_count)
1942 next = 0;
1943 q[1] = &figure->vertices[next];
1945 d2d_point_subtract(&v_p, p[1], p[0]);
1946 d2d_point_subtract(&v_q, q[1], q[0]);
1947 d2d_point_subtract(&v_qp, p[0], q[0]);
1949 det = v_p.x * v_q.y - v_p.y * v_q.x;
1950 if (det == 0.0f)
1951 return TRUE;
1953 s = (v_q.x * v_qp.y - v_q.y * v_qp.x) / det;
1954 t = (v_p.x * v_qp.y - v_p.y * v_qp.x) / det;
1956 if (s < 0.0f || s > 1.0f || t < 0.0f || t > 1.0f)
1957 return TRUE;
1959 intersection.x = p[0]->x + v_p.x * s;
1960 intersection.y = p[0]->y + v_p.y * s;
1962 if (s > 0.0f && s < 1.0f && !d2d_geometry_intersections_add(intersections, idx_p, s, intersection))
1963 return FALSE;
1965 if (t > 0.0f && t < 1.0f && !d2d_geometry_intersections_add(intersections, idx_q, t, intersection))
1966 return FALSE;
1968 return TRUE;
1971 static BOOL d2d_geometry_add_bezier_line_intersections(struct d2d_geometry *geometry,
1972 struct d2d_geometry_intersections *intersections, const struct d2d_segment_idx *idx_p,
1973 const D2D1_POINT_2F **p, const struct d2d_segment_idx *idx_q, const D2D1_POINT_2F **q, float s)
1975 D2D1_POINT_2F intersection;
1976 float t;
1978 d2d_point_calculate_bezier(&intersection, p[0], p[1], p[2], s);
1979 if (fabsf(q[1]->x - q[0]->x) > fabsf(q[1]->y - q[0]->y))
1980 t = (intersection.x - q[0]->x) / (q[1]->x - q[0]->x);
1981 else
1982 t = (intersection.y - q[0]->y) / (q[1]->y - q[0]->y);
1983 if (t < 0.0f || t > 1.0f)
1984 return TRUE;
1986 d2d_point_lerp(&intersection, q[0], q[1], t);
1988 if (s > 0.0f && s < 1.0f && !d2d_geometry_intersections_add(intersections, idx_p, s, intersection))
1989 return FALSE;
1991 if (t > 0.0f && t < 1.0f && !d2d_geometry_intersections_add(intersections, idx_q, t, intersection))
1992 return FALSE;
1994 return TRUE;
1997 static BOOL d2d_geometry_intersect_bezier_line(struct d2d_geometry *geometry,
1998 struct d2d_geometry_intersections *intersections,
1999 const struct d2d_segment_idx *idx_p, const struct d2d_segment_idx *idx_q)
2001 const D2D1_POINT_2F *p[3], *q[2];
2002 const struct d2d_figure *figure;
2003 float y[3], root, theta, d, e;
2004 size_t next;
2006 figure = &geometry->u.path.figures[idx_p->figure_idx];
2007 p[0] = &figure->vertices[idx_p->vertex_idx];
2008 p[1] = &figure->bezier_controls[idx_p->control_idx];
2009 next = idx_p->vertex_idx + 1;
2010 p[2] = &figure->vertices[next];
2012 figure = &geometry->u.path.figures[idx_q->figure_idx];
2013 q[0] = &figure->vertices[idx_q->vertex_idx];
2014 next = idx_q->vertex_idx + 1;
2015 if (next == figure->vertex_count)
2016 next = 0;
2017 q[1] = &figure->vertices[next];
2019 /* Align the line with x-axis. */
2020 theta = -atan2f(q[1]->y - q[0]->y, q[1]->x - q[0]->x);
2021 y[0] = (p[0]->x - q[0]->x) * sinf(theta) + (p[0]->y - q[0]->y) * cosf(theta);
2022 y[1] = (p[1]->x - q[0]->x) * sinf(theta) + (p[1]->y - q[0]->y) * cosf(theta);
2023 y[2] = (p[2]->x - q[0]->x) * sinf(theta) + (p[2]->y - q[0]->y) * cosf(theta);
2025 /* Intersect the transformed curve with the x-axis.
2027 * f(t) = (1 - t)²P₀ + 2(1 - t)tP₁ + t²P₂
2028 * = (P₀ - 2P₁ + P₂)t² + 2(P₁ - P₀)t + P₀
2030 * a = P₀ - 2P₁ + P₂
2031 * b = 2(P₁ - P₀)
2032 * c = P₀
2034 * f(t) = 0
2035 * t = (-b ± √(b² - 4ac)) / 2a
2036 * = (-2(P₁ - P₀) ± √((2(P₁ - P₀))² - 4((P₀ - 2P₁ + P₂)P₀))) / 2(P₀ - 2P₁ + P₂)
2037 * = (2P₀ - 2P₁ ± √(4P₀² + 4P₁² - 8P₀P₁ - 4P₀² + 8P₀P₁ - 4P₀P₂)) / (2P₀ - 4P₁ + 2P₂)
2038 * = (P₀ - P₁ ± √(P₁² - P₀P₂)) / (P₀ - 2P₁ + P₂) */
2040 d = y[0] - 2 * y[1] + y[2];
2041 if (d == 0.0f)
2043 /* P₀ - 2P₁ + P₂ = 0
2044 * f(t) = (P₀ - 2P₁ + P₂)t² + 2(P₁ - P₀)t + P₀ = 0
2045 * t = -P₀ / 2(P₁ - P₀) */
2046 root = -y[0] / (2.0f * (y[1] - y[0]));
2047 if (root < 0.0f || root > 1.0f)
2048 return TRUE;
2050 return d2d_geometry_add_bezier_line_intersections(geometry, intersections, idx_p, p, idx_q, q, root);
2053 e = y[1] * y[1] - y[0] * y[2];
2054 if (e < 0.0f)
2055 return TRUE;
2057 root = (y[0] - y[1] + sqrtf(e)) / d;
2058 if (root >= 0.0f && root <= 1.0f && !d2d_geometry_add_bezier_line_intersections(geometry,
2059 intersections, idx_p, p, idx_q, q, root))
2060 return FALSE;
2062 root = (y[0] - y[1] - sqrtf(e)) / d;
2063 if (root >= 0.0f && root <= 1.0f && !d2d_geometry_add_bezier_line_intersections(geometry,
2064 intersections, idx_p, p, idx_q, q, root))
2065 return FALSE;
2067 return TRUE;
2070 static BOOL d2d_geometry_intersect_bezier_bezier(struct d2d_geometry *geometry,
2071 struct d2d_geometry_intersections *intersections,
2072 const struct d2d_segment_idx *idx_p, float start_p, float end_p,
2073 const struct d2d_segment_idx *idx_q, float start_q, float end_q)
2075 const D2D1_POINT_2F *p[3], *q[3];
2076 const struct d2d_figure *figure;
2077 D2D_RECT_F p_bounds, q_bounds;
2078 D2D1_POINT_2F intersection;
2079 float centre_p, centre_q;
2080 size_t next;
2082 figure = &geometry->u.path.figures[idx_p->figure_idx];
2083 p[0] = &figure->vertices[idx_p->vertex_idx];
2084 p[1] = &figure->bezier_controls[idx_p->control_idx];
2085 next = idx_p->vertex_idx + 1;
2086 p[2] = &figure->vertices[next];
2088 figure = &geometry->u.path.figures[idx_q->figure_idx];
2089 q[0] = &figure->vertices[idx_q->vertex_idx];
2090 q[1] = &figure->bezier_controls[idx_q->control_idx];
2091 next = idx_q->vertex_idx + 1;
2092 q[2] = &figure->vertices[next];
2094 d2d_rect_get_bezier_segment_bounds(&p_bounds, p[0], p[1], p[2], start_p, end_p);
2095 d2d_rect_get_bezier_segment_bounds(&q_bounds, q[0], q[1], q[2], start_q, end_q);
2097 if (!d2d_rect_check_overlap(&p_bounds, &q_bounds))
2098 return TRUE;
2100 centre_p = (start_p + end_p) / 2.0f;
2101 centre_q = (start_q + end_q) / 2.0f;
2103 if (end_p - start_p < 1e-3f)
2105 d2d_point_calculate_bezier(&intersection, p[0], p[1], p[2], centre_p);
2106 if (start_p > 0.0f && end_p < 1.0f && !d2d_geometry_intersections_add(intersections,
2107 idx_p, centre_p, intersection))
2108 return FALSE;
2109 if (start_q > 0.0f && end_q < 1.0f && !d2d_geometry_intersections_add(intersections,
2110 idx_q, centre_q, intersection))
2111 return FALSE;
2112 return TRUE;
2115 if (!d2d_geometry_intersect_bezier_bezier(geometry, intersections,
2116 idx_p, start_p, centre_p, idx_q, start_q, centre_q))
2117 return FALSE;
2118 if (!d2d_geometry_intersect_bezier_bezier(geometry, intersections,
2119 idx_p, start_p, centre_p, idx_q, centre_q, end_q))
2120 return FALSE;
2121 if (!d2d_geometry_intersect_bezier_bezier(geometry, intersections,
2122 idx_p, centre_p, end_p, idx_q, start_q, centre_q))
2123 return FALSE;
2124 if (!d2d_geometry_intersect_bezier_bezier(geometry, intersections,
2125 idx_p, centre_p, end_p, idx_q, centre_q, end_q))
2126 return FALSE;
2128 return TRUE;
2131 static BOOL d2d_geometry_apply_intersections(struct d2d_geometry *geometry,
2132 struct d2d_geometry_intersections *intersections)
2134 size_t vertex_offset, control_offset, next, i;
2135 struct d2d_geometry_intersection *inter;
2136 enum d2d_vertex_type vertex_type;
2137 const D2D1_POINT_2F *p[3];
2138 struct d2d_figure *figure;
2139 D2D1_POINT_2F q[2];
2140 float t, t_prev;
2142 for (i = 0; i < intersections->intersection_count; ++i)
2144 inter = &intersections->intersections[i];
2145 if (!i || inter->figure_idx != intersections->intersections[i - 1].figure_idx)
2146 vertex_offset = control_offset = 0;
2148 figure = &geometry->u.path.figures[inter->figure_idx];
2149 vertex_type = figure->vertex_types[inter->vertex_idx + vertex_offset];
2150 if (!d2d_vertex_type_is_bezier(vertex_type))
2152 if (!d2d_figure_insert_vertex(&geometry->u.path.figures[inter->figure_idx],
2153 inter->vertex_idx + vertex_offset + 1, inter->p))
2154 return FALSE;
2155 ++vertex_offset;
2156 continue;
2159 t = inter->t;
2160 if (i && inter->figure_idx == intersections->intersections[i - 1].figure_idx
2161 && inter->vertex_idx == intersections->intersections[i - 1].vertex_idx)
2163 t_prev = intersections->intersections[i - 1].t;
2164 if (t - t_prev < 1e-3f)
2166 inter->t = intersections->intersections[i - 1].t;
2167 continue;
2169 t = (t - t_prev) / (1.0f - t_prev);
2172 p[0] = &figure->vertices[inter->vertex_idx + vertex_offset];
2173 p[1] = &figure->bezier_controls[inter->control_idx + control_offset];
2174 next = inter->vertex_idx + vertex_offset + 1;
2175 p[2] = &figure->vertices[next];
2177 d2d_point_lerp(&q[0], p[0], p[1], t);
2178 d2d_point_lerp(&q[1], p[1], p[2], t);
2180 figure->bezier_controls[inter->control_idx + control_offset] = q[0];
2181 if (!(d2d_figure_insert_bezier_controls(figure, inter->control_idx + control_offset + 1, 1, &q[1])))
2182 return FALSE;
2183 ++control_offset;
2185 if (!(d2d_figure_insert_vertex(figure, inter->vertex_idx + vertex_offset + 1, inter->p)))
2186 return FALSE;
2187 figure->vertex_types[inter->vertex_idx + vertex_offset + 1] = D2D_VERTEX_TYPE_SPLIT_BEZIER;
2188 ++vertex_offset;
2191 return TRUE;
2194 /* Intersect the geometry's segments with themselves. This uses the
2195 * straightforward approach of testing everything against everything, but
2196 * there certainly exist more scalable algorithms for this. */
2197 static BOOL d2d_geometry_intersect_self(struct d2d_geometry *geometry)
2199 struct d2d_geometry_intersections intersections = {0};
2200 const struct d2d_figure *figure_p, *figure_q;
2201 struct d2d_segment_idx idx_p, idx_q;
2202 enum d2d_vertex_type type_p, type_q;
2203 BOOL ret = FALSE;
2204 size_t max_q;
2206 if (!geometry->u.path.figure_count)
2207 return TRUE;
2209 for (idx_p.figure_idx = 0; idx_p.figure_idx < geometry->u.path.figure_count; ++idx_p.figure_idx)
2211 figure_p = &geometry->u.path.figures[idx_p.figure_idx];
2212 idx_p.control_idx = 0;
2213 for (idx_p.vertex_idx = 0; idx_p.vertex_idx < figure_p->vertex_count; ++idx_p.vertex_idx)
2215 if ((type_p = figure_p->vertex_types[idx_p.vertex_idx]) == D2D_VERTEX_TYPE_END)
2216 continue;
2218 for (idx_q.figure_idx = 0; idx_q.figure_idx <= idx_p.figure_idx; ++idx_q.figure_idx)
2220 figure_q = &geometry->u.path.figures[idx_q.figure_idx];
2221 if (idx_q.figure_idx != idx_p.figure_idx)
2223 if (!d2d_rect_check_overlap(&figure_p->bounds, &figure_q->bounds))
2224 continue;
2225 if ((max_q = figure_q->vertex_count)
2226 && figure_q->vertex_types[max_q - 1] == D2D_VERTEX_TYPE_END)
2227 --max_q;
2229 else
2231 max_q = idx_p.vertex_idx;
2234 idx_q.control_idx = 0;
2235 for (idx_q.vertex_idx = 0; idx_q.vertex_idx < max_q; ++idx_q.vertex_idx)
2237 type_q = figure_q->vertex_types[idx_q.vertex_idx];
2238 if (d2d_vertex_type_is_bezier(type_q))
2240 if (d2d_vertex_type_is_bezier(type_p))
2242 if (!d2d_geometry_intersect_bezier_bezier(geometry, &intersections,
2243 &idx_p, 0.0f, 1.0f, &idx_q, 0.0f, 1.0f))
2244 goto done;
2246 else
2248 if (!d2d_geometry_intersect_bezier_line(geometry, &intersections, &idx_q, &idx_p))
2249 goto done;
2251 ++idx_q.control_idx;
2253 else
2255 if (d2d_vertex_type_is_bezier(type_p))
2257 if (!d2d_geometry_intersect_bezier_line(geometry, &intersections, &idx_p, &idx_q))
2258 goto done;
2260 else
2262 if (!d2d_geometry_intersect_line_line(geometry, &intersections, &idx_p, &idx_q))
2263 goto done;
2268 if (d2d_vertex_type_is_bezier(type_p))
2269 ++idx_p.control_idx;
2273 qsort(intersections.intersections, intersections.intersection_count,
2274 sizeof(*intersections.intersections), d2d_geometry_intersections_compare);
2275 ret = d2d_geometry_apply_intersections(geometry, &intersections);
2277 done:
2278 heap_free(intersections.intersections);
2279 return ret;
2282 static HRESULT d2d_path_geometry_triangulate(struct d2d_geometry *geometry)
2284 struct d2d_cdt_edge_ref left_edge, right_edge;
2285 size_t vertex_count, i, j;
2286 struct d2d_cdt cdt = {0};
2287 D2D1_POINT_2F *vertices;
2289 for (i = 0, vertex_count = 0; i < geometry->u.path.figure_count; ++i)
2291 if (geometry->u.path.figures[i].flags & D2D_FIGURE_FLAG_HOLLOW)
2292 continue;
2293 vertex_count += geometry->u.path.figures[i].vertex_count;
2296 if (vertex_count < 3)
2298 WARN("Geometry has %lu vertices.\n", (long)vertex_count);
2299 return S_OK;
2302 if (!(vertices = heap_calloc(vertex_count, sizeof(*vertices))))
2303 return E_OUTOFMEMORY;
2305 for (i = 0, j = 0; i < geometry->u.path.figure_count; ++i)
2307 if (geometry->u.path.figures[i].flags & D2D_FIGURE_FLAG_HOLLOW)
2308 continue;
2309 memcpy(&vertices[j], geometry->u.path.figures[i].vertices,
2310 geometry->u.path.figures[i].vertex_count * sizeof(*vertices));
2311 j += geometry->u.path.figures[i].vertex_count;
2314 /* Sort vertices, eliminate duplicates. */
2315 qsort(vertices, vertex_count, sizeof(*vertices), d2d_cdt_compare_vertices);
2316 for (i = 1; i < vertex_count; ++i)
2318 if (!memcmp(&vertices[i - 1], &vertices[i], sizeof(*vertices)))
2320 --vertex_count;
2321 memmove(&vertices[i], &vertices[i + 1], (vertex_count - i) * sizeof(*vertices));
2322 --i;
2326 if (vertex_count < 3)
2328 WARN("Geometry has %lu vertices after eliminating duplicates.\n", (long)vertex_count);
2329 heap_free(vertices);
2330 return S_OK;
2333 geometry->fill.vertices = vertices;
2334 geometry->fill.vertex_count = vertex_count;
2336 cdt.free_edge = ~0u;
2337 cdt.vertices = vertices;
2338 if (!d2d_cdt_triangulate(&cdt, 0, vertex_count, &left_edge, &right_edge))
2339 goto fail;
2340 if (!d2d_cdt_insert_segments(&cdt, geometry))
2341 goto fail;
2342 if (!d2d_cdt_generate_faces(&cdt, geometry))
2343 goto fail;
2345 heap_free(cdt.edges);
2346 return S_OK;
2348 fail:
2349 geometry->fill.vertices = NULL;
2350 geometry->fill.vertex_count = 0;
2351 heap_free(vertices);
2352 heap_free(cdt.edges);
2353 return E_FAIL;
2356 static BOOL d2d_path_geometry_add_figure(struct d2d_geometry *geometry)
2358 struct d2d_figure *figure;
2360 if (!d2d_array_reserve((void **)&geometry->u.path.figures, &geometry->u.path.figures_size,
2361 geometry->u.path.figure_count + 1, sizeof(*geometry->u.path.figures)))
2363 ERR("Failed to grow figures array.\n");
2364 return FALSE;
2367 figure = &geometry->u.path.figures[geometry->u.path.figure_count];
2368 memset(figure, 0, sizeof(*figure));
2369 figure->bounds.left = FLT_MAX;
2370 figure->bounds.top = FLT_MAX;
2371 figure->bounds.right = -FLT_MAX;
2372 figure->bounds.bottom = -FLT_MAX;
2374 ++geometry->u.path.figure_count;
2375 return TRUE;
2378 static BOOL d2d_geometry_outline_add_join(struct d2d_geometry *geometry,
2379 const D2D1_POINT_2F *prev, const D2D1_POINT_2F *p0, const D2D1_POINT_2F *next)
2381 static const D2D1_POINT_2F origin = {0.0f, 0.0f};
2382 struct d2d_outline_vertex *v;
2383 struct d2d_face *f;
2384 size_t base_idx;
2385 float ccw;
2387 if (!d2d_array_reserve((void **)&geometry->outline.vertices, &geometry->outline.vertices_size,
2388 geometry->outline.vertex_count + 4, sizeof(*geometry->outline.vertices)))
2390 ERR("Failed to grow outline vertices array.\n");
2391 return FALSE;
2393 base_idx = geometry->outline.vertex_count;
2394 v = &geometry->outline.vertices[base_idx];
2396 if (!d2d_array_reserve((void **)&geometry->outline.faces, &geometry->outline.faces_size,
2397 geometry->outline.face_count + 2, sizeof(*geometry->outline.faces)))
2399 ERR("Failed to grow outline faces array.\n");
2400 return FALSE;
2402 f = &geometry->outline.faces[geometry->outline.face_count];
2404 ccw = d2d_point_ccw(&origin, prev, next);
2405 if (ccw == 0.0f)
2407 d2d_outline_vertex_set(&v[0], p0->x, p0->y, -prev->x, -prev->y, -prev->x, -prev->y);
2408 d2d_outline_vertex_set(&v[1], p0->x, p0->y, prev->x, prev->y, prev->x, prev->y);
2409 d2d_outline_vertex_set(&v[2], p0->x + 25.0f * -prev->x, p0->y + 25.0f * -prev->y,
2410 prev->x, prev->y, prev->x, prev->y);
2411 d2d_outline_vertex_set(&v[3], p0->x + 25.0f * -prev->x, p0->y + 25.0f * -prev->y,
2412 -prev->x, -prev->y, -prev->x, -prev->y);
2414 else if (ccw < 0.0f)
2416 d2d_outline_vertex_set(&v[0], p0->x, p0->y, next->x, next->y, -prev->x, -prev->y);
2417 d2d_outline_vertex_set(&v[1], p0->x, p0->y, -next->x, -next->y, -next->x, -next->y);
2418 d2d_outline_vertex_set(&v[2], p0->x, p0->y, -next->x, -next->y, prev->x, prev->y);
2419 d2d_outline_vertex_set(&v[3], p0->x, p0->y, prev->x, prev->y, prev->x, prev->y);
2421 else
2423 d2d_outline_vertex_set(&v[0], p0->x, p0->y, prev->x, prev->y, -next->x, -next->y);
2424 d2d_outline_vertex_set(&v[1], p0->x, p0->y, -prev->x, -prev->y, -prev->x, -prev->y);
2425 d2d_outline_vertex_set(&v[2], p0->x, p0->y, -prev->x, -prev->y, next->x, next->y);
2426 d2d_outline_vertex_set(&v[3], p0->x, p0->y, next->x, next->y, next->x, next->y);
2428 geometry->outline.vertex_count += 4;
2430 d2d_face_set(&f[0], base_idx + 1, base_idx + 0, base_idx + 2);
2431 d2d_face_set(&f[1], base_idx + 2, base_idx + 0, base_idx + 3);
2432 geometry->outline.face_count += 2;
2434 return TRUE;
2437 static BOOL d2d_geometry_outline_add_line_segment(struct d2d_geometry *geometry,
2438 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *next)
2440 struct d2d_outline_vertex *v;
2441 D2D1_POINT_2F q_next;
2442 struct d2d_face *f;
2443 size_t base_idx;
2445 if (!d2d_array_reserve((void **)&geometry->outline.vertices, &geometry->outline.vertices_size,
2446 geometry->outline.vertex_count + 4, sizeof(*geometry->outline.vertices)))
2448 ERR("Failed to grow outline vertices array.\n");
2449 return FALSE;
2451 base_idx = geometry->outline.vertex_count;
2452 v = &geometry->outline.vertices[base_idx];
2454 if (!d2d_array_reserve((void **)&geometry->outline.faces, &geometry->outline.faces_size,
2455 geometry->outline.face_count + 2, sizeof(*geometry->outline.faces)))
2457 ERR("Failed to grow outline faces array.\n");
2458 return FALSE;
2460 f = &geometry->outline.faces[geometry->outline.face_count];
2462 d2d_point_subtract(&q_next, next, p0);
2463 d2d_point_normalise(&q_next);
2465 d2d_outline_vertex_set(&v[0], p0->x, p0->y, q_next.x, q_next.y, q_next.x, q_next.y);
2466 d2d_outline_vertex_set(&v[1], p0->x, p0->y, -q_next.x, -q_next.y, -q_next.x, -q_next.y);
2467 d2d_outline_vertex_set(&v[2], next->x, next->y, q_next.x, q_next.y, q_next.x, q_next.y);
2468 d2d_outline_vertex_set(&v[3], next->x, next->y, -q_next.x, -q_next.y, -q_next.x, -q_next.y);
2469 geometry->outline.vertex_count += 4;
2471 d2d_face_set(&f[0], base_idx + 0, base_idx + 1, base_idx + 2);
2472 d2d_face_set(&f[1], base_idx + 2, base_idx + 1, base_idx + 3);
2473 geometry->outline.face_count += 2;
2475 return TRUE;
2478 static BOOL d2d_geometry_outline_add_bezier_segment(struct d2d_geometry *geometry,
2479 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2)
2481 struct d2d_curve_outline_vertex *b;
2482 D2D1_POINT_2F r0, r1, r2;
2483 D2D1_POINT_2F q0, q1, q2;
2484 struct d2d_face *f;
2485 size_t base_idx;
2487 if (!d2d_array_reserve((void **)&geometry->outline.beziers, &geometry->outline.beziers_size,
2488 geometry->outline.bezier_count + 7, sizeof(*geometry->outline.beziers)))
2490 ERR("Failed to grow outline beziers array.\n");
2491 return FALSE;
2493 base_idx = geometry->outline.bezier_count;
2494 b = &geometry->outline.beziers[base_idx];
2496 if (!d2d_array_reserve((void **)&geometry->outline.bezier_faces, &geometry->outline.bezier_faces_size,
2497 geometry->outline.bezier_face_count + 5, sizeof(*geometry->outline.bezier_faces)))
2499 ERR("Failed to grow outline faces array.\n");
2500 return FALSE;
2502 f = &geometry->outline.bezier_faces[geometry->outline.bezier_face_count];
2504 d2d_point_lerp(&q0, p0, p1, 0.5f);
2505 d2d_point_lerp(&q1, p1, p2, 0.5f);
2506 d2d_point_lerp(&q2, &q0, &q1, 0.5f);
2508 d2d_point_subtract(&r0, &q0, p0);
2509 d2d_point_subtract(&r1, &q1, &q0);
2510 d2d_point_subtract(&r2, p2, &q1);
2512 d2d_point_normalise(&r0);
2513 d2d_point_normalise(&r1);
2514 d2d_point_normalise(&r2);
2516 if (d2d_point_ccw(p0, p1, p2) > 0.0f)
2518 d2d_point_scale(&r0, -1.0f);
2519 d2d_point_scale(&r1, -1.0f);
2520 d2d_point_scale(&r2, -1.0f);
2523 d2d_curve_outline_vertex_set(&b[0], p0, p0, p1, p2, r0.x, r0.y, r0.x, r0.y);
2524 d2d_curve_outline_vertex_set(&b[1], p0, p0, p1, p2, -r0.x, -r0.y, -r0.x, -r0.y);
2525 d2d_curve_outline_vertex_set(&b[2], &q0, p0, p1, p2, r0.x, r0.y, r1.x, r1.y);
2526 d2d_curve_outline_vertex_set(&b[3], &q2, p0, p1, p2, -r1.x, -r1.y, -r1.x, -r1.y);
2527 d2d_curve_outline_vertex_set(&b[4], &q1, p0, p1, p2, r1.x, r1.y, r2.x, r2.y);
2528 d2d_curve_outline_vertex_set(&b[5], p2, p0, p1, p2, -r2.x, -r2.y, -r2.x, -r2.y);
2529 d2d_curve_outline_vertex_set(&b[6], p2, p0, p1, p2, r2.x, r2.y, r2.x, r2.y);
2530 geometry->outline.bezier_count += 7;
2532 d2d_face_set(&f[0], base_idx + 0, base_idx + 1, base_idx + 2);
2533 d2d_face_set(&f[1], base_idx + 2, base_idx + 1, base_idx + 3);
2534 d2d_face_set(&f[2], base_idx + 3, base_idx + 4, base_idx + 2);
2535 d2d_face_set(&f[3], base_idx + 5, base_idx + 4, base_idx + 3);
2536 d2d_face_set(&f[4], base_idx + 5, base_idx + 6, base_idx + 4);
2537 geometry->outline.bezier_face_count += 5;
2539 return TRUE;
2542 static BOOL d2d_geometry_outline_add_arc_quadrant(struct d2d_geometry *geometry,
2543 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2)
2545 struct d2d_curve_outline_vertex *a;
2546 D2D1_POINT_2F r0, r1;
2547 struct d2d_face *f;
2548 size_t base_idx;
2550 if (!d2d_array_reserve((void **)&geometry->outline.arcs, &geometry->outline.arcs_size,
2551 geometry->outline.arc_count + 5, sizeof(*geometry->outline.arcs)))
2553 ERR("Failed to grow outline arcs array.\n");
2554 return FALSE;
2556 base_idx = geometry->outline.arc_count;
2557 a = &geometry->outline.arcs[base_idx];
2559 if (!d2d_array_reserve((void **)&geometry->outline.arc_faces, &geometry->outline.arc_faces_size,
2560 geometry->outline.arc_face_count + 3, sizeof(*geometry->outline.arc_faces)))
2562 ERR("Failed to grow outline faces array.\n");
2563 return FALSE;
2565 f = &geometry->outline.arc_faces[geometry->outline.arc_face_count];
2567 d2d_point_subtract(&r0, p1, p0);
2568 d2d_point_subtract(&r1, p2, p1);
2570 d2d_point_normalise(&r0);
2571 d2d_point_normalise(&r1);
2573 if (d2d_point_ccw(p0, p1, p2) > 0.0f)
2575 d2d_point_scale(&r0, -1.0f);
2576 d2d_point_scale(&r1, -1.0f);
2579 d2d_curve_outline_vertex_set(&a[0], p0, p0, p1, p2, r0.x, r0.y, r0.x, r0.y);
2580 d2d_curve_outline_vertex_set(&a[1], p0, p0, p1, p2, -r0.x, -r0.y, -r0.x, -r0.y);
2581 d2d_curve_outline_vertex_set(&a[2], p1, p0, p1, p2, r0.x, r0.y, r1.x, r1.y);
2582 d2d_curve_outline_vertex_set(&a[3], p2, p0, p1, p2, -r1.x, -r1.y, -r1.x, -r1.y);
2583 d2d_curve_outline_vertex_set(&a[4], p2, p0, p1, p2, r1.x, r1.y, r1.x, r1.y);
2584 geometry->outline.arc_count += 5;
2586 d2d_face_set(&f[0], base_idx + 0, base_idx + 1, base_idx + 2);
2587 d2d_face_set(&f[1], base_idx + 2, base_idx + 1, base_idx + 3);
2588 d2d_face_set(&f[2], base_idx + 2, base_idx + 4, base_idx + 3);
2589 geometry->outline.arc_face_count += 3;
2591 return TRUE;
2594 static BOOL d2d_geometry_add_figure_outline(struct d2d_geometry *geometry,
2595 struct d2d_figure *figure, D2D1_FIGURE_END figure_end)
2597 const D2D1_POINT_2F *prev, *p0, *p1, *next, *next_prev;
2598 size_t bezier_idx, i, vertex_count;
2599 enum d2d_vertex_type type;
2601 if (!(vertex_count = figure->vertex_count))
2602 return TRUE;
2604 p0 = &figure->vertices[0];
2605 if (figure_end == D2D1_FIGURE_END_CLOSED)
2607 if (figure->vertex_types[vertex_count - 1] == D2D_VERTEX_TYPE_END && !--vertex_count)
2608 return TRUE;
2610 /* In case of a CLOSED path, a join between first and last vertex is
2611 * required. */
2612 if (d2d_vertex_type_is_bezier(figure->vertex_types[vertex_count - 1]))
2613 prev = &figure->bezier_controls[figure->bezier_control_count - 1];
2614 else
2615 prev = &figure->vertices[vertex_count - 1];
2617 else
2619 if (!--vertex_count)
2620 return TRUE;
2621 prev = p0;
2624 for (i = 0, bezier_idx = 0; i < vertex_count; ++i)
2626 if ((type = figure->vertex_types[i]) == D2D_VERTEX_TYPE_NONE)
2628 prev = next_prev = &figure->vertices[i];
2629 continue;
2632 /* next: tangent along next segment, at p0.
2633 * p1: next vertex. */
2634 if (d2d_vertex_type_is_bezier(type))
2636 next_prev = next = &figure->bezier_controls[bezier_idx++];
2637 /* type BEZIER implies i + 1 < figure->vertex_count. */
2638 p1 = &figure->vertices[i + 1];
2640 if (!d2d_geometry_outline_add_bezier_segment(geometry, p0, next, p1))
2642 ERR("Failed to add bezier segment.\n");
2643 return FALSE;
2646 else
2648 if (i + 1 == figure->vertex_count)
2649 next = p1 = &figure->vertices[0];
2650 else
2651 next = p1 = &figure->vertices[i + 1];
2652 next_prev = p0;
2654 if (!d2d_geometry_outline_add_line_segment(geometry, p0, p1))
2656 ERR("Failed to add line segment.\n");
2657 return FALSE;
2661 if (i || figure_end == D2D1_FIGURE_END_CLOSED)
2663 D2D1_POINT_2F q_next, q_prev;
2665 d2d_point_subtract(&q_prev, prev, p0);
2666 d2d_point_subtract(&q_next, next, p0);
2668 d2d_point_normalise(&q_prev);
2669 d2d_point_normalise(&q_next);
2671 if (!d2d_geometry_outline_add_join(geometry, &q_prev, p0, &q_next))
2673 ERR("Failed to add join.\n");
2674 return FALSE;
2678 p0 = p1;
2679 prev = next_prev;
2682 return TRUE;
2685 static BOOL d2d_geometry_fill_add_arc_triangle(struct d2d_geometry *geometry,
2686 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2)
2688 struct d2d_curve_vertex *a;
2690 if (!d2d_array_reserve((void **)&geometry->fill.arc_vertices, &geometry->fill.arc_vertices_size,
2691 geometry->fill.arc_vertex_count + 3, sizeof(*geometry->fill.arc_vertices)))
2692 return FALSE;
2694 a = &geometry->fill.arc_vertices[geometry->fill.arc_vertex_count];
2695 d2d_curve_vertex_set(&a[0], p0, 0.0f, 1.0f, -1.0f);
2696 d2d_curve_vertex_set(&a[1], p1, 1.0f, 1.0f, -1.0f);
2697 d2d_curve_vertex_set(&a[2], p2, 1.0f, 0.0f, -1.0f);
2698 geometry->fill.arc_vertex_count += 3;
2700 return TRUE;
2703 static void d2d_geometry_cleanup(struct d2d_geometry *geometry)
2705 heap_free(geometry->outline.arc_faces);
2706 heap_free(geometry->outline.arcs);
2707 heap_free(geometry->outline.bezier_faces);
2708 heap_free(geometry->outline.beziers);
2709 heap_free(geometry->outline.faces);
2710 heap_free(geometry->outline.vertices);
2711 heap_free(geometry->fill.arc_vertices);
2712 heap_free(geometry->fill.bezier_vertices);
2713 heap_free(geometry->fill.faces);
2714 heap_free(geometry->fill.vertices);
2715 ID2D1Factory_Release(geometry->factory);
2718 static void d2d_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
2719 const D2D1_MATRIX_3X2_F *transform, const struct ID2D1GeometryVtbl *vtbl)
2721 geometry->ID2D1Geometry_iface.lpVtbl = vtbl;
2722 geometry->refcount = 1;
2723 ID2D1Factory_AddRef(geometry->factory = factory);
2724 geometry->transform = *transform;
2727 static inline struct d2d_geometry *impl_from_ID2D1GeometrySink(ID2D1GeometrySink *iface)
2729 return CONTAINING_RECORD(iface, struct d2d_geometry, u.path.ID2D1GeometrySink_iface);
2732 static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_QueryInterface(ID2D1GeometrySink *iface, REFIID iid, void **out)
2734 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
2736 if (IsEqualGUID(iid, &IID_ID2D1GeometrySink)
2737 || IsEqualGUID(iid, &IID_ID2D1SimplifiedGeometrySink)
2738 || IsEqualGUID(iid, &IID_IUnknown))
2740 ID2D1GeometrySink_AddRef(iface);
2741 *out = iface;
2742 return S_OK;
2745 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
2747 *out = NULL;
2748 return E_NOINTERFACE;
2751 static ULONG STDMETHODCALLTYPE d2d_geometry_sink_AddRef(ID2D1GeometrySink *iface)
2753 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2755 TRACE("iface %p.\n", iface);
2757 return ID2D1Geometry_AddRef(&geometry->ID2D1Geometry_iface);
2760 static ULONG STDMETHODCALLTYPE d2d_geometry_sink_Release(ID2D1GeometrySink *iface)
2762 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2764 TRACE("iface %p.\n", iface);
2766 return ID2D1Geometry_Release(&geometry->ID2D1Geometry_iface);
2769 static void STDMETHODCALLTYPE d2d_geometry_sink_SetFillMode(ID2D1GeometrySink *iface, D2D1_FILL_MODE mode)
2771 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2773 TRACE("iface %p, mode %#x.\n", iface, mode);
2775 if (geometry->u.path.state == D2D_GEOMETRY_STATE_CLOSED)
2776 return;
2777 geometry->u.path.fill_mode = mode;
2780 static void STDMETHODCALLTYPE d2d_geometry_sink_SetSegmentFlags(ID2D1GeometrySink *iface, D2D1_PATH_SEGMENT flags)
2782 TRACE("iface %p, flags %#x.\n", iface, flags);
2784 if (flags != D2D1_PATH_SEGMENT_NONE)
2785 FIXME("Ignoring flags %#x.\n", flags);
2788 static void STDMETHODCALLTYPE d2d_geometry_sink_BeginFigure(ID2D1GeometrySink *iface,
2789 D2D1_POINT_2F start_point, D2D1_FIGURE_BEGIN figure_begin)
2791 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2792 struct d2d_figure *figure;
2794 TRACE("iface %p, start_point %s, figure_begin %#x.\n",
2795 iface, debug_d2d_point_2f(&start_point), figure_begin);
2797 if (geometry->u.path.state != D2D_GEOMETRY_STATE_OPEN)
2799 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2800 return;
2803 if (!d2d_path_geometry_add_figure(geometry))
2805 ERR("Failed to add figure.\n");
2806 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2807 return;
2810 figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2811 if (figure_begin == D2D1_FIGURE_BEGIN_HOLLOW)
2812 figure->flags |= D2D_FIGURE_FLAG_HOLLOW;
2814 if (!d2d_figure_add_vertex(figure, start_point))
2816 ERR("Failed to add vertex.\n");
2817 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2818 return;
2821 geometry->u.path.state = D2D_GEOMETRY_STATE_FIGURE;
2824 static void STDMETHODCALLTYPE d2d_geometry_sink_AddLines(ID2D1GeometrySink *iface,
2825 const D2D1_POINT_2F *points, UINT32 count)
2827 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2828 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2829 unsigned int i;
2831 TRACE("iface %p, points %p, count %u.\n", iface, points, count);
2833 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2835 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2836 return;
2839 for (i = 0; i < count; ++i)
2841 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_LINE;
2842 if (!d2d_figure_add_vertex(figure, points[i]))
2844 ERR("Failed to add vertex.\n");
2845 return;
2849 geometry->u.path.segment_count += count;
2852 static void STDMETHODCALLTYPE d2d_geometry_sink_AddBeziers(ID2D1GeometrySink *iface,
2853 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
2855 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2856 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2857 D2D1_POINT_2F p;
2858 unsigned int i;
2860 TRACE("iface %p, beziers %p, count %u.\n", iface, beziers, count);
2862 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2864 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2865 return;
2868 for (i = 0; i < count; ++i)
2870 D2D1_RECT_F bezier_bounds;
2872 if (!d2d_figure_add_original_bezier_controls(figure, 1, &beziers[i].point1)
2873 || !d2d_figure_add_original_bezier_controls(figure, 1, &beziers[i].point2))
2875 ERR("Failed to add cubic Bézier controls.\n");
2876 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2877 return;
2880 /* FIXME: This tries to approximate a cubic Bézier with a quadratic one. */
2881 p.x = (beziers[i].point1.x + beziers[i].point2.x) * 0.75f;
2882 p.y = (beziers[i].point1.y + beziers[i].point2.y) * 0.75f;
2883 p.x -= (figure->vertices[figure->vertex_count - 1].x + beziers[i].point3.x) * 0.25f;
2884 p.y -= (figure->vertices[figure->vertex_count - 1].y + beziers[i].point3.y) * 0.25f;
2885 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_BEZIER;
2887 d2d_rect_get_bezier_bounds(&bezier_bounds, &figure->vertices[figure->vertex_count - 1],
2888 &p, &beziers[i].point3);
2890 if (!d2d_figure_add_bezier_controls(figure, 1, &p))
2892 ERR("Failed to add bezier control.\n");
2893 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2894 return;
2897 if (!d2d_figure_add_vertex(figure, beziers[i].point3))
2899 ERR("Failed to add bezier vertex.\n");
2900 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2901 return;
2904 d2d_rect_union(&figure->bounds, &bezier_bounds);
2907 geometry->u.path.segment_count += count;
2910 static void STDMETHODCALLTYPE d2d_geometry_sink_EndFigure(ID2D1GeometrySink *iface, D2D1_FIGURE_END figure_end)
2912 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2913 struct d2d_figure *figure;
2915 TRACE("iface %p, figure_end %#x.\n", iface, figure_end);
2917 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2919 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2920 return;
2923 figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2924 if (memcmp(&figure->vertices[0], &figure->vertices[figure->vertex_count - 1], sizeof(*figure->vertices)))
2925 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_LINE;
2926 else
2927 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_END;
2928 if (figure_end == D2D1_FIGURE_END_CLOSED)
2930 ++geometry->u.path.segment_count;
2931 figure->flags |= D2D_FIGURE_FLAG_CLOSED;
2934 if (!d2d_geometry_add_figure_outline(geometry, figure, figure_end))
2936 ERR("Failed to add figure outline.\n");
2937 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2938 return;
2941 geometry->u.path.state = D2D_GEOMETRY_STATE_OPEN;
2944 static void d2d_path_geometry_free_figures(struct d2d_geometry *geometry)
2946 size_t i;
2948 if (!geometry->u.path.figures)
2949 return;
2951 for (i = 0; i < geometry->u.path.figure_count; ++i)
2953 heap_free(geometry->u.path.figures[i].original_bezier_controls);
2954 heap_free(geometry->u.path.figures[i].bezier_controls);
2955 heap_free(geometry->u.path.figures[i].vertices);
2957 heap_free(geometry->u.path.figures);
2958 geometry->u.path.figures = NULL;
2959 geometry->u.path.figures_size = 0;
2962 static BOOL d2d_geometry_get_bezier_segment_idx(struct d2d_geometry *geometry, struct d2d_segment_idx *idx, BOOL next)
2964 if (next)
2966 ++idx->vertex_idx;
2967 ++idx->control_idx;
2970 for (; idx->figure_idx < geometry->u.path.figure_count; ++idx->figure_idx, idx->vertex_idx = idx->control_idx = 0)
2972 struct d2d_figure *figure = &geometry->u.path.figures[idx->figure_idx];
2974 if (!figure->bezier_control_count || figure->flags & D2D_FIGURE_FLAG_HOLLOW)
2975 continue;
2977 for (; idx->vertex_idx < figure->vertex_count; ++idx->vertex_idx)
2979 if (d2d_vertex_type_is_bezier(figure->vertex_types[idx->vertex_idx]))
2980 return TRUE;
2984 return FALSE;
2987 static BOOL d2d_geometry_get_first_bezier_segment_idx(struct d2d_geometry *geometry, struct d2d_segment_idx *idx)
2989 memset(idx, 0, sizeof(*idx));
2991 return d2d_geometry_get_bezier_segment_idx(geometry, idx, FALSE);
2994 static BOOL d2d_geometry_get_next_bezier_segment_idx(struct d2d_geometry *geometry, struct d2d_segment_idx *idx)
2996 return d2d_geometry_get_bezier_segment_idx(geometry, idx, TRUE);
2999 static BOOL d2d_geometry_check_bezier_overlap(struct d2d_geometry *geometry,
3000 const struct d2d_segment_idx *idx_p, const struct d2d_segment_idx *idx_q)
3002 const D2D1_POINT_2F *a[3], *b[3], *p[2], *q;
3003 const struct d2d_figure *figure;
3004 D2D1_POINT_2F v_q[3], v_p, v_qp;
3005 unsigned int i, j, score;
3006 float det, t;
3008 figure = &geometry->u.path.figures[idx_p->figure_idx];
3009 a[0] = &figure->vertices[idx_p->vertex_idx];
3010 a[1] = &figure->bezier_controls[idx_p->control_idx];
3011 a[2] = &figure->vertices[idx_p->vertex_idx + 1];
3013 figure = &geometry->u.path.figures[idx_q->figure_idx];
3014 b[0] = &figure->vertices[idx_q->vertex_idx];
3015 b[1] = &figure->bezier_controls[idx_q->control_idx];
3016 b[2] = &figure->vertices[idx_q->vertex_idx + 1];
3018 if (d2d_point_ccw(a[0], a[1], a[2]) == 0.0f || d2d_point_ccw(b[0], b[1], b[2]) == 0.0f)
3019 return FALSE;
3021 d2d_point_subtract(&v_q[0], b[1], b[0]);
3022 d2d_point_subtract(&v_q[1], b[2], b[0]);
3023 d2d_point_subtract(&v_q[2], b[1], b[2]);
3025 /* Check for intersections between the edges. Strictly speaking we'd only
3026 * need to check 8 of the 9 possible intersections, since if there's any
3027 * intersection there has to be a second intersection as well. */
3028 for (i = 0; i < 3; ++i)
3030 d2d_point_subtract(&v_p, a[(i & 1) + 1], a[i & 2]);
3031 for (j = 0; j < 3; ++j)
3033 det = v_p.x * v_q[j].y - v_p.y * v_q[j].x;
3034 if (det == 0.0f)
3035 continue;
3037 d2d_point_subtract(&v_qp, a[i & 2], b[j & 2]);
3038 t = (v_q[j].x * v_qp.y - v_q[j].y * v_qp.x) / det;
3039 if (t <= 0.0f || t >= 1.0f)
3040 continue;
3042 t = (v_p.x * v_qp.y - v_p.y * v_qp.x) / det;
3043 if (t <= 0.0f || t >= 1.0f)
3044 continue;
3046 return TRUE;
3050 /* Check if one triangle is contained within the other. */
3051 for (j = 0, score = 0, q = a[1], p[0] = b[2]; j < 3; ++j)
3053 p[1] = b[j];
3054 d2d_point_subtract(&v_p, p[1], p[0]);
3055 d2d_point_subtract(&v_qp, q, p[0]);
3057 if ((q->y < p[0]->y) != (q->y < p[1]->y) && v_qp.x < v_p.x * (v_qp.y / v_p.y))
3058 ++score;
3060 p[0] = p[1];
3063 if (score & 1)
3064 return TRUE;
3066 for (j = 0, score = 0, q = b[1], p[0] = a[2]; j < 3; ++j)
3068 p[1] = a[j];
3069 d2d_point_subtract(&v_p, p[1], p[0]);
3070 d2d_point_subtract(&v_qp, q, p[0]);
3072 if ((q->y < p[0]->y) != (q->y < p[1]->y) && v_qp.x < v_p.x * (v_qp.y / v_p.y))
3073 ++score;
3075 p[0] = p[1];
3078 return score & 1;
3081 static float d2d_geometry_bezier_ccw(struct d2d_geometry *geometry, const struct d2d_segment_idx *idx)
3083 const struct d2d_figure *figure = &geometry->u.path.figures[idx->figure_idx];
3084 size_t next = idx->vertex_idx + 1;
3086 return d2d_point_ccw(&figure->vertices[idx->vertex_idx],
3087 &figure->bezier_controls[idx->control_idx], &figure->vertices[next]);
3090 static BOOL d2d_geometry_split_bezier(struct d2d_geometry *geometry, const struct d2d_segment_idx *idx)
3092 const D2D1_POINT_2F *p[3];
3093 struct d2d_figure *figure;
3094 D2D1_POINT_2F q[3];
3095 size_t next;
3097 figure = &geometry->u.path.figures[idx->figure_idx];
3098 p[0] = &figure->vertices[idx->vertex_idx];
3099 p[1] = &figure->bezier_controls[idx->control_idx];
3100 next = idx->vertex_idx + 1;
3101 p[2] = &figure->vertices[next];
3103 d2d_point_lerp(&q[0], p[0], p[1], 0.5f);
3104 d2d_point_lerp(&q[1], p[1], p[2], 0.5f);
3105 d2d_point_lerp(&q[2], &q[0], &q[1], 0.5f);
3107 figure->bezier_controls[idx->control_idx] = q[0];
3108 if (!(d2d_figure_insert_bezier_controls(figure, idx->control_idx + 1, 1, &q[1])))
3109 return FALSE;
3110 if (!(d2d_figure_insert_vertex(figure, idx->vertex_idx + 1, q[2])))
3111 return FALSE;
3112 figure->vertex_types[idx->vertex_idx + 1] = D2D_VERTEX_TYPE_SPLIT_BEZIER;
3114 return TRUE;
3117 static HRESULT d2d_geometry_resolve_beziers(struct d2d_geometry *geometry)
3119 struct d2d_segment_idx idx_p, idx_q;
3120 struct d2d_curve_vertex *b;
3121 const D2D1_POINT_2F *p[3];
3122 struct d2d_figure *figure;
3123 size_t bezier_idx, i;
3125 if (!d2d_geometry_get_first_bezier_segment_idx(geometry, &idx_p))
3126 return S_OK;
3128 /* Split overlapping bezier control triangles. */
3129 while (d2d_geometry_get_next_bezier_segment_idx(geometry, &idx_p))
3131 d2d_geometry_get_first_bezier_segment_idx(geometry, &idx_q);
3132 while (idx_q.figure_idx < idx_p.figure_idx || idx_q.vertex_idx < idx_p.vertex_idx)
3134 while (d2d_geometry_check_bezier_overlap(geometry, &idx_p, &idx_q))
3136 if (fabsf(d2d_geometry_bezier_ccw(geometry, &idx_q)) > fabsf(d2d_geometry_bezier_ccw(geometry, &idx_p)))
3138 if (!d2d_geometry_split_bezier(geometry, &idx_q))
3139 return E_OUTOFMEMORY;
3140 if (idx_p.figure_idx == idx_q.figure_idx)
3142 ++idx_p.vertex_idx;
3143 ++idx_p.control_idx;
3146 else
3148 if (!d2d_geometry_split_bezier(geometry, &idx_p))
3149 return E_OUTOFMEMORY;
3152 d2d_geometry_get_next_bezier_segment_idx(geometry, &idx_q);
3156 for (i = 0; i < geometry->u.path.figure_count; ++i)
3158 if (geometry->u.path.figures[i].flags & D2D_FIGURE_FLAG_HOLLOW)
3159 continue;
3160 geometry->fill.bezier_vertex_count += 3 * geometry->u.path.figures[i].bezier_control_count;
3163 if (!(geometry->fill.bezier_vertices = heap_calloc(geometry->fill.bezier_vertex_count,
3164 sizeof(*geometry->fill.bezier_vertices))))
3166 ERR("Failed to allocate bezier vertices array.\n");
3167 geometry->fill.bezier_vertex_count = 0;
3168 return E_OUTOFMEMORY;
3171 bezier_idx = 0;
3172 d2d_geometry_get_first_bezier_segment_idx(geometry, &idx_p);
3173 for (;;)
3175 float sign = -1.0f;
3177 figure = &geometry->u.path.figures[idx_p.figure_idx];
3178 p[0] = &figure->vertices[idx_p.vertex_idx];
3179 p[1] = &figure->bezier_controls[idx_p.control_idx];
3181 i = idx_p.vertex_idx + 1;
3182 if (d2d_path_geometry_point_inside(geometry, p[1], FALSE))
3184 sign = 1.0f;
3185 d2d_figure_insert_vertex(figure, i, *p[1]);
3186 /* Inserting a vertex potentially invalidates p[0]. */
3187 p[0] = &figure->vertices[idx_p.vertex_idx];
3188 ++i;
3191 if (i == figure->vertex_count)
3192 i = 0;
3193 p[2] = &figure->vertices[i];
3195 b = &geometry->fill.bezier_vertices[bezier_idx * 3];
3196 d2d_curve_vertex_set(&b[0], p[0], 0.0f, 0.0f, sign);
3197 d2d_curve_vertex_set(&b[1], p[1], 0.5f, 0.0f, sign);
3198 d2d_curve_vertex_set(&b[2], p[2], 1.0f, 1.0f, sign);
3200 if (!d2d_geometry_get_next_bezier_segment_idx(geometry, &idx_p))
3201 break;
3202 ++bezier_idx;
3205 return S_OK;
3208 static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_Close(ID2D1GeometrySink *iface)
3210 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
3211 HRESULT hr = E_FAIL;
3213 TRACE("iface %p.\n", iface);
3215 if (geometry->u.path.state != D2D_GEOMETRY_STATE_OPEN)
3217 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
3218 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3219 return D2DERR_WRONG_STATE;
3221 geometry->u.path.state = D2D_GEOMETRY_STATE_CLOSED;
3223 if (!d2d_geometry_intersect_self(geometry))
3224 goto done;
3225 if (FAILED(hr = d2d_geometry_resolve_beziers(geometry)))
3226 goto done;
3227 if (FAILED(hr = d2d_path_geometry_triangulate(geometry)))
3228 goto done;
3230 done:
3231 if (FAILED(hr))
3233 heap_free(geometry->fill.bezier_vertices);
3234 geometry->fill.bezier_vertex_count = 0;
3235 d2d_path_geometry_free_figures(geometry);
3236 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3238 return hr;
3241 static void STDMETHODCALLTYPE d2d_geometry_sink_AddLine(ID2D1GeometrySink *iface, D2D1_POINT_2F point)
3243 TRACE("iface %p, point %s.\n", iface, debug_d2d_point_2f(&point));
3245 d2d_geometry_sink_AddLines(iface, &point, 1);
3248 static void STDMETHODCALLTYPE d2d_geometry_sink_AddBezier(ID2D1GeometrySink *iface, const D2D1_BEZIER_SEGMENT *bezier)
3250 TRACE("iface %p, bezier %p.\n", iface, bezier);
3252 d2d_geometry_sink_AddBeziers(iface, bezier, 1);
3255 static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBezier(ID2D1GeometrySink *iface,
3256 const D2D1_QUADRATIC_BEZIER_SEGMENT *bezier)
3258 TRACE("iface %p, bezier %p.\n", iface, bezier);
3260 ID2D1GeometrySink_AddQuadraticBeziers(iface, bezier, 1);
3263 static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBeziers(ID2D1GeometrySink *iface,
3264 const D2D1_QUADRATIC_BEZIER_SEGMENT *beziers, UINT32 bezier_count)
3266 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
3267 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
3268 unsigned int i;
3270 TRACE("iface %p, beziers %p, bezier_count %u.\n", iface, beziers, bezier_count);
3272 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
3274 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3275 return;
3278 for (i = 0; i < bezier_count; ++i)
3280 D2D1_RECT_F bezier_bounds;
3281 D2D1_POINT_2F p[2];
3283 /* Construct a cubic curve. */
3284 d2d_point_lerp(&p[0], &figure->vertices[figure->vertex_count - 1], &beziers[i].point1, 2.0f / 3.0f);
3285 d2d_point_lerp(&p[1], &beziers[i].point2, &beziers[i].point1, 2.0f / 3.0f);
3286 if (!d2d_figure_add_original_bezier_controls(figure, 2, p))
3288 ERR("Failed to add cubic Bézier controls.\n");
3289 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3290 return;
3293 d2d_rect_get_bezier_bounds(&bezier_bounds, &figure->vertices[figure->vertex_count - 1],
3294 &beziers[i].point1, &beziers[i].point2);
3296 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_BEZIER;
3297 if (!d2d_figure_add_bezier_controls(figure, 1, &beziers[i].point1))
3299 ERR("Failed to add bezier.\n");
3300 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3301 return;
3304 if (!d2d_figure_add_vertex(figure, beziers[i].point2))
3306 ERR("Failed to add bezier vertex.\n");
3307 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3308 return;
3311 d2d_rect_union(&figure->bounds, &bezier_bounds);
3314 geometry->u.path.segment_count += bezier_count;
3317 static void STDMETHODCALLTYPE d2d_geometry_sink_AddArc(ID2D1GeometrySink *iface, const D2D1_ARC_SEGMENT *arc)
3319 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
3321 FIXME("iface %p, arc %p stub!\n", iface, arc);
3323 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
3325 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3326 return;
3329 if (!d2d_figure_add_vertex(&geometry->u.path.figures[geometry->u.path.figure_count - 1], arc->point))
3331 ERR("Failed to add vertex.\n");
3332 return;
3335 ++geometry->u.path.segment_count;
3338 static const struct ID2D1GeometrySinkVtbl d2d_geometry_sink_vtbl =
3340 d2d_geometry_sink_QueryInterface,
3341 d2d_geometry_sink_AddRef,
3342 d2d_geometry_sink_Release,
3343 d2d_geometry_sink_SetFillMode,
3344 d2d_geometry_sink_SetSegmentFlags,
3345 d2d_geometry_sink_BeginFigure,
3346 d2d_geometry_sink_AddLines,
3347 d2d_geometry_sink_AddBeziers,
3348 d2d_geometry_sink_EndFigure,
3349 d2d_geometry_sink_Close,
3350 d2d_geometry_sink_AddLine,
3351 d2d_geometry_sink_AddBezier,
3352 d2d_geometry_sink_AddQuadraticBezier,
3353 d2d_geometry_sink_AddQuadraticBeziers,
3354 d2d_geometry_sink_AddArc,
3357 static inline struct d2d_geometry *impl_from_ID2D1PathGeometry(ID2D1PathGeometry *iface)
3359 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
3362 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_QueryInterface(ID2D1PathGeometry *iface, REFIID iid, void **out)
3364 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
3366 if (IsEqualGUID(iid, &IID_ID2D1PathGeometry)
3367 || IsEqualGUID(iid, &IID_ID2D1Geometry)
3368 || IsEqualGUID(iid, &IID_ID2D1Resource)
3369 || IsEqualGUID(iid, &IID_IUnknown))
3371 ID2D1PathGeometry_AddRef(iface);
3372 *out = iface;
3373 return S_OK;
3376 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
3378 *out = NULL;
3379 return E_NOINTERFACE;
3382 static ULONG STDMETHODCALLTYPE d2d_path_geometry_AddRef(ID2D1PathGeometry *iface)
3384 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3385 ULONG refcount = InterlockedIncrement(&geometry->refcount);
3387 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
3389 return refcount;
3392 static ULONG STDMETHODCALLTYPE d2d_path_geometry_Release(ID2D1PathGeometry *iface)
3394 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3395 ULONG refcount = InterlockedDecrement(&geometry->refcount);
3397 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
3399 if (!refcount)
3401 d2d_path_geometry_free_figures(geometry);
3402 d2d_geometry_cleanup(geometry);
3403 heap_free(geometry);
3406 return refcount;
3409 static void STDMETHODCALLTYPE d2d_path_geometry_GetFactory(ID2D1PathGeometry *iface, ID2D1Factory **factory)
3411 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3413 TRACE("iface %p, factory %p.\n", iface, factory);
3415 ID2D1Factory_AddRef(*factory = geometry->factory);
3418 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetBounds(ID2D1PathGeometry *iface,
3419 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
3421 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3422 size_t i;
3424 TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
3426 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
3427 return D2DERR_WRONG_STATE;
3429 bounds->left = FLT_MAX;
3430 bounds->top = FLT_MAX;
3431 bounds->right = -FLT_MAX;
3432 bounds->bottom = -FLT_MAX;
3434 if (!transform)
3436 if (geometry->u.path.bounds.left > geometry->u.path.bounds.right
3437 && !isinf(geometry->u.path.bounds.left))
3439 for (i = 0; i < geometry->u.path.figure_count; ++i)
3441 if (geometry->u.path.figures[i].flags & D2D_FIGURE_FLAG_HOLLOW)
3442 continue;
3443 d2d_rect_union(&geometry->u.path.bounds, &geometry->u.path.figures[i].bounds);
3445 if (geometry->u.path.bounds.left > geometry->u.path.bounds.right)
3447 geometry->u.path.bounds.left = INFINITY;
3448 geometry->u.path.bounds.right = FLT_MAX;
3449 geometry->u.path.bounds.top = INFINITY;
3450 geometry->u.path.bounds.bottom = FLT_MAX;
3454 *bounds = geometry->u.path.bounds;
3455 return S_OK;
3458 for (i = 0; i < geometry->u.path.figure_count; ++i)
3460 const struct d2d_figure *figure = &geometry->u.path.figures[i];
3461 enum d2d_vertex_type type = D2D_VERTEX_TYPE_NONE;
3462 D2D1_RECT_F bezier_bounds;
3463 D2D1_POINT_2F p, p1, p2;
3464 size_t j, bezier_idx;
3466 if (figure->flags & D2D_FIGURE_FLAG_HOLLOW)
3467 continue;
3469 for (j = 0; j < figure->vertex_count; ++j)
3471 if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
3472 continue;
3474 p = figure->vertices[j];
3475 type = figure->vertex_types[j];
3476 d2d_point_transform(&p, transform, p.x, p.y);
3477 d2d_rect_expand(bounds, &p);
3478 break;
3481 for (bezier_idx = 0, ++j; j < figure->vertex_count; ++j)
3483 enum d2d_vertex_type next_type;
3485 if ((next_type = figure->vertex_types[j]) == D2D_VERTEX_TYPE_NONE
3486 || d2d_vertex_type_is_split_bezier(next_type))
3487 continue;
3489 switch (type)
3491 case D2D_VERTEX_TYPE_LINE:
3492 p = figure->vertices[j];
3493 d2d_point_transform(&p, transform, p.x, p.y);
3494 d2d_rect_expand(bounds, &p);
3495 break;
3497 case D2D_VERTEX_TYPE_BEZIER:
3498 /* FIXME: This attempts to approximate a cubic Bézier with
3499 * a quadratic one. */
3500 p1 = figure->original_bezier_controls[bezier_idx++];
3501 d2d_point_transform(&p1, transform, p1.x, p1.y);
3502 p2 = figure->original_bezier_controls[bezier_idx++];
3503 d2d_point_transform(&p2, transform, p2.x, p2.y);
3504 p1.x = (p1.x + p2.x) * 0.75f;
3505 p1.y = (p1.y + p2.y) * 0.75f;
3506 p2 = figure->vertices[j];
3507 d2d_point_transform(&p2, transform, p2.x, p2.y);
3508 p1.x -= (p.x + p2.x) * 0.25f;
3509 p1.y -= (p.y + p2.y) * 0.25f;
3511 d2d_rect_get_bezier_bounds(&bezier_bounds, &p, &p1, &p2);
3512 d2d_rect_union(bounds, &bezier_bounds);
3513 p = p2;
3514 break;
3516 default:
3517 FIXME("Unhandled vertex type %#x.\n", type);
3518 p = figure->vertices[j];
3519 d2d_point_transform(&p, transform, p.x, p.y);
3520 d2d_rect_expand(bounds, &p);
3521 break;
3524 type = next_type;
3528 if (bounds->left > bounds->right)
3530 bounds->left = INFINITY;
3531 bounds->right = FLT_MAX;
3532 bounds->top = INFINITY;
3533 bounds->bottom = FLT_MAX;
3536 return S_OK;
3539 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetWidenedBounds(ID2D1PathGeometry *iface, float stroke_width,
3540 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_RECT_F *bounds)
3542 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
3543 iface, stroke_width, stroke_style, transform, tolerance, bounds);
3545 return E_NOTIMPL;
3548 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_StrokeContainsPoint(ID2D1PathGeometry *iface,
3549 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
3550 float tolerance, BOOL *contains)
3552 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3553 enum d2d_vertex_type type = D2D_VERTEX_TYPE_NONE;
3554 unsigned int i, j, bezier_idx;
3555 D2D1_BEZIER_SEGMENT b;
3556 D2D1_POINT_2F p, p1;
3558 TRACE("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p.\n",
3559 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
3561 if (stroke_style)
3562 FIXME("Ignoring stroke style %p.\n", stroke_style);
3564 if (!transform)
3565 transform = &identity;
3567 if (tolerance <= 0.0f)
3568 tolerance = D2D1_DEFAULT_FLATTENING_TOLERANCE;
3570 *contains = FALSE;
3571 for (i = 0; i < geometry->u.path.figure_count; ++i)
3573 const struct d2d_figure *figure = &geometry->u.path.figures[i];
3575 for (j = 0; j < figure->vertex_count; ++j)
3577 if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
3578 continue;
3580 p = figure->vertices[j];
3581 type = figure->vertex_types[j];
3582 break;
3585 for (bezier_idx = 0, ++j; j < figure->vertex_count; ++j)
3587 enum d2d_vertex_type next_type;
3589 if ((next_type = figure->vertex_types[j]) == D2D_VERTEX_TYPE_NONE
3590 || d2d_vertex_type_is_split_bezier(next_type))
3591 continue;
3593 switch (type)
3595 case D2D_VERTEX_TYPE_LINE:
3596 p1 = figure->vertices[j];
3597 *contains = d2d_point_on_line_segment(&point, &p, &p1, transform, stroke_width * 0.5f, tolerance);
3598 p = p1;
3599 break;
3601 case D2D_VERTEX_TYPE_BEZIER:
3602 b.point1 = figure->original_bezier_controls[bezier_idx++];
3603 b.point2 = figure->original_bezier_controls[bezier_idx++];
3604 b.point3 = figure->vertices[j];
3605 *contains = d2d_point_on_bezier_segment(&point, &p, &b, transform, stroke_width, tolerance);
3606 p = b.point3;
3607 break;
3609 default:
3610 FIXME("Unhandled vertex type %#x.\n", type);
3611 p = figure->vertices[j];
3612 break;
3614 if (*contains)
3615 return S_OK;
3616 type = next_type;
3619 if (type == D2D_VERTEX_TYPE_LINE)
3621 p1 = figure->vertices[0];
3622 if (figure->flags & D2D_FIGURE_FLAG_CLOSED)
3623 *contains = d2d_point_on_line_segment(&point, &p, &p1, transform, stroke_width * 0.5f, tolerance);
3626 if (*contains)
3627 return S_OK;
3630 return S_OK;
3633 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_FillContainsPoint(ID2D1PathGeometry *iface,
3634 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
3636 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3637 D2D1_MATRIX_3X2_F g_i;
3639 TRACE("iface %p, point %s, transform %p, tolerance %.8e, contains %p.\n",
3640 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
3642 if (transform)
3644 if (!d2d_matrix_invert(&g_i, transform))
3645 return D2DERR_UNSUPPORTED_OPERATION;
3646 d2d_point_transform(&point, &g_i, point.x, point.y);
3649 *contains = !!d2d_path_geometry_point_inside(geometry, &point, FALSE);
3651 TRACE("-> %#x.\n", *contains);
3653 return S_OK;
3656 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_CompareWithGeometry(ID2D1PathGeometry *iface,
3657 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
3659 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
3660 iface, geometry, transform, tolerance, relation);
3662 return E_NOTIMPL;
3665 static void d2d_geometry_flatten_cubic(ID2D1SimplifiedGeometrySink *sink, const D2D1_POINT_2F *p0,
3666 const D2D1_BEZIER_SEGMENT *b, float tolerance)
3668 D2D1_BEZIER_SEGMENT b0, b1;
3669 D2D1_POINT_2F q;
3670 float d;
3672 /* It's certainly possible to calculate the maximum deviation of the
3673 * approximation from the curve, but it's a little involved. Instead, note
3674 * that if the control points were evenly spaced and collinear, p1 would
3675 * be exactly between p0 and p2, and p2 would be exactly between p1 and
3676 * p3. The deviation is a decent enough approximation, and much easier to
3677 * calculate.
3679 * p1' = (p0 + p2) / 2
3680 * p2' = (p1 + p3) / 2
3681 * d = ‖p1 - p1'‖₁ + ‖p2 - p2'‖₁ */
3682 d2d_point_lerp(&q, p0, &b->point2, 0.5f);
3683 d2d_point_subtract(&q, &b->point1, &q);
3684 d = fabsf(q.x) + fabsf(q.y);
3685 d2d_point_lerp(&q, &b->point1, &b->point3, 0.5f);
3686 d2d_point_subtract(&q, &b->point2, &q);
3687 d += fabsf(q.x) + fabsf(q.y);
3688 if (d < tolerance)
3690 ID2D1SimplifiedGeometrySink_AddLines(sink, &b->point3, 1);
3691 return;
3694 d2d_point_lerp(&q, &b->point1, &b->point2, 0.5f);
3696 b1.point3 = b->point3;
3697 d2d_point_lerp(&b1.point2, &b1.point3, &b->point2, 0.5f);
3698 d2d_point_lerp(&b1.point1, &b1.point2, &q, 0.5f);
3700 d2d_point_lerp(&b0.point1, p0, &b->point1, 0.5f);
3701 d2d_point_lerp(&b0.point2, &b0.point1, &q, 0.5f);
3702 d2d_point_lerp(&b0.point3, &b0.point2, &b1.point1, 0.5f);
3704 d2d_geometry_flatten_cubic(sink, p0, &b0, tolerance);
3705 ID2D1SimplifiedGeometrySink_SetSegmentFlags(sink, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN);
3706 d2d_geometry_flatten_cubic(sink, &b0.point3, &b1, tolerance);
3707 ID2D1SimplifiedGeometrySink_SetSegmentFlags(sink, D2D1_PATH_SEGMENT_NONE);
3710 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *iface,
3711 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
3712 ID2D1SimplifiedGeometrySink *sink)
3714 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3715 enum d2d_vertex_type type = D2D_VERTEX_TYPE_NONE;
3716 unsigned int i, j, bezier_idx;
3717 D2D1_FIGURE_BEGIN begin;
3718 D2D1_BEZIER_SEGMENT b;
3719 D2D1_FIGURE_END end;
3720 D2D1_POINT_2F p;
3722 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
3723 iface, option, transform, tolerance, sink);
3725 ID2D1SimplifiedGeometrySink_SetFillMode(sink, geometry->u.path.fill_mode);
3726 for (i = 0; i < geometry->u.path.figure_count; ++i)
3728 const struct d2d_figure *figure = &geometry->u.path.figures[i];
3730 for (j = 0; j < figure->vertex_count; ++j)
3732 if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
3733 continue;
3735 p = figure->vertices[j];
3736 if (transform)
3737 d2d_point_transform(&p, transform, p.x, p.y);
3738 begin = figure->flags & D2D_FIGURE_FLAG_HOLLOW ? D2D1_FIGURE_BEGIN_HOLLOW : D2D1_FIGURE_BEGIN_FILLED;
3739 ID2D1SimplifiedGeometrySink_BeginFigure(sink, p, begin);
3740 type = figure->vertex_types[j];
3741 break;
3744 for (bezier_idx = 0, ++j; j < figure->vertex_count; ++j)
3746 enum d2d_vertex_type next_type;
3748 if ((next_type = figure->vertex_types[j]) == D2D_VERTEX_TYPE_NONE
3749 || d2d_vertex_type_is_split_bezier(next_type))
3750 continue;
3752 switch (type)
3754 case D2D_VERTEX_TYPE_LINE:
3755 p = figure->vertices[j];
3756 if (transform)
3757 d2d_point_transform(&p, transform, p.x, p.y);
3758 ID2D1SimplifiedGeometrySink_AddLines(sink, &p, 1);
3759 break;
3761 case D2D_VERTEX_TYPE_BEZIER:
3762 b.point1 = figure->original_bezier_controls[bezier_idx++];
3763 b.point2 = figure->original_bezier_controls[bezier_idx++];
3764 b.point3 = figure->vertices[j];
3765 if (transform)
3767 d2d_point_transform(&b.point1, transform, b.point1.x, b.point1.y);
3768 d2d_point_transform(&b.point2, transform, b.point2.x, b.point2.y);
3769 d2d_point_transform(&b.point3, transform, b.point3.x, b.point3.y);
3772 if (option == D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES)
3773 d2d_geometry_flatten_cubic(sink, &p, &b, tolerance);
3774 else
3775 ID2D1SimplifiedGeometrySink_AddBeziers(sink, &b, 1);
3776 p = b.point3;
3777 break;
3779 default:
3780 FIXME("Unhandled vertex type %#x.\n", type);
3781 p = figure->vertices[j];
3782 if (transform)
3783 d2d_point_transform(&p, transform, p.x, p.y);
3784 ID2D1SimplifiedGeometrySink_AddLines(sink, &p, 1);
3785 break;
3788 type = next_type;
3791 end = figure->flags & D2D_FIGURE_FLAG_CLOSED ? D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN;
3792 ID2D1SimplifiedGeometrySink_EndFigure(sink, end);
3795 return S_OK;
3798 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Tessellate(ID2D1PathGeometry *iface,
3799 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
3801 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
3803 return E_NOTIMPL;
3806 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_CombineWithGeometry(ID2D1PathGeometry *iface,
3807 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
3808 float tolerance, ID2D1SimplifiedGeometrySink *sink)
3810 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
3811 iface, geometry, combine_mode, transform, tolerance, sink);
3813 return E_NOTIMPL;
3816 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Outline(ID2D1PathGeometry *iface,
3817 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
3819 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
3821 return E_NOTIMPL;
3824 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeArea(ID2D1PathGeometry *iface,
3825 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
3827 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
3829 return E_NOTIMPL;
3832 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeLength(ID2D1PathGeometry *iface,
3833 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
3835 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
3837 return E_NOTIMPL;
3840 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputePointAtLength(ID2D1PathGeometry *iface, float length,
3841 const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point, D2D1_POINT_2F *tangent)
3843 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
3844 iface, length, transform, tolerance, point, tangent);
3846 return E_NOTIMPL;
3849 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Widen(ID2D1PathGeometry *iface, float stroke_width,
3850 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
3851 ID2D1SimplifiedGeometrySink *sink)
3853 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
3854 iface, stroke_width, stroke_style, transform, tolerance, sink);
3856 return E_NOTIMPL;
3859 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Open(ID2D1PathGeometry *iface, ID2D1GeometrySink **sink)
3861 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3863 TRACE("iface %p, sink %p.\n", iface, sink);
3865 if (geometry->u.path.state != D2D_GEOMETRY_STATE_INITIAL)
3866 return D2DERR_WRONG_STATE;
3868 *sink = &geometry->u.path.ID2D1GeometrySink_iface;
3869 ID2D1GeometrySink_AddRef(*sink);
3871 geometry->u.path.state = D2D_GEOMETRY_STATE_OPEN;
3873 return S_OK;
3876 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Stream(ID2D1PathGeometry *iface, ID2D1GeometrySink *sink)
3878 FIXME("iface %p, sink %p stub!\n", iface, sink);
3880 return E_NOTIMPL;
3883 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetSegmentCount(ID2D1PathGeometry *iface, UINT32 *count)
3885 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3887 TRACE("iface %p, count %p.\n", iface, count);
3889 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
3890 return D2DERR_WRONG_STATE;
3892 *count = geometry->u.path.segment_count;
3894 return S_OK;
3897 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetFigureCount(ID2D1PathGeometry *iface, UINT32 *count)
3899 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
3901 TRACE("iface %p, count %p.\n", iface, count);
3903 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
3904 return D2DERR_WRONG_STATE;
3906 *count = geometry->u.path.figure_count;
3908 return S_OK;
3911 static const struct ID2D1PathGeometryVtbl d2d_path_geometry_vtbl =
3913 d2d_path_geometry_QueryInterface,
3914 d2d_path_geometry_AddRef,
3915 d2d_path_geometry_Release,
3916 d2d_path_geometry_GetFactory,
3917 d2d_path_geometry_GetBounds,
3918 d2d_path_geometry_GetWidenedBounds,
3919 d2d_path_geometry_StrokeContainsPoint,
3920 d2d_path_geometry_FillContainsPoint,
3921 d2d_path_geometry_CompareWithGeometry,
3922 d2d_path_geometry_Simplify,
3923 d2d_path_geometry_Tessellate,
3924 d2d_path_geometry_CombineWithGeometry,
3925 d2d_path_geometry_Outline,
3926 d2d_path_geometry_ComputeArea,
3927 d2d_path_geometry_ComputeLength,
3928 d2d_path_geometry_ComputePointAtLength,
3929 d2d_path_geometry_Widen,
3930 d2d_path_geometry_Open,
3931 d2d_path_geometry_Stream,
3932 d2d_path_geometry_GetSegmentCount,
3933 d2d_path_geometry_GetFigureCount,
3936 void d2d_path_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory)
3938 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl);
3939 geometry->u.path.ID2D1GeometrySink_iface.lpVtbl = &d2d_geometry_sink_vtbl;
3940 geometry->u.path.bounds.left = FLT_MAX;
3941 geometry->u.path.bounds.right = -FLT_MAX;
3942 geometry->u.path.bounds.top = FLT_MAX;
3943 geometry->u.path.bounds.bottom = -FLT_MAX;
3946 static inline struct d2d_geometry *impl_from_ID2D1EllipseGeometry(ID2D1EllipseGeometry *iface)
3948 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
3951 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_QueryInterface(ID2D1EllipseGeometry *iface,
3952 REFIID iid, void **out)
3954 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
3956 if (IsEqualGUID(iid, &IID_ID2D1EllipseGeometry)
3957 || IsEqualGUID(iid, &IID_ID2D1Geometry)
3958 || IsEqualGUID(iid, &IID_ID2D1Resource)
3959 || IsEqualGUID(iid, &IID_IUnknown))
3961 ID2D1EllipseGeometry_AddRef(iface);
3962 *out = iface;
3963 return S_OK;
3966 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
3968 *out = NULL;
3969 return E_NOINTERFACE;
3972 static ULONG STDMETHODCALLTYPE d2d_ellipse_geometry_AddRef(ID2D1EllipseGeometry *iface)
3974 struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface);
3975 ULONG refcount = InterlockedIncrement(&geometry->refcount);
3977 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
3979 return refcount;
3982 static ULONG STDMETHODCALLTYPE d2d_ellipse_geometry_Release(ID2D1EllipseGeometry *iface)
3984 struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface);
3985 ULONG refcount = InterlockedDecrement(&geometry->refcount);
3987 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
3989 if (!refcount)
3991 d2d_geometry_cleanup(geometry);
3992 heap_free(geometry);
3995 return refcount;
3998 static void STDMETHODCALLTYPE d2d_ellipse_geometry_GetFactory(ID2D1EllipseGeometry *iface, ID2D1Factory **factory)
4000 struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface);
4002 TRACE("iface %p, factory %p.\n", iface, factory);
4004 ID2D1Factory_AddRef(*factory = geometry->factory);
4007 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_GetBounds(ID2D1EllipseGeometry *iface,
4008 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
4010 FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
4012 return E_NOTIMPL;
4015 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_GetWidenedBounds(ID2D1EllipseGeometry *iface,
4016 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4017 float tolerance, D2D1_RECT_F *bounds)
4019 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
4020 iface, stroke_width, stroke_style, transform, tolerance, bounds);
4022 return E_NOTIMPL;
4025 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_StrokeContainsPoint(ID2D1EllipseGeometry *iface,
4026 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4027 float tolerance, BOOL *contains)
4029 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p stub!\n",
4030 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
4032 return E_NOTIMPL;
4035 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_FillContainsPoint(ID2D1EllipseGeometry *iface,
4036 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
4038 FIXME("iface %p, point %s, transform %p, tolerance %.8e, contains %p stub!\n",
4039 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
4041 return E_NOTIMPL;
4044 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_CompareWithGeometry(ID2D1EllipseGeometry *iface,
4045 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
4047 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
4048 iface, geometry, transform, tolerance, relation);
4050 return E_NOTIMPL;
4053 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Simplify(ID2D1EllipseGeometry *iface,
4054 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4055 ID2D1SimplifiedGeometrySink *sink)
4057 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4058 iface, option, transform, tolerance, sink);
4060 return E_NOTIMPL;
4063 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Tessellate(ID2D1EllipseGeometry *iface,
4064 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
4066 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4068 return E_NOTIMPL;
4071 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_CombineWithGeometry(ID2D1EllipseGeometry *iface,
4072 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
4073 float tolerance, ID2D1SimplifiedGeometrySink *sink)
4075 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4076 iface, geometry, combine_mode, transform, tolerance, sink);
4078 return E_NOTIMPL;
4081 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Outline(ID2D1EllipseGeometry *iface,
4082 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
4084 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4086 return E_NOTIMPL;
4089 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_ComputeArea(ID2D1EllipseGeometry *iface,
4090 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
4092 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
4094 return E_NOTIMPL;
4097 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_ComputeLength(ID2D1EllipseGeometry *iface,
4098 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
4100 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
4102 return E_NOTIMPL;
4105 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_ComputePointAtLength(ID2D1EllipseGeometry *iface,
4106 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
4107 D2D1_POINT_2F *tangent)
4109 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
4110 iface, length, transform, tolerance, point, tangent);
4112 return E_NOTIMPL;
4115 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Widen(ID2D1EllipseGeometry *iface, float stroke_width,
4116 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4117 ID2D1SimplifiedGeometrySink *sink)
4119 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
4120 iface, stroke_width, stroke_style, transform, tolerance, sink);
4122 return E_NOTIMPL;
4125 static void STDMETHODCALLTYPE d2d_ellipse_geometry_GetEllipse(ID2D1EllipseGeometry *iface, D2D1_ELLIPSE *ellipse)
4127 struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface);
4129 TRACE("iface %p, ellipse %p.\n", iface, ellipse);
4131 *ellipse = geometry->u.ellipse.ellipse;
4134 static const struct ID2D1EllipseGeometryVtbl d2d_ellipse_geometry_vtbl =
4136 d2d_ellipse_geometry_QueryInterface,
4137 d2d_ellipse_geometry_AddRef,
4138 d2d_ellipse_geometry_Release,
4139 d2d_ellipse_geometry_GetFactory,
4140 d2d_ellipse_geometry_GetBounds,
4141 d2d_ellipse_geometry_GetWidenedBounds,
4142 d2d_ellipse_geometry_StrokeContainsPoint,
4143 d2d_ellipse_geometry_FillContainsPoint,
4144 d2d_ellipse_geometry_CompareWithGeometry,
4145 d2d_ellipse_geometry_Simplify,
4146 d2d_ellipse_geometry_Tessellate,
4147 d2d_ellipse_geometry_CombineWithGeometry,
4148 d2d_ellipse_geometry_Outline,
4149 d2d_ellipse_geometry_ComputeArea,
4150 d2d_ellipse_geometry_ComputeLength,
4151 d2d_ellipse_geometry_ComputePointAtLength,
4152 d2d_ellipse_geometry_Widen,
4153 d2d_ellipse_geometry_GetEllipse,
4156 HRESULT d2d_ellipse_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_ELLIPSE *ellipse)
4158 D2D1_POINT_2F *v, v1, v2, v3, v4;
4159 struct d2d_face *f;
4160 float l, r, t, b;
4162 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_ellipse_geometry_vtbl);
4163 geometry->u.ellipse.ellipse = *ellipse;
4165 if (!(geometry->fill.vertices = heap_alloc(4 * sizeof(*geometry->fill.vertices))))
4166 goto fail;
4167 if (!d2d_array_reserve((void **)&geometry->fill.faces,
4168 &geometry->fill.faces_size, 2, sizeof(*geometry->fill.faces)))
4169 goto fail;
4171 l = ellipse->point.x - ellipse->radiusX;
4172 r = ellipse->point.x + ellipse->radiusX;
4173 t = ellipse->point.y - ellipse->radiusY;
4174 b = ellipse->point.y + ellipse->radiusY;
4176 d2d_point_set(&v1, r, t);
4177 d2d_point_set(&v2, r, b);
4178 d2d_point_set(&v3, l, b);
4179 d2d_point_set(&v4, l, t);
4181 v = geometry->fill.vertices;
4182 d2d_point_set(&v[0], ellipse->point.x, t);
4183 d2d_point_set(&v[1], r, ellipse->point.y);
4184 d2d_point_set(&v[2], ellipse->point.x, b);
4185 d2d_point_set(&v[3], l, ellipse->point.y);
4186 geometry->fill.vertex_count = 4;
4188 f = geometry->fill.faces;
4189 d2d_face_set(&f[0], 0, 3, 2);
4190 d2d_face_set(&f[1], 0, 2, 1);
4191 geometry->fill.face_count = 2;
4193 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[0], &v1, &v[1]))
4194 goto fail;
4195 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[1], &v2, &v[2]))
4196 goto fail;
4197 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[2], &v3, &v[3]))
4198 goto fail;
4199 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[3], &v4, &v[0]))
4200 goto fail;
4202 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[0], &v1, &v[1]))
4203 goto fail;
4204 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[1], &v2, &v[2]))
4205 goto fail;
4206 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[2], &v3, &v[3]))
4207 goto fail;
4208 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[3], &v4, &v[0]))
4209 goto fail;
4211 return S_OK;
4213 fail:
4214 d2d_geometry_cleanup(geometry);
4215 return E_OUTOFMEMORY;
4218 static inline struct d2d_geometry *impl_from_ID2D1RectangleGeometry(ID2D1RectangleGeometry *iface)
4220 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
4223 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_QueryInterface(ID2D1RectangleGeometry *iface,
4224 REFIID iid, void **out)
4226 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
4228 if (IsEqualGUID(iid, &IID_ID2D1RectangleGeometry)
4229 || IsEqualGUID(iid, &IID_ID2D1Geometry)
4230 || IsEqualGUID(iid, &IID_ID2D1Resource)
4231 || IsEqualGUID(iid, &IID_IUnknown))
4233 ID2D1RectangleGeometry_AddRef(iface);
4234 *out = iface;
4235 return S_OK;
4238 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
4240 *out = NULL;
4241 return E_NOINTERFACE;
4244 static ULONG STDMETHODCALLTYPE d2d_rectangle_geometry_AddRef(ID2D1RectangleGeometry *iface)
4246 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4247 ULONG refcount = InterlockedIncrement(&geometry->refcount);
4249 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
4251 return refcount;
4254 static ULONG STDMETHODCALLTYPE d2d_rectangle_geometry_Release(ID2D1RectangleGeometry *iface)
4256 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4257 ULONG refcount = InterlockedDecrement(&geometry->refcount);
4259 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
4261 if (!refcount)
4263 d2d_geometry_cleanup(geometry);
4264 heap_free(geometry);
4267 return refcount;
4270 static void STDMETHODCALLTYPE d2d_rectangle_geometry_GetFactory(ID2D1RectangleGeometry *iface, ID2D1Factory **factory)
4272 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4274 TRACE("iface %p, factory %p.\n", iface, factory);
4276 ID2D1Factory_AddRef(*factory = geometry->factory);
4279 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_GetBounds(ID2D1RectangleGeometry *iface,
4280 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
4282 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4283 D2D1_RECT_F *rect;
4284 D2D1_POINT_2F p;
4286 TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
4288 rect = &geometry->u.rectangle.rect;
4289 if (!transform)
4291 *bounds = *rect;
4292 return S_OK;
4295 bounds->left = FLT_MAX;
4296 bounds->top = FLT_MAX;
4297 bounds->right = -FLT_MAX;
4298 bounds->bottom = -FLT_MAX;
4300 d2d_point_transform(&p, transform, rect->left, rect->top);
4301 d2d_rect_expand(bounds, &p);
4302 d2d_point_transform(&p, transform, rect->left, rect->bottom);
4303 d2d_rect_expand(bounds, &p);
4304 d2d_point_transform(&p, transform, rect->right, rect->bottom);
4305 d2d_rect_expand(bounds, &p);
4306 d2d_point_transform(&p, transform, rect->right, rect->top);
4307 d2d_rect_expand(bounds, &p);
4309 return S_OK;
4312 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_GetWidenedBounds(ID2D1RectangleGeometry *iface,
4313 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4314 float tolerance, D2D1_RECT_F *bounds)
4316 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
4317 iface, stroke_width, stroke_style, transform, tolerance, bounds);
4319 return E_NOTIMPL;
4322 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_StrokeContainsPoint(ID2D1RectangleGeometry *iface,
4323 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4324 float tolerance, BOOL *contains)
4326 const struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4327 const D2D1_RECT_F *rect = &geometry->u.rectangle.rect;
4328 unsigned int i;
4329 struct
4331 D2D1_POINT_2F s, e;
4333 segments[4];
4335 TRACE("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p.\n",
4336 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
4338 if (stroke_style)
4339 FIXME("Ignoring stroke style %p.\n", stroke_style);
4341 tolerance = fabsf(tolerance);
4343 if (!transform)
4345 D2D1_POINT_2F d, s;
4347 s.x = rect->right - rect->left;
4348 s.y = rect->bottom - rect->top;
4349 d.x = fabsf((rect->right + rect->left) * 0.5f - point.x);
4350 d.y = fabsf((rect->bottom + rect->top) * 0.5f - point.y);
4352 /* Inside test. */
4353 if (d.x <= (s.x - stroke_width) * 0.5f - tolerance && d.y <= (s.y - stroke_width) * 0.5f - tolerance)
4355 *contains = FALSE;
4356 return S_OK;
4359 if (tolerance == 0.0f)
4361 *contains = d.x < (s.x + stroke_width) * 0.5f && d.y < (s.y + stroke_width) * 0.5f;
4363 else
4365 d.x = max(d.x - (s.x + stroke_width) * 0.5f, 0.0f);
4366 d.y = max(d.y - (s.y + stroke_width) * 0.5f, 0.0f);
4368 *contains = d2d_point_dot(&d, &d) < tolerance * tolerance;
4371 return S_OK;
4374 stroke_width *= 0.5f;
4376 d2d_point_set(&segments[0].s, rect->left - stroke_width, rect->bottom);
4377 d2d_point_set(&segments[0].e, rect->right + stroke_width, rect->bottom);
4378 d2d_point_set(&segments[1].s, rect->right, rect->bottom + stroke_width);
4379 d2d_point_set(&segments[1].e, rect->right, rect->top - stroke_width);
4380 d2d_point_set(&segments[2].s, rect->right + stroke_width, rect->top);
4381 d2d_point_set(&segments[2].e, rect->left - stroke_width, rect->top);
4382 d2d_point_set(&segments[3].s, rect->left, rect->top - stroke_width);
4383 d2d_point_set(&segments[3].e, rect->left, rect->bottom + stroke_width);
4385 *contains = FALSE;
4386 for (i = 0; i < ARRAY_SIZE(segments); ++i)
4388 if (d2d_point_on_line_segment(&point, &segments[i].s, &segments[i].e, transform, stroke_width, tolerance))
4390 *contains = TRUE;
4391 break;
4395 return S_OK;
4398 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_FillContainsPoint(ID2D1RectangleGeometry *iface,
4399 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
4401 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4402 D2D1_RECT_F *rect = &geometry->u.rectangle.rect;
4403 float dx, dy;
4405 TRACE("iface %p, point %s, transform %p, tolerance %.8e, contains %p.\n",
4406 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
4408 if (transform)
4410 D2D1_MATRIX_3X2_F g_i;
4412 if (!d2d_matrix_invert(&g_i, transform))
4413 return D2DERR_UNSUPPORTED_OPERATION;
4414 d2d_point_transform(&point, &g_i, point.x, point.y);
4417 if (tolerance == 0.0f)
4418 tolerance = D2D1_DEFAULT_FLATTENING_TOLERANCE;
4420 dx = max(fabsf((rect->right + rect->left) / 2.0f - point.x) - (rect->right - rect->left) / 2.0f, 0.0f);
4421 dy = max(fabsf((rect->bottom + rect->top) / 2.0f - point.y) - (rect->bottom - rect->top) / 2.0f, 0.0f);
4423 *contains = tolerance * tolerance > (dx * dx + dy * dy);
4424 return S_OK;
4427 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_CompareWithGeometry(ID2D1RectangleGeometry *iface,
4428 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
4430 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
4431 iface, geometry, transform, tolerance, relation);
4433 return E_NOTIMPL;
4436 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Simplify(ID2D1RectangleGeometry *iface,
4437 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4438 ID2D1SimplifiedGeometrySink *sink)
4440 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4441 D2D1_RECT_F *rect = &geometry->u.rectangle.rect;
4442 D2D1_POINT_2F p[4];
4443 unsigned int i;
4445 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
4446 iface, option, transform, tolerance, sink);
4448 d2d_point_set(&p[0], rect->left, rect->top);
4449 d2d_point_set(&p[1], rect->right, rect->top);
4450 d2d_point_set(&p[2], rect->right, rect->bottom);
4451 d2d_point_set(&p[3], rect->left, rect->bottom);
4453 if (transform)
4455 for (i = 0; i < ARRAY_SIZE(p); ++i)
4457 d2d_point_transform(&p[i], transform, p[i].x, p[i].y);
4461 ID2D1SimplifiedGeometrySink_SetFillMode(sink, D2D1_FILL_MODE_ALTERNATE);
4462 ID2D1SimplifiedGeometrySink_BeginFigure(sink, p[0], D2D1_FIGURE_BEGIN_FILLED);
4463 ID2D1SimplifiedGeometrySink_AddLines(sink, &p[1], 3);
4464 ID2D1SimplifiedGeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
4466 return S_OK;
4469 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Tessellate(ID2D1RectangleGeometry *iface,
4470 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
4472 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4474 return E_NOTIMPL;
4477 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_CombineWithGeometry(ID2D1RectangleGeometry *iface,
4478 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
4479 float tolerance, ID2D1SimplifiedGeometrySink *sink)
4481 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4482 iface, geometry, combine_mode, transform, tolerance, sink);
4484 return E_NOTIMPL;
4487 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Outline(ID2D1RectangleGeometry *iface,
4488 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
4490 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4492 return E_NOTIMPL;
4495 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputeArea(ID2D1RectangleGeometry *iface,
4496 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
4498 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
4500 return E_NOTIMPL;
4503 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputeLength(ID2D1RectangleGeometry *iface,
4504 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
4506 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
4508 return E_NOTIMPL;
4511 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputePointAtLength(ID2D1RectangleGeometry *iface,
4512 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
4513 D2D1_POINT_2F *tangent)
4515 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
4516 iface, length, transform, tolerance, point, tangent);
4518 return E_NOTIMPL;
4521 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Widen(ID2D1RectangleGeometry *iface, float stroke_width,
4522 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4523 ID2D1SimplifiedGeometrySink *sink)
4525 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
4526 iface, stroke_width, stroke_style, transform, tolerance, sink);
4528 return E_NOTIMPL;
4531 static void STDMETHODCALLTYPE d2d_rectangle_geometry_GetRect(ID2D1RectangleGeometry *iface, D2D1_RECT_F *rect)
4533 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4535 TRACE("iface %p, rect %p.\n", iface, rect);
4537 *rect = geometry->u.rectangle.rect;
4540 static const struct ID2D1RectangleGeometryVtbl d2d_rectangle_geometry_vtbl =
4542 d2d_rectangle_geometry_QueryInterface,
4543 d2d_rectangle_geometry_AddRef,
4544 d2d_rectangle_geometry_Release,
4545 d2d_rectangle_geometry_GetFactory,
4546 d2d_rectangle_geometry_GetBounds,
4547 d2d_rectangle_geometry_GetWidenedBounds,
4548 d2d_rectangle_geometry_StrokeContainsPoint,
4549 d2d_rectangle_geometry_FillContainsPoint,
4550 d2d_rectangle_geometry_CompareWithGeometry,
4551 d2d_rectangle_geometry_Simplify,
4552 d2d_rectangle_geometry_Tessellate,
4553 d2d_rectangle_geometry_CombineWithGeometry,
4554 d2d_rectangle_geometry_Outline,
4555 d2d_rectangle_geometry_ComputeArea,
4556 d2d_rectangle_geometry_ComputeLength,
4557 d2d_rectangle_geometry_ComputePointAtLength,
4558 d2d_rectangle_geometry_Widen,
4559 d2d_rectangle_geometry_GetRect,
4562 HRESULT d2d_rectangle_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_RECT_F *rect)
4564 struct d2d_face *f;
4565 D2D1_POINT_2F *v;
4566 float l, r, t, b;
4568 static const D2D1_POINT_2F prev[] =
4570 { 1.0f, 0.0f},
4571 { 0.0f, -1.0f},
4572 {-1.0f, 0.0f},
4573 { 0.0f, 1.0f},
4575 static const D2D1_POINT_2F next[] =
4577 { 0.0f, 1.0f},
4578 { 1.0f, 0.0f},
4579 { 0.0f, -1.0f},
4580 {-1.0f, 0.0f},
4583 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl);
4584 geometry->u.rectangle.rect = *rect;
4586 if (!(geometry->fill.vertices = heap_alloc(4 * sizeof(*geometry->fill.vertices))))
4587 goto fail;
4588 if (!d2d_array_reserve((void **)&geometry->fill.faces,
4589 &geometry->fill.faces_size, 2, sizeof(*geometry->fill.faces)))
4590 goto fail;
4592 l = min(rect->left, rect->right);
4593 r = max(rect->left, rect->right);
4594 t = min(rect->top, rect->bottom);
4595 b = max(rect->top, rect->bottom);
4597 v = geometry->fill.vertices;
4598 d2d_point_set(&v[0], l, t);
4599 d2d_point_set(&v[1], l, b);
4600 d2d_point_set(&v[2], r, b);
4601 d2d_point_set(&v[3], r, t);
4602 geometry->fill.vertex_count = 4;
4604 f = geometry->fill.faces;
4605 d2d_face_set(&f[0], 1, 2, 0);
4606 d2d_face_set(&f[1], 0, 2, 3);
4607 geometry->fill.face_count = 2;
4609 if (!d2d_geometry_outline_add_line_segment(geometry, &v[0], &v[1]))
4610 goto fail;
4611 if (!d2d_geometry_outline_add_line_segment(geometry, &v[1], &v[2]))
4612 goto fail;
4613 if (!d2d_geometry_outline_add_line_segment(geometry, &v[2], &v[3]))
4614 goto fail;
4615 if (!d2d_geometry_outline_add_line_segment(geometry, &v[3], &v[0]))
4616 goto fail;
4618 if (!d2d_geometry_outline_add_join(geometry, &prev[0], &v[0], &next[0]))
4619 goto fail;
4620 if (!d2d_geometry_outline_add_join(geometry, &prev[1], &v[1], &next[1]))
4621 goto fail;
4622 if (!d2d_geometry_outline_add_join(geometry, &prev[2], &v[2], &next[2]))
4623 goto fail;
4624 if (!d2d_geometry_outline_add_join(geometry, &prev[3], &v[3], &next[3]))
4625 goto fail;
4627 return S_OK;
4629 fail:
4630 d2d_geometry_cleanup(geometry);
4631 return E_OUTOFMEMORY;
4634 static inline struct d2d_geometry *impl_from_ID2D1RoundedRectangleGeometry(ID2D1RoundedRectangleGeometry *iface)
4636 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
4639 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_QueryInterface(ID2D1RoundedRectangleGeometry *iface,
4640 REFIID iid, void **out)
4642 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
4644 if (IsEqualGUID(iid, &IID_ID2D1RoundedRectangleGeometry)
4645 || IsEqualGUID(iid, &IID_ID2D1Geometry)
4646 || IsEqualGUID(iid, &IID_ID2D1Resource)
4647 || IsEqualGUID(iid, &IID_IUnknown))
4649 ID2D1RoundedRectangleGeometry_AddRef(iface);
4650 *out = iface;
4651 return S_OK;
4654 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
4656 *out = NULL;
4657 return E_NOINTERFACE;
4660 static ULONG STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_AddRef(ID2D1RoundedRectangleGeometry *iface)
4662 struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface);
4663 ULONG refcount = InterlockedIncrement(&geometry->refcount);
4665 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
4667 return refcount;
4670 static ULONG STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Release(ID2D1RoundedRectangleGeometry *iface)
4672 struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface);
4673 ULONG refcount = InterlockedDecrement(&geometry->refcount);
4675 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
4677 if (!refcount)
4679 d2d_geometry_cleanup(geometry);
4680 heap_free(geometry);
4683 return refcount;
4686 static void STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetFactory(ID2D1RoundedRectangleGeometry *iface,
4687 ID2D1Factory **factory)
4689 struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface);
4691 TRACE("iface %p, factory %p.\n", iface, factory);
4693 ID2D1Factory_AddRef(*factory = geometry->factory);
4696 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetBounds(ID2D1RoundedRectangleGeometry *iface,
4697 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
4699 FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
4701 return E_NOTIMPL;
4704 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetWidenedBounds(ID2D1RoundedRectangleGeometry *iface,
4705 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4706 float tolerance, D2D1_RECT_F *bounds)
4708 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
4709 iface, stroke_width, stroke_style, transform, tolerance, bounds);
4711 return E_NOTIMPL;
4714 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_StrokeContainsPoint(
4715 ID2D1RoundedRectangleGeometry *iface, D2D1_POINT_2F point, float stroke_width,
4716 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
4718 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p stub!\n",
4719 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
4721 return E_NOTIMPL;
4724 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_FillContainsPoint(ID2D1RoundedRectangleGeometry *iface,
4725 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
4727 FIXME("iface %p, point %s, transform %p, tolerance %.8e, contains %p stub!\n",
4728 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
4730 return E_NOTIMPL;
4733 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_CompareWithGeometry(
4734 ID2D1RoundedRectangleGeometry *iface, ID2D1Geometry *geometry,
4735 const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
4737 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
4738 iface, geometry, transform, tolerance, relation);
4740 return E_NOTIMPL;
4743 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Simplify(ID2D1RoundedRectangleGeometry *iface,
4744 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4745 ID2D1SimplifiedGeometrySink *sink)
4747 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4748 iface, option, transform, tolerance, sink);
4750 return E_NOTIMPL;
4753 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Tessellate(ID2D1RoundedRectangleGeometry *iface,
4754 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
4756 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4758 return E_NOTIMPL;
4761 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_CombineWithGeometry(
4762 ID2D1RoundedRectangleGeometry *iface, ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode,
4763 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
4765 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4766 iface, geometry, combine_mode, transform, tolerance, sink);
4768 return E_NOTIMPL;
4771 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Outline(ID2D1RoundedRectangleGeometry *iface,
4772 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
4774 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4776 return E_NOTIMPL;
4779 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_ComputeArea(ID2D1RoundedRectangleGeometry *iface,
4780 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
4782 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
4784 return E_NOTIMPL;
4787 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_ComputeLength(ID2D1RoundedRectangleGeometry *iface,
4788 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
4790 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
4792 return E_NOTIMPL;
4795 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_ComputePointAtLength(
4796 ID2D1RoundedRectangleGeometry *iface, float length, const D2D1_MATRIX_3X2_F *transform,
4797 float tolerance, D2D1_POINT_2F *point, D2D1_POINT_2F *tangent)
4799 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
4800 iface, length, transform, tolerance, point, tangent);
4802 return E_NOTIMPL;
4805 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Widen(ID2D1RoundedRectangleGeometry *iface,
4806 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4807 float tolerance, ID2D1SimplifiedGeometrySink *sink)
4809 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
4810 iface, stroke_width, stroke_style, transform, tolerance, sink);
4812 return E_NOTIMPL;
4815 static void STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetRoundedRect(ID2D1RoundedRectangleGeometry *iface,
4816 D2D1_ROUNDED_RECT *rounded_rect)
4818 struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface);
4820 TRACE("iface %p, rounded_rect %p.\n", iface, rounded_rect);
4822 *rounded_rect = geometry->u.rounded_rectangle.rounded_rect;
4825 static const struct ID2D1RoundedRectangleGeometryVtbl d2d_rounded_rectangle_geometry_vtbl =
4827 d2d_rounded_rectangle_geometry_QueryInterface,
4828 d2d_rounded_rectangle_geometry_AddRef,
4829 d2d_rounded_rectangle_geometry_Release,
4830 d2d_rounded_rectangle_geometry_GetFactory,
4831 d2d_rounded_rectangle_geometry_GetBounds,
4832 d2d_rounded_rectangle_geometry_GetWidenedBounds,
4833 d2d_rounded_rectangle_geometry_StrokeContainsPoint,
4834 d2d_rounded_rectangle_geometry_FillContainsPoint,
4835 d2d_rounded_rectangle_geometry_CompareWithGeometry,
4836 d2d_rounded_rectangle_geometry_Simplify,
4837 d2d_rounded_rectangle_geometry_Tessellate,
4838 d2d_rounded_rectangle_geometry_CombineWithGeometry,
4839 d2d_rounded_rectangle_geometry_Outline,
4840 d2d_rounded_rectangle_geometry_ComputeArea,
4841 d2d_rounded_rectangle_geometry_ComputeLength,
4842 d2d_rounded_rectangle_geometry_ComputePointAtLength,
4843 d2d_rounded_rectangle_geometry_Widen,
4844 d2d_rounded_rectangle_geometry_GetRoundedRect,
4847 HRESULT d2d_rounded_rectangle_geometry_init(struct d2d_geometry *geometry,
4848 ID2D1Factory *factory, const D2D1_ROUNDED_RECT *rounded_rect)
4850 D2D1_POINT_2F *v, v1, v2, v3, v4;
4851 struct d2d_face *f;
4852 float l, r, t, b;
4853 float rx, ry;
4855 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rounded_rectangle_geometry_vtbl);
4856 geometry->u.rounded_rectangle.rounded_rect = *rounded_rect;
4858 if (!(geometry->fill.vertices = heap_alloc(8 * sizeof(*geometry->fill.vertices))))
4859 goto fail;
4860 if (!d2d_array_reserve((void **)&geometry->fill.faces,
4861 &geometry->fill.faces_size, 6, sizeof(*geometry->fill.faces)))
4862 goto fail;
4864 l = min(rounded_rect->rect.left, rounded_rect->rect.right);
4865 r = max(rounded_rect->rect.left, rounded_rect->rect.right);
4866 t = min(rounded_rect->rect.top, rounded_rect->rect.bottom);
4867 b = max(rounded_rect->rect.top, rounded_rect->rect.bottom);
4869 rx = min(rounded_rect->radiusX, 0.5f * (r - l));
4870 ry = min(rounded_rect->radiusY, 0.5f * (b - t));
4872 d2d_point_set(&v1, r, t);
4873 d2d_point_set(&v2, r, b);
4874 d2d_point_set(&v3, l, b);
4875 d2d_point_set(&v4, l, t);
4877 v = geometry->fill.vertices;
4878 d2d_point_set(&v[0], l + rx, t);
4879 d2d_point_set(&v[1], r - rx, t);
4880 d2d_point_set(&v[2], r, t + ry);
4881 d2d_point_set(&v[3], r, b - ry);
4882 d2d_point_set(&v[4], r - rx, b);
4883 d2d_point_set(&v[5], l + rx, b);
4884 d2d_point_set(&v[6], l, b - ry);
4885 d2d_point_set(&v[7], l, t + ry);
4886 geometry->fill.vertex_count = 8;
4888 f = geometry->fill.faces;
4889 d2d_face_set(&f[0], 0, 7, 6);
4890 d2d_face_set(&f[1], 0, 6, 5);
4891 d2d_face_set(&f[2], 0, 5, 4);
4892 d2d_face_set(&f[3], 0, 4, 1);
4893 d2d_face_set(&f[4], 1, 4, 3);
4894 d2d_face_set(&f[5], 1, 3, 2);
4895 geometry->fill.face_count = 6;
4897 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[1], &v1, &v[2]))
4898 goto fail;
4899 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[3], &v2, &v[4]))
4900 goto fail;
4901 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[5], &v3, &v[6]))
4902 goto fail;
4903 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[7], &v4, &v[0]))
4904 goto fail;
4906 if (!d2d_geometry_outline_add_line_segment(geometry, &v[0], &v[1]))
4907 goto fail;
4908 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[1], &v1, &v[2]))
4909 goto fail;
4910 if (!d2d_geometry_outline_add_line_segment(geometry, &v[2], &v[3]))
4911 goto fail;
4912 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[3], &v2, &v[4]))
4913 goto fail;
4914 if (!d2d_geometry_outline_add_line_segment(geometry, &v[4], &v[5]))
4915 goto fail;
4916 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[5], &v3, &v[6]))
4917 goto fail;
4918 if (!d2d_geometry_outline_add_line_segment(geometry, &v[6], &v[7]))
4919 goto fail;
4920 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[7], &v4, &v[0]))
4921 goto fail;
4923 return S_OK;
4925 fail:
4926 d2d_geometry_cleanup(geometry);
4927 return E_OUTOFMEMORY;
4930 static inline struct d2d_geometry *impl_from_ID2D1TransformedGeometry(ID2D1TransformedGeometry *iface)
4932 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
4935 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_QueryInterface(ID2D1TransformedGeometry *iface,
4936 REFIID iid, void **out)
4938 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
4940 if (IsEqualGUID(iid, &IID_ID2D1TransformedGeometry)
4941 || IsEqualGUID(iid, &IID_ID2D1Geometry)
4942 || IsEqualGUID(iid, &IID_ID2D1Resource)
4943 || IsEqualGUID(iid, &IID_IUnknown))
4945 ID2D1TransformedGeometry_AddRef(iface);
4946 *out = iface;
4947 return S_OK;
4950 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
4952 *out = NULL;
4953 return E_NOINTERFACE;
4956 static ULONG STDMETHODCALLTYPE d2d_transformed_geometry_AddRef(ID2D1TransformedGeometry *iface)
4958 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4959 ULONG refcount = InterlockedIncrement(&geometry->refcount);
4961 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
4963 return refcount;
4966 static ULONG STDMETHODCALLTYPE d2d_transformed_geometry_Release(ID2D1TransformedGeometry *iface)
4968 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4969 ULONG refcount = InterlockedDecrement(&geometry->refcount);
4971 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
4973 if (!refcount)
4975 geometry->outline.arc_faces = NULL;
4976 geometry->outline.arcs = NULL;
4977 geometry->outline.bezier_faces = NULL;
4978 geometry->outline.beziers = NULL;
4979 geometry->outline.faces = NULL;
4980 geometry->outline.vertices = NULL;
4981 geometry->fill.arc_vertices = NULL;
4982 geometry->fill.bezier_vertices = NULL;
4983 geometry->fill.faces = NULL;
4984 geometry->fill.vertices = NULL;
4985 ID2D1Geometry_Release(geometry->u.transformed.src_geometry);
4986 d2d_geometry_cleanup(geometry);
4987 heap_free(geometry);
4990 return refcount;
4993 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetFactory(ID2D1TransformedGeometry *iface,
4994 ID2D1Factory **factory)
4996 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4998 TRACE("iface %p, factory %p.\n", iface, factory);
5000 ID2D1Factory_AddRef(*factory = geometry->factory);
5003 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_GetBounds(ID2D1TransformedGeometry *iface,
5004 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
5006 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
5007 D2D1_MATRIX_3X2_F g;
5009 TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
5011 g = geometry->transform;
5012 if (transform)
5013 d2d_matrix_multiply(&g, transform);
5015 return ID2D1Geometry_GetBounds(geometry->u.transformed.src_geometry, &g, bounds);
5018 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_GetWidenedBounds(ID2D1TransformedGeometry *iface,
5019 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
5020 float tolerance, D2D1_RECT_F *bounds)
5022 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
5023 iface, stroke_width, stroke_style, transform, tolerance, bounds);
5025 return E_NOTIMPL;
5028 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_StrokeContainsPoint(ID2D1TransformedGeometry *iface,
5029 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
5030 float tolerance, BOOL *contains)
5032 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
5033 D2D1_MATRIX_3X2_F g;
5035 TRACE("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p.\n",
5036 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
5038 g = geometry->transform;
5039 if (transform)
5040 d2d_matrix_multiply(&g, transform);
5042 return ID2D1Geometry_StrokeContainsPoint(geometry->u.transformed.src_geometry, point, stroke_width, stroke_style,
5043 &g, tolerance, contains);
5046 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_FillContainsPoint(ID2D1TransformedGeometry *iface,
5047 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
5049 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
5050 D2D1_MATRIX_3X2_F g;
5052 TRACE("iface %p, point %s, transform %p, tolerance %.8e, contains %p.\n",
5053 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
5055 g = geometry->transform;
5056 if (transform)
5057 d2d_matrix_multiply(&g, transform);
5059 return ID2D1Geometry_FillContainsPoint(geometry->u.transformed.src_geometry, point, &g, tolerance, contains);
5062 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_CompareWithGeometry(ID2D1TransformedGeometry *iface,
5063 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
5065 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
5066 iface, geometry, transform, tolerance, relation);
5068 return E_NOTIMPL;
5071 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Simplify(ID2D1TransformedGeometry *iface,
5072 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
5073 ID2D1SimplifiedGeometrySink *sink)
5075 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
5076 D2D1_MATRIX_3X2_F g;
5078 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
5079 iface, option, transform, tolerance, sink);
5081 g = geometry->transform;
5082 if (transform)
5083 d2d_matrix_multiply(&g, transform);
5085 return ID2D1Geometry_Simplify(geometry->u.transformed.src_geometry, option, &g, tolerance, sink);
5088 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Tessellate(ID2D1TransformedGeometry *iface,
5089 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
5091 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
5093 return E_NOTIMPL;
5096 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_CombineWithGeometry(ID2D1TransformedGeometry *iface,
5097 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
5098 float tolerance, ID2D1SimplifiedGeometrySink *sink)
5100 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
5101 iface, geometry, combine_mode, transform, tolerance, sink);
5103 return E_NOTIMPL;
5106 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Outline(ID2D1TransformedGeometry *iface,
5107 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
5109 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
5111 return E_NOTIMPL;
5114 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputeArea(ID2D1TransformedGeometry *iface,
5115 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
5117 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
5119 return E_NOTIMPL;
5122 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputeLength(ID2D1TransformedGeometry *iface,
5123 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
5125 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
5127 return E_NOTIMPL;
5130 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputePointAtLength(ID2D1TransformedGeometry *iface,
5131 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
5132 D2D1_POINT_2F *tangent)
5134 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
5135 iface, length, transform, tolerance, point, tangent);
5137 return E_NOTIMPL;
5140 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Widen(ID2D1TransformedGeometry *iface, float stroke_width,
5141 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
5142 ID2D1SimplifiedGeometrySink *sink)
5144 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
5145 iface, stroke_width, stroke_style, transform, tolerance, sink);
5147 return E_NOTIMPL;
5150 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetSourceGeometry(ID2D1TransformedGeometry *iface,
5151 ID2D1Geometry **src_geometry)
5153 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
5155 TRACE("iface %p, src_geometry %p.\n", iface, src_geometry);
5157 ID2D1Geometry_AddRef(*src_geometry = geometry->u.transformed.src_geometry);
5160 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetTransform(ID2D1TransformedGeometry *iface,
5161 D2D1_MATRIX_3X2_F *transform)
5163 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
5165 TRACE("iface %p, transform %p.\n", iface, transform);
5167 *transform = geometry->u.transformed.transform;
5170 static const struct ID2D1TransformedGeometryVtbl d2d_transformed_geometry_vtbl =
5172 d2d_transformed_geometry_QueryInterface,
5173 d2d_transformed_geometry_AddRef,
5174 d2d_transformed_geometry_Release,
5175 d2d_transformed_geometry_GetFactory,
5176 d2d_transformed_geometry_GetBounds,
5177 d2d_transformed_geometry_GetWidenedBounds,
5178 d2d_transformed_geometry_StrokeContainsPoint,
5179 d2d_transformed_geometry_FillContainsPoint,
5180 d2d_transformed_geometry_CompareWithGeometry,
5181 d2d_transformed_geometry_Simplify,
5182 d2d_transformed_geometry_Tessellate,
5183 d2d_transformed_geometry_CombineWithGeometry,
5184 d2d_transformed_geometry_Outline,
5185 d2d_transformed_geometry_ComputeArea,
5186 d2d_transformed_geometry_ComputeLength,
5187 d2d_transformed_geometry_ComputePointAtLength,
5188 d2d_transformed_geometry_Widen,
5189 d2d_transformed_geometry_GetSourceGeometry,
5190 d2d_transformed_geometry_GetTransform,
5193 void d2d_transformed_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
5194 ID2D1Geometry *src_geometry, const D2D_MATRIX_3X2_F *transform)
5196 struct d2d_geometry *src_impl;
5197 D2D_MATRIX_3X2_F g;
5199 src_impl = unsafe_impl_from_ID2D1Geometry(src_geometry);
5201 g = src_impl->transform;
5202 d2d_matrix_multiply(&g, transform);
5203 d2d_geometry_init(geometry, factory, &g, (ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl);
5204 ID2D1Geometry_AddRef(geometry->u.transformed.src_geometry = src_geometry);
5205 geometry->u.transformed.transform = *transform;
5206 geometry->fill = src_impl->fill;
5207 geometry->outline = src_impl->outline;
5210 static inline struct d2d_geometry *impl_from_ID2D1GeometryGroup(ID2D1GeometryGroup *iface)
5212 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
5215 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_QueryInterface(ID2D1GeometryGroup *iface,
5216 REFIID iid, void **out)
5218 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
5220 if (IsEqualGUID(iid, &IID_ID2D1GeometryGroup)
5221 || IsEqualGUID(iid, &IID_ID2D1Geometry)
5222 || IsEqualGUID(iid, &IID_ID2D1Resource)
5223 || IsEqualGUID(iid, &IID_IUnknown))
5225 ID2D1GeometryGroup_AddRef(iface);
5226 *out = iface;
5227 return S_OK;
5230 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
5232 *out = NULL;
5233 return E_NOINTERFACE;
5236 static ULONG STDMETHODCALLTYPE d2d_geometry_group_AddRef(ID2D1GeometryGroup *iface)
5238 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5239 ULONG refcount = InterlockedIncrement(&geometry->refcount);
5241 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
5243 return refcount;
5246 static ULONG STDMETHODCALLTYPE d2d_geometry_group_Release(ID2D1GeometryGroup *iface)
5248 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5249 ULONG refcount = InterlockedDecrement(&geometry->refcount);
5250 unsigned int i;
5252 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
5254 if (!refcount)
5256 for (i = 0; i < geometry->u.group.geometry_count; ++i)
5257 ID2D1Geometry_Release(geometry->u.group.src_geometries[i]);
5258 heap_free(geometry->u.group.src_geometries);
5259 d2d_geometry_cleanup(geometry);
5260 heap_free(geometry);
5263 return refcount;
5266 static void STDMETHODCALLTYPE d2d_geometry_group_GetFactory(ID2D1GeometryGroup *iface,
5267 ID2D1Factory **factory)
5269 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5271 TRACE("iface %p, factory %p.\n", iface, factory);
5273 ID2D1Factory_AddRef(*factory = geometry->factory);
5276 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_GetBounds(ID2D1GeometryGroup *iface,
5277 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
5279 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5280 D2D1_RECT_F rect;
5281 unsigned int i;
5283 TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
5285 bounds->left = FLT_MAX;
5286 bounds->top = FLT_MAX;
5287 bounds->right = -FLT_MAX;
5288 bounds->bottom = -FLT_MAX;
5290 for (i = 0; i < geometry->u.group.geometry_count; ++i)
5292 if (SUCCEEDED(ID2D1Geometry_GetBounds(geometry->u.group.src_geometries[i], transform, &rect)))
5293 d2d_rect_union(bounds, &rect);
5296 return S_OK;
5299 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_GetWidenedBounds(ID2D1GeometryGroup *iface,
5300 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
5301 float tolerance, D2D1_RECT_F *bounds)
5303 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
5304 iface, stroke_width, stroke_style, transform, tolerance, bounds);
5306 return E_NOTIMPL;
5309 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_StrokeContainsPoint(ID2D1GeometryGroup *iface,
5310 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
5311 float tolerance, BOOL *contains)
5313 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p.\n",
5314 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
5316 return E_NOTIMPL;
5319 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_FillContainsPoint(ID2D1GeometryGroup *iface,
5320 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
5322 FIXME("iface %p, point %s, transform %p, tolerance %.8e, contains %p stub!.\n",
5323 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
5325 return E_NOTIMPL;
5328 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_CompareWithGeometry(ID2D1GeometryGroup *iface,
5329 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
5331 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
5332 iface, geometry, transform, tolerance, relation);
5334 return E_NOTIMPL;
5337 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_Simplify(ID2D1GeometryGroup *iface,
5338 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
5339 ID2D1SimplifiedGeometrySink *sink)
5341 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!.\n",
5342 iface, option, transform, tolerance, sink);
5344 return E_NOTIMPL;
5347 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_Tessellate(ID2D1GeometryGroup *iface,
5348 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
5350 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
5352 return E_NOTIMPL;
5355 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_CombineWithGeometry(ID2D1GeometryGroup *iface,
5356 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
5357 float tolerance, ID2D1SimplifiedGeometrySink *sink)
5359 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
5360 iface, geometry, combine_mode, transform, tolerance, sink);
5362 return E_NOTIMPL;
5365 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_Outline(ID2D1GeometryGroup *iface,
5366 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
5368 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
5370 return E_NOTIMPL;
5373 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_ComputeArea(ID2D1GeometryGroup *iface,
5374 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
5376 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
5378 return E_NOTIMPL;
5381 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_ComputeLength(ID2D1GeometryGroup *iface,
5382 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
5384 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
5386 return E_NOTIMPL;
5389 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_ComputePointAtLength(ID2D1GeometryGroup *iface,
5390 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
5391 D2D1_POINT_2F *tangent)
5393 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
5394 iface, length, transform, tolerance, point, tangent);
5396 return E_NOTIMPL;
5399 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_Widen(ID2D1GeometryGroup *iface, float stroke_width,
5400 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
5401 ID2D1SimplifiedGeometrySink *sink)
5403 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
5404 iface, stroke_width, stroke_style, transform, tolerance, sink);
5406 return E_NOTIMPL;
5409 static D2D1_FILL_MODE STDMETHODCALLTYPE d2d_geometry_group_GetFillMode(ID2D1GeometryGroup *iface)
5411 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5413 TRACE("iface %p.\n", iface);
5415 return geometry->u.group.fill_mode;
5418 static UINT32 STDMETHODCALLTYPE d2d_geometry_group_GetSourceGeometryCount(ID2D1GeometryGroup *iface)
5420 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5422 TRACE("iface %p.\n", iface);
5424 return geometry->u.group.geometry_count;
5427 static void STDMETHODCALLTYPE d2d_geometry_group_GetSourceGeometries(ID2D1GeometryGroup *iface,
5428 ID2D1Geometry **geometries, UINT32 geometry_count)
5430 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5431 unsigned int i;
5433 TRACE("iface %p, geometries %p, geometry_count %u.\n", iface, geometries, geometry_count);
5435 geometry_count = min(geometry_count, geometry->u.group.geometry_count);
5436 for (i = 0; i < geometry_count; ++i)
5437 ID2D1Geometry_AddRef(geometries[i] = geometry->u.group.src_geometries[i]);
5440 static const struct ID2D1GeometryGroupVtbl d2d_geometry_group_vtbl =
5442 d2d_geometry_group_QueryInterface,
5443 d2d_geometry_group_AddRef,
5444 d2d_geometry_group_Release,
5445 d2d_geometry_group_GetFactory,
5446 d2d_geometry_group_GetBounds,
5447 d2d_geometry_group_GetWidenedBounds,
5448 d2d_geometry_group_StrokeContainsPoint,
5449 d2d_geometry_group_FillContainsPoint,
5450 d2d_geometry_group_CompareWithGeometry,
5451 d2d_geometry_group_Simplify,
5452 d2d_geometry_group_Tessellate,
5453 d2d_geometry_group_CombineWithGeometry,
5454 d2d_geometry_group_Outline,
5455 d2d_geometry_group_ComputeArea,
5456 d2d_geometry_group_ComputeLength,
5457 d2d_geometry_group_ComputePointAtLength,
5458 d2d_geometry_group_Widen,
5459 d2d_geometry_group_GetFillMode,
5460 d2d_geometry_group_GetSourceGeometryCount,
5461 d2d_geometry_group_GetSourceGeometries,
5464 HRESULT d2d_geometry_group_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
5465 D2D1_FILL_MODE fill_mode, ID2D1Geometry **geometries, unsigned int geometry_count)
5467 unsigned int i;
5469 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_geometry_group_vtbl);
5471 if (!(geometry->u.group.src_geometries = heap_calloc(geometry_count, sizeof(*geometries))))
5473 d2d_geometry_cleanup(geometry);
5474 return E_OUTOFMEMORY;
5477 for (i = 0; i < geometry_count; ++i)
5479 ID2D1Geometry_AddRef(geometry->u.group.src_geometries[i] = geometries[i]);
5481 geometry->u.group.geometry_count = geometry_count;
5482 geometry->u.group.fill_mode = fill_mode;
5484 return S_OK;
5487 struct d2d_geometry *unsafe_impl_from_ID2D1Geometry(ID2D1Geometry *iface)
5489 if (!iface)
5490 return NULL;
5491 assert(iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_ellipse_geometry_vtbl
5492 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl
5493 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl
5494 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_rounded_rectangle_geometry_vtbl
5495 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl
5496 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_geometry_group_vtbl);
5497 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);