windowscodecs: Silence fixme for IID_CMetaBitmapRenderTarget.
[wine.git] / dlls / d2d1 / geometry.c
blob3da3ad2e65bc65ae57d0154e90f4ab13731a09d0
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 three 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 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 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;
2288 #ifdef __i386__
2289 unsigned int control_word_x87, mask = 0;
2290 #endif
2292 for (i = 0, vertex_count = 0; i < geometry->u.path.figure_count; ++i)
2294 if (geometry->u.path.figures[i].flags & D2D_FIGURE_FLAG_HOLLOW)
2295 continue;
2296 vertex_count += geometry->u.path.figures[i].vertex_count;
2299 if (vertex_count < 3)
2301 WARN("Geometry has %lu vertices.\n", (long)vertex_count);
2302 return S_OK;
2305 if (!(vertices = calloc(vertex_count, sizeof(*vertices))))
2306 return E_OUTOFMEMORY;
2308 for (i = 0, j = 0; i < geometry->u.path.figure_count; ++i)
2310 if (geometry->u.path.figures[i].flags & D2D_FIGURE_FLAG_HOLLOW)
2311 continue;
2312 memcpy(&vertices[j], geometry->u.path.figures[i].vertices,
2313 geometry->u.path.figures[i].vertex_count * sizeof(*vertices));
2314 j += geometry->u.path.figures[i].vertex_count;
2317 /* Sort vertices, eliminate duplicates. */
2318 qsort(vertices, vertex_count, sizeof(*vertices), d2d_cdt_compare_vertices);
2319 for (i = 1; i < vertex_count; ++i)
2321 if (!memcmp(&vertices[i - 1], &vertices[i], sizeof(*vertices)))
2323 --vertex_count;
2324 memmove(&vertices[i], &vertices[i + 1], (vertex_count - i) * sizeof(*vertices));
2325 --i;
2329 if (vertex_count < 3)
2331 WARN("Geometry has %lu vertices after eliminating duplicates.\n", (long)vertex_count);
2332 free(vertices);
2333 return S_OK;
2336 geometry->fill.vertices = vertices;
2337 geometry->fill.vertex_count = vertex_count;
2339 cdt.free_edge = ~0u;
2340 cdt.vertices = vertices;
2342 #ifdef __i386__
2343 control_word_x87 = _controlfp(0, 0);
2344 _controlfp(_PC_24, mask = _MCW_PC);
2345 #endif
2346 if (!d2d_cdt_triangulate(&cdt, 0, vertex_count, &left_edge, &right_edge))
2347 goto fail;
2348 if (!d2d_cdt_insert_segments(&cdt, geometry))
2349 goto fail;
2350 #ifdef __i386__
2351 _controlfp(control_word_x87, _MCW_PC);
2352 mask = 0;
2353 #endif
2355 if (!d2d_cdt_generate_faces(&cdt, geometry))
2356 goto fail;
2358 free(cdt.edges);
2359 return S_OK;
2361 fail:
2362 geometry->fill.vertices = NULL;
2363 geometry->fill.vertex_count = 0;
2364 free(vertices);
2365 free(cdt.edges);
2366 #ifdef __i386__
2367 if (mask) _controlfp(control_word_x87, mask);
2368 #endif
2369 return E_FAIL;
2372 static BOOL d2d_path_geometry_add_figure(struct d2d_geometry *geometry)
2374 struct d2d_figure *figure;
2376 if (!d2d_array_reserve((void **)&geometry->u.path.figures, &geometry->u.path.figures_size,
2377 geometry->u.path.figure_count + 1, sizeof(*geometry->u.path.figures)))
2379 ERR("Failed to grow figures array.\n");
2380 return FALSE;
2383 figure = &geometry->u.path.figures[geometry->u.path.figure_count];
2384 memset(figure, 0, sizeof(*figure));
2385 figure->bounds.left = FLT_MAX;
2386 figure->bounds.top = FLT_MAX;
2387 figure->bounds.right = -FLT_MAX;
2388 figure->bounds.bottom = -FLT_MAX;
2390 ++geometry->u.path.figure_count;
2391 return TRUE;
2394 static BOOL d2d_geometry_outline_add_join(struct d2d_geometry *geometry,
2395 const D2D1_POINT_2F *prev, const D2D1_POINT_2F *p0, const D2D1_POINT_2F *next)
2397 static const D2D1_POINT_2F origin = {0.0f, 0.0f};
2398 struct d2d_outline_vertex *v;
2399 struct d2d_face *f;
2400 size_t base_idx;
2401 float ccw;
2403 if (!d2d_array_reserve((void **)&geometry->outline.vertices, &geometry->outline.vertices_size,
2404 geometry->outline.vertex_count + 4, sizeof(*geometry->outline.vertices)))
2406 ERR("Failed to grow outline vertices array.\n");
2407 return FALSE;
2409 base_idx = geometry->outline.vertex_count;
2410 v = &geometry->outline.vertices[base_idx];
2412 if (!d2d_array_reserve((void **)&geometry->outline.faces, &geometry->outline.faces_size,
2413 geometry->outline.face_count + 2, sizeof(*geometry->outline.faces)))
2415 ERR("Failed to grow outline faces array.\n");
2416 return FALSE;
2418 f = &geometry->outline.faces[geometry->outline.face_count];
2420 ccw = d2d_point_ccw(&origin, prev, next);
2421 if (ccw == 0.0f)
2423 d2d_outline_vertex_set(&v[0], p0->x, p0->y, -prev->x, -prev->y, -prev->x, -prev->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 + 25.0f * -prev->x, p0->y + 25.0f * -prev->y,
2426 prev->x, prev->y, prev->x, prev->y);
2427 d2d_outline_vertex_set(&v[3], p0->x + 25.0f * -prev->x, p0->y + 25.0f * -prev->y,
2428 -prev->x, -prev->y, -prev->x, -prev->y);
2430 else if (ccw < 0.0f)
2432 d2d_outline_vertex_set(&v[0], p0->x, p0->y, next->x, next->y, -prev->x, -prev->y);
2433 d2d_outline_vertex_set(&v[1], p0->x, p0->y, -next->x, -next->y, -next->x, -next->y);
2434 d2d_outline_vertex_set(&v[2], p0->x, p0->y, -next->x, -next->y, prev->x, prev->y);
2435 d2d_outline_vertex_set(&v[3], p0->x, p0->y, prev->x, prev->y, prev->x, prev->y);
2437 else
2439 d2d_outline_vertex_set(&v[0], p0->x, p0->y, prev->x, prev->y, -next->x, -next->y);
2440 d2d_outline_vertex_set(&v[1], p0->x, p0->y, -prev->x, -prev->y, -prev->x, -prev->y);
2441 d2d_outline_vertex_set(&v[2], p0->x, p0->y, -prev->x, -prev->y, next->x, next->y);
2442 d2d_outline_vertex_set(&v[3], p0->x, p0->y, next->x, next->y, next->x, next->y);
2444 geometry->outline.vertex_count += 4;
2446 d2d_face_set(&f[0], base_idx + 1, base_idx + 0, base_idx + 2);
2447 d2d_face_set(&f[1], base_idx + 2, base_idx + 0, base_idx + 3);
2448 geometry->outline.face_count += 2;
2450 return TRUE;
2453 static BOOL d2d_geometry_outline_add_line_segment(struct d2d_geometry *geometry,
2454 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *next)
2456 struct d2d_outline_vertex *v;
2457 D2D1_POINT_2F q_next;
2458 struct d2d_face *f;
2459 size_t base_idx;
2461 if (!d2d_array_reserve((void **)&geometry->outline.vertices, &geometry->outline.vertices_size,
2462 geometry->outline.vertex_count + 4, sizeof(*geometry->outline.vertices)))
2464 ERR("Failed to grow outline vertices array.\n");
2465 return FALSE;
2467 base_idx = geometry->outline.vertex_count;
2468 v = &geometry->outline.vertices[base_idx];
2470 if (!d2d_array_reserve((void **)&geometry->outline.faces, &geometry->outline.faces_size,
2471 geometry->outline.face_count + 2, sizeof(*geometry->outline.faces)))
2473 ERR("Failed to grow outline faces array.\n");
2474 return FALSE;
2476 f = &geometry->outline.faces[geometry->outline.face_count];
2478 d2d_point_subtract(&q_next, next, p0);
2479 d2d_point_normalise(&q_next);
2481 d2d_outline_vertex_set(&v[0], p0->x, p0->y, q_next.x, q_next.y, q_next.x, q_next.y);
2482 d2d_outline_vertex_set(&v[1], p0->x, p0->y, -q_next.x, -q_next.y, -q_next.x, -q_next.y);
2483 d2d_outline_vertex_set(&v[2], next->x, next->y, q_next.x, q_next.y, q_next.x, q_next.y);
2484 d2d_outline_vertex_set(&v[3], next->x, next->y, -q_next.x, -q_next.y, -q_next.x, -q_next.y);
2485 geometry->outline.vertex_count += 4;
2487 d2d_face_set(&f[0], base_idx + 0, base_idx + 1, base_idx + 2);
2488 d2d_face_set(&f[1], base_idx + 2, base_idx + 1, base_idx + 3);
2489 geometry->outline.face_count += 2;
2491 return TRUE;
2494 static BOOL d2d_geometry_outline_add_bezier_segment(struct d2d_geometry *geometry,
2495 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2)
2497 struct d2d_curve_outline_vertex *b;
2498 D2D1_POINT_2F r0, r1, r2;
2499 D2D1_POINT_2F q0, q1, q2;
2500 struct d2d_face *f;
2501 size_t base_idx;
2503 if (!d2d_array_reserve((void **)&geometry->outline.beziers, &geometry->outline.beziers_size,
2504 geometry->outline.bezier_count + 7, sizeof(*geometry->outline.beziers)))
2506 ERR("Failed to grow outline beziers array.\n");
2507 return FALSE;
2509 base_idx = geometry->outline.bezier_count;
2510 b = &geometry->outline.beziers[base_idx];
2512 if (!d2d_array_reserve((void **)&geometry->outline.bezier_faces, &geometry->outline.bezier_faces_size,
2513 geometry->outline.bezier_face_count + 5, sizeof(*geometry->outline.bezier_faces)))
2515 ERR("Failed to grow outline faces array.\n");
2516 return FALSE;
2518 f = &geometry->outline.bezier_faces[geometry->outline.bezier_face_count];
2520 d2d_point_lerp(&q0, p0, p1, 0.5f);
2521 d2d_point_lerp(&q1, p1, p2, 0.5f);
2522 d2d_point_lerp(&q2, &q0, &q1, 0.5f);
2524 d2d_point_subtract(&r0, &q0, p0);
2525 d2d_point_subtract(&r1, &q1, &q0);
2526 d2d_point_subtract(&r2, p2, &q1);
2528 d2d_point_normalise(&r0);
2529 d2d_point_normalise(&r1);
2530 d2d_point_normalise(&r2);
2532 if (d2d_point_ccw(p0, p1, p2) > 0.0f)
2534 d2d_point_scale(&r0, -1.0f);
2535 d2d_point_scale(&r1, -1.0f);
2536 d2d_point_scale(&r2, -1.0f);
2539 d2d_curve_outline_vertex_set(&b[0], p0, p0, p1, p2, r0.x, r0.y, r0.x, r0.y);
2540 d2d_curve_outline_vertex_set(&b[1], p0, p0, p1, p2, -r0.x, -r0.y, -r0.x, -r0.y);
2541 d2d_curve_outline_vertex_set(&b[2], &q0, p0, p1, p2, r0.x, r0.y, r1.x, r1.y);
2542 d2d_curve_outline_vertex_set(&b[3], &q2, p0, p1, p2, -r1.x, -r1.y, -r1.x, -r1.y);
2543 d2d_curve_outline_vertex_set(&b[4], &q1, p0, p1, p2, r1.x, r1.y, r2.x, r2.y);
2544 d2d_curve_outline_vertex_set(&b[5], p2, p0, p1, p2, -r2.x, -r2.y, -r2.x, -r2.y);
2545 d2d_curve_outline_vertex_set(&b[6], p2, p0, p1, p2, r2.x, r2.y, r2.x, r2.y);
2546 geometry->outline.bezier_count += 7;
2548 d2d_face_set(&f[0], base_idx + 0, base_idx + 1, base_idx + 2);
2549 d2d_face_set(&f[1], base_idx + 2, base_idx + 1, base_idx + 3);
2550 d2d_face_set(&f[2], base_idx + 3, base_idx + 4, base_idx + 2);
2551 d2d_face_set(&f[3], base_idx + 5, base_idx + 4, base_idx + 3);
2552 d2d_face_set(&f[4], base_idx + 5, base_idx + 6, base_idx + 4);
2553 geometry->outline.bezier_face_count += 5;
2555 return TRUE;
2558 static BOOL d2d_geometry_outline_add_arc_quadrant(struct d2d_geometry *geometry,
2559 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2)
2561 struct d2d_curve_outline_vertex *a;
2562 D2D1_POINT_2F r0, r1;
2563 struct d2d_face *f;
2564 size_t base_idx;
2566 if (!d2d_array_reserve((void **)&geometry->outline.arcs, &geometry->outline.arcs_size,
2567 geometry->outline.arc_count + 5, sizeof(*geometry->outline.arcs)))
2569 ERR("Failed to grow outline arcs array.\n");
2570 return FALSE;
2572 base_idx = geometry->outline.arc_count;
2573 a = &geometry->outline.arcs[base_idx];
2575 if (!d2d_array_reserve((void **)&geometry->outline.arc_faces, &geometry->outline.arc_faces_size,
2576 geometry->outline.arc_face_count + 3, sizeof(*geometry->outline.arc_faces)))
2578 ERR("Failed to grow outline faces array.\n");
2579 return FALSE;
2581 f = &geometry->outline.arc_faces[geometry->outline.arc_face_count];
2583 d2d_point_subtract(&r0, p1, p0);
2584 d2d_point_subtract(&r1, p2, p1);
2586 d2d_point_normalise(&r0);
2587 d2d_point_normalise(&r1);
2589 if (d2d_point_ccw(p0, p1, p2) > 0.0f)
2591 d2d_point_scale(&r0, -1.0f);
2592 d2d_point_scale(&r1, -1.0f);
2595 d2d_curve_outline_vertex_set(&a[0], p0, p0, p1, p2, r0.x, r0.y, r0.x, r0.y);
2596 d2d_curve_outline_vertex_set(&a[1], p0, p0, p1, p2, -r0.x, -r0.y, -r0.x, -r0.y);
2597 d2d_curve_outline_vertex_set(&a[2], p1, p0, p1, p2, r0.x, r0.y, r1.x, r1.y);
2598 d2d_curve_outline_vertex_set(&a[3], p2, p0, p1, p2, -r1.x, -r1.y, -r1.x, -r1.y);
2599 d2d_curve_outline_vertex_set(&a[4], p2, p0, p1, p2, r1.x, r1.y, r1.x, r1.y);
2600 geometry->outline.arc_count += 5;
2602 d2d_face_set(&f[0], base_idx + 0, base_idx + 1, base_idx + 2);
2603 d2d_face_set(&f[1], base_idx + 2, base_idx + 1, base_idx + 3);
2604 d2d_face_set(&f[2], base_idx + 2, base_idx + 4, base_idx + 3);
2605 geometry->outline.arc_face_count += 3;
2607 return TRUE;
2610 static BOOL d2d_geometry_add_figure_outline(struct d2d_geometry *geometry,
2611 struct d2d_figure *figure, D2D1_FIGURE_END figure_end)
2613 const D2D1_POINT_2F *prev, *p0, *p1, *next, *next_prev;
2614 size_t bezier_idx, i, vertex_count;
2615 enum d2d_vertex_type type;
2617 if (!(vertex_count = figure->vertex_count))
2618 return TRUE;
2620 p0 = &figure->vertices[0];
2621 if (figure_end == D2D1_FIGURE_END_CLOSED)
2623 if (figure->vertex_types[vertex_count - 1] == D2D_VERTEX_TYPE_END && !--vertex_count)
2624 return TRUE;
2626 /* In case of a CLOSED path, a join between first and last vertex is
2627 * required. */
2628 if (d2d_vertex_type_is_bezier(figure->vertex_types[vertex_count - 1]))
2629 prev = &figure->bezier_controls[figure->bezier_control_count - 1];
2630 else
2631 prev = &figure->vertices[vertex_count - 1];
2633 else
2635 if (!--vertex_count)
2636 return TRUE;
2637 prev = p0;
2640 for (i = 0, bezier_idx = 0; i < vertex_count; ++i)
2642 if ((type = figure->vertex_types[i]) == D2D_VERTEX_TYPE_NONE)
2644 prev = next_prev = &figure->vertices[i];
2645 continue;
2648 /* next: tangent along next segment, at p0.
2649 * p1: next vertex. */
2650 if (d2d_vertex_type_is_bezier(type))
2652 next_prev = next = &figure->bezier_controls[bezier_idx++];
2653 /* type BEZIER implies i + 1 < figure->vertex_count. */
2654 p1 = &figure->vertices[i + 1];
2656 if (!d2d_geometry_outline_add_bezier_segment(geometry, p0, next, p1))
2658 ERR("Failed to add bezier segment.\n");
2659 return FALSE;
2662 else
2664 if (i + 1 == figure->vertex_count)
2665 next = p1 = &figure->vertices[0];
2666 else
2667 next = p1 = &figure->vertices[i + 1];
2668 next_prev = p0;
2670 if (!d2d_geometry_outline_add_line_segment(geometry, p0, p1))
2672 ERR("Failed to add line segment.\n");
2673 return FALSE;
2677 if (i || figure_end == D2D1_FIGURE_END_CLOSED)
2679 D2D1_POINT_2F q_next, q_prev;
2681 d2d_point_subtract(&q_prev, prev, p0);
2682 d2d_point_subtract(&q_next, next, p0);
2684 d2d_point_normalise(&q_prev);
2685 d2d_point_normalise(&q_next);
2687 if (!d2d_geometry_outline_add_join(geometry, &q_prev, p0, &q_next))
2689 ERR("Failed to add join.\n");
2690 return FALSE;
2694 p0 = p1;
2695 prev = next_prev;
2698 return TRUE;
2701 static BOOL d2d_geometry_fill_add_arc_triangle(struct d2d_geometry *geometry,
2702 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2)
2704 struct d2d_curve_vertex *a;
2706 if (!d2d_array_reserve((void **)&geometry->fill.arc_vertices, &geometry->fill.arc_vertices_size,
2707 geometry->fill.arc_vertex_count + 3, sizeof(*geometry->fill.arc_vertices)))
2708 return FALSE;
2710 a = &geometry->fill.arc_vertices[geometry->fill.arc_vertex_count];
2711 d2d_curve_vertex_set(&a[0], p0, 0.0f, 1.0f, -1.0f);
2712 d2d_curve_vertex_set(&a[1], p1, 1.0f, 1.0f, -1.0f);
2713 d2d_curve_vertex_set(&a[2], p2, 1.0f, 0.0f, -1.0f);
2714 geometry->fill.arc_vertex_count += 3;
2716 return TRUE;
2719 static void d2d_geometry_cleanup(struct d2d_geometry *geometry)
2721 free(geometry->outline.arc_faces);
2722 free(geometry->outline.arcs);
2723 free(geometry->outline.bezier_faces);
2724 free(geometry->outline.beziers);
2725 free(geometry->outline.faces);
2726 free(geometry->outline.vertices);
2727 free(geometry->fill.arc_vertices);
2728 free(geometry->fill.bezier_vertices);
2729 free(geometry->fill.faces);
2730 free(geometry->fill.vertices);
2731 ID2D1Factory_Release(geometry->factory);
2734 static void d2d_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
2735 const D2D1_MATRIX_3X2_F *transform, const struct ID2D1GeometryVtbl *vtbl)
2737 geometry->ID2D1Geometry_iface.lpVtbl = vtbl;
2738 geometry->refcount = 1;
2739 ID2D1Factory_AddRef(geometry->factory = factory);
2740 geometry->transform = *transform;
2743 static inline struct d2d_geometry *impl_from_ID2D1GeometrySink(ID2D1GeometrySink *iface)
2745 return CONTAINING_RECORD(iface, struct d2d_geometry, u.path.ID2D1GeometrySink_iface);
2748 static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_QueryInterface(ID2D1GeometrySink *iface, REFIID iid, void **out)
2750 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
2752 if (IsEqualGUID(iid, &IID_ID2D1GeometrySink)
2753 || IsEqualGUID(iid, &IID_ID2D1SimplifiedGeometrySink)
2754 || IsEqualGUID(iid, &IID_IUnknown))
2756 ID2D1GeometrySink_AddRef(iface);
2757 *out = iface;
2758 return S_OK;
2761 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
2763 *out = NULL;
2764 return E_NOINTERFACE;
2767 static ULONG STDMETHODCALLTYPE d2d_geometry_sink_AddRef(ID2D1GeometrySink *iface)
2769 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2771 TRACE("iface %p.\n", iface);
2773 return ID2D1Geometry_AddRef(&geometry->ID2D1Geometry_iface);
2776 static ULONG STDMETHODCALLTYPE d2d_geometry_sink_Release(ID2D1GeometrySink *iface)
2778 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2780 TRACE("iface %p.\n", iface);
2782 return ID2D1Geometry_Release(&geometry->ID2D1Geometry_iface);
2785 static void STDMETHODCALLTYPE d2d_geometry_sink_SetFillMode(ID2D1GeometrySink *iface, D2D1_FILL_MODE mode)
2787 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2789 TRACE("iface %p, mode %#x.\n", iface, mode);
2791 if (geometry->u.path.state == D2D_GEOMETRY_STATE_CLOSED)
2792 return;
2793 geometry->u.path.fill_mode = mode;
2796 static void STDMETHODCALLTYPE d2d_geometry_sink_SetSegmentFlags(ID2D1GeometrySink *iface, D2D1_PATH_SEGMENT flags)
2798 TRACE("iface %p, flags %#x.\n", iface, flags);
2800 if (flags != D2D1_PATH_SEGMENT_NONE)
2801 FIXME("Ignoring flags %#x.\n", flags);
2804 static void STDMETHODCALLTYPE d2d_geometry_sink_BeginFigure(ID2D1GeometrySink *iface,
2805 D2D1_POINT_2F start_point, D2D1_FIGURE_BEGIN figure_begin)
2807 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2808 struct d2d_figure *figure;
2810 TRACE("iface %p, start_point %s, figure_begin %#x.\n",
2811 iface, debug_d2d_point_2f(&start_point), figure_begin);
2813 if (geometry->u.path.state != D2D_GEOMETRY_STATE_OPEN)
2815 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2816 return;
2819 if (!d2d_path_geometry_add_figure(geometry))
2821 ERR("Failed to add figure.\n");
2822 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2823 return;
2826 figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2827 if (figure_begin == D2D1_FIGURE_BEGIN_HOLLOW)
2828 figure->flags |= D2D_FIGURE_FLAG_HOLLOW;
2830 if (!d2d_figure_add_vertex(figure, start_point))
2832 ERR("Failed to add vertex.\n");
2833 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2834 return;
2837 geometry->u.path.state = D2D_GEOMETRY_STATE_FIGURE;
2840 static void STDMETHODCALLTYPE d2d_geometry_sink_AddLines(ID2D1GeometrySink *iface,
2841 const D2D1_POINT_2F *points, UINT32 count)
2843 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2844 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2845 unsigned int i;
2847 TRACE("iface %p, points %p, count %u.\n", iface, points, count);
2849 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2851 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2852 return;
2855 for (i = 0; i < count; ++i)
2857 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_LINE;
2858 if (!d2d_figure_add_vertex(figure, points[i]))
2860 ERR("Failed to add vertex.\n");
2861 return;
2865 geometry->u.path.segment_count += count;
2868 static void STDMETHODCALLTYPE d2d_geometry_sink_AddBeziers(ID2D1GeometrySink *iface,
2869 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
2871 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2872 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2873 D2D1_POINT_2F p;
2874 unsigned int i;
2876 TRACE("iface %p, beziers %p, count %u.\n", iface, beziers, count);
2878 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2880 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2881 return;
2884 for (i = 0; i < count; ++i)
2886 D2D1_RECT_F bezier_bounds;
2888 if (!d2d_figure_add_original_bezier_controls(figure, 1, &beziers[i].point1)
2889 || !d2d_figure_add_original_bezier_controls(figure, 1, &beziers[i].point2))
2891 ERR("Failed to add cubic Bézier controls.\n");
2892 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2893 return;
2896 /* FIXME: This tries to approximate a cubic Bézier with a quadratic one. */
2897 p.x = (beziers[i].point1.x + beziers[i].point2.x) * 0.75f;
2898 p.y = (beziers[i].point1.y + beziers[i].point2.y) * 0.75f;
2899 p.x -= (figure->vertices[figure->vertex_count - 1].x + beziers[i].point3.x) * 0.25f;
2900 p.y -= (figure->vertices[figure->vertex_count - 1].y + beziers[i].point3.y) * 0.25f;
2901 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_BEZIER;
2903 d2d_rect_get_bezier_bounds(&bezier_bounds, &figure->vertices[figure->vertex_count - 1],
2904 &p, &beziers[i].point3);
2906 if (!d2d_figure_add_bezier_controls(figure, 1, &p))
2908 ERR("Failed to add bezier control.\n");
2909 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2910 return;
2913 if (!d2d_figure_add_vertex(figure, beziers[i].point3))
2915 ERR("Failed to add bezier vertex.\n");
2916 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2917 return;
2920 d2d_rect_union(&figure->bounds, &bezier_bounds);
2923 geometry->u.path.segment_count += count;
2926 static void STDMETHODCALLTYPE d2d_geometry_sink_EndFigure(ID2D1GeometrySink *iface, D2D1_FIGURE_END figure_end)
2928 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2929 struct d2d_figure *figure;
2931 TRACE("iface %p, figure_end %#x.\n", iface, figure_end);
2933 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2935 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2936 return;
2939 figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2940 if (memcmp(&figure->vertices[0], &figure->vertices[figure->vertex_count - 1], sizeof(*figure->vertices)))
2941 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_LINE;
2942 else
2943 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_END;
2944 if (figure_end == D2D1_FIGURE_END_CLOSED)
2946 ++geometry->u.path.segment_count;
2947 figure->flags |= D2D_FIGURE_FLAG_CLOSED;
2950 if (!d2d_geometry_add_figure_outline(geometry, figure, figure_end))
2952 ERR("Failed to add figure outline.\n");
2953 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2954 return;
2957 geometry->u.path.state = D2D_GEOMETRY_STATE_OPEN;
2960 static void d2d_path_geometry_free_figures(struct d2d_geometry *geometry)
2962 size_t i;
2964 if (!geometry->u.path.figures)
2965 return;
2967 for (i = 0; i < geometry->u.path.figure_count; ++i)
2969 free(geometry->u.path.figures[i].original_bezier_controls);
2970 free(geometry->u.path.figures[i].bezier_controls);
2971 free(geometry->u.path.figures[i].vertices);
2973 free(geometry->u.path.figures);
2974 geometry->u.path.figures = NULL;
2975 geometry->u.path.figures_size = 0;
2978 static BOOL d2d_geometry_get_bezier_segment_idx(struct d2d_geometry *geometry, struct d2d_segment_idx *idx, BOOL next)
2980 if (next)
2982 ++idx->vertex_idx;
2983 ++idx->control_idx;
2986 for (; idx->figure_idx < geometry->u.path.figure_count; ++idx->figure_idx, idx->vertex_idx = idx->control_idx = 0)
2988 struct d2d_figure *figure = &geometry->u.path.figures[idx->figure_idx];
2990 if (!figure->bezier_control_count || figure->flags & D2D_FIGURE_FLAG_HOLLOW)
2991 continue;
2993 for (; idx->vertex_idx < figure->vertex_count; ++idx->vertex_idx)
2995 if (d2d_vertex_type_is_bezier(figure->vertex_types[idx->vertex_idx]))
2996 return TRUE;
3000 return FALSE;
3003 static BOOL d2d_geometry_get_first_bezier_segment_idx(struct d2d_geometry *geometry, struct d2d_segment_idx *idx)
3005 memset(idx, 0, sizeof(*idx));
3007 return d2d_geometry_get_bezier_segment_idx(geometry, idx, FALSE);
3010 static BOOL d2d_geometry_get_next_bezier_segment_idx(struct d2d_geometry *geometry, struct d2d_segment_idx *idx)
3012 return d2d_geometry_get_bezier_segment_idx(geometry, idx, TRUE);
3015 static BOOL d2d_geometry_check_bezier_overlap(struct d2d_geometry *geometry,
3016 const struct d2d_segment_idx *idx_p, const struct d2d_segment_idx *idx_q)
3018 const D2D1_POINT_2F *a[3], *b[3], *p[2], *q;
3019 const struct d2d_figure *figure;
3020 D2D1_POINT_2F v_q[3], v_p, v_qp;
3021 unsigned int i, j, score;
3022 float det, t;
3024 figure = &geometry->u.path.figures[idx_p->figure_idx];
3025 a[0] = &figure->vertices[idx_p->vertex_idx];
3026 a[1] = &figure->bezier_controls[idx_p->control_idx];
3027 a[2] = &figure->vertices[idx_p->vertex_idx + 1];
3029 figure = &geometry->u.path.figures[idx_q->figure_idx];
3030 b[0] = &figure->vertices[idx_q->vertex_idx];
3031 b[1] = &figure->bezier_controls[idx_q->control_idx];
3032 b[2] = &figure->vertices[idx_q->vertex_idx + 1];
3034 if (d2d_point_ccw(a[0], a[1], a[2]) == 0.0f || d2d_point_ccw(b[0], b[1], b[2]) == 0.0f)
3035 return FALSE;
3037 d2d_point_subtract(&v_q[0], b[1], b[0]);
3038 d2d_point_subtract(&v_q[1], b[2], b[0]);
3039 d2d_point_subtract(&v_q[2], b[1], b[2]);
3041 /* Check for intersections between the edges. Strictly speaking we'd only
3042 * need to check 8 of the 9 possible intersections, since if there's any
3043 * intersection there has to be a second intersection as well. */
3044 for (i = 0; i < 3; ++i)
3046 d2d_point_subtract(&v_p, a[(i & 1) + 1], a[i & 2]);
3047 for (j = 0; j < 3; ++j)
3049 det = v_p.x * v_q[j].y - v_p.y * v_q[j].x;
3050 if (det == 0.0f)
3051 continue;
3053 d2d_point_subtract(&v_qp, a[i & 2], b[j & 2]);
3054 t = (v_q[j].x * v_qp.y - v_q[j].y * v_qp.x) / det;
3055 if (t <= 0.0f || t >= 1.0f)
3056 continue;
3058 t = (v_p.x * v_qp.y - v_p.y * v_qp.x) / det;
3059 if (t <= 0.0f || t >= 1.0f)
3060 continue;
3062 return TRUE;
3066 /* Check if one triangle is contained within the other. */
3067 for (j = 0, score = 0, q = a[1], p[0] = b[2]; j < 3; ++j)
3069 p[1] = b[j];
3070 d2d_point_subtract(&v_p, p[1], p[0]);
3071 d2d_point_subtract(&v_qp, q, p[0]);
3073 if ((q->y < p[0]->y) != (q->y < p[1]->y) && v_qp.x < v_p.x * (v_qp.y / v_p.y))
3074 ++score;
3076 p[0] = p[1];
3079 if (score & 1)
3080 return TRUE;
3082 for (j = 0, score = 0, q = b[1], p[0] = a[2]; j < 3; ++j)
3084 p[1] = a[j];
3085 d2d_point_subtract(&v_p, p[1], p[0]);
3086 d2d_point_subtract(&v_qp, q, p[0]);
3088 if ((q->y < p[0]->y) != (q->y < p[1]->y) && v_qp.x < v_p.x * (v_qp.y / v_p.y))
3089 ++score;
3091 p[0] = p[1];
3094 return score & 1;
3097 static float d2d_geometry_bezier_ccw(struct d2d_geometry *geometry, const struct d2d_segment_idx *idx)
3099 const struct d2d_figure *figure = &geometry->u.path.figures[idx->figure_idx];
3100 size_t next = idx->vertex_idx + 1;
3102 return d2d_point_ccw(&figure->vertices[idx->vertex_idx],
3103 &figure->bezier_controls[idx->control_idx], &figure->vertices[next]);
3106 static BOOL d2d_geometry_split_bezier(struct d2d_geometry *geometry, const struct d2d_segment_idx *idx)
3108 const D2D1_POINT_2F *p[3];
3109 struct d2d_figure *figure;
3110 D2D1_POINT_2F q[3];
3111 size_t next;
3113 figure = &geometry->u.path.figures[idx->figure_idx];
3114 p[0] = &figure->vertices[idx->vertex_idx];
3115 p[1] = &figure->bezier_controls[idx->control_idx];
3116 next = idx->vertex_idx + 1;
3117 p[2] = &figure->vertices[next];
3119 d2d_point_lerp(&q[0], p[0], p[1], 0.5f);
3120 d2d_point_lerp(&q[1], p[1], p[2], 0.5f);
3121 d2d_point_lerp(&q[2], &q[0], &q[1], 0.5f);
3123 figure->bezier_controls[idx->control_idx] = q[0];
3124 if (!(d2d_figure_insert_bezier_controls(figure, idx->control_idx + 1, 1, &q[1])))
3125 return FALSE;
3126 if (!(d2d_figure_insert_vertex(figure, idx->vertex_idx + 1, q[2])))
3127 return FALSE;
3128 figure->vertex_types[idx->vertex_idx + 1] = D2D_VERTEX_TYPE_SPLIT_BEZIER;
3130 return TRUE;
3133 static HRESULT d2d_geometry_resolve_beziers(struct d2d_geometry *geometry)
3135 struct d2d_segment_idx idx_p, idx_q;
3136 struct d2d_curve_vertex *b;
3137 const D2D1_POINT_2F *p[3];
3138 struct d2d_figure *figure;
3139 size_t bezier_idx, i;
3141 if (!d2d_geometry_get_first_bezier_segment_idx(geometry, &idx_p))
3142 return S_OK;
3144 /* Split overlapping bezier control triangles. */
3145 while (d2d_geometry_get_next_bezier_segment_idx(geometry, &idx_p))
3147 d2d_geometry_get_first_bezier_segment_idx(geometry, &idx_q);
3148 while (idx_q.figure_idx < idx_p.figure_idx || idx_q.vertex_idx < idx_p.vertex_idx)
3150 while (d2d_geometry_check_bezier_overlap(geometry, &idx_p, &idx_q))
3152 if (fabsf(d2d_geometry_bezier_ccw(geometry, &idx_q)) > fabsf(d2d_geometry_bezier_ccw(geometry, &idx_p)))
3154 if (!d2d_geometry_split_bezier(geometry, &idx_q))
3155 return E_OUTOFMEMORY;
3156 if (idx_p.figure_idx == idx_q.figure_idx)
3158 ++idx_p.vertex_idx;
3159 ++idx_p.control_idx;
3162 else
3164 if (!d2d_geometry_split_bezier(geometry, &idx_p))
3165 return E_OUTOFMEMORY;
3168 d2d_geometry_get_next_bezier_segment_idx(geometry, &idx_q);
3172 for (i = 0; i < geometry->u.path.figure_count; ++i)
3174 if (geometry->u.path.figures[i].flags & D2D_FIGURE_FLAG_HOLLOW)
3175 continue;
3176 geometry->fill.bezier_vertex_count += 3 * geometry->u.path.figures[i].bezier_control_count;
3179 if (!(geometry->fill.bezier_vertices = calloc(geometry->fill.bezier_vertex_count,
3180 sizeof(*geometry->fill.bezier_vertices))))
3182 ERR("Failed to allocate bezier vertices array.\n");
3183 geometry->fill.bezier_vertex_count = 0;
3184 return E_OUTOFMEMORY;
3187 bezier_idx = 0;
3188 d2d_geometry_get_first_bezier_segment_idx(geometry, &idx_p);
3189 for (;;)
3191 float sign = -1.0f;
3193 figure = &geometry->u.path.figures[idx_p.figure_idx];
3194 p[0] = &figure->vertices[idx_p.vertex_idx];
3195 p[1] = &figure->bezier_controls[idx_p.control_idx];
3197 i = idx_p.vertex_idx + 1;
3198 if (d2d_path_geometry_point_inside(geometry, p[1], FALSE))
3200 sign = 1.0f;
3201 d2d_figure_insert_vertex(figure, i, *p[1]);
3202 /* Inserting a vertex potentially invalidates p[0]. */
3203 p[0] = &figure->vertices[idx_p.vertex_idx];
3204 ++i;
3207 if (i == figure->vertex_count)
3208 i = 0;
3209 p[2] = &figure->vertices[i];
3211 b = &geometry->fill.bezier_vertices[bezier_idx * 3];
3212 d2d_curve_vertex_set(&b[0], p[0], 0.0f, 0.0f, sign);
3213 d2d_curve_vertex_set(&b[1], p[1], 0.5f, 0.0f, sign);
3214 d2d_curve_vertex_set(&b[2], p[2], 1.0f, 1.0f, sign);
3216 if (!d2d_geometry_get_next_bezier_segment_idx(geometry, &idx_p))
3217 break;
3218 ++bezier_idx;
3221 return S_OK;
3224 static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_Close(ID2D1GeometrySink *iface)
3226 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
3227 HRESULT hr = E_FAIL;
3229 TRACE("iface %p.\n", iface);
3231 if (geometry->u.path.state != D2D_GEOMETRY_STATE_OPEN)
3233 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
3234 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3235 return D2DERR_WRONG_STATE;
3237 geometry->u.path.state = D2D_GEOMETRY_STATE_CLOSED;
3239 if (!d2d_geometry_intersect_self(geometry))
3240 goto done;
3241 if (FAILED(hr = d2d_geometry_resolve_beziers(geometry)))
3242 goto done;
3243 if (FAILED(hr = d2d_path_geometry_triangulate(geometry)))
3244 goto done;
3246 done:
3247 if (FAILED(hr))
3249 free(geometry->fill.bezier_vertices);
3250 geometry->fill.bezier_vertices = NULL;
3251 geometry->fill.bezier_vertex_count = 0;
3252 d2d_path_geometry_free_figures(geometry);
3253 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3255 return hr;
3258 static void STDMETHODCALLTYPE d2d_geometry_sink_AddLine(ID2D1GeometrySink *iface, D2D1_POINT_2F point)
3260 TRACE("iface %p, point %s.\n", iface, debug_d2d_point_2f(&point));
3262 d2d_geometry_sink_AddLines(iface, &point, 1);
3265 static void STDMETHODCALLTYPE d2d_geometry_sink_AddBezier(ID2D1GeometrySink *iface, const D2D1_BEZIER_SEGMENT *bezier)
3267 TRACE("iface %p, bezier %p.\n", iface, bezier);
3269 d2d_geometry_sink_AddBeziers(iface, bezier, 1);
3272 static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBezier(ID2D1GeometrySink *iface,
3273 const D2D1_QUADRATIC_BEZIER_SEGMENT *bezier)
3275 TRACE("iface %p, bezier %p.\n", iface, bezier);
3277 ID2D1GeometrySink_AddQuadraticBeziers(iface, bezier, 1);
3280 static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBeziers(ID2D1GeometrySink *iface,
3281 const D2D1_QUADRATIC_BEZIER_SEGMENT *beziers, UINT32 bezier_count)
3283 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
3284 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
3285 unsigned int i;
3287 TRACE("iface %p, beziers %p, bezier_count %u.\n", iface, beziers, bezier_count);
3289 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
3291 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3292 return;
3295 for (i = 0; i < bezier_count; ++i)
3297 D2D1_RECT_F bezier_bounds;
3298 D2D1_POINT_2F p[2];
3300 /* Construct a cubic curve. */
3301 d2d_point_lerp(&p[0], &figure->vertices[figure->vertex_count - 1], &beziers[i].point1, 2.0f / 3.0f);
3302 d2d_point_lerp(&p[1], &beziers[i].point2, &beziers[i].point1, 2.0f / 3.0f);
3303 if (!d2d_figure_add_original_bezier_controls(figure, 2, p))
3305 ERR("Failed to add cubic Bézier controls.\n");
3306 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3307 return;
3310 d2d_rect_get_bezier_bounds(&bezier_bounds, &figure->vertices[figure->vertex_count - 1],
3311 &beziers[i].point1, &beziers[i].point2);
3313 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_BEZIER;
3314 if (!d2d_figure_add_bezier_controls(figure, 1, &beziers[i].point1))
3316 ERR("Failed to add bezier.\n");
3317 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3318 return;
3321 if (!d2d_figure_add_vertex(figure, beziers[i].point2))
3323 ERR("Failed to add bezier vertex.\n");
3324 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3325 return;
3328 d2d_rect_union(&figure->bounds, &bezier_bounds);
3331 geometry->u.path.segment_count += bezier_count;
3334 static void STDMETHODCALLTYPE d2d_geometry_sink_AddArc(ID2D1GeometrySink *iface, const D2D1_ARC_SEGMENT *arc)
3336 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
3338 FIXME("iface %p, arc %p stub!\n", iface, arc);
3340 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
3342 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3343 return;
3346 if (!d2d_figure_add_vertex(&geometry->u.path.figures[geometry->u.path.figure_count - 1], arc->point))
3348 ERR("Failed to add vertex.\n");
3349 return;
3352 ++geometry->u.path.segment_count;
3355 static const struct ID2D1GeometrySinkVtbl d2d_geometry_sink_vtbl =
3357 d2d_geometry_sink_QueryInterface,
3358 d2d_geometry_sink_AddRef,
3359 d2d_geometry_sink_Release,
3360 d2d_geometry_sink_SetFillMode,
3361 d2d_geometry_sink_SetSegmentFlags,
3362 d2d_geometry_sink_BeginFigure,
3363 d2d_geometry_sink_AddLines,
3364 d2d_geometry_sink_AddBeziers,
3365 d2d_geometry_sink_EndFigure,
3366 d2d_geometry_sink_Close,
3367 d2d_geometry_sink_AddLine,
3368 d2d_geometry_sink_AddBezier,
3369 d2d_geometry_sink_AddQuadraticBezier,
3370 d2d_geometry_sink_AddQuadraticBeziers,
3371 d2d_geometry_sink_AddArc,
3374 static inline struct d2d_geometry *impl_from_ID2D1PathGeometry1(ID2D1PathGeometry1 *iface)
3376 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
3379 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_QueryInterface(ID2D1PathGeometry1 *iface, REFIID iid, void **out)
3381 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
3383 if (IsEqualGUID(iid, &IID_ID2D1PathGeometry1)
3384 || IsEqualGUID(iid, &IID_ID2D1PathGeometry)
3385 || IsEqualGUID(iid, &IID_ID2D1Geometry)
3386 || IsEqualGUID(iid, &IID_ID2D1Resource)
3387 || IsEqualGUID(iid, &IID_IUnknown))
3389 ID2D1PathGeometry1_AddRef(iface);
3390 *out = iface;
3391 return S_OK;
3394 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
3396 *out = NULL;
3397 return E_NOINTERFACE;
3400 static ULONG STDMETHODCALLTYPE d2d_path_geometry_AddRef(ID2D1PathGeometry1 *iface)
3402 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface);
3403 ULONG refcount = InterlockedIncrement(&geometry->refcount);
3405 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
3407 return refcount;
3410 static ULONG STDMETHODCALLTYPE d2d_path_geometry_Release(ID2D1PathGeometry1 *iface)
3412 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface);
3413 ULONG refcount = InterlockedDecrement(&geometry->refcount);
3415 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
3417 if (!refcount)
3419 d2d_path_geometry_free_figures(geometry);
3420 d2d_geometry_cleanup(geometry);
3421 free(geometry);
3424 return refcount;
3427 static void STDMETHODCALLTYPE d2d_path_geometry_GetFactory(ID2D1PathGeometry1 *iface, ID2D1Factory **factory)
3429 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface);
3431 TRACE("iface %p, factory %p.\n", iface, factory);
3433 ID2D1Factory_AddRef(*factory = geometry->factory);
3436 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetBounds(ID2D1PathGeometry1 *iface,
3437 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
3439 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface);
3440 size_t i;
3442 TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
3444 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
3445 return D2DERR_WRONG_STATE;
3447 bounds->left = FLT_MAX;
3448 bounds->top = FLT_MAX;
3449 bounds->right = -FLT_MAX;
3450 bounds->bottom = -FLT_MAX;
3452 if (!transform)
3454 if (geometry->u.path.bounds.left > geometry->u.path.bounds.right
3455 && !isinf(geometry->u.path.bounds.left))
3457 for (i = 0; i < geometry->u.path.figure_count; ++i)
3459 if (geometry->u.path.figures[i].flags & D2D_FIGURE_FLAG_HOLLOW)
3460 continue;
3461 d2d_rect_union(&geometry->u.path.bounds, &geometry->u.path.figures[i].bounds);
3463 if (geometry->u.path.bounds.left > geometry->u.path.bounds.right)
3465 geometry->u.path.bounds.left = INFINITY;
3466 geometry->u.path.bounds.right = FLT_MAX;
3467 geometry->u.path.bounds.top = INFINITY;
3468 geometry->u.path.bounds.bottom = FLT_MAX;
3472 *bounds = geometry->u.path.bounds;
3473 return S_OK;
3476 for (i = 0; i < geometry->u.path.figure_count; ++i)
3478 const struct d2d_figure *figure = &geometry->u.path.figures[i];
3479 enum d2d_vertex_type type = D2D_VERTEX_TYPE_NONE;
3480 D2D1_RECT_F bezier_bounds;
3481 D2D1_POINT_2F p, p1, p2;
3482 size_t j, bezier_idx;
3484 if (figure->flags & D2D_FIGURE_FLAG_HOLLOW)
3485 continue;
3487 for (j = 0; j < figure->vertex_count; ++j)
3489 if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
3490 continue;
3492 p = figure->vertices[j];
3493 type = figure->vertex_types[j];
3494 d2d_point_transform(&p, transform, p.x, p.y);
3495 d2d_rect_expand(bounds, &p);
3496 break;
3499 for (bezier_idx = 0, ++j; j < figure->vertex_count; ++j)
3501 enum d2d_vertex_type next_type;
3503 if ((next_type = figure->vertex_types[j]) == D2D_VERTEX_TYPE_NONE
3504 || d2d_vertex_type_is_split_bezier(next_type))
3505 continue;
3507 switch (type)
3509 case D2D_VERTEX_TYPE_LINE:
3510 p = figure->vertices[j];
3511 d2d_point_transform(&p, transform, p.x, p.y);
3512 d2d_rect_expand(bounds, &p);
3513 break;
3515 case D2D_VERTEX_TYPE_BEZIER:
3516 /* FIXME: This attempts to approximate a cubic Bézier with
3517 * a quadratic one. */
3518 p1 = figure->original_bezier_controls[bezier_idx++];
3519 d2d_point_transform(&p1, transform, p1.x, p1.y);
3520 p2 = figure->original_bezier_controls[bezier_idx++];
3521 d2d_point_transform(&p2, transform, p2.x, p2.y);
3522 p1.x = (p1.x + p2.x) * 0.75f;
3523 p1.y = (p1.y + p2.y) * 0.75f;
3524 p2 = figure->vertices[j];
3525 d2d_point_transform(&p2, transform, p2.x, p2.y);
3526 p1.x -= (p.x + p2.x) * 0.25f;
3527 p1.y -= (p.y + p2.y) * 0.25f;
3529 d2d_rect_get_bezier_bounds(&bezier_bounds, &p, &p1, &p2);
3530 d2d_rect_union(bounds, &bezier_bounds);
3531 p = p2;
3532 break;
3534 default:
3535 FIXME("Unhandled vertex type %#x.\n", type);
3536 p = figure->vertices[j];
3537 d2d_point_transform(&p, transform, p.x, p.y);
3538 d2d_rect_expand(bounds, &p);
3539 break;
3542 type = next_type;
3546 if (bounds->left > bounds->right)
3548 bounds->left = INFINITY;
3549 bounds->right = FLT_MAX;
3550 bounds->top = INFINITY;
3551 bounds->bottom = FLT_MAX;
3554 return S_OK;
3557 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetWidenedBounds(ID2D1PathGeometry1 *iface, float stroke_width,
3558 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_RECT_F *bounds)
3560 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
3561 iface, stroke_width, stroke_style, transform, tolerance, bounds);
3563 return E_NOTIMPL;
3566 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_StrokeContainsPoint(ID2D1PathGeometry1 *iface,
3567 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
3568 float tolerance, BOOL *contains)
3570 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface);
3571 enum d2d_vertex_type type = D2D_VERTEX_TYPE_NONE;
3572 unsigned int i, j, bezier_idx;
3573 D2D1_BEZIER_SEGMENT b;
3574 D2D1_POINT_2F p, p1;
3576 TRACE("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p.\n",
3577 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
3579 if (stroke_style)
3580 FIXME("Ignoring stroke style %p.\n", stroke_style);
3582 if (!transform)
3583 transform = &identity;
3585 if (tolerance <= 0.0f)
3586 tolerance = D2D1_DEFAULT_FLATTENING_TOLERANCE;
3588 *contains = FALSE;
3589 for (i = 0; i < geometry->u.path.figure_count; ++i)
3591 const struct d2d_figure *figure = &geometry->u.path.figures[i];
3593 for (j = 0; j < figure->vertex_count; ++j)
3595 if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
3596 continue;
3598 p = figure->vertices[j];
3599 type = figure->vertex_types[j];
3600 break;
3603 for (bezier_idx = 0, ++j; j < figure->vertex_count; ++j)
3605 enum d2d_vertex_type next_type;
3607 if ((next_type = figure->vertex_types[j]) == D2D_VERTEX_TYPE_NONE
3608 || d2d_vertex_type_is_split_bezier(next_type))
3609 continue;
3611 switch (type)
3613 case D2D_VERTEX_TYPE_LINE:
3614 p1 = figure->vertices[j];
3615 *contains = d2d_point_on_line_segment(&point, &p, &p1, transform, stroke_width * 0.5f, tolerance);
3616 p = p1;
3617 break;
3619 case D2D_VERTEX_TYPE_BEZIER:
3620 b.point1 = figure->original_bezier_controls[bezier_idx++];
3621 b.point2 = figure->original_bezier_controls[bezier_idx++];
3622 b.point3 = figure->vertices[j];
3623 *contains = d2d_point_on_bezier_segment(&point, &p, &b, transform, stroke_width, tolerance);
3624 p = b.point3;
3625 break;
3627 default:
3628 FIXME("Unhandled vertex type %#x.\n", type);
3629 p = figure->vertices[j];
3630 break;
3632 if (*contains)
3633 return S_OK;
3634 type = next_type;
3637 if (type == D2D_VERTEX_TYPE_LINE)
3639 p1 = figure->vertices[0];
3640 if (figure->flags & D2D_FIGURE_FLAG_CLOSED)
3641 *contains = d2d_point_on_line_segment(&point, &p, &p1, transform, stroke_width * 0.5f, tolerance);
3644 if (*contains)
3645 return S_OK;
3648 return S_OK;
3651 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_FillContainsPoint(ID2D1PathGeometry1 *iface,
3652 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
3654 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface);
3655 D2D1_MATRIX_3X2_F g_i;
3657 TRACE("iface %p, point %s, transform %p, tolerance %.8e, contains %p.\n",
3658 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
3660 if (transform)
3662 if (!d2d_matrix_invert(&g_i, transform))
3663 return D2DERR_UNSUPPORTED_OPERATION;
3664 d2d_point_transform(&point, &g_i, point.x, point.y);
3667 *contains = !!d2d_path_geometry_point_inside(geometry, &point, FALSE);
3669 TRACE("-> %#x.\n", *contains);
3671 return S_OK;
3674 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_CompareWithGeometry(ID2D1PathGeometry1 *iface,
3675 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
3677 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
3678 iface, geometry, transform, tolerance, relation);
3680 return E_NOTIMPL;
3683 static void d2d_geometry_flatten_cubic(ID2D1SimplifiedGeometrySink *sink, const D2D1_POINT_2F *p0,
3684 const D2D1_BEZIER_SEGMENT *b, float tolerance)
3686 D2D1_BEZIER_SEGMENT b0, b1;
3687 D2D1_POINT_2F q;
3688 float d;
3690 /* It's certainly possible to calculate the maximum deviation of the
3691 * approximation from the curve, but it's a little involved. Instead, note
3692 * that if the control points were evenly spaced and collinear, p1 would
3693 * be exactly between p0 and p2, and p2 would be exactly between p1 and
3694 * p3. The deviation is a decent enough approximation, and much easier to
3695 * calculate.
3697 * p1' = (p0 + p2) / 2
3698 * p2' = (p1 + p3) / 2
3699 * d = ‖p1 - p1'‖₁ + ‖p2 - p2'‖₁ */
3700 d2d_point_lerp(&q, p0, &b->point2, 0.5f);
3701 d2d_point_subtract(&q, &b->point1, &q);
3702 d = fabsf(q.x) + fabsf(q.y);
3703 d2d_point_lerp(&q, &b->point1, &b->point3, 0.5f);
3704 d2d_point_subtract(&q, &b->point2, &q);
3705 d += fabsf(q.x) + fabsf(q.y);
3706 if (d < tolerance)
3708 ID2D1SimplifiedGeometrySink_AddLines(sink, &b->point3, 1);
3709 return;
3712 d2d_point_lerp(&q, &b->point1, &b->point2, 0.5f);
3714 b1.point3 = b->point3;
3715 d2d_point_lerp(&b1.point2, &b1.point3, &b->point2, 0.5f);
3716 d2d_point_lerp(&b1.point1, &b1.point2, &q, 0.5f);
3718 d2d_point_lerp(&b0.point1, p0, &b->point1, 0.5f);
3719 d2d_point_lerp(&b0.point2, &b0.point1, &q, 0.5f);
3720 d2d_point_lerp(&b0.point3, &b0.point2, &b1.point1, 0.5f);
3722 d2d_geometry_flatten_cubic(sink, p0, &b0, tolerance);
3723 ID2D1SimplifiedGeometrySink_SetSegmentFlags(sink, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN);
3724 d2d_geometry_flatten_cubic(sink, &b0.point3, &b1, tolerance);
3725 ID2D1SimplifiedGeometrySink_SetSegmentFlags(sink, D2D1_PATH_SEGMENT_NONE);
3728 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry1 *iface,
3729 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
3730 ID2D1SimplifiedGeometrySink *sink)
3732 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface);
3733 enum d2d_vertex_type type = D2D_VERTEX_TYPE_NONE;
3734 unsigned int i, j, bezier_idx;
3735 D2D1_FIGURE_BEGIN begin;
3736 D2D1_BEZIER_SEGMENT b;
3737 D2D1_FIGURE_END end;
3738 D2D1_POINT_2F p;
3740 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
3741 iface, option, transform, tolerance, sink);
3743 ID2D1SimplifiedGeometrySink_SetFillMode(sink, geometry->u.path.fill_mode);
3744 for (i = 0; i < geometry->u.path.figure_count; ++i)
3746 const struct d2d_figure *figure = &geometry->u.path.figures[i];
3748 for (j = 0; j < figure->vertex_count; ++j)
3750 if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
3751 continue;
3753 p = figure->vertices[j];
3754 if (transform)
3755 d2d_point_transform(&p, transform, p.x, p.y);
3756 begin = figure->flags & D2D_FIGURE_FLAG_HOLLOW ? D2D1_FIGURE_BEGIN_HOLLOW : D2D1_FIGURE_BEGIN_FILLED;
3757 ID2D1SimplifiedGeometrySink_BeginFigure(sink, p, begin);
3758 type = figure->vertex_types[j];
3759 break;
3762 for (bezier_idx = 0, ++j; j < figure->vertex_count; ++j)
3764 enum d2d_vertex_type next_type;
3766 if ((next_type = figure->vertex_types[j]) == D2D_VERTEX_TYPE_NONE
3767 || d2d_vertex_type_is_split_bezier(next_type))
3768 continue;
3770 switch (type)
3772 case D2D_VERTEX_TYPE_LINE:
3773 p = figure->vertices[j];
3774 if (transform)
3775 d2d_point_transform(&p, transform, p.x, p.y);
3776 ID2D1SimplifiedGeometrySink_AddLines(sink, &p, 1);
3777 break;
3779 case D2D_VERTEX_TYPE_BEZIER:
3780 b.point1 = figure->original_bezier_controls[bezier_idx++];
3781 b.point2 = figure->original_bezier_controls[bezier_idx++];
3782 b.point3 = figure->vertices[j];
3783 if (transform)
3785 d2d_point_transform(&b.point1, transform, b.point1.x, b.point1.y);
3786 d2d_point_transform(&b.point2, transform, b.point2.x, b.point2.y);
3787 d2d_point_transform(&b.point3, transform, b.point3.x, b.point3.y);
3790 if (option == D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES)
3791 d2d_geometry_flatten_cubic(sink, &p, &b, tolerance);
3792 else
3793 ID2D1SimplifiedGeometrySink_AddBeziers(sink, &b, 1);
3794 p = b.point3;
3795 break;
3797 default:
3798 FIXME("Unhandled vertex type %#x.\n", type);
3799 p = figure->vertices[j];
3800 if (transform)
3801 d2d_point_transform(&p, transform, p.x, p.y);
3802 ID2D1SimplifiedGeometrySink_AddLines(sink, &p, 1);
3803 break;
3806 type = next_type;
3809 end = figure->flags & D2D_FIGURE_FLAG_CLOSED ? D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN;
3810 ID2D1SimplifiedGeometrySink_EndFigure(sink, end);
3813 return S_OK;
3816 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Tessellate(ID2D1PathGeometry1 *iface,
3817 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *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_CombineWithGeometry(ID2D1PathGeometry1 *iface,
3825 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
3826 float tolerance, ID2D1SimplifiedGeometrySink *sink)
3828 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
3829 iface, geometry, combine_mode, transform, tolerance, sink);
3831 return E_NOTIMPL;
3834 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Outline(ID2D1PathGeometry1 *iface,
3835 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
3837 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
3839 return E_NOTIMPL;
3842 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeArea(ID2D1PathGeometry1 *iface,
3843 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
3845 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
3847 return E_NOTIMPL;
3850 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeLength(ID2D1PathGeometry1 *iface,
3851 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
3853 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
3855 return E_NOTIMPL;
3858 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputePointAtLength(ID2D1PathGeometry1 *iface, float length,
3859 const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point, D2D1_POINT_2F *tangent)
3861 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
3862 iface, length, transform, tolerance, point, tangent);
3864 return E_NOTIMPL;
3867 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Widen(ID2D1PathGeometry1 *iface, float stroke_width,
3868 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
3869 ID2D1SimplifiedGeometrySink *sink)
3871 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
3872 iface, stroke_width, stroke_style, transform, tolerance, sink);
3874 return E_NOTIMPL;
3877 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Open(ID2D1PathGeometry1 *iface, ID2D1GeometrySink **sink)
3879 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface);
3881 TRACE("iface %p, sink %p.\n", iface, sink);
3883 if (geometry->u.path.state != D2D_GEOMETRY_STATE_INITIAL)
3884 return D2DERR_WRONG_STATE;
3886 *sink = &geometry->u.path.ID2D1GeometrySink_iface;
3887 ID2D1GeometrySink_AddRef(*sink);
3889 geometry->u.path.state = D2D_GEOMETRY_STATE_OPEN;
3891 return S_OK;
3894 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Stream(ID2D1PathGeometry1 *iface, ID2D1GeometrySink *sink)
3896 FIXME("iface %p, sink %p stub!\n", iface, sink);
3898 return E_NOTIMPL;
3901 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetSegmentCount(ID2D1PathGeometry1 *iface, UINT32 *count)
3903 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface);
3905 TRACE("iface %p, count %p.\n", iface, count);
3907 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
3908 return D2DERR_WRONG_STATE;
3910 *count = geometry->u.path.segment_count;
3912 return S_OK;
3915 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetFigureCount(ID2D1PathGeometry1 *iface, UINT32 *count)
3917 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface);
3919 TRACE("iface %p, count %p.\n", iface, count);
3921 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
3922 return D2DERR_WRONG_STATE;
3924 *count = geometry->u.path.figure_count;
3926 return S_OK;
3929 static HRESULT STDMETHODCALLTYPE d2d_path_geometry1_ComputePointAndSegmentAtLength(ID2D1PathGeometry1 *iface,
3930 float length, UINT32 start_segment, const D2D1_MATRIX_3X2_F *transform, float tolerance,
3931 D2D1_POINT_DESCRIPTION *point_desc)
3933 FIXME("iface %p, length %.8e, start_segment %u, transform %p, tolerance %.8e, point_desc %p.\n",
3934 iface, length, start_segment, transform, tolerance, point_desc);
3936 return E_NOTIMPL;
3939 static const struct ID2D1PathGeometry1Vtbl d2d_path_geometry_vtbl =
3941 d2d_path_geometry_QueryInterface,
3942 d2d_path_geometry_AddRef,
3943 d2d_path_geometry_Release,
3944 d2d_path_geometry_GetFactory,
3945 d2d_path_geometry_GetBounds,
3946 d2d_path_geometry_GetWidenedBounds,
3947 d2d_path_geometry_StrokeContainsPoint,
3948 d2d_path_geometry_FillContainsPoint,
3949 d2d_path_geometry_CompareWithGeometry,
3950 d2d_path_geometry_Simplify,
3951 d2d_path_geometry_Tessellate,
3952 d2d_path_geometry_CombineWithGeometry,
3953 d2d_path_geometry_Outline,
3954 d2d_path_geometry_ComputeArea,
3955 d2d_path_geometry_ComputeLength,
3956 d2d_path_geometry_ComputePointAtLength,
3957 d2d_path_geometry_Widen,
3958 d2d_path_geometry_Open,
3959 d2d_path_geometry_Stream,
3960 d2d_path_geometry_GetSegmentCount,
3961 d2d_path_geometry_GetFigureCount,
3962 d2d_path_geometry1_ComputePointAndSegmentAtLength,
3965 void d2d_path_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory)
3967 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl);
3968 geometry->u.path.ID2D1GeometrySink_iface.lpVtbl = &d2d_geometry_sink_vtbl;
3969 geometry->u.path.bounds.left = FLT_MAX;
3970 geometry->u.path.bounds.right = -FLT_MAX;
3971 geometry->u.path.bounds.top = FLT_MAX;
3972 geometry->u.path.bounds.bottom = -FLT_MAX;
3975 static inline struct d2d_geometry *impl_from_ID2D1EllipseGeometry(ID2D1EllipseGeometry *iface)
3977 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
3980 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_QueryInterface(ID2D1EllipseGeometry *iface,
3981 REFIID iid, void **out)
3983 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
3985 if (IsEqualGUID(iid, &IID_ID2D1EllipseGeometry)
3986 || IsEqualGUID(iid, &IID_ID2D1Geometry)
3987 || IsEqualGUID(iid, &IID_ID2D1Resource)
3988 || IsEqualGUID(iid, &IID_IUnknown))
3990 ID2D1EllipseGeometry_AddRef(iface);
3991 *out = iface;
3992 return S_OK;
3995 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
3997 *out = NULL;
3998 return E_NOINTERFACE;
4001 static ULONG STDMETHODCALLTYPE d2d_ellipse_geometry_AddRef(ID2D1EllipseGeometry *iface)
4003 struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface);
4004 ULONG refcount = InterlockedIncrement(&geometry->refcount);
4006 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
4008 return refcount;
4011 static ULONG STDMETHODCALLTYPE d2d_ellipse_geometry_Release(ID2D1EllipseGeometry *iface)
4013 struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface);
4014 ULONG refcount = InterlockedDecrement(&geometry->refcount);
4016 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
4018 if (!refcount)
4020 d2d_geometry_cleanup(geometry);
4021 free(geometry);
4024 return refcount;
4027 static void STDMETHODCALLTYPE d2d_ellipse_geometry_GetFactory(ID2D1EllipseGeometry *iface, ID2D1Factory **factory)
4029 struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface);
4031 TRACE("iface %p, factory %p.\n", iface, factory);
4033 ID2D1Factory_AddRef(*factory = geometry->factory);
4036 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_GetBounds(ID2D1EllipseGeometry *iface,
4037 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
4039 FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
4041 return E_NOTIMPL;
4044 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_GetWidenedBounds(ID2D1EllipseGeometry *iface,
4045 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4046 float tolerance, D2D1_RECT_F *bounds)
4048 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
4049 iface, stroke_width, stroke_style, transform, tolerance, bounds);
4051 return E_NOTIMPL;
4054 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_StrokeContainsPoint(ID2D1EllipseGeometry *iface,
4055 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4056 float tolerance, BOOL *contains)
4058 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p stub!\n",
4059 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
4061 return E_NOTIMPL;
4064 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_FillContainsPoint(ID2D1EllipseGeometry *iface,
4065 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
4067 FIXME("iface %p, point %s, transform %p, tolerance %.8e, contains %p stub!\n",
4068 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
4070 return E_NOTIMPL;
4073 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_CompareWithGeometry(ID2D1EllipseGeometry *iface,
4074 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
4076 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
4077 iface, geometry, transform, tolerance, relation);
4079 return E_NOTIMPL;
4082 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Simplify(ID2D1EllipseGeometry *iface,
4083 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4084 ID2D1SimplifiedGeometrySink *sink)
4086 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4087 iface, option, transform, tolerance, sink);
4089 return E_NOTIMPL;
4092 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Tessellate(ID2D1EllipseGeometry *iface,
4093 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
4095 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4097 return E_NOTIMPL;
4100 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_CombineWithGeometry(ID2D1EllipseGeometry *iface,
4101 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
4102 float tolerance, ID2D1SimplifiedGeometrySink *sink)
4104 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4105 iface, geometry, combine_mode, transform, tolerance, sink);
4107 return E_NOTIMPL;
4110 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Outline(ID2D1EllipseGeometry *iface,
4111 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
4113 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4115 return E_NOTIMPL;
4118 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_ComputeArea(ID2D1EllipseGeometry *iface,
4119 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
4121 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
4123 return E_NOTIMPL;
4126 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_ComputeLength(ID2D1EllipseGeometry *iface,
4127 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
4129 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
4131 return E_NOTIMPL;
4134 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_ComputePointAtLength(ID2D1EllipseGeometry *iface,
4135 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
4136 D2D1_POINT_2F *tangent)
4138 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
4139 iface, length, transform, tolerance, point, tangent);
4141 return E_NOTIMPL;
4144 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Widen(ID2D1EllipseGeometry *iface, float stroke_width,
4145 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4146 ID2D1SimplifiedGeometrySink *sink)
4148 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
4149 iface, stroke_width, stroke_style, transform, tolerance, sink);
4151 return E_NOTIMPL;
4154 static void STDMETHODCALLTYPE d2d_ellipse_geometry_GetEllipse(ID2D1EllipseGeometry *iface, D2D1_ELLIPSE *ellipse)
4156 struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface);
4158 TRACE("iface %p, ellipse %p.\n", iface, ellipse);
4160 *ellipse = geometry->u.ellipse.ellipse;
4163 static const struct ID2D1EllipseGeometryVtbl d2d_ellipse_geometry_vtbl =
4165 d2d_ellipse_geometry_QueryInterface,
4166 d2d_ellipse_geometry_AddRef,
4167 d2d_ellipse_geometry_Release,
4168 d2d_ellipse_geometry_GetFactory,
4169 d2d_ellipse_geometry_GetBounds,
4170 d2d_ellipse_geometry_GetWidenedBounds,
4171 d2d_ellipse_geometry_StrokeContainsPoint,
4172 d2d_ellipse_geometry_FillContainsPoint,
4173 d2d_ellipse_geometry_CompareWithGeometry,
4174 d2d_ellipse_geometry_Simplify,
4175 d2d_ellipse_geometry_Tessellate,
4176 d2d_ellipse_geometry_CombineWithGeometry,
4177 d2d_ellipse_geometry_Outline,
4178 d2d_ellipse_geometry_ComputeArea,
4179 d2d_ellipse_geometry_ComputeLength,
4180 d2d_ellipse_geometry_ComputePointAtLength,
4181 d2d_ellipse_geometry_Widen,
4182 d2d_ellipse_geometry_GetEllipse,
4185 HRESULT d2d_ellipse_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_ELLIPSE *ellipse)
4187 D2D1_POINT_2F *v, v1, v2, v3, v4;
4188 struct d2d_face *f;
4189 float l, r, t, b;
4191 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_ellipse_geometry_vtbl);
4192 geometry->u.ellipse.ellipse = *ellipse;
4194 if (!(geometry->fill.vertices = malloc(4 * sizeof(*geometry->fill.vertices))))
4195 goto fail;
4196 if (!d2d_array_reserve((void **)&geometry->fill.faces,
4197 &geometry->fill.faces_size, 2, sizeof(*geometry->fill.faces)))
4198 goto fail;
4200 l = ellipse->point.x - ellipse->radiusX;
4201 r = ellipse->point.x + ellipse->radiusX;
4202 t = ellipse->point.y - ellipse->radiusY;
4203 b = ellipse->point.y + ellipse->radiusY;
4205 d2d_point_set(&v1, r, t);
4206 d2d_point_set(&v2, r, b);
4207 d2d_point_set(&v3, l, b);
4208 d2d_point_set(&v4, l, t);
4210 v = geometry->fill.vertices;
4211 d2d_point_set(&v[0], ellipse->point.x, t);
4212 d2d_point_set(&v[1], r, ellipse->point.y);
4213 d2d_point_set(&v[2], ellipse->point.x, b);
4214 d2d_point_set(&v[3], l, ellipse->point.y);
4215 geometry->fill.vertex_count = 4;
4217 f = geometry->fill.faces;
4218 d2d_face_set(&f[0], 0, 3, 2);
4219 d2d_face_set(&f[1], 0, 2, 1);
4220 geometry->fill.face_count = 2;
4222 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[0], &v1, &v[1]))
4223 goto fail;
4224 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[1], &v2, &v[2]))
4225 goto fail;
4226 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[2], &v3, &v[3]))
4227 goto fail;
4228 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[3], &v4, &v[0]))
4229 goto fail;
4231 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[0], &v1, &v[1]))
4232 goto fail;
4233 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[1], &v2, &v[2]))
4234 goto fail;
4235 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[2], &v3, &v[3]))
4236 goto fail;
4237 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[3], &v4, &v[0]))
4238 goto fail;
4240 return S_OK;
4242 fail:
4243 d2d_geometry_cleanup(geometry);
4244 return E_OUTOFMEMORY;
4247 static inline struct d2d_geometry *impl_from_ID2D1RectangleGeometry(ID2D1RectangleGeometry *iface)
4249 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
4252 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_QueryInterface(ID2D1RectangleGeometry *iface,
4253 REFIID iid, void **out)
4255 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
4257 if (IsEqualGUID(iid, &IID_ID2D1RectangleGeometry)
4258 || IsEqualGUID(iid, &IID_ID2D1Geometry)
4259 || IsEqualGUID(iid, &IID_ID2D1Resource)
4260 || IsEqualGUID(iid, &IID_IUnknown))
4262 ID2D1RectangleGeometry_AddRef(iface);
4263 *out = iface;
4264 return S_OK;
4267 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
4269 *out = NULL;
4270 return E_NOINTERFACE;
4273 static ULONG STDMETHODCALLTYPE d2d_rectangle_geometry_AddRef(ID2D1RectangleGeometry *iface)
4275 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4276 ULONG refcount = InterlockedIncrement(&geometry->refcount);
4278 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
4280 return refcount;
4283 static ULONG STDMETHODCALLTYPE d2d_rectangle_geometry_Release(ID2D1RectangleGeometry *iface)
4285 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4286 ULONG refcount = InterlockedDecrement(&geometry->refcount);
4288 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
4290 if (!refcount)
4292 d2d_geometry_cleanup(geometry);
4293 free(geometry);
4296 return refcount;
4299 static void STDMETHODCALLTYPE d2d_rectangle_geometry_GetFactory(ID2D1RectangleGeometry *iface, ID2D1Factory **factory)
4301 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4303 TRACE("iface %p, factory %p.\n", iface, factory);
4305 ID2D1Factory_AddRef(*factory = geometry->factory);
4308 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_GetBounds(ID2D1RectangleGeometry *iface,
4309 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
4311 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4312 D2D1_RECT_F *rect;
4313 D2D1_POINT_2F p;
4315 TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
4317 rect = &geometry->u.rectangle.rect;
4318 if (!transform)
4320 *bounds = *rect;
4321 return S_OK;
4324 bounds->left = FLT_MAX;
4325 bounds->top = FLT_MAX;
4326 bounds->right = -FLT_MAX;
4327 bounds->bottom = -FLT_MAX;
4329 d2d_point_transform(&p, transform, rect->left, rect->top);
4330 d2d_rect_expand(bounds, &p);
4331 d2d_point_transform(&p, transform, rect->left, rect->bottom);
4332 d2d_rect_expand(bounds, &p);
4333 d2d_point_transform(&p, transform, rect->right, rect->bottom);
4334 d2d_rect_expand(bounds, &p);
4335 d2d_point_transform(&p, transform, rect->right, rect->top);
4336 d2d_rect_expand(bounds, &p);
4338 return S_OK;
4341 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_GetWidenedBounds(ID2D1RectangleGeometry *iface,
4342 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4343 float tolerance, D2D1_RECT_F *bounds)
4345 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
4346 iface, stroke_width, stroke_style, transform, tolerance, bounds);
4348 return E_NOTIMPL;
4351 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_StrokeContainsPoint(ID2D1RectangleGeometry *iface,
4352 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4353 float tolerance, BOOL *contains)
4355 const struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4356 const D2D1_RECT_F *rect = &geometry->u.rectangle.rect;
4357 unsigned int i;
4358 struct
4360 D2D1_POINT_2F s, e;
4362 segments[4];
4364 TRACE("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p.\n",
4365 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
4367 if (stroke_style)
4368 FIXME("Ignoring stroke style %p.\n", stroke_style);
4370 tolerance = fabsf(tolerance);
4372 if (!transform)
4374 D2D1_POINT_2F d, s;
4376 s.x = rect->right - rect->left;
4377 s.y = rect->bottom - rect->top;
4378 d.x = fabsf((rect->right + rect->left) * 0.5f - point.x);
4379 d.y = fabsf((rect->bottom + rect->top) * 0.5f - point.y);
4381 /* Inside test. */
4382 if (d.x <= (s.x - stroke_width) * 0.5f - tolerance && d.y <= (s.y - stroke_width) * 0.5f - tolerance)
4384 *contains = FALSE;
4385 return S_OK;
4388 if (tolerance == 0.0f)
4390 *contains = d.x < (s.x + stroke_width) * 0.5f && d.y < (s.y + stroke_width) * 0.5f;
4392 else
4394 d.x = max(d.x - (s.x + stroke_width) * 0.5f, 0.0f);
4395 d.y = max(d.y - (s.y + stroke_width) * 0.5f, 0.0f);
4397 *contains = d2d_point_dot(&d, &d) < tolerance * tolerance;
4400 return S_OK;
4403 stroke_width *= 0.5f;
4405 d2d_point_set(&segments[0].s, rect->left - stroke_width, rect->bottom);
4406 d2d_point_set(&segments[0].e, rect->right + stroke_width, rect->bottom);
4407 d2d_point_set(&segments[1].s, rect->right, rect->bottom + stroke_width);
4408 d2d_point_set(&segments[1].e, rect->right, rect->top - stroke_width);
4409 d2d_point_set(&segments[2].s, rect->right + stroke_width, rect->top);
4410 d2d_point_set(&segments[2].e, rect->left - stroke_width, rect->top);
4411 d2d_point_set(&segments[3].s, rect->left, rect->top - stroke_width);
4412 d2d_point_set(&segments[3].e, rect->left, rect->bottom + stroke_width);
4414 *contains = FALSE;
4415 for (i = 0; i < ARRAY_SIZE(segments); ++i)
4417 if (d2d_point_on_line_segment(&point, &segments[i].s, &segments[i].e, transform, stroke_width, tolerance))
4419 *contains = TRUE;
4420 break;
4424 return S_OK;
4427 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_FillContainsPoint(ID2D1RectangleGeometry *iface,
4428 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
4430 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4431 D2D1_RECT_F *rect = &geometry->u.rectangle.rect;
4432 float dx, dy;
4434 TRACE("iface %p, point %s, transform %p, tolerance %.8e, contains %p.\n",
4435 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
4437 if (transform)
4439 D2D1_MATRIX_3X2_F g_i;
4441 if (!d2d_matrix_invert(&g_i, transform))
4442 return D2DERR_UNSUPPORTED_OPERATION;
4443 d2d_point_transform(&point, &g_i, point.x, point.y);
4446 if (tolerance == 0.0f)
4447 tolerance = D2D1_DEFAULT_FLATTENING_TOLERANCE;
4449 dx = max(fabsf((rect->right + rect->left) / 2.0f - point.x) - (rect->right - rect->left) / 2.0f, 0.0f);
4450 dy = max(fabsf((rect->bottom + rect->top) / 2.0f - point.y) - (rect->bottom - rect->top) / 2.0f, 0.0f);
4452 *contains = tolerance * tolerance > (dx * dx + dy * dy);
4453 return S_OK;
4456 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_CompareWithGeometry(ID2D1RectangleGeometry *iface,
4457 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
4459 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
4460 iface, geometry, transform, tolerance, relation);
4462 return E_NOTIMPL;
4465 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Simplify(ID2D1RectangleGeometry *iface,
4466 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4467 ID2D1SimplifiedGeometrySink *sink)
4469 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4470 D2D1_RECT_F *rect = &geometry->u.rectangle.rect;
4471 D2D1_POINT_2F p[4];
4472 unsigned int i;
4474 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
4475 iface, option, transform, tolerance, sink);
4477 d2d_point_set(&p[0], rect->left, rect->top);
4478 d2d_point_set(&p[1], rect->right, rect->top);
4479 d2d_point_set(&p[2], rect->right, rect->bottom);
4480 d2d_point_set(&p[3], rect->left, rect->bottom);
4482 if (transform)
4484 for (i = 0; i < ARRAY_SIZE(p); ++i)
4486 d2d_point_transform(&p[i], transform, p[i].x, p[i].y);
4490 ID2D1SimplifiedGeometrySink_SetFillMode(sink, D2D1_FILL_MODE_ALTERNATE);
4491 ID2D1SimplifiedGeometrySink_BeginFigure(sink, p[0], D2D1_FIGURE_BEGIN_FILLED);
4492 ID2D1SimplifiedGeometrySink_AddLines(sink, &p[1], 3);
4493 ID2D1SimplifiedGeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
4495 return S_OK;
4498 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Tessellate(ID2D1RectangleGeometry *iface,
4499 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
4501 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4503 return E_NOTIMPL;
4506 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_CombineWithGeometry(ID2D1RectangleGeometry *iface,
4507 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
4508 float tolerance, ID2D1SimplifiedGeometrySink *sink)
4510 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4511 iface, geometry, combine_mode, transform, tolerance, sink);
4513 return E_NOTIMPL;
4516 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Outline(ID2D1RectangleGeometry *iface,
4517 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
4519 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4521 return E_NOTIMPL;
4524 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputeArea(ID2D1RectangleGeometry *iface,
4525 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
4527 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
4529 return E_NOTIMPL;
4532 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputeLength(ID2D1RectangleGeometry *iface,
4533 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
4535 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
4537 return E_NOTIMPL;
4540 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputePointAtLength(ID2D1RectangleGeometry *iface,
4541 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
4542 D2D1_POINT_2F *tangent)
4544 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
4545 iface, length, transform, tolerance, point, tangent);
4547 return E_NOTIMPL;
4550 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Widen(ID2D1RectangleGeometry *iface, float stroke_width,
4551 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4552 ID2D1SimplifiedGeometrySink *sink)
4554 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
4555 iface, stroke_width, stroke_style, transform, tolerance, sink);
4557 return E_NOTIMPL;
4560 static void STDMETHODCALLTYPE d2d_rectangle_geometry_GetRect(ID2D1RectangleGeometry *iface, D2D1_RECT_F *rect)
4562 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4564 TRACE("iface %p, rect %p.\n", iface, rect);
4566 *rect = geometry->u.rectangle.rect;
4569 static const struct ID2D1RectangleGeometryVtbl d2d_rectangle_geometry_vtbl =
4571 d2d_rectangle_geometry_QueryInterface,
4572 d2d_rectangle_geometry_AddRef,
4573 d2d_rectangle_geometry_Release,
4574 d2d_rectangle_geometry_GetFactory,
4575 d2d_rectangle_geometry_GetBounds,
4576 d2d_rectangle_geometry_GetWidenedBounds,
4577 d2d_rectangle_geometry_StrokeContainsPoint,
4578 d2d_rectangle_geometry_FillContainsPoint,
4579 d2d_rectangle_geometry_CompareWithGeometry,
4580 d2d_rectangle_geometry_Simplify,
4581 d2d_rectangle_geometry_Tessellate,
4582 d2d_rectangle_geometry_CombineWithGeometry,
4583 d2d_rectangle_geometry_Outline,
4584 d2d_rectangle_geometry_ComputeArea,
4585 d2d_rectangle_geometry_ComputeLength,
4586 d2d_rectangle_geometry_ComputePointAtLength,
4587 d2d_rectangle_geometry_Widen,
4588 d2d_rectangle_geometry_GetRect,
4591 HRESULT d2d_rectangle_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_RECT_F *rect)
4593 struct d2d_face *f;
4594 D2D1_POINT_2F *v;
4595 float l, r, t, b;
4597 static const D2D1_POINT_2F prev[] =
4599 { 1.0f, 0.0f},
4600 { 0.0f, -1.0f},
4601 {-1.0f, 0.0f},
4602 { 0.0f, 1.0f},
4604 static const D2D1_POINT_2F next[] =
4606 { 0.0f, 1.0f},
4607 { 1.0f, 0.0f},
4608 { 0.0f, -1.0f},
4609 {-1.0f, 0.0f},
4612 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl);
4613 geometry->u.rectangle.rect = *rect;
4615 if (!(geometry->fill.vertices = malloc(4 * sizeof(*geometry->fill.vertices))))
4616 goto fail;
4617 if (!d2d_array_reserve((void **)&geometry->fill.faces,
4618 &geometry->fill.faces_size, 2, sizeof(*geometry->fill.faces)))
4619 goto fail;
4621 l = min(rect->left, rect->right);
4622 r = max(rect->left, rect->right);
4623 t = min(rect->top, rect->bottom);
4624 b = max(rect->top, rect->bottom);
4626 v = geometry->fill.vertices;
4627 d2d_point_set(&v[0], l, t);
4628 d2d_point_set(&v[1], l, b);
4629 d2d_point_set(&v[2], r, b);
4630 d2d_point_set(&v[3], r, t);
4631 geometry->fill.vertex_count = 4;
4633 f = geometry->fill.faces;
4634 d2d_face_set(&f[0], 1, 2, 0);
4635 d2d_face_set(&f[1], 0, 2, 3);
4636 geometry->fill.face_count = 2;
4638 if (!d2d_geometry_outline_add_line_segment(geometry, &v[0], &v[1]))
4639 goto fail;
4640 if (!d2d_geometry_outline_add_line_segment(geometry, &v[1], &v[2]))
4641 goto fail;
4642 if (!d2d_geometry_outline_add_line_segment(geometry, &v[2], &v[3]))
4643 goto fail;
4644 if (!d2d_geometry_outline_add_line_segment(geometry, &v[3], &v[0]))
4645 goto fail;
4647 if (!d2d_geometry_outline_add_join(geometry, &prev[0], &v[0], &next[0]))
4648 goto fail;
4649 if (!d2d_geometry_outline_add_join(geometry, &prev[1], &v[1], &next[1]))
4650 goto fail;
4651 if (!d2d_geometry_outline_add_join(geometry, &prev[2], &v[2], &next[2]))
4652 goto fail;
4653 if (!d2d_geometry_outline_add_join(geometry, &prev[3], &v[3], &next[3]))
4654 goto fail;
4656 return S_OK;
4658 fail:
4659 d2d_geometry_cleanup(geometry);
4660 return E_OUTOFMEMORY;
4663 static inline struct d2d_geometry *impl_from_ID2D1RoundedRectangleGeometry(ID2D1RoundedRectangleGeometry *iface)
4665 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
4668 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_QueryInterface(ID2D1RoundedRectangleGeometry *iface,
4669 REFIID iid, void **out)
4671 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
4673 if (IsEqualGUID(iid, &IID_ID2D1RoundedRectangleGeometry)
4674 || IsEqualGUID(iid, &IID_ID2D1Geometry)
4675 || IsEqualGUID(iid, &IID_ID2D1Resource)
4676 || IsEqualGUID(iid, &IID_IUnknown))
4678 ID2D1RoundedRectangleGeometry_AddRef(iface);
4679 *out = iface;
4680 return S_OK;
4683 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
4685 *out = NULL;
4686 return E_NOINTERFACE;
4689 static ULONG STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_AddRef(ID2D1RoundedRectangleGeometry *iface)
4691 struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface);
4692 ULONG refcount = InterlockedIncrement(&geometry->refcount);
4694 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
4696 return refcount;
4699 static ULONG STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Release(ID2D1RoundedRectangleGeometry *iface)
4701 struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface);
4702 ULONG refcount = InterlockedDecrement(&geometry->refcount);
4704 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
4706 if (!refcount)
4708 d2d_geometry_cleanup(geometry);
4709 free(geometry);
4712 return refcount;
4715 static void STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetFactory(ID2D1RoundedRectangleGeometry *iface,
4716 ID2D1Factory **factory)
4718 struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface);
4720 TRACE("iface %p, factory %p.\n", iface, factory);
4722 ID2D1Factory_AddRef(*factory = geometry->factory);
4725 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetBounds(ID2D1RoundedRectangleGeometry *iface,
4726 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
4728 FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
4730 return E_NOTIMPL;
4733 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetWidenedBounds(ID2D1RoundedRectangleGeometry *iface,
4734 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4735 float tolerance, D2D1_RECT_F *bounds)
4737 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
4738 iface, stroke_width, stroke_style, transform, tolerance, bounds);
4740 return E_NOTIMPL;
4743 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_StrokeContainsPoint(
4744 ID2D1RoundedRectangleGeometry *iface, D2D1_POINT_2F point, float stroke_width,
4745 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
4747 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p stub!\n",
4748 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
4750 return E_NOTIMPL;
4753 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_FillContainsPoint(ID2D1RoundedRectangleGeometry *iface,
4754 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
4756 FIXME("iface %p, point %s, transform %p, tolerance %.8e, contains %p stub!\n",
4757 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
4759 return E_NOTIMPL;
4762 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_CompareWithGeometry(
4763 ID2D1RoundedRectangleGeometry *iface, ID2D1Geometry *geometry,
4764 const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
4766 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
4767 iface, geometry, transform, tolerance, relation);
4769 return E_NOTIMPL;
4772 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Simplify(ID2D1RoundedRectangleGeometry *iface,
4773 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4774 ID2D1SimplifiedGeometrySink *sink)
4776 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4777 iface, option, transform, tolerance, sink);
4779 return E_NOTIMPL;
4782 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Tessellate(ID2D1RoundedRectangleGeometry *iface,
4783 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
4785 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4787 return E_NOTIMPL;
4790 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_CombineWithGeometry(
4791 ID2D1RoundedRectangleGeometry *iface, ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode,
4792 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
4794 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4795 iface, geometry, combine_mode, transform, tolerance, sink);
4797 return E_NOTIMPL;
4800 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Outline(ID2D1RoundedRectangleGeometry *iface,
4801 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
4803 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4805 return E_NOTIMPL;
4808 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_ComputeArea(ID2D1RoundedRectangleGeometry *iface,
4809 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
4811 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
4813 return E_NOTIMPL;
4816 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_ComputeLength(ID2D1RoundedRectangleGeometry *iface,
4817 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
4819 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
4821 return E_NOTIMPL;
4824 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_ComputePointAtLength(
4825 ID2D1RoundedRectangleGeometry *iface, float length, const D2D1_MATRIX_3X2_F *transform,
4826 float tolerance, D2D1_POINT_2F *point, D2D1_POINT_2F *tangent)
4828 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
4829 iface, length, transform, tolerance, point, tangent);
4831 return E_NOTIMPL;
4834 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Widen(ID2D1RoundedRectangleGeometry *iface,
4835 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4836 float tolerance, ID2D1SimplifiedGeometrySink *sink)
4838 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
4839 iface, stroke_width, stroke_style, transform, tolerance, sink);
4841 return E_NOTIMPL;
4844 static void STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetRoundedRect(ID2D1RoundedRectangleGeometry *iface,
4845 D2D1_ROUNDED_RECT *rounded_rect)
4847 struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface);
4849 TRACE("iface %p, rounded_rect %p.\n", iface, rounded_rect);
4851 *rounded_rect = geometry->u.rounded_rectangle.rounded_rect;
4854 static const struct ID2D1RoundedRectangleGeometryVtbl d2d_rounded_rectangle_geometry_vtbl =
4856 d2d_rounded_rectangle_geometry_QueryInterface,
4857 d2d_rounded_rectangle_geometry_AddRef,
4858 d2d_rounded_rectangle_geometry_Release,
4859 d2d_rounded_rectangle_geometry_GetFactory,
4860 d2d_rounded_rectangle_geometry_GetBounds,
4861 d2d_rounded_rectangle_geometry_GetWidenedBounds,
4862 d2d_rounded_rectangle_geometry_StrokeContainsPoint,
4863 d2d_rounded_rectangle_geometry_FillContainsPoint,
4864 d2d_rounded_rectangle_geometry_CompareWithGeometry,
4865 d2d_rounded_rectangle_geometry_Simplify,
4866 d2d_rounded_rectangle_geometry_Tessellate,
4867 d2d_rounded_rectangle_geometry_CombineWithGeometry,
4868 d2d_rounded_rectangle_geometry_Outline,
4869 d2d_rounded_rectangle_geometry_ComputeArea,
4870 d2d_rounded_rectangle_geometry_ComputeLength,
4871 d2d_rounded_rectangle_geometry_ComputePointAtLength,
4872 d2d_rounded_rectangle_geometry_Widen,
4873 d2d_rounded_rectangle_geometry_GetRoundedRect,
4876 HRESULT d2d_rounded_rectangle_geometry_init(struct d2d_geometry *geometry,
4877 ID2D1Factory *factory, const D2D1_ROUNDED_RECT *rounded_rect)
4879 D2D1_POINT_2F *v, v1, v2, v3, v4;
4880 struct d2d_face *f;
4881 float l, r, t, b;
4882 float rx, ry;
4884 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rounded_rectangle_geometry_vtbl);
4885 geometry->u.rounded_rectangle.rounded_rect = *rounded_rect;
4887 if (!(geometry->fill.vertices = malloc(8 * sizeof(*geometry->fill.vertices))))
4888 goto fail;
4889 if (!d2d_array_reserve((void **)&geometry->fill.faces,
4890 &geometry->fill.faces_size, 6, sizeof(*geometry->fill.faces)))
4891 goto fail;
4893 l = min(rounded_rect->rect.left, rounded_rect->rect.right);
4894 r = max(rounded_rect->rect.left, rounded_rect->rect.right);
4895 t = min(rounded_rect->rect.top, rounded_rect->rect.bottom);
4896 b = max(rounded_rect->rect.top, rounded_rect->rect.bottom);
4898 rx = min(rounded_rect->radiusX, 0.5f * (r - l));
4899 ry = min(rounded_rect->radiusY, 0.5f * (b - t));
4901 d2d_point_set(&v1, r, t);
4902 d2d_point_set(&v2, r, b);
4903 d2d_point_set(&v3, l, b);
4904 d2d_point_set(&v4, l, t);
4906 v = geometry->fill.vertices;
4907 d2d_point_set(&v[0], l + rx, t);
4908 d2d_point_set(&v[1], r - rx, t);
4909 d2d_point_set(&v[2], r, t + ry);
4910 d2d_point_set(&v[3], r, b - ry);
4911 d2d_point_set(&v[4], r - rx, b);
4912 d2d_point_set(&v[5], l + rx, b);
4913 d2d_point_set(&v[6], l, b - ry);
4914 d2d_point_set(&v[7], l, t + ry);
4915 geometry->fill.vertex_count = 8;
4917 f = geometry->fill.faces;
4918 d2d_face_set(&f[0], 0, 7, 6);
4919 d2d_face_set(&f[1], 0, 6, 5);
4920 d2d_face_set(&f[2], 0, 5, 4);
4921 d2d_face_set(&f[3], 0, 4, 1);
4922 d2d_face_set(&f[4], 1, 4, 3);
4923 d2d_face_set(&f[5], 1, 3, 2);
4924 geometry->fill.face_count = 6;
4926 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[1], &v1, &v[2]))
4927 goto fail;
4928 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[3], &v2, &v[4]))
4929 goto fail;
4930 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[5], &v3, &v[6]))
4931 goto fail;
4932 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[7], &v4, &v[0]))
4933 goto fail;
4935 if (!d2d_geometry_outline_add_line_segment(geometry, &v[0], &v[1]))
4936 goto fail;
4937 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[1], &v1, &v[2]))
4938 goto fail;
4939 if (!d2d_geometry_outline_add_line_segment(geometry, &v[2], &v[3]))
4940 goto fail;
4941 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[3], &v2, &v[4]))
4942 goto fail;
4943 if (!d2d_geometry_outline_add_line_segment(geometry, &v[4], &v[5]))
4944 goto fail;
4945 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[5], &v3, &v[6]))
4946 goto fail;
4947 if (!d2d_geometry_outline_add_line_segment(geometry, &v[6], &v[7]))
4948 goto fail;
4949 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[7], &v4, &v[0]))
4950 goto fail;
4952 return S_OK;
4954 fail:
4955 d2d_geometry_cleanup(geometry);
4956 return E_OUTOFMEMORY;
4959 static inline struct d2d_geometry *impl_from_ID2D1TransformedGeometry(ID2D1TransformedGeometry *iface)
4961 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
4964 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_QueryInterface(ID2D1TransformedGeometry *iface,
4965 REFIID iid, void **out)
4967 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
4969 if (IsEqualGUID(iid, &IID_ID2D1TransformedGeometry)
4970 || IsEqualGUID(iid, &IID_ID2D1Geometry)
4971 || IsEqualGUID(iid, &IID_ID2D1Resource)
4972 || IsEqualGUID(iid, &IID_IUnknown))
4974 ID2D1TransformedGeometry_AddRef(iface);
4975 *out = iface;
4976 return S_OK;
4979 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
4981 *out = NULL;
4982 return E_NOINTERFACE;
4985 static ULONG STDMETHODCALLTYPE d2d_transformed_geometry_AddRef(ID2D1TransformedGeometry *iface)
4987 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4988 ULONG refcount = InterlockedIncrement(&geometry->refcount);
4990 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
4992 return refcount;
4995 static ULONG STDMETHODCALLTYPE d2d_transformed_geometry_Release(ID2D1TransformedGeometry *iface)
4997 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4998 ULONG refcount = InterlockedDecrement(&geometry->refcount);
5000 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
5002 if (!refcount)
5004 geometry->outline.arc_faces = NULL;
5005 geometry->outline.arcs = NULL;
5006 geometry->outline.bezier_faces = NULL;
5007 geometry->outline.beziers = NULL;
5008 geometry->outline.faces = NULL;
5009 geometry->outline.vertices = NULL;
5010 geometry->fill.arc_vertices = NULL;
5011 geometry->fill.bezier_vertices = NULL;
5012 geometry->fill.faces = NULL;
5013 geometry->fill.vertices = NULL;
5014 ID2D1Geometry_Release(geometry->u.transformed.src_geometry);
5015 d2d_geometry_cleanup(geometry);
5016 free(geometry);
5019 return refcount;
5022 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetFactory(ID2D1TransformedGeometry *iface,
5023 ID2D1Factory **factory)
5025 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
5027 TRACE("iface %p, factory %p.\n", iface, factory);
5029 ID2D1Factory_AddRef(*factory = geometry->factory);
5032 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_GetBounds(ID2D1TransformedGeometry *iface,
5033 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
5035 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
5036 D2D1_MATRIX_3X2_F g;
5038 TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
5040 g = geometry->transform;
5041 if (transform)
5042 d2d_matrix_multiply(&g, transform);
5044 return ID2D1Geometry_GetBounds(geometry->u.transformed.src_geometry, &g, bounds);
5047 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_GetWidenedBounds(ID2D1TransformedGeometry *iface,
5048 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
5049 float tolerance, D2D1_RECT_F *bounds)
5051 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
5052 iface, stroke_width, stroke_style, transform, tolerance, bounds);
5054 return E_NOTIMPL;
5057 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_StrokeContainsPoint(ID2D1TransformedGeometry *iface,
5058 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
5059 float tolerance, BOOL *contains)
5061 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
5062 D2D1_MATRIX_3X2_F g;
5064 TRACE("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p.\n",
5065 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
5067 g = geometry->transform;
5068 stroke_width /= g.m11;
5069 if (transform)
5070 d2d_matrix_multiply(&g, transform);
5072 if (tolerance <= 0.0f)
5073 tolerance = D2D1_DEFAULT_FLATTENING_TOLERANCE;
5075 return ID2D1Geometry_StrokeContainsPoint(geometry->u.transformed.src_geometry, point, stroke_width, stroke_style,
5076 &g, tolerance, contains);
5079 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_FillContainsPoint(ID2D1TransformedGeometry *iface,
5080 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
5082 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
5083 D2D1_MATRIX_3X2_F g;
5085 TRACE("iface %p, point %s, transform %p, tolerance %.8e, contains %p.\n",
5086 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
5088 g = geometry->transform;
5089 if (transform)
5090 d2d_matrix_multiply(&g, transform);
5092 return ID2D1Geometry_FillContainsPoint(geometry->u.transformed.src_geometry, point, &g, tolerance, contains);
5095 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_CompareWithGeometry(ID2D1TransformedGeometry *iface,
5096 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
5098 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
5099 iface, geometry, transform, tolerance, relation);
5101 return E_NOTIMPL;
5104 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Simplify(ID2D1TransformedGeometry *iface,
5105 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
5106 ID2D1SimplifiedGeometrySink *sink)
5108 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
5109 D2D1_MATRIX_3X2_F g;
5111 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
5112 iface, option, transform, tolerance, sink);
5114 g = geometry->transform;
5115 if (transform)
5116 d2d_matrix_multiply(&g, transform);
5118 return ID2D1Geometry_Simplify(geometry->u.transformed.src_geometry, option, &g, tolerance, sink);
5121 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Tessellate(ID2D1TransformedGeometry *iface,
5122 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
5124 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
5126 return E_NOTIMPL;
5129 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_CombineWithGeometry(ID2D1TransformedGeometry *iface,
5130 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
5131 float tolerance, ID2D1SimplifiedGeometrySink *sink)
5133 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
5134 iface, geometry, combine_mode, transform, tolerance, sink);
5136 return E_NOTIMPL;
5139 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Outline(ID2D1TransformedGeometry *iface,
5140 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
5142 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
5144 return E_NOTIMPL;
5147 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputeArea(ID2D1TransformedGeometry *iface,
5148 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
5150 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
5152 return E_NOTIMPL;
5155 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputeLength(ID2D1TransformedGeometry *iface,
5156 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
5158 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
5160 return E_NOTIMPL;
5163 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputePointAtLength(ID2D1TransformedGeometry *iface,
5164 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
5165 D2D1_POINT_2F *tangent)
5167 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
5168 iface, length, transform, tolerance, point, tangent);
5170 return E_NOTIMPL;
5173 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Widen(ID2D1TransformedGeometry *iface, float stroke_width,
5174 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
5175 ID2D1SimplifiedGeometrySink *sink)
5177 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
5178 iface, stroke_width, stroke_style, transform, tolerance, sink);
5180 return E_NOTIMPL;
5183 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetSourceGeometry(ID2D1TransformedGeometry *iface,
5184 ID2D1Geometry **src_geometry)
5186 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
5188 TRACE("iface %p, src_geometry %p.\n", iface, src_geometry);
5190 ID2D1Geometry_AddRef(*src_geometry = geometry->u.transformed.src_geometry);
5193 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetTransform(ID2D1TransformedGeometry *iface,
5194 D2D1_MATRIX_3X2_F *transform)
5196 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
5198 TRACE("iface %p, transform %p.\n", iface, transform);
5200 *transform = geometry->u.transformed.transform;
5203 static const struct ID2D1TransformedGeometryVtbl d2d_transformed_geometry_vtbl =
5205 d2d_transformed_geometry_QueryInterface,
5206 d2d_transformed_geometry_AddRef,
5207 d2d_transformed_geometry_Release,
5208 d2d_transformed_geometry_GetFactory,
5209 d2d_transformed_geometry_GetBounds,
5210 d2d_transformed_geometry_GetWidenedBounds,
5211 d2d_transformed_geometry_StrokeContainsPoint,
5212 d2d_transformed_geometry_FillContainsPoint,
5213 d2d_transformed_geometry_CompareWithGeometry,
5214 d2d_transformed_geometry_Simplify,
5215 d2d_transformed_geometry_Tessellate,
5216 d2d_transformed_geometry_CombineWithGeometry,
5217 d2d_transformed_geometry_Outline,
5218 d2d_transformed_geometry_ComputeArea,
5219 d2d_transformed_geometry_ComputeLength,
5220 d2d_transformed_geometry_ComputePointAtLength,
5221 d2d_transformed_geometry_Widen,
5222 d2d_transformed_geometry_GetSourceGeometry,
5223 d2d_transformed_geometry_GetTransform,
5226 void d2d_transformed_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
5227 ID2D1Geometry *src_geometry, const D2D_MATRIX_3X2_F *transform)
5229 struct d2d_geometry *src_impl;
5230 D2D_MATRIX_3X2_F g;
5232 src_impl = unsafe_impl_from_ID2D1Geometry(src_geometry);
5234 g = src_impl->transform;
5235 d2d_matrix_multiply(&g, transform);
5236 d2d_geometry_init(geometry, factory, &g, (ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl);
5237 ID2D1Geometry_AddRef(geometry->u.transformed.src_geometry = src_geometry);
5238 geometry->u.transformed.transform = *transform;
5239 geometry->fill = src_impl->fill;
5240 geometry->outline = src_impl->outline;
5243 static inline struct d2d_geometry *impl_from_ID2D1GeometryGroup(ID2D1GeometryGroup *iface)
5245 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
5248 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_QueryInterface(ID2D1GeometryGroup *iface,
5249 REFIID iid, void **out)
5251 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
5253 if (IsEqualGUID(iid, &IID_ID2D1GeometryGroup)
5254 || IsEqualGUID(iid, &IID_ID2D1Geometry)
5255 || IsEqualGUID(iid, &IID_ID2D1Resource)
5256 || IsEqualGUID(iid, &IID_IUnknown))
5258 ID2D1GeometryGroup_AddRef(iface);
5259 *out = iface;
5260 return S_OK;
5263 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
5265 *out = NULL;
5266 return E_NOINTERFACE;
5269 static ULONG STDMETHODCALLTYPE d2d_geometry_group_AddRef(ID2D1GeometryGroup *iface)
5271 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5272 ULONG refcount = InterlockedIncrement(&geometry->refcount);
5274 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
5276 return refcount;
5279 static ULONG STDMETHODCALLTYPE d2d_geometry_group_Release(ID2D1GeometryGroup *iface)
5281 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5282 ULONG refcount = InterlockedDecrement(&geometry->refcount);
5283 unsigned int i;
5285 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
5287 if (!refcount)
5289 for (i = 0; i < geometry->u.group.geometry_count; ++i)
5290 ID2D1Geometry_Release(geometry->u.group.src_geometries[i]);
5291 free(geometry->u.group.src_geometries);
5292 d2d_geometry_cleanup(geometry);
5293 free(geometry);
5296 return refcount;
5299 static void STDMETHODCALLTYPE d2d_geometry_group_GetFactory(ID2D1GeometryGroup *iface,
5300 ID2D1Factory **factory)
5302 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5304 TRACE("iface %p, factory %p.\n", iface, factory);
5306 ID2D1Factory_AddRef(*factory = geometry->factory);
5309 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_GetBounds(ID2D1GeometryGroup *iface,
5310 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
5312 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5313 D2D1_RECT_F rect;
5314 unsigned int i;
5316 TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
5318 bounds->left = FLT_MAX;
5319 bounds->top = FLT_MAX;
5320 bounds->right = -FLT_MAX;
5321 bounds->bottom = -FLT_MAX;
5323 for (i = 0; i < geometry->u.group.geometry_count; ++i)
5325 if (SUCCEEDED(ID2D1Geometry_GetBounds(geometry->u.group.src_geometries[i], transform, &rect)))
5326 d2d_rect_union(bounds, &rect);
5329 return S_OK;
5332 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_GetWidenedBounds(ID2D1GeometryGroup *iface,
5333 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
5334 float tolerance, D2D1_RECT_F *bounds)
5336 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
5337 iface, stroke_width, stroke_style, transform, tolerance, bounds);
5339 return E_NOTIMPL;
5342 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_StrokeContainsPoint(ID2D1GeometryGroup *iface,
5343 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
5344 float tolerance, BOOL *contains)
5346 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p.\n",
5347 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
5349 return E_NOTIMPL;
5352 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_FillContainsPoint(ID2D1GeometryGroup *iface,
5353 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
5355 FIXME("iface %p, point %s, transform %p, tolerance %.8e, contains %p stub!.\n",
5356 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
5358 return E_NOTIMPL;
5361 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_CompareWithGeometry(ID2D1GeometryGroup *iface,
5362 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
5364 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
5365 iface, geometry, transform, tolerance, relation);
5367 return E_NOTIMPL;
5370 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_Simplify(ID2D1GeometryGroup *iface,
5371 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
5372 ID2D1SimplifiedGeometrySink *sink)
5374 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!.\n",
5375 iface, option, transform, tolerance, sink);
5377 return E_NOTIMPL;
5380 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_Tessellate(ID2D1GeometryGroup *iface,
5381 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
5383 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
5385 return E_NOTIMPL;
5388 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_CombineWithGeometry(ID2D1GeometryGroup *iface,
5389 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
5390 float tolerance, ID2D1SimplifiedGeometrySink *sink)
5392 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
5393 iface, geometry, combine_mode, transform, tolerance, sink);
5395 return E_NOTIMPL;
5398 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_Outline(ID2D1GeometryGroup *iface,
5399 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
5401 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
5403 return E_NOTIMPL;
5406 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_ComputeArea(ID2D1GeometryGroup *iface,
5407 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
5409 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
5411 return E_NOTIMPL;
5414 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_ComputeLength(ID2D1GeometryGroup *iface,
5415 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
5417 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
5419 return E_NOTIMPL;
5422 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_ComputePointAtLength(ID2D1GeometryGroup *iface,
5423 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
5424 D2D1_POINT_2F *tangent)
5426 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
5427 iface, length, transform, tolerance, point, tangent);
5429 return E_NOTIMPL;
5432 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_Widen(ID2D1GeometryGroup *iface, float stroke_width,
5433 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
5434 ID2D1SimplifiedGeometrySink *sink)
5436 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
5437 iface, stroke_width, stroke_style, transform, tolerance, sink);
5439 return E_NOTIMPL;
5442 static D2D1_FILL_MODE STDMETHODCALLTYPE d2d_geometry_group_GetFillMode(ID2D1GeometryGroup *iface)
5444 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5446 TRACE("iface %p.\n", iface);
5448 return geometry->u.group.fill_mode;
5451 static UINT32 STDMETHODCALLTYPE d2d_geometry_group_GetSourceGeometryCount(ID2D1GeometryGroup *iface)
5453 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5455 TRACE("iface %p.\n", iface);
5457 return geometry->u.group.geometry_count;
5460 static void STDMETHODCALLTYPE d2d_geometry_group_GetSourceGeometries(ID2D1GeometryGroup *iface,
5461 ID2D1Geometry **geometries, UINT32 geometry_count)
5463 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5464 unsigned int i;
5466 TRACE("iface %p, geometries %p, geometry_count %u.\n", iface, geometries, geometry_count);
5468 geometry_count = min(geometry_count, geometry->u.group.geometry_count);
5469 for (i = 0; i < geometry_count; ++i)
5470 ID2D1Geometry_AddRef(geometries[i] = geometry->u.group.src_geometries[i]);
5473 static const struct ID2D1GeometryGroupVtbl d2d_geometry_group_vtbl =
5475 d2d_geometry_group_QueryInterface,
5476 d2d_geometry_group_AddRef,
5477 d2d_geometry_group_Release,
5478 d2d_geometry_group_GetFactory,
5479 d2d_geometry_group_GetBounds,
5480 d2d_geometry_group_GetWidenedBounds,
5481 d2d_geometry_group_StrokeContainsPoint,
5482 d2d_geometry_group_FillContainsPoint,
5483 d2d_geometry_group_CompareWithGeometry,
5484 d2d_geometry_group_Simplify,
5485 d2d_geometry_group_Tessellate,
5486 d2d_geometry_group_CombineWithGeometry,
5487 d2d_geometry_group_Outline,
5488 d2d_geometry_group_ComputeArea,
5489 d2d_geometry_group_ComputeLength,
5490 d2d_geometry_group_ComputePointAtLength,
5491 d2d_geometry_group_Widen,
5492 d2d_geometry_group_GetFillMode,
5493 d2d_geometry_group_GetSourceGeometryCount,
5494 d2d_geometry_group_GetSourceGeometries,
5497 HRESULT d2d_geometry_group_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
5498 D2D1_FILL_MODE fill_mode, ID2D1Geometry **geometries, unsigned int geometry_count)
5500 unsigned int i;
5502 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_geometry_group_vtbl);
5504 if (!(geometry->u.group.src_geometries = calloc(geometry_count, sizeof(*geometries))))
5506 d2d_geometry_cleanup(geometry);
5507 return E_OUTOFMEMORY;
5510 for (i = 0; i < geometry_count; ++i)
5512 ID2D1Geometry_AddRef(geometry->u.group.src_geometries[i] = geometries[i]);
5514 geometry->u.group.geometry_count = geometry_count;
5515 geometry->u.group.fill_mode = fill_mode;
5517 return S_OK;
5520 struct d2d_geometry *unsafe_impl_from_ID2D1Geometry(ID2D1Geometry *iface)
5522 if (!iface)
5523 return NULL;
5524 assert(iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_ellipse_geometry_vtbl
5525 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl
5526 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl
5527 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_rounded_rectangle_geometry_vtbl
5528 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl
5529 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_geometry_group_vtbl);
5530 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);