d2d1/tests: Add some tests for ID2D1DeviceContext::CreateImageBrush().
[wine.git] / dlls / d2d1 / geometry.c
blobe97bae0b54a7fd1940b7830473be33f41d7061c8
1 /*
2 * Copyright 2015 Henri Verbeet for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "d2d1_private.h"
20 #include <float.h>
22 WINE_DEFAULT_DEBUG_CHANNEL(d2d);
24 #define D2D_FIGURE_FLAG_CLOSED 0x00000001u
25 #define D2D_FIGURE_FLAG_HOLLOW 0x00000002u
27 #define D2D_CDT_EDGE_FLAG_FREED 0x80000000u
28 #define D2D_CDT_EDGE_FLAG_VISITED(r) (1u << (r))
30 #define D2D_FP_EPS (1.0f / (1 << FLT_MANT_DIG))
32 static const D2D1_MATRIX_3X2_F identity =
33 {{{
34 1.0f, 0.0f,
35 0.0f, 1.0f,
36 0.0f, 0.0f,
37 }}};
39 enum d2d_cdt_edge_next
41 D2D_EDGE_NEXT_ORIGIN = 0,
42 D2D_EDGE_NEXT_ROT = 1,
43 D2D_EDGE_NEXT_SYM = 2,
44 D2D_EDGE_NEXT_TOR = 3,
47 enum d2d_vertex_type
49 D2D_VERTEX_TYPE_NONE,
50 D2D_VERTEX_TYPE_LINE,
51 D2D_VERTEX_TYPE_BEZIER,
52 D2D_VERTEX_TYPE_SPLIT_BEZIER,
53 D2D_VERTEX_TYPE_END,
56 struct d2d_segment_idx
58 size_t figure_idx;
59 size_t vertex_idx;
60 size_t control_idx;
63 struct d2d_figure
65 D2D1_POINT_2F *vertices;
66 size_t vertices_size;
67 enum d2d_vertex_type *vertex_types;
68 size_t vertex_types_size;
69 size_t vertex_count;
71 D2D1_POINT_2F *bezier_controls;
72 size_t bezier_controls_size;
73 size_t bezier_control_count;
75 D2D1_POINT_2F *original_bezier_controls;
76 size_t original_bezier_controls_size;
77 size_t original_bezier_control_count;
79 D2D1_RECT_F bounds;
80 unsigned int flags;
83 struct d2d_cdt_edge_ref
85 size_t idx;
86 enum d2d_cdt_edge_next r;
89 struct d2d_cdt_edge
91 struct d2d_cdt_edge_ref next[4];
92 size_t vertex[2];
93 unsigned int flags;
96 struct d2d_cdt
98 struct d2d_cdt_edge *edges;
99 size_t edges_size;
100 size_t edge_count;
101 size_t free_edge;
103 const D2D1_POINT_2F *vertices;
106 struct d2d_geometry_intersection
108 size_t figure_idx;
109 size_t vertex_idx;
110 size_t control_idx;
111 float t;
112 D2D1_POINT_2F p;
115 struct d2d_geometry_intersections
117 struct d2d_geometry_intersection *intersections;
118 size_t intersections_size;
119 size_t intersection_count;
122 struct d2d_fp_two_vec2
124 float x[2];
125 float y[2];
128 struct d2d_fp_fin
130 float *now, *other;
131 size_t length;
134 static void d2d_curve_vertex_set(struct d2d_curve_vertex *b,
135 const D2D1_POINT_2F *p, float u, float v, float sign)
137 b->position = *p;
138 b->texcoord.u = u;
139 b->texcoord.v = v;
140 b->texcoord.sign = sign;
143 static void d2d_face_set(struct d2d_face *f, UINT16 v0, UINT16 v1, UINT16 v2)
145 f->v[0] = v0;
146 f->v[1] = v1;
147 f->v[2] = v2;
150 static void d2d_outline_vertex_set(struct d2d_outline_vertex *v, float x, float y,
151 float prev_x, float prev_y, float next_x, float next_y)
153 d2d_point_set(&v->position, x, y);
154 d2d_point_set(&v->prev, prev_x, prev_y);
155 d2d_point_set(&v->next, next_x, next_y);
158 static void d2d_curve_outline_vertex_set(struct d2d_curve_outline_vertex *a, const D2D1_POINT_2F *position,
159 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2,
160 float prev_x, float prev_y, float next_x, float next_y)
162 a->position = *position;
163 a->p0 = *p0;
164 a->p1 = *p1;
165 a->p2 = *p2;
166 d2d_point_set(&a->prev, prev_x, prev_y);
167 d2d_point_set(&a->next, next_x, next_y);
170 static void d2d_fp_two_sum(float *out, float a, float b)
172 float a_virt, a_round, b_virt, b_round;
174 out[1] = a + b;
175 b_virt = out[1] - a;
176 a_virt = out[1] - b_virt;
177 b_round = b - b_virt;
178 a_round = a - a_virt;
179 out[0] = a_round + b_round;
182 static void d2d_fp_fast_two_sum(float *out, float a, float b)
184 float b_virt;
186 out[1] = a + b;
187 b_virt = out[1] - a;
188 out[0] = b - b_virt;
191 static void d2d_fp_two_two_sum(float *out, const float *a, const float *b)
193 float sum[2];
195 d2d_fp_two_sum(out, a[0], b[0]);
196 d2d_fp_two_sum(sum, a[1], out[1]);
197 d2d_fp_two_sum(&out[1], sum[0], b[1]);
198 d2d_fp_two_sum(&out[2], sum[1], out[2]);
201 static void d2d_fp_two_diff_tail(float *out, float a, float b, float x)
203 float a_virt, a_round, b_virt, b_round;
205 b_virt = a - x;
206 a_virt = x + b_virt;
207 b_round = b_virt - b;
208 a_round = a - a_virt;
209 *out = a_round + b_round;
212 static void d2d_fp_two_two_diff(float *out, const float *a, const float *b)
214 float sum[2], diff;
216 diff = a[0] - b[0];
217 d2d_fp_two_diff_tail(out, a[0], b[0], diff);
218 d2d_fp_two_sum(sum, a[1], diff);
219 diff = sum[0] - b[1];
220 d2d_fp_two_diff_tail(&out[1], sum[0], b[1], diff);
221 d2d_fp_two_sum(&out[2], sum[1], diff);
224 static void d2d_fp_split(float *out, float a)
226 float a_big, c;
228 c = a * ((1 << (FLT_MANT_DIG / 2)) + 1.0f);
229 a_big = c - a;
230 out[1] = c - a_big;
231 out[0] = a - out[1];
234 static void d2d_fp_two_product_presplit(float *out, float a, float b, const float *b_split)
236 float a_split[2], err1, err2, err3;
238 out[1] = a * b;
239 d2d_fp_split(a_split, a);
240 err1 = out[1] - (a_split[1] * b_split[1]);
241 err2 = err1 - (a_split[0] * b_split[1]);
242 err3 = err2 - (a_split[1] * b_split[0]);
243 out[0] = (a_split[0] * b_split[0]) - err3;
246 static void d2d_fp_two_product(float *out, float a, float b)
248 float b_split[2];
250 d2d_fp_split(b_split, b);
251 d2d_fp_two_product_presplit(out, a, b, b_split);
254 static void d2d_fp_square(float *out, float a)
256 float a_split[2], err1, err2;
258 out[1] = a * a;
259 d2d_fp_split(a_split, a);
260 err1 = out[1] - (a_split[1] * a_split[1]);
261 err2 = err1 - ((a_split[1] + a_split[1]) * a_split[0]);
262 out[0] = (a_split[0] * a_split[0]) - err2;
265 static float d2d_fp_estimate(float *a, size_t len)
267 float out = a[0];
268 size_t idx = 1;
270 while (idx < len)
271 out += a[idx++];
273 return out;
276 static void d2d_fp_fast_expansion_sum_zeroelim(float *out, size_t *out_len,
277 const float *a, size_t a_len, const float *b, size_t b_len)
279 float sum[2], q, a_curr, b_curr;
280 size_t a_idx, b_idx, out_idx;
282 a_curr = a[0];
283 b_curr = b[0];
284 a_idx = b_idx = 0;
285 if ((b_curr > a_curr) == (b_curr > -a_curr))
287 q = a_curr;
288 a_curr = a[++a_idx];
290 else
292 q = b_curr;
293 b_curr = b[++b_idx];
295 out_idx = 0;
296 if (a_idx < a_len && b_idx < b_len)
298 if ((b_curr > a_curr) == (b_curr > -a_curr))
300 d2d_fp_fast_two_sum(sum, a_curr, q);
301 a_curr = a[++a_idx];
303 else
305 d2d_fp_fast_two_sum(sum, b_curr, q);
306 b_curr = b[++b_idx];
308 if (sum[0] != 0.0f)
309 out[out_idx++] = sum[0];
310 q = sum[1];
311 while (a_idx < a_len && b_idx < b_len)
313 if ((b_curr > a_curr) == (b_curr > -a_curr))
315 d2d_fp_two_sum(sum, q, a_curr);
316 a_curr = a[++a_idx];
318 else
320 d2d_fp_two_sum(sum, q, b_curr);
321 b_curr = b[++b_idx];
323 if (sum[0] != 0.0f)
324 out[out_idx++] = sum[0];
325 q = sum[1];
328 while (a_idx < a_len)
330 d2d_fp_two_sum(sum, q, a_curr);
331 a_curr = a[++a_idx];
332 if (sum[0] != 0.0f)
333 out[out_idx++] = sum[0];
334 q = sum[1];
336 while (b_idx < b_len)
338 d2d_fp_two_sum(sum, q, b_curr);
339 b_curr = b[++b_idx];
340 if (sum[0] != 0.0f)
341 out[out_idx++] = sum[0];
342 q = sum[1];
344 if (q != 0.0f || !out_idx)
345 out[out_idx++] = q;
347 *out_len = out_idx;
350 static void d2d_fp_scale_expansion_zeroelim(float *out, size_t *out_len, const float *a, size_t a_len, float b)
352 float product[2], sum[2], b_split[2], q[2], a_curr;
353 size_t a_idx, out_idx;
355 d2d_fp_split(b_split, b);
356 d2d_fp_two_product_presplit(q, a[0], b, b_split);
357 out_idx = 0;
358 if (q[0] != 0.0f)
359 out[out_idx++] = q[0];
360 for (a_idx = 1; a_idx < a_len; ++a_idx)
362 a_curr = a[a_idx];
363 d2d_fp_two_product_presplit(product, a_curr, b, b_split);
364 d2d_fp_two_sum(sum, q[1], product[0]);
365 if (sum[0] != 0.0f)
366 out[out_idx++] = sum[0];
367 d2d_fp_fast_two_sum(q, product[1], sum[1]);
368 if (q[0] != 0.0f)
369 out[out_idx++] = q[0];
371 if (q[1] != 0.0f || !out_idx)
372 out[out_idx++] = q[1];
374 *out_len = out_idx;
377 static void d2d_point_subtract(D2D1_POINT_2F *out,
378 const D2D1_POINT_2F *a, const D2D1_POINT_2F *b)
380 out->x = a->x - b->x;
381 out->y = a->y - b->y;
384 static void d2d_point_scale(D2D1_POINT_2F *p, float scale)
386 p->x *= scale;
387 p->y *= scale;
390 static void d2d_point_lerp(D2D1_POINT_2F *out,
391 const D2D1_POINT_2F *a, const D2D1_POINT_2F *b, float t)
393 out->x = a->x * (1.0f - t) + b->x * t;
394 out->y = a->y * (1.0f - t) + b->y * t;
397 static void d2d_point_calculate_bezier(D2D1_POINT_2F *out, const D2D1_POINT_2F *p0,
398 const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2, float t)
400 float t_c = 1.0f - t;
402 out->x = t_c * (t_c * p0->x + t * p1->x) + t * (t_c * p1->x + t * p2->x);
403 out->y = t_c * (t_c * p0->y + t * p1->y) + t * (t_c * p1->y + t * p2->y);
406 static float d2d_point_length(const D2D1_POINT_2F *p)
408 return sqrtf(d2d_point_dot(p, p));
411 static void d2d_point_normalise(D2D1_POINT_2F *p)
413 float l;
415 if ((l = d2d_point_length(p)) != 0.0f)
416 d2d_point_scale(p, 1.0f / l);
419 static BOOL d2d_vertex_type_is_bezier(enum d2d_vertex_type t)
421 return (t == D2D_VERTEX_TYPE_BEZIER || t == D2D_VERTEX_TYPE_SPLIT_BEZIER);
424 static BOOL d2d_vertex_type_is_split_bezier(enum d2d_vertex_type t)
426 return t == D2D_VERTEX_TYPE_SPLIT_BEZIER;
429 /* This implementation is based on the paper "Adaptive Precision
430 * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
431 * associated (Public Domain) code by Jonathan Richard Shewchuk. */
432 static float d2d_point_ccw(const D2D1_POINT_2F *a, const D2D1_POINT_2F *b, const D2D1_POINT_2F *c)
434 static const float err_bound_result = (3.0f + 8.0f * D2D_FP_EPS) * D2D_FP_EPS;
435 static const float err_bound_a = (3.0f + 16.0f * D2D_FP_EPS) * D2D_FP_EPS;
436 static const float err_bound_b = (2.0f + 12.0f * D2D_FP_EPS) * D2D_FP_EPS;
437 static const float err_bound_c = (9.0f + 64.0f * D2D_FP_EPS) * D2D_FP_EPS * D2D_FP_EPS;
438 float det_d[16], det_c2[12], det_c1[8], det_b[4], temp4[4], temp2a[2], temp2b[2], abxacy[2], abyacx[2];
439 size_t det_d_len, det_c2_len, det_c1_len;
440 float det, det_sum, err_bound;
441 struct d2d_fp_two_vec2 ab, ac;
443 ab.x[1] = b->x - a->x;
444 ab.y[1] = b->y - a->y;
445 ac.x[1] = c->x - a->x;
446 ac.y[1] = c->y - a->y;
448 abxacy[1] = ab.x[1] * ac.y[1];
449 abyacx[1] = ab.y[1] * ac.x[1];
450 det = abxacy[1] - abyacx[1];
452 if (abxacy[1] > 0.0f)
454 if (abyacx[1] <= 0.0f)
455 return det;
456 det_sum = abxacy[1] + abyacx[1];
458 else if (abxacy[1] < 0.0f)
460 if (abyacx[1] >= 0.0f)
461 return det;
462 det_sum = -abxacy[1] - abyacx[1];
464 else
466 return det;
469 err_bound = err_bound_a * det_sum;
470 if (det >= err_bound || -det >= err_bound)
471 return det;
473 d2d_fp_two_product(abxacy, ab.x[1], ac.y[1]);
474 d2d_fp_two_product(abyacx, ab.y[1], ac.x[1]);
475 d2d_fp_two_two_diff(det_b, abxacy, abyacx);
477 det = d2d_fp_estimate(det_b, 4);
478 err_bound = err_bound_b * det_sum;
479 if (det >= err_bound || -det >= err_bound)
480 return det;
482 d2d_fp_two_diff_tail(&ab.x[0], b->x, a->x, ab.x[1]);
483 d2d_fp_two_diff_tail(&ab.y[0], b->y, a->y, ab.y[1]);
484 d2d_fp_two_diff_tail(&ac.x[0], c->x, a->x, ac.x[1]);
485 d2d_fp_two_diff_tail(&ac.y[0], c->y, a->y, ac.y[1]);
487 if (ab.x[0] == 0.0f && ab.y[0] == 0.0f && ac.x[0] == 0.0f && ac.y[0] == 0.0f)
488 return det;
490 err_bound = err_bound_c * det_sum + err_bound_result * fabsf(det);
491 det += (ab.x[1] * ac.y[0] + ac.y[1] * ab.x[0]) - (ab.y[1] * ac.x[0] + ac.x[1] * ab.y[0]);
492 if (det >= err_bound || -det >= err_bound)
493 return det;
495 d2d_fp_two_product(temp2a, ab.x[0], ac.y[1]);
496 d2d_fp_two_product(temp2b, ab.y[0], ac.x[1]);
497 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
498 d2d_fp_fast_expansion_sum_zeroelim(det_c1, &det_c1_len, det_b, 4, temp4, 4);
500 d2d_fp_two_product(temp2a, ab.x[1], ac.y[0]);
501 d2d_fp_two_product(temp2b, ab.y[1], ac.x[0]);
502 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
503 d2d_fp_fast_expansion_sum_zeroelim(det_c2, &det_c2_len, det_c1, det_c1_len, temp4, 4);
505 d2d_fp_two_product(temp2a, ab.x[0], ac.y[0]);
506 d2d_fp_two_product(temp2b, ab.y[0], ac.x[0]);
507 d2d_fp_two_two_diff(temp4, temp2a, temp2b);
508 d2d_fp_fast_expansion_sum_zeroelim(det_d, &det_d_len, det_c2, det_c2_len, temp4, 4);
510 return det_d[det_d_len - 1];
513 /* Determine whether the point q is within the given tolerance of the line
514 * segment defined by p0 and p1, with the given stroke width and transform.
515 * Note that we don't care about the tolerance with respect to end-points or
516 * joins here; those are handled separately. */
517 static BOOL d2d_point_on_line_segment(const D2D1_POINT_2F *q, const D2D1_POINT_2F *p0,
518 const D2D1_POINT_2F *p1, const D2D1_MATRIX_3X2_F *transform, float stroke_width, float tolerance)
520 D2D1_POINT_2F v_n, v_p, v_q, v_r;
521 float l;
523 d2d_point_subtract(&v_p, p1, p0);
524 if ((l = d2d_point_length(&v_p)) == 0.0f)
525 return FALSE;
527 /* After (shear) transformation, the line segment is a parallelogram
528 * defined by p⃑' and n⃑':
530 * p⃑ = P₁ - P₀
531 * n⃑ = wp̂⟂
532 * p⃑' = p⃑T
533 * n⃑' = n⃑T */
534 l = stroke_width / l;
535 d2d_point_set(&v_r, transform->_31, transform->_32);
536 d2d_point_transform(&v_n, transform, -v_p.y * l, v_p.x * l);
537 d2d_point_subtract(&v_n, &v_n, &v_r);
538 d2d_point_transform(&v_p, transform, v_p.x, v_p.y);
539 d2d_point_subtract(&v_p, &v_p, &v_r);
541 /* Decompose the vector q⃑ = Q - P₀T into a linear combination of
542 * p⃑' and n⃑':
544 * lq⃑ = xp⃑' + yn⃑' */
545 d2d_point_transform(&v_q, transform, p0->x, p0->y);
546 d2d_point_subtract(&v_q, q, &v_q);
547 l = v_p.x * v_n.y - v_p.y * v_n.x;
548 v_r.x = v_q.x * v_n.y - v_q.y * v_n.x;
549 v_r.y = v_q.x * v_p.y - v_q.y * v_p.x;
551 if (l < 0.0f)
553 l *= -1.0f;
554 v_r.x *= -1.0f;
557 /* Check where Q projects onto p⃑'. */
558 if (v_r.x < 0.0f || v_r.x > l)
559 return FALSE;
561 /* Check where Q projects onto n⃑'. */
562 if (fabs(v_r.y) < l)
563 return TRUE;
565 /* Q lies outside the segment. Check whether the distance to the edge is
566 * within the tolerance.
568 * P₀' = P₀T + n⃑'
569 * q⃑' = Q - P₀'
570 * = q⃑ - n⃑'
572 * The distance is then q⃑' · p̂'⟂. */
574 if (v_r.y > 0.0f)
575 d2d_point_scale(&v_n, -1.0f);
576 d2d_point_subtract(&v_q, &v_q, &v_n);
578 /* Check where Q projects onto p⃑' + n⃑'. */
579 l = d2d_point_dot(&v_q, &v_p);
580 if (l < 0.0f || l > d2d_point_dot(&v_p, &v_p))
581 return FALSE;
583 v_n.x = -v_p.y;
584 v_n.y = v_p.x;
585 d2d_point_normalise(&v_n);
587 return fabsf(d2d_point_dot(&v_q, &v_n)) < tolerance;
590 /* Approximate the Bézier segment with a (wide) line segment. If the point
591 * lies outside the approximation, we're done. If the width of the
592 * approximation is less than the tolerance and the point lies inside, we're
593 * also done. If neither of those is the case, we subdivide the Bézier segment
594 * and try again. */
595 static BOOL d2d_point_on_bezier_segment(const D2D1_POINT_2F *q, const D2D1_POINT_2F *p0,
596 const D2D1_BEZIER_SEGMENT *b, const D2D1_MATRIX_3X2_F *transform, float stroke_width, float tolerance)
598 float d1, d2, d3, d4, d, l, m, w, w2;
599 D2D1_POINT_2F t[7], start, end, v_p;
600 D2D1_BEZIER_SEGMENT b0, b1;
602 m = 1.0f;
603 w = stroke_width * 0.5f;
605 d2d_point_subtract(&v_p, &b->point3, p0);
606 /* If the endpoints coincide, use the line through the control points as
607 * the direction vector. That choice is somewhat arbitrary; other choices
608 * with tighter error bounds exist. */
609 if ((l = d2d_point_dot(&v_p, &v_p)) == 0.0f)
611 d2d_point_subtract(&v_p, &b->point2, &b->point1);
612 /* If the control points also coincide, the curve is in fact a line. */
613 if ((l = d2d_point_dot(&v_p, &v_p)) == 0.0f)
615 d2d_point_subtract(&v_p, &b->point1, p0);
616 end.x = p0->x + 0.75f * v_p.x;
617 end.y = p0->y + 0.75f * v_p.y;
619 return d2d_point_on_line_segment(q, p0, &end, transform, w, tolerance);
621 m = 0.0f;
623 l = sqrtf(l);
624 d2d_point_scale(&v_p, 1.0f / l);
625 m *= l;
627 /* Calculate the width w2 of the approximation. */
629 end.x = p0->x + v_p.x;
630 end.y = p0->y + v_p.y;
631 /* Here, d1 and d2 are the maximum (signed) distance of the control points
632 * from the line through the start and end points. */
633 d1 = d2d_point_ccw(p0, &end, &b->point1);
634 d2 = d2d_point_ccw(p0, &end, &b->point2);
635 /* It can be shown that if the control points of a cubic Bézier curve lie
636 * on the same side of the line through the endpoints, the distance of the
637 * curve itself to that line will be within 3/4 of the distance of the
638 * control points to that line; if the control points lie on opposite
639 * sides, that distance will be within 4/9 of the distance of the
640 * corresponding control point. We're taking that as a given here. */
641 if (d1 * d2 > 0.0f)
643 d1 *= 0.75f;
644 d2 *= 0.75f;
646 else
648 d1 = (d1 * 4.0f) / 9.0f;
649 d2 = (d2 * 4.0f) / 9.0f;
651 w2 = max(fabsf(d1), fabsf(d2));
653 /* Project the control points onto the line through the endpoints of the
654 * curve. We will use these to calculate the endpoints of the
655 * approximation. */
656 d2d_point_subtract(&t[1], &b->point1, p0);
657 d1 = d2d_point_dot(&v_p, &t[1]);
658 d2d_point_subtract(&t[2], &b->point2, p0);
659 d2 = d2d_point_dot(&v_p, &t[2]);
661 /* Calculate the start point of the approximation. Like further above, the
662 * actual curve is somewhat closer to the endpoints than the control
663 * points are. */
664 d = min(min(d1, d2), 0);
665 if (d1 * d2 > 0.0f)
666 d *= 0.75f;
667 else
668 d = (d * 4.0f) / 9.0f;
669 /* Account for the stroke width and tolerance around the endpoints by
670 * adjusting the endpoints here. This matters because there are no joins
671 * in the original geometry for the places where we subdivide the original
672 * curve. We do this here because it's easy; alternatively we could
673 * explicitly test for this when subdividing the curve further below. */
674 d -= min(w + tolerance, w2);
675 start.x = p0->x + d * v_p.x;
676 start.y = p0->y + d * v_p.y;
678 /* Calculate the end point of the approximation. */
679 d1 -= m;
680 d2 -= m;
681 d = max(max(d1, d2), 0);
682 if (d1 * d2 > 0.0f)
683 d = m + d * 0.75f;
684 else
685 d = m + (d * 4.0f) / 9.0f;
686 d += min(w2, w + tolerance);
687 end.x = p0->x + d * v_p.x;
688 end.y = p0->y + d * v_p.y;
690 /* Calculate the error bounds of the approximation. We do this in
691 * transformed space because we need these to be relative to the given
692 * tolerance. */
694 d2d_point_transform(&t[0], transform, p0->x, p0->y);
695 d2d_point_transform(&t[1], transform, b->point1.x, b->point1.y);
696 d2d_point_transform(&t[2], transform, b->point2.x, b->point2.y);
697 d2d_point_transform(&t[3], transform, b->point3.x, b->point3.y);
698 d2d_point_transform(&t[4], transform, start.x, start.y);
699 d2d_point_transform(&t[5], transform, end.x, end.y);
701 d2d_point_subtract(&t[6], &t[5], &t[4]);
702 l = d2d_point_length(&t[6]);
703 /* Here, d1 and d2 are the maximum (signed) distance of the control points
704 * from the line through the start and end points. */
705 d1 = d2d_point_ccw(&t[4], &t[5], &t[1]) / l;
706 d2 = d2d_point_ccw(&t[4], &t[5], &t[2]) / l;
707 if (d1 * d2 > 0.0f)
709 d1 *= 0.75f;
710 d2 *= 0.75f;
712 else
714 d1 = (d1 * 4.0f) / 9.0f;
715 d2 = (d2 * 4.0f) / 9.0f;
717 l = max(max(d1, d2), 0) - min(min(d1, d2), 0);
719 /* d3 and d4 are the (unsigned) distance of the endpoints of the
720 * approximation from the original endpoints. */
721 d2d_point_subtract(&t[6], &t[4], &t[0]);
722 d3 = d2d_point_length(&t[6]);
723 d2d_point_subtract(&t[6], &t[5], &t[3]);
724 d4 = d2d_point_length(&t[6]);
725 l = max(max(d3, d4), l);
727 /* If the error of the approximation is less than the tolerance, and Q
728 * lies on the approximation, the distance of Q to the stroked curve is
729 * definitely within the tolerance. */
730 if (l <= tolerance && d2d_point_on_line_segment(q, &start, &end, transform, w, tolerance - l))
731 return TRUE;
732 /* On the other hand, if the distance of Q to the stroked curve is more
733 * than the sum of the tolerance and d, the distance of Q to the stroked
734 * curve can't possibly be within the tolerance. */
735 if (!d2d_point_on_line_segment(q, &start, &end, transform, w + w2, tolerance))
736 return FALSE;
738 /* Subdivide the curve. Note that simply splitting the segment in half
739 * here works and is easy, but may not be optimal. We could potentially
740 * reduce the number of iterations we need to do by splitting based on
741 * curvature or segment length. */
742 d2d_point_lerp(&t[0], &b->point1, &b->point2, 0.5f);
744 b1.point3 = b->point3;
745 d2d_point_lerp(&b1.point2, &b->point3, &b->point2, 0.5f);
746 d2d_point_lerp(&b1.point1, &t[0], &b1.point2, 0.5f);
748 d2d_point_lerp(&b0.point1, p0, &b->point1, 0.5f);
749 d2d_point_lerp(&b0.point2, &t[0], &b0.point1, 0.5f);
750 d2d_point_lerp(&b0.point3, &b0.point2, &b1.point1, 0.5f);
752 return d2d_point_on_bezier_segment(q, p0, &b0, transform, stroke_width, tolerance)
753 || d2d_point_on_bezier_segment(q, &b0.point3, &b1, transform, stroke_width, tolerance);
756 static void d2d_rect_union(D2D1_RECT_F *l, const D2D1_RECT_F *r)
758 l->left = min(l->left, r->left);
759 l->top = min(l->top, r->top);
760 l->right = max(l->right, r->right);
761 l->bottom = max(l->bottom, r->bottom);
764 static BOOL d2d_rect_check_overlap(const D2D_RECT_F *p, const D2D_RECT_F *q)
766 return p->left < q->right && p->top < q->bottom && p->right > q->left && p->bottom > q->top;
769 static void d2d_rect_get_bezier_bounds(D2D_RECT_F *bounds, const D2D1_POINT_2F *p0,
770 const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2)
772 D2D1_POINT_2F p;
773 float root;
775 bounds->left = p0->x;
776 bounds->top = p0->y;
777 bounds->right = p0->x;
778 bounds->bottom = p0->y;
780 d2d_rect_expand(bounds, p2);
782 /* f(t) = (1 - t)²P₀ + 2(1 - t)tP₁ + t²P₂
783 * f'(t) = 2(1 - t)(P₁ - P₀) + 2t(P₂ - P₁)
784 * = 2(P₂ - 2P₁ + P₀)t + 2(P₁ - P₀)
786 * f'(t) = 0
787 * t = (P₀ - P₁) / (P₂ - 2P₁ + P₀) */
788 root = (p0->x - p1->x) / (p2->x - 2.0f * p1->x + p0->x);
789 if (root > 0.0f && root < 1.0f)
791 d2d_point_calculate_bezier(&p, p0, p1, p2, root);
792 d2d_rect_expand(bounds, &p);
795 root = (p0->y - p1->y) / (p2->y - 2.0f * p1->y + p0->y);
796 if (root > 0.0f && root < 1.0f)
798 d2d_point_calculate_bezier(&p, p0, p1, p2, root);
799 d2d_rect_expand(bounds, &p);
803 static void d2d_rect_get_bezier_segment_bounds(D2D_RECT_F *bounds, const D2D1_POINT_2F *p0,
804 const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2, float start, float end)
806 D2D1_POINT_2F q[3], r[2];
808 d2d_point_lerp(&r[0], p0, p1, start);
809 d2d_point_lerp(&r[1], p1, p2, start);
810 d2d_point_lerp(&q[0], &r[0], &r[1], start);
812 end = (end - start) / (1.0f - start);
813 d2d_point_lerp(&q[1], &q[0], &r[1], end);
814 d2d_point_lerp(&r[0], &r[1], p2, end);
815 d2d_point_lerp(&q[2], &q[1], &r[0], end);
817 d2d_rect_get_bezier_bounds(bounds, &q[0], &q[1], &q[2]);
820 static BOOL d2d_figure_insert_vertex(struct d2d_figure *figure, size_t idx, D2D1_POINT_2F vertex)
822 if (!d2d_array_reserve((void **)&figure->vertices, &figure->vertices_size,
823 figure->vertex_count + 1, sizeof(*figure->vertices)))
825 ERR("Failed to grow vertices array.\n");
826 return FALSE;
829 if (!d2d_array_reserve((void **)&figure->vertex_types, &figure->vertex_types_size,
830 figure->vertex_count + 1, sizeof(*figure->vertex_types)))
832 ERR("Failed to grow vertex types array.\n");
833 return FALSE;
836 memmove(&figure->vertices[idx + 1], &figure->vertices[idx],
837 (figure->vertex_count - idx) * sizeof(*figure->vertices));
838 memmove(&figure->vertex_types[idx + 1], &figure->vertex_types[idx],
839 (figure->vertex_count - idx) * sizeof(*figure->vertex_types));
840 figure->vertices[idx] = vertex;
841 figure->vertex_types[idx] = D2D_VERTEX_TYPE_NONE;
842 d2d_rect_expand(&figure->bounds, &vertex);
843 ++figure->vertex_count;
844 return TRUE;
847 static BOOL d2d_figure_add_vertex(struct d2d_figure *figure, D2D1_POINT_2F vertex)
849 size_t last = figure->vertex_count - 1;
851 if (figure->vertex_count && figure->vertex_types[last] == D2D_VERTEX_TYPE_LINE
852 && !memcmp(&figure->vertices[last], &vertex, sizeof(vertex)))
853 return TRUE;
855 if (!d2d_array_reserve((void **)&figure->vertices, &figure->vertices_size,
856 figure->vertex_count + 1, sizeof(*figure->vertices)))
858 ERR("Failed to grow vertices array.\n");
859 return FALSE;
862 if (!d2d_array_reserve((void **)&figure->vertex_types, &figure->vertex_types_size,
863 figure->vertex_count + 1, sizeof(*figure->vertex_types)))
865 ERR("Failed to grow vertex types array.\n");
866 return FALSE;
869 figure->vertices[figure->vertex_count] = vertex;
870 figure->vertex_types[figure->vertex_count] = D2D_VERTEX_TYPE_NONE;
871 d2d_rect_expand(&figure->bounds, &vertex);
872 ++figure->vertex_count;
873 return TRUE;
876 static BOOL d2d_figure_insert_bezier_controls(struct d2d_figure *figure,
877 size_t idx, size_t count, const D2D1_POINT_2F *p)
879 if (!d2d_array_reserve((void **)&figure->bezier_controls, &figure->bezier_controls_size,
880 figure->bezier_control_count + count, sizeof(*figure->bezier_controls)))
882 ERR("Failed to grow bezier controls array.\n");
883 return FALSE;
886 memmove(&figure->bezier_controls[idx + count], &figure->bezier_controls[idx],
887 (figure->bezier_control_count - idx) * sizeof(*figure->bezier_controls));
888 memcpy(&figure->bezier_controls[idx], p, count * sizeof(*figure->bezier_controls));
889 figure->bezier_control_count += count;
891 return TRUE;
894 static BOOL d2d_figure_add_bezier_controls(struct d2d_figure *figure, size_t count, const D2D1_POINT_2F *p)
896 if (!d2d_array_reserve((void **)&figure->bezier_controls, &figure->bezier_controls_size,
897 figure->bezier_control_count + count, sizeof(*figure->bezier_controls)))
899 ERR("Failed to grow bezier controls array.\n");
900 return FALSE;
903 memcpy(&figure->bezier_controls[figure->bezier_control_count], p, count * sizeof(*figure->bezier_controls));
904 figure->bezier_control_count += count;
906 return TRUE;
909 static BOOL d2d_figure_add_original_bezier_controls(struct d2d_figure *figure, size_t count, const D2D1_POINT_2F *p)
911 if (!d2d_array_reserve((void **)&figure->original_bezier_controls, &figure->original_bezier_controls_size,
912 figure->original_bezier_control_count + count, sizeof(*figure->original_bezier_controls)))
914 ERR("Failed to grow cubic Bézier controls array.\n");
915 return FALSE;
918 memcpy(&figure->original_bezier_controls[figure->original_bezier_control_count],
919 p, count * sizeof(*figure->original_bezier_controls));
920 figure->original_bezier_control_count += count;
922 return TRUE;
925 static void d2d_cdt_edge_rot(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
927 dst->idx = src->idx;
928 dst->r = (src->r + D2D_EDGE_NEXT_ROT) & 3;
931 static void d2d_cdt_edge_sym(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
933 dst->idx = src->idx;
934 dst->r = (src->r + D2D_EDGE_NEXT_SYM) & 3;
937 static void d2d_cdt_edge_tor(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
939 dst->idx = src->idx;
940 dst->r = (src->r + D2D_EDGE_NEXT_TOR) & 3;
943 static void d2d_cdt_edge_next_left(const struct d2d_cdt *cdt,
944 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
946 d2d_cdt_edge_rot(dst, &cdt->edges[src->idx].next[(src->r + D2D_EDGE_NEXT_TOR) & 3]);
949 static void d2d_cdt_edge_next_origin(const struct d2d_cdt *cdt,
950 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
952 *dst = cdt->edges[src->idx].next[src->r];
955 static void d2d_cdt_edge_prev_origin(const struct d2d_cdt *cdt,
956 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
958 d2d_cdt_edge_rot(dst, &cdt->edges[src->idx].next[(src->r + D2D_EDGE_NEXT_ROT) & 3]);
961 static size_t d2d_cdt_edge_origin(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
963 return cdt->edges[e->idx].vertex[e->r >> 1];
966 static size_t d2d_cdt_edge_destination(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
968 return cdt->edges[e->idx].vertex[!(e->r >> 1)];
971 static void d2d_cdt_edge_set_origin(const struct d2d_cdt *cdt,
972 const struct d2d_cdt_edge_ref *e, size_t vertex)
974 cdt->edges[e->idx].vertex[e->r >> 1] = vertex;
977 static void d2d_cdt_edge_set_destination(const struct d2d_cdt *cdt,
978 const struct d2d_cdt_edge_ref *e, size_t vertex)
980 cdt->edges[e->idx].vertex[!(e->r >> 1)] = vertex;
983 static float d2d_cdt_ccw(const struct d2d_cdt *cdt, size_t a, size_t b, size_t c)
985 return d2d_point_ccw(&cdt->vertices[a], &cdt->vertices[b], &cdt->vertices[c]);
988 static BOOL d2d_cdt_rightof(const struct d2d_cdt *cdt, size_t p, const struct d2d_cdt_edge_ref *e)
990 return d2d_cdt_ccw(cdt, p, d2d_cdt_edge_destination(cdt, e), d2d_cdt_edge_origin(cdt, e)) > 0.0f;
993 static BOOL d2d_cdt_leftof(const struct d2d_cdt *cdt, size_t p, const struct d2d_cdt_edge_ref *e)
995 return d2d_cdt_ccw(cdt, p, d2d_cdt_edge_origin(cdt, e), d2d_cdt_edge_destination(cdt, e)) > 0.0f;
998 /* |ax ay|
999 * |bx by| */
1000 static void d2d_fp_four_det2x2(float *out, float ax, float ay, float bx, float by)
1002 float axby[2], aybx[2];
1004 d2d_fp_two_product(axby, ax, by);
1005 d2d_fp_two_product(aybx, ay, bx);
1006 d2d_fp_two_two_diff(out, axby, aybx);
1009 /* (a->x² + a->y²) * det2x2 */
1010 static void d2d_fp_sub_det3x3(float *out, size_t *out_len, const struct d2d_fp_two_vec2 *a, const float *det2x2)
1012 size_t axd_len, ayd_len, axxd_len, ayyd_len;
1013 float axd[8], ayd[8], axxd[16], ayyd[16];
1015 d2d_fp_scale_expansion_zeroelim(axd, &axd_len, det2x2, 4, a->x[1]);
1016 d2d_fp_scale_expansion_zeroelim(axxd, &axxd_len, axd, axd_len, a->x[1]);
1017 d2d_fp_scale_expansion_zeroelim(ayd, &ayd_len, det2x2, 4, a->y[1]);
1018 d2d_fp_scale_expansion_zeroelim(ayyd, &ayyd_len, ayd, ayd_len, a->y[1]);
1019 d2d_fp_fast_expansion_sum_zeroelim(out, out_len, axxd, axxd_len, ayyd, ayyd_len);
1022 /* det_abt = det_ab * c[0]
1023 * fin += c[0] * (az * b - bz * a + c[1] * det_ab * 2.0f) */
1024 static void d2d_cdt_incircle_refine1(struct d2d_fp_fin *fin, float *det_abt, size_t *det_abt_len,
1025 const float *det_ab, float a, const float *az, float b, const float *bz, const float *c)
1027 size_t temp48_len, temp32_len, temp16a_len, temp16b_len, temp16c_len, temp8_len;
1028 float temp48[48], temp32[32], temp16a[16], temp16b[16], temp16c[16], temp8[8];
1029 float *swap;
1031 d2d_fp_scale_expansion_zeroelim(det_abt, det_abt_len, det_ab, 4, c[0]);
1032 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, det_abt, *det_abt_len, 2.0f * c[1]);
1033 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, az, 4, c[0]);
1034 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, temp8, temp8_len, b);
1035 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, bz, 4, c[0]);
1036 d2d_fp_scale_expansion_zeroelim(temp16c, &temp16c_len, temp8, temp8_len, -a);
1037 d2d_fp_fast_expansion_sum_zeroelim(temp32, &temp32_len, temp16a, temp16a_len, temp16b, temp16b_len);
1038 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16c, temp16c_len, temp32, temp32_len);
1039 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
1040 swap = fin->now; fin->now = fin->other; fin->other = swap;
1043 static void d2d_cdt_incircle_refine2(struct d2d_fp_fin *fin, const struct d2d_fp_two_vec2 *a,
1044 const struct d2d_fp_two_vec2 *b, const float *bz, const struct d2d_fp_two_vec2 *c, const float *cz,
1045 const float *axt_det_bc, size_t axt_det_bc_len, const float *ayt_det_bc, size_t ayt_det_bc_len)
1047 size_t temp64_len, temp48_len, temp32a_len, temp32b_len, temp16a_len, temp16b_len, temp8_len;
1048 float temp64[64], temp48[48], temp32a[32], temp32b[32], temp16a[16], temp16b[16], temp8[8];
1049 float bct[8], bctt[4], temp4a[4], temp4b[4], temp2a[2], temp2b[2];
1050 size_t bct_len, bctt_len;
1051 float *swap;
1053 /* bct = (b->x[0] * c->y[1] + b->x[1] * c->y[0]) - (c->x[0] * b->y[1] + c->x[1] * b->y[0]) */
1054 /* bctt = b->x[0] * c->y[0] + c->x[0] * b->y[0] */
1055 if (b->x[0] != 0.0f || b->y[0] != 0.0f || c->x[0] != 0.0f || c->y[0] != 0.0f)
1057 d2d_fp_two_product(temp2a, b->x[0], c->y[1]);
1058 d2d_fp_two_product(temp2b, b->x[1], c->y[0]);
1059 d2d_fp_two_two_sum(temp4a, temp2a, temp2b);
1060 d2d_fp_two_product(temp2a, c->x[0], -b->y[1]);
1061 d2d_fp_two_product(temp2b, c->x[1], -b->y[0]);
1062 d2d_fp_two_two_sum(temp4b, temp2a, temp2b);
1063 d2d_fp_fast_expansion_sum_zeroelim(bct, &bct_len, temp4a, 4, temp4b, 4);
1065 d2d_fp_two_product(temp2a, b->x[0], c->y[0]);
1066 d2d_fp_two_product(temp2b, c->x[0], b->y[0]);
1067 d2d_fp_two_two_diff(bctt, temp2a, temp2b);
1068 bctt_len = 4;
1070 else
1072 bct[0] = 0.0f;
1073 bct_len = 1;
1074 bctt[0] = 0.0f;
1075 bctt_len = 1;
1078 if (a->x[0] != 0.0f)
1080 size_t axt_bct_len, axt_bctt_len;
1081 float axt_bct[16], axt_bctt[8];
1083 /* fin += a->x[0] * (axt_det_bc + bct * 2.0f * a->x[1]) */
1084 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, axt_det_bc, axt_det_bc_len, a->x[0]);
1085 d2d_fp_scale_expansion_zeroelim(axt_bct, &axt_bct_len, bct, bct_len, a->x[0]);
1086 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, axt_bct, axt_bct_len, 2.0f * a->x[1]);
1087 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16a, temp16a_len, temp32a, temp32a_len);
1088 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
1089 swap = fin->now; fin->now = fin->other; fin->other = swap;
1091 if (b->y[0] != 0.0f)
1093 /* fin += a->x[0] * cz * b->y[0] */
1094 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, cz, 4, a->x[0]);
1095 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, temp8, temp8_len, b->y[0]);
1096 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp16a, temp16a_len);
1097 swap = fin->now; fin->now = fin->other; fin->other = swap;
1100 if (c->y[0] != 0.0f)
1102 /* fin -= a->x[0] * bz * c->y[0] */
1103 d2d_fp_scale_expansion_zeroelim(temp8, &temp8_len, bz, 4, -a->x[0]);
1104 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, temp8, temp8_len, c->y[0]);
1105 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp16a, temp16a_len);
1106 swap = fin->now; fin->now = fin->other; fin->other = swap;
1109 /* fin += a->x[0] * (bct * a->x[0] + bctt * (2.0f * a->x[1] + a->x[0])) */
1110 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, axt_bct, axt_bct_len, a->x[0]);
1111 d2d_fp_scale_expansion_zeroelim(axt_bctt, &axt_bctt_len, bctt, bctt_len, a->x[0]);
1112 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, axt_bctt, axt_bctt_len, 2.0f * a->x[1]);
1113 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, axt_bctt, axt_bctt_len, a->x[0]);
1114 d2d_fp_fast_expansion_sum_zeroelim(temp32b, &temp32b_len, temp16a, temp16a_len, temp16b, temp16b_len);
1115 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, temp32a, temp32a_len, temp32b, temp32b_len);
1116 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp64, temp64_len);
1117 swap = fin->now; fin->now = fin->other; fin->other = swap;
1120 if (a->y[0] != 0.0f)
1122 size_t ayt_bct_len, ayt_bctt_len;
1123 float ayt_bct[16], ayt_bctt[8];
1125 /* fin += a->y[0] * (ayt_det_bc + bct * 2.0f * a->y[1]) */
1126 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, ayt_det_bc, ayt_det_bc_len, a->y[0]);
1127 d2d_fp_scale_expansion_zeroelim(ayt_bct, &ayt_bct_len, bct, bct_len, a->y[0]);
1128 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, ayt_bct, ayt_bct_len, 2.0f * a->y[1]);
1129 d2d_fp_fast_expansion_sum_zeroelim(temp48, &temp48_len, temp16a, temp16a_len, temp32a, temp32a_len);
1130 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp48, temp48_len);
1131 swap = fin->now; fin->now = fin->other; fin->other = swap;
1133 /* fin += a->y[0] * (bct * a->y[0] + bctt * (2.0f * a->y[1] + a->y[0])) */
1134 d2d_fp_scale_expansion_zeroelim(temp32a, &temp32a_len, ayt_bct, ayt_bct_len, a->y[0]);
1135 d2d_fp_scale_expansion_zeroelim(ayt_bctt, &ayt_bctt_len, bctt, bctt_len, a->y[0]);
1136 d2d_fp_scale_expansion_zeroelim(temp16a, &temp16a_len, ayt_bctt, ayt_bctt_len, 2.0f * a->y[1]);
1137 d2d_fp_scale_expansion_zeroelim(temp16b, &temp16b_len, ayt_bctt, ayt_bctt_len, a->y[0]);
1138 d2d_fp_fast_expansion_sum_zeroelim(temp32b, &temp32b_len, temp16a, temp16a_len, temp16b, temp16b_len);
1139 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, temp32a, temp32a_len, temp32b, temp32b_len);
1140 d2d_fp_fast_expansion_sum_zeroelim(fin->other, &fin->length, fin->now, fin->length, temp64, temp64_len);
1141 swap = fin->now; fin->now = fin->other; fin->other = swap;
1145 /* Determine if point D is inside or outside the circle defined by points A,
1146 * B, C. As explained in the paper by Guibas and Stolfi, this is equivalent to
1147 * calculating the signed volume of the tetrahedron defined by projecting the
1148 * points onto the paraboloid of revolution x = x² + y²,
1149 * λ:(x, y) → (x, y, x² + y²). I.e., D is inside the cirlce if
1151 * |λ(A) 1|
1152 * |λ(B) 1| > 0
1153 * |λ(C) 1|
1154 * |λ(D) 1|
1156 * After translating D to the origin, that becomes:
1158 * |λ(A-D)|
1159 * |λ(B-D)| > 0
1160 * |λ(C-D)|
1162 * This implementation is based on the paper "Adaptive Precision
1163 * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
1164 * associated (Public Domain) code by Jonathan Richard Shewchuk. */
1165 static BOOL d2d_cdt_incircle(const struct d2d_cdt *cdt, size_t a, size_t b, size_t c, size_t d)
1167 static const float err_bound_result = (3.0f + 8.0f * D2D_FP_EPS) * D2D_FP_EPS;
1168 static const float err_bound_a = (10.0f + 96.0f * D2D_FP_EPS) * D2D_FP_EPS;
1169 static const float err_bound_b = (4.0f + 48.0f * D2D_FP_EPS) * D2D_FP_EPS;
1170 static const float err_bound_c = (44.0f + 576.0f * D2D_FP_EPS) * D2D_FP_EPS * D2D_FP_EPS;
1172 size_t axt_det_bc_len, ayt_det_bc_len, bxt_det_ca_len, byt_det_ca_len, cxt_det_ab_len, cyt_det_ab_len;
1173 float axt_det_bc[8], ayt_det_bc[8], bxt_det_ca[8], byt_det_ca[8], cxt_det_ab[8], cyt_det_ab[8];
1174 float fin1[1152], fin2[1152], temp64[64], sub_det_a[32], sub_det_b[32], sub_det_c[32];
1175 float det_bc[4], det_ca[4], det_ab[4], daz[4], dbz[4], dcz[4], temp2a[2], temp2b[2];
1176 size_t temp64_len, sub_det_a_len, sub_det_b_len, sub_det_c_len;
1177 float dbxdcy, dbydcx, dcxday, dcydax, daxdby, daydbx;
1178 const D2D1_POINT_2F *p = cdt->vertices;
1179 struct d2d_fp_two_vec2 da, db, dc;
1180 float permanent, err_bound, det;
1181 struct d2d_fp_fin fin;
1183 da.x[1] = p[a].x - p[d].x;
1184 da.y[1] = p[a].y - p[d].y;
1185 db.x[1] = p[b].x - p[d].x;
1186 db.y[1] = p[b].y - p[d].y;
1187 dc.x[1] = p[c].x - p[d].x;
1188 dc.y[1] = p[c].y - p[d].y;
1190 daz[3] = da.x[1] * da.x[1] + da.y[1] * da.y[1];
1191 dbxdcy = db.x[1] * dc.y[1];
1192 dbydcx = db.y[1] * dc.x[1];
1194 dbz[3] = db.x[1] * db.x[1] + db.y[1] * db.y[1];
1195 dcxday = dc.x[1] * da.y[1];
1196 dcydax = dc.y[1] * da.x[1];
1198 dcz[3] = dc.x[1] * dc.x[1] + dc.y[1] * dc.y[1];
1199 daxdby = da.x[1] * db.y[1];
1200 daydbx = da.y[1] * db.x[1];
1202 det = daz[3] * (dbxdcy - dbydcx) + dbz[3] * (dcxday - dcydax) + dcz[3] * (daxdby - daydbx);
1203 permanent = daz[3] * (fabsf(dbxdcy) + fabsf(dbydcx))
1204 + dbz[3] * (fabsf(dcxday) + fabsf(dcydax))
1205 + dcz[3] * (fabsf(daxdby) + fabsf(daydbx));
1206 err_bound = err_bound_a * permanent;
1207 if (det > err_bound || -det > err_bound)
1208 return det > 0.0f;
1210 fin.now = fin1;
1211 fin.other = fin2;
1213 d2d_fp_four_det2x2(det_bc, db.x[1], db.y[1], dc.x[1], dc.y[1]);
1214 d2d_fp_sub_det3x3(sub_det_a, &sub_det_a_len, &da, det_bc);
1216 d2d_fp_four_det2x2(det_ca, dc.x[1], dc.y[1], da.x[1], da.y[1]);
1217 d2d_fp_sub_det3x3(sub_det_b, &sub_det_b_len, &db, det_ca);
1219 d2d_fp_four_det2x2(det_ab, da.x[1], da.y[1], db.x[1], db.y[1]);
1220 d2d_fp_sub_det3x3(sub_det_c, &sub_det_c_len, &dc, det_ab);
1222 d2d_fp_fast_expansion_sum_zeroelim(temp64, &temp64_len, sub_det_a, sub_det_a_len, sub_det_b, sub_det_b_len);
1223 d2d_fp_fast_expansion_sum_zeroelim(fin.now, &fin.length, temp64, temp64_len, sub_det_c, sub_det_c_len);
1224 det = d2d_fp_estimate(fin.now, fin.length);
1225 err_bound = err_bound_b * permanent;
1226 if (det >= err_bound || -det >= err_bound)
1227 return det > 0.0f;
1229 d2d_fp_two_diff_tail(&da.x[0], p[a].x, p[d].x, da.x[1]);
1230 d2d_fp_two_diff_tail(&da.y[0], p[a].y, p[d].y, da.y[1]);
1231 d2d_fp_two_diff_tail(&db.x[0], p[b].x, p[d].x, db.x[1]);
1232 d2d_fp_two_diff_tail(&db.y[0], p[b].y, p[d].y, db.y[1]);
1233 d2d_fp_two_diff_tail(&dc.x[0], p[c].x, p[d].x, dc.x[1]);
1234 d2d_fp_two_diff_tail(&dc.y[0], p[c].y, p[d].y, dc.y[1]);
1235 if (da.x[0] == 0.0f && db.x[0] == 0.0f && dc.x[0] == 0.0f
1236 && da.y[0] == 0.0f && db.y[0] == 0.0f && dc.y[0] == 0.0f)
1237 return det > 0.0f;
1239 err_bound = err_bound_c * permanent + err_bound_result * fabsf(det);
1240 det += (daz[3] * ((db.x[1] * dc.y[0] + dc.y[1] * db.x[0]) - (db.y[1] * dc.x[0] + dc.x[1] * db.y[0]))
1241 + 2.0f * (da.x[1] * da.x[0] + da.y[1] * da.y[0]) * (db.x[1] * dc.y[1] - db.y[1] * dc.x[1]))
1242 + (dbz[3] * ((dc.x[1] * da.y[0] + da.y[1] * dc.x[0]) - (dc.y[1] * da.x[0] + da.x[1] * dc.y[0]))
1243 + 2.0f * (db.x[1] * db.x[0] + db.y[1] * db.y[0]) * (dc.x[1] * da.y[1] - dc.y[1] * da.x[1]))
1244 + (dcz[3] * ((da.x[1] * db.y[0] + db.y[1] * da.x[0]) - (da.y[1] * db.x[0] + db.x[1] * da.y[0]))
1245 + 2.0f * (dc.x[1] * dc.x[0] + dc.y[1] * dc.y[0]) * (da.x[1] * db.y[1] - da.y[1] * db.x[1]));
1246 if (det >= err_bound || -det >= err_bound)
1247 return det > 0.0f;
1249 if (db.x[0] != 0.0f || db.y[0] != 0.0f || dc.x[0] != 0.0f || dc.y[0] != 0.0f)
1251 d2d_fp_square(temp2a, da.x[1]);
1252 d2d_fp_square(temp2b, da.y[1]);
1253 d2d_fp_two_two_sum(daz, temp2a, temp2b);
1255 if (dc.x[0] != 0.0f || dc.y[0] != 0.0f || da.x[0] != 0.0f || da.y[0] != 0.0f)
1257 d2d_fp_square(temp2a, db.x[1]);
1258 d2d_fp_square(temp2b, db.y[1]);
1259 d2d_fp_two_two_sum(dbz, temp2a, temp2b);
1261 if (da.x[0] != 0.0f || da.y[0] != 0.0f || db.x[0] != 0.0f || db.y[0] != 0.0f)
1263 d2d_fp_square(temp2a, dc.x[1]);
1264 d2d_fp_square(temp2b, dc.y[1]);
1265 d2d_fp_two_two_sum(dcz, temp2a, temp2b);
1268 if (da.x[0] != 0.0f)
1269 d2d_cdt_incircle_refine1(&fin, axt_det_bc, &axt_det_bc_len, det_bc, dc.y[1], dcz, db.y[1], dbz, da.x);
1270 if (da.y[0] != 0.0f)
1271 d2d_cdt_incircle_refine1(&fin, ayt_det_bc, &ayt_det_bc_len, det_bc, db.x[1], dbz, dc.x[1], dcz, da.y);
1272 if (db.x[0] != 0.0f)
1273 d2d_cdt_incircle_refine1(&fin, bxt_det_ca, &bxt_det_ca_len, det_ca, da.y[1], daz, dc.y[1], dcz, db.x);
1274 if (db.y[0] != 0.0f)
1275 d2d_cdt_incircle_refine1(&fin, byt_det_ca, &byt_det_ca_len, det_ca, dc.x[1], dcz, da.x[1], daz, db.y);
1276 if (dc.x[0] != 0.0f)
1277 d2d_cdt_incircle_refine1(&fin, cxt_det_ab, &cxt_det_ab_len, det_ab, db.y[1], dbz, da.y[1], daz, dc.x);
1278 if (dc.y[0] != 0.0f)
1279 d2d_cdt_incircle_refine1(&fin, cyt_det_ab, &cyt_det_ab_len, det_ab, da.x[1], daz, db.x[1], dbz, dc.y);
1281 if (da.x[0] != 0.0f || da.y[0] != 0.0f)
1282 d2d_cdt_incircle_refine2(&fin, &da, &db, dbz, &dc, dcz,
1283 axt_det_bc, axt_det_bc_len, ayt_det_bc, ayt_det_bc_len);
1284 if (db.x[0] != 0.0f || db.y[0] != 0.0f)
1285 d2d_cdt_incircle_refine2(&fin, &db, &dc, dcz, &da, daz,
1286 bxt_det_ca, bxt_det_ca_len, byt_det_ca, byt_det_ca_len);
1287 if (dc.x[0] != 0.0f || dc.y[0] != 0.0f)
1288 d2d_cdt_incircle_refine2(&fin, &dc, &da, daz, &db, dbz,
1289 cxt_det_ab, cxt_det_ab_len, cyt_det_ab, cyt_det_ab_len);
1291 return fin.now[fin.length - 1] > 0.0f;
1294 static void d2d_cdt_splice(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *a,
1295 const struct d2d_cdt_edge_ref *b)
1297 struct d2d_cdt_edge_ref ta, tb, alpha, beta;
1299 ta = cdt->edges[a->idx].next[a->r];
1300 tb = cdt->edges[b->idx].next[b->r];
1301 cdt->edges[a->idx].next[a->r] = tb;
1302 cdt->edges[b->idx].next[b->r] = ta;
1304 d2d_cdt_edge_rot(&alpha, &ta);
1305 d2d_cdt_edge_rot(&beta, &tb);
1307 ta = cdt->edges[alpha.idx].next[alpha.r];
1308 tb = cdt->edges[beta.idx].next[beta.r];
1309 cdt->edges[alpha.idx].next[alpha.r] = tb;
1310 cdt->edges[beta.idx].next[beta.r] = ta;
1313 static BOOL d2d_cdt_create_edge(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *e)
1315 struct d2d_cdt_edge *edge;
1317 if (cdt->free_edge != ~0u)
1319 e->idx = cdt->free_edge;
1320 cdt->free_edge = cdt->edges[e->idx].next[D2D_EDGE_NEXT_ORIGIN].idx;
1322 else
1324 if (!d2d_array_reserve((void **)&cdt->edges, &cdt->edges_size, cdt->edge_count + 1, sizeof(*cdt->edges)))
1326 ERR("Failed to grow edges array.\n");
1327 return FALSE;
1329 e->idx = cdt->edge_count++;
1331 e->r = 0;
1333 edge = &cdt->edges[e->idx];
1334 edge->next[D2D_EDGE_NEXT_ORIGIN] = *e;
1335 d2d_cdt_edge_tor(&edge->next[D2D_EDGE_NEXT_ROT], e);
1336 d2d_cdt_edge_sym(&edge->next[D2D_EDGE_NEXT_SYM], e);
1337 d2d_cdt_edge_rot(&edge->next[D2D_EDGE_NEXT_TOR], e);
1338 edge->flags = 0;
1340 return TRUE;
1343 static void d2d_cdt_destroy_edge(struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
1345 struct d2d_cdt_edge_ref next, sym, prev;
1347 d2d_cdt_edge_next_origin(cdt, &next, e);
1348 if (next.idx != e->idx || next.r != e->r)
1350 d2d_cdt_edge_prev_origin(cdt, &prev, e);
1351 d2d_cdt_splice(cdt, e, &prev);
1354 d2d_cdt_edge_sym(&sym, e);
1356 d2d_cdt_edge_next_origin(cdt, &next, &sym);
1357 if (next.idx != sym.idx || next.r != sym.r)
1359 d2d_cdt_edge_prev_origin(cdt, &prev, &sym);
1360 d2d_cdt_splice(cdt, &sym, &prev);
1363 cdt->edges[e->idx].flags |= D2D_CDT_EDGE_FLAG_FREED;
1364 cdt->edges[e->idx].next[D2D_EDGE_NEXT_ORIGIN].idx = cdt->free_edge;
1365 cdt->free_edge = e->idx;
1368 static BOOL d2d_cdt_connect(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *e,
1369 const struct d2d_cdt_edge_ref *a, const struct d2d_cdt_edge_ref *b)
1371 struct d2d_cdt_edge_ref tmp;
1373 if (!d2d_cdt_create_edge(cdt, e))
1374 return FALSE;
1375 d2d_cdt_edge_set_origin(cdt, e, d2d_cdt_edge_destination(cdt, a));
1376 d2d_cdt_edge_set_destination(cdt, e, d2d_cdt_edge_origin(cdt, b));
1377 d2d_cdt_edge_next_left(cdt, &tmp, a);
1378 d2d_cdt_splice(cdt, e, &tmp);
1379 d2d_cdt_edge_sym(&tmp, e);
1380 d2d_cdt_splice(cdt, &tmp, b);
1382 return TRUE;
1385 static BOOL d2d_cdt_merge(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *left_outer,
1386 struct d2d_cdt_edge_ref *left_inner, struct d2d_cdt_edge_ref *right_inner,
1387 struct d2d_cdt_edge_ref *right_outer)
1389 struct d2d_cdt_edge_ref base_edge, tmp;
1391 /* Create the base edge between both parts. */
1392 for (;;)
1394 if (d2d_cdt_leftof(cdt, d2d_cdt_edge_origin(cdt, right_inner), left_inner))
1396 d2d_cdt_edge_next_left(cdt, left_inner, left_inner);
1398 else if (d2d_cdt_rightof(cdt, d2d_cdt_edge_origin(cdt, left_inner), right_inner))
1400 d2d_cdt_edge_sym(&tmp, right_inner);
1401 d2d_cdt_edge_next_origin(cdt, right_inner, &tmp);
1403 else
1405 break;
1409 d2d_cdt_edge_sym(&tmp, right_inner);
1410 if (!d2d_cdt_connect(cdt, &base_edge, &tmp, left_inner))
1411 return FALSE;
1412 if (d2d_cdt_edge_origin(cdt, left_inner) == d2d_cdt_edge_origin(cdt, left_outer))
1413 d2d_cdt_edge_sym(left_outer, &base_edge);
1414 if (d2d_cdt_edge_origin(cdt, right_inner) == d2d_cdt_edge_origin(cdt, right_outer))
1415 *right_outer = base_edge;
1417 for (;;)
1419 struct d2d_cdt_edge_ref left_candidate, right_candidate, sym_base_edge;
1420 BOOL left_valid, right_valid;
1422 /* Find the left candidate. */
1423 d2d_cdt_edge_sym(&sym_base_edge, &base_edge);
1424 d2d_cdt_edge_next_origin(cdt, &left_candidate, &sym_base_edge);
1425 if ((left_valid = d2d_cdt_leftof(cdt, d2d_cdt_edge_destination(cdt, &left_candidate), &sym_base_edge)))
1427 d2d_cdt_edge_next_origin(cdt, &tmp, &left_candidate);
1428 while (d2d_cdt_edge_destination(cdt, &tmp) != d2d_cdt_edge_destination(cdt, &sym_base_edge)
1429 && d2d_cdt_incircle(cdt,
1430 d2d_cdt_edge_origin(cdt, &sym_base_edge), d2d_cdt_edge_destination(cdt, &sym_base_edge),
1431 d2d_cdt_edge_destination(cdt, &left_candidate), d2d_cdt_edge_destination(cdt, &tmp)))
1433 d2d_cdt_destroy_edge(cdt, &left_candidate);
1434 left_candidate = tmp;
1435 d2d_cdt_edge_next_origin(cdt, &tmp, &left_candidate);
1438 d2d_cdt_edge_sym(&left_candidate, &left_candidate);
1440 /* Find the right candidate. */
1441 d2d_cdt_edge_prev_origin(cdt, &right_candidate, &base_edge);
1442 if ((right_valid = d2d_cdt_rightof(cdt, d2d_cdt_edge_destination(cdt, &right_candidate), &base_edge)))
1444 d2d_cdt_edge_prev_origin(cdt, &tmp, &right_candidate);
1445 while (d2d_cdt_edge_destination(cdt, &tmp) != d2d_cdt_edge_destination(cdt, &base_edge)
1446 && d2d_cdt_incircle(cdt,
1447 d2d_cdt_edge_origin(cdt, &sym_base_edge), d2d_cdt_edge_destination(cdt, &sym_base_edge),
1448 d2d_cdt_edge_destination(cdt, &right_candidate), d2d_cdt_edge_destination(cdt, &tmp)))
1450 d2d_cdt_destroy_edge(cdt, &right_candidate);
1451 right_candidate = tmp;
1452 d2d_cdt_edge_prev_origin(cdt, &tmp, &right_candidate);
1456 if (!left_valid && !right_valid)
1457 break;
1459 /* Connect the appropriate candidate with the base edge. */
1460 if (!left_valid || (right_valid && d2d_cdt_incircle(cdt,
1461 d2d_cdt_edge_origin(cdt, &left_candidate), d2d_cdt_edge_destination(cdt, &left_candidate),
1462 d2d_cdt_edge_origin(cdt, &right_candidate), d2d_cdt_edge_destination(cdt, &right_candidate))))
1464 if (!d2d_cdt_connect(cdt, &base_edge, &right_candidate, &sym_base_edge))
1465 return FALSE;
1467 else
1469 if (!d2d_cdt_connect(cdt, &base_edge, &sym_base_edge, &left_candidate))
1470 return FALSE;
1474 return TRUE;
1477 /* Create a Delaunay triangulation from a set of vertices. This is an
1478 * implementation of the divide-and-conquer algorithm described by Guibas and
1479 * Stolfi. Should be called with at least two vertices. */
1480 static BOOL d2d_cdt_triangulate(struct d2d_cdt *cdt, size_t start_vertex, size_t vertex_count,
1481 struct d2d_cdt_edge_ref *left_edge, struct d2d_cdt_edge_ref *right_edge)
1483 struct d2d_cdt_edge_ref left_inner, left_outer, right_inner, right_outer, tmp;
1484 size_t cut;
1486 /* Only two vertices, create a single edge. */
1487 if (vertex_count == 2)
1489 struct d2d_cdt_edge_ref a;
1491 if (!d2d_cdt_create_edge(cdt, &a))
1492 return FALSE;
1493 d2d_cdt_edge_set_origin(cdt, &a, start_vertex);
1494 d2d_cdt_edge_set_destination(cdt, &a, start_vertex + 1);
1496 *left_edge = a;
1497 d2d_cdt_edge_sym(right_edge, &a);
1499 return TRUE;
1502 /* Three vertices, create a triangle. */
1503 if (vertex_count == 3)
1505 struct d2d_cdt_edge_ref a, b, c;
1506 float det;
1508 if (!d2d_cdt_create_edge(cdt, &a))
1509 return FALSE;
1510 if (!d2d_cdt_create_edge(cdt, &b))
1511 return FALSE;
1512 d2d_cdt_edge_sym(&tmp, &a);
1513 d2d_cdt_splice(cdt, &tmp, &b);
1515 d2d_cdt_edge_set_origin(cdt, &a, start_vertex);
1516 d2d_cdt_edge_set_destination(cdt, &a, start_vertex + 1);
1517 d2d_cdt_edge_set_origin(cdt, &b, start_vertex + 1);
1518 d2d_cdt_edge_set_destination(cdt, &b, start_vertex + 2);
1520 det = d2d_cdt_ccw(cdt, start_vertex, start_vertex + 1, start_vertex + 2);
1521 if (det != 0.0f && !d2d_cdt_connect(cdt, &c, &b, &a))
1522 return FALSE;
1524 if (det < 0.0f)
1526 d2d_cdt_edge_sym(left_edge, &c);
1527 *right_edge = c;
1529 else
1531 *left_edge = a;
1532 d2d_cdt_edge_sym(right_edge, &b);
1535 return TRUE;
1538 /* More than tree vertices, divide. */
1539 cut = vertex_count / 2;
1540 if (!d2d_cdt_triangulate(cdt, start_vertex, cut, &left_outer, &left_inner))
1541 return FALSE;
1542 if (!d2d_cdt_triangulate(cdt, start_vertex + cut, vertex_count - cut, &right_inner, &right_outer))
1543 return FALSE;
1544 /* Merge the left and right parts. */
1545 if (!d2d_cdt_merge(cdt, &left_outer, &left_inner, &right_inner, &right_outer))
1546 return FALSE;
1548 *left_edge = left_outer;
1549 *right_edge = right_outer;
1550 return TRUE;
1553 static int __cdecl d2d_cdt_compare_vertices(const void *a, const void *b)
1555 const D2D1_POINT_2F *p0 = a;
1556 const D2D1_POINT_2F *p1 = b;
1557 float diff = p0->x - p1->x;
1559 if (diff == 0.0f)
1560 diff = p0->y - p1->y;
1562 return diff == 0.0f ? 0 : (diff > 0.0f ? 1 : -1);
1565 /* Determine whether a given point is inside the geometry, using the current
1566 * fill mode rule. */
1567 static BOOL d2d_path_geometry_point_inside(const struct d2d_geometry *geometry,
1568 const D2D1_POINT_2F *probe, BOOL triangles_only)
1570 const D2D1_POINT_2F *p0, *p1;
1571 D2D1_POINT_2F v_p, v_probe;
1572 unsigned int score;
1573 size_t i, j, last;
1575 for (i = 0, score = 0; i < geometry->u.path.figure_count; ++i)
1577 const struct d2d_figure *figure = &geometry->u.path.figures[i];
1579 if (probe->x < figure->bounds.left || probe->x > figure->bounds.right
1580 || probe->y < figure->bounds.top || probe->y > figure->bounds.bottom)
1581 continue;
1583 last = figure->vertex_count - 1;
1584 if (!triangles_only)
1586 while (last && figure->vertex_types[last] == D2D_VERTEX_TYPE_NONE)
1587 --last;
1589 p0 = &figure->vertices[last];
1590 for (j = 0; j <= last; ++j)
1592 if (!triangles_only && figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
1593 continue;
1595 p1 = &figure->vertices[j];
1596 d2d_point_subtract(&v_p, p1, p0);
1597 d2d_point_subtract(&v_probe, probe, p0);
1599 if ((probe->y < p0->y) != (probe->y < p1->y) && v_probe.x < v_p.x * (v_probe.y / v_p.y))
1601 if (geometry->u.path.fill_mode == D2D1_FILL_MODE_ALTERNATE || (probe->y < p0->y))
1602 ++score;
1603 else
1604 --score;
1607 p0 = p1;
1611 return geometry->u.path.fill_mode == D2D1_FILL_MODE_ALTERNATE ? score & 1 : score;
1614 static BOOL d2d_path_geometry_add_fill_face(struct d2d_geometry *geometry, const struct d2d_cdt *cdt,
1615 const struct d2d_cdt_edge_ref *base_edge)
1617 struct d2d_cdt_edge_ref tmp;
1618 struct d2d_face *face;
1619 D2D1_POINT_2F probe;
1621 if (cdt->edges[base_edge->idx].flags & D2D_CDT_EDGE_FLAG_VISITED(base_edge->r))
1622 return TRUE;
1624 if (!d2d_array_reserve((void **)&geometry->fill.faces, &geometry->fill.faces_size,
1625 geometry->fill.face_count + 1, sizeof(*geometry->fill.faces)))
1627 ERR("Failed to grow faces array.\n");
1628 return FALSE;
1631 face = &geometry->fill.faces[geometry->fill.face_count];
1633 /* It may seem tempting to use the center of the face as probe origin, but
1634 * multiplying by powers of two works much better for preserving accuracy. */
1636 tmp = *base_edge;
1637 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1638 face->v[0] = d2d_cdt_edge_origin(cdt, &tmp);
1639 probe.x = cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.25f;
1640 probe.y = cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.25f;
1642 d2d_cdt_edge_next_left(cdt, &tmp, &tmp);
1643 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1644 face->v[1] = d2d_cdt_edge_origin(cdt, &tmp);
1645 probe.x += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.25f;
1646 probe.y += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.25f;
1648 d2d_cdt_edge_next_left(cdt, &tmp, &tmp);
1649 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
1650 face->v[2] = d2d_cdt_edge_origin(cdt, &tmp);
1651 probe.x += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.50f;
1652 probe.y += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.50f;
1654 if (d2d_cdt_leftof(cdt, face->v[2], base_edge) && d2d_path_geometry_point_inside(geometry, &probe, TRUE))
1655 ++geometry->fill.face_count;
1657 return TRUE;
1660 static BOOL d2d_cdt_generate_faces(const struct d2d_cdt *cdt, struct d2d_geometry *geometry)
1662 struct d2d_cdt_edge_ref base_edge;
1663 size_t i;
1665 for (i = 0; i < cdt->edge_count; ++i)
1667 if (cdt->edges[i].flags & D2D_CDT_EDGE_FLAG_FREED)
1668 continue;
1670 base_edge.idx = i;
1671 base_edge.r = 0;
1672 if (!d2d_path_geometry_add_fill_face(geometry, cdt, &base_edge))
1673 goto fail;
1674 d2d_cdt_edge_sym(&base_edge, &base_edge);
1675 if (!d2d_path_geometry_add_fill_face(geometry, cdt, &base_edge))
1676 goto fail;
1679 return TRUE;
1681 fail:
1682 heap_free(geometry->fill.faces);
1683 geometry->fill.faces = NULL;
1684 geometry->fill.faces_size = 0;
1685 geometry->fill.face_count = 0;
1686 return FALSE;
1689 static BOOL d2d_cdt_fixup(struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *base_edge)
1691 struct d2d_cdt_edge_ref candidate, next, new_base;
1692 unsigned int count = 0;
1694 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1695 if (next.idx == base_edge->idx)
1697 ERR("Degenerate face.\n");
1698 return FALSE;
1701 candidate = next;
1702 while (d2d_cdt_edge_destination(cdt, &next) != d2d_cdt_edge_origin(cdt, base_edge))
1704 if (d2d_cdt_incircle(cdt, d2d_cdt_edge_origin(cdt, base_edge), d2d_cdt_edge_destination(cdt, base_edge),
1705 d2d_cdt_edge_destination(cdt, &candidate), d2d_cdt_edge_destination(cdt, &next)))
1706 candidate = next;
1707 d2d_cdt_edge_next_left(cdt, &next, &next);
1708 ++count;
1711 if (count > 1)
1713 d2d_cdt_edge_next_left(cdt, &next, &candidate);
1714 if (d2d_cdt_edge_destination(cdt, &next) == d2d_cdt_edge_origin(cdt, base_edge))
1715 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1716 else
1717 next = *base_edge;
1718 if (!d2d_cdt_connect(cdt, &new_base, &candidate, &next))
1719 return FALSE;
1720 if (!d2d_cdt_fixup(cdt, &new_base))
1721 return FALSE;
1722 d2d_cdt_edge_sym(&new_base, &new_base);
1723 if (!d2d_cdt_fixup(cdt, &new_base))
1724 return FALSE;
1727 return TRUE;
1730 static void d2d_cdt_cut_edges(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *end_edge,
1731 const struct d2d_cdt_edge_ref *base_edge, size_t start_vertex, size_t end_vertex)
1733 struct d2d_cdt_edge_ref next;
1734 float ccw;
1736 d2d_cdt_edge_next_left(cdt, &next, base_edge);
1737 if (d2d_cdt_edge_destination(cdt, &next) == end_vertex)
1739 *end_edge = next;
1740 return;
1743 ccw = d2d_cdt_ccw(cdt, d2d_cdt_edge_destination(cdt, &next), end_vertex, start_vertex);
1744 if (ccw == 0.0f)
1746 *end_edge = next;
1747 return;
1750 if (ccw > 0.0f)
1751 d2d_cdt_edge_next_left(cdt, &next, &next);
1753 d2d_cdt_edge_sym(&next, &next);
1754 d2d_cdt_cut_edges(cdt, end_edge, &next, start_vertex, end_vertex);
1755 d2d_cdt_destroy_edge(cdt, &next);
1758 static BOOL d2d_cdt_insert_segment(struct d2d_cdt *cdt, struct d2d_geometry *geometry,
1759 const struct d2d_cdt_edge_ref *origin, struct d2d_cdt_edge_ref *edge, size_t end_vertex)
1761 struct d2d_cdt_edge_ref base_edge, current, new_origin, next, target;
1762 size_t current_destination, current_origin;
1764 for (current = *origin;; current = next)
1766 d2d_cdt_edge_next_origin(cdt, &next, &current);
1768 current_destination = d2d_cdt_edge_destination(cdt, &current);
1769 if (current_destination == end_vertex)
1771 d2d_cdt_edge_sym(edge, &current);
1772 return TRUE;
1775 current_origin = d2d_cdt_edge_origin(cdt, &current);
1776 if (d2d_cdt_ccw(cdt, end_vertex, current_origin, current_destination) == 0.0f
1777 && (cdt->vertices[current_destination].x > cdt->vertices[current_origin].x)
1778 == (cdt->vertices[end_vertex].x > cdt->vertices[current_origin].x)
1779 && (cdt->vertices[current_destination].y > cdt->vertices[current_origin].y)
1780 == (cdt->vertices[end_vertex].y > cdt->vertices[current_origin].y))
1782 d2d_cdt_edge_sym(&new_origin, &current);
1783 return d2d_cdt_insert_segment(cdt, geometry, &new_origin, edge, end_vertex);
1786 if (d2d_cdt_rightof(cdt, end_vertex, &next) && d2d_cdt_leftof(cdt, end_vertex, &current))
1788 d2d_cdt_edge_next_left(cdt, &base_edge, &current);
1790 d2d_cdt_edge_sym(&base_edge, &base_edge);
1791 d2d_cdt_cut_edges(cdt, &target, &base_edge, d2d_cdt_edge_origin(cdt, origin), end_vertex);
1792 d2d_cdt_destroy_edge(cdt, &base_edge);
1794 if (!d2d_cdt_connect(cdt, &base_edge, &target, &current))
1795 return FALSE;
1796 *edge = base_edge;
1797 if (!d2d_cdt_fixup(cdt, &base_edge))
1798 return FALSE;
1799 d2d_cdt_edge_sym(&base_edge, &base_edge);
1800 if (!d2d_cdt_fixup(cdt, &base_edge))
1801 return FALSE;
1803 if (d2d_cdt_edge_origin(cdt, edge) == end_vertex)
1804 return TRUE;
1805 new_origin = *edge;
1806 return d2d_cdt_insert_segment(cdt, geometry, &new_origin, edge, end_vertex);
1809 if (next.idx == origin->idx)
1811 ERR("Triangle not found.\n");
1812 return FALSE;
1817 static BOOL d2d_cdt_insert_segments(struct d2d_cdt *cdt, struct d2d_geometry *geometry)
1819 size_t start_vertex, end_vertex, i, j, k;
1820 struct d2d_cdt_edge_ref edge, new_edge;
1821 const struct d2d_figure *figure;
1822 const D2D1_POINT_2F *p;
1823 BOOL found;
1825 for (i = 0; i < geometry->u.path.figure_count; ++i)
1827 figure = &geometry->u.path.figures[i];
1829 if (figure->flags & D2D_FIGURE_FLAG_HOLLOW)
1830 continue;
1832 /* Degenerate figure. */
1833 if (figure->vertex_count < 2)
1834 continue;
1836 p = bsearch(&figure->vertices[figure->vertex_count - 1], cdt->vertices,
1837 geometry->fill.vertex_count, sizeof(*p), d2d_cdt_compare_vertices);
1838 start_vertex = p - cdt->vertices;
1840 for (k = 0, found = FALSE; k < cdt->edge_count; ++k)
1842 if (cdt->edges[k].flags & D2D_CDT_EDGE_FLAG_FREED)
1843 continue;
1845 edge.idx = k;
1846 edge.r = 0;
1848 if (d2d_cdt_edge_origin(cdt, &edge) == start_vertex)
1850 found = TRUE;
1851 break;
1853 d2d_cdt_edge_sym(&edge, &edge);
1854 if (d2d_cdt_edge_origin(cdt, &edge) == start_vertex)
1856 found = TRUE;
1857 break;
1861 if (!found)
1863 ERR("Edge not found.\n");
1864 return FALSE;
1867 for (j = 0; j < figure->vertex_count; start_vertex = end_vertex, ++j)
1869 p = bsearch(&figure->vertices[j], cdt->vertices,
1870 geometry->fill.vertex_count, sizeof(*p), d2d_cdt_compare_vertices);
1871 end_vertex = p - cdt->vertices;
1873 if (start_vertex == end_vertex)
1874 continue;
1876 if (!d2d_cdt_insert_segment(cdt, geometry, &edge, &new_edge, end_vertex))
1877 return FALSE;
1878 edge = new_edge;
1882 return TRUE;
1885 static BOOL d2d_geometry_intersections_add(struct d2d_geometry_intersections *i,
1886 const struct d2d_segment_idx *segment_idx, float t, D2D1_POINT_2F p)
1888 struct d2d_geometry_intersection *intersection;
1890 if (!d2d_array_reserve((void **)&i->intersections, &i->intersections_size,
1891 i->intersection_count + 1, sizeof(*i->intersections)))
1893 ERR("Failed to grow intersections array.\n");
1894 return FALSE;
1897 intersection = &i->intersections[i->intersection_count++];
1898 intersection->figure_idx = segment_idx->figure_idx;
1899 intersection->vertex_idx = segment_idx->vertex_idx;
1900 intersection->control_idx = segment_idx->control_idx;
1901 intersection->t = t;
1902 intersection->p = p;
1904 return TRUE;
1907 static int __cdecl d2d_geometry_intersections_compare(const void *a, const void *b)
1909 const struct d2d_geometry_intersection *i0 = a;
1910 const struct d2d_geometry_intersection *i1 = b;
1912 if (i0->figure_idx != i1->figure_idx)
1913 return i0->figure_idx - i1->figure_idx;
1914 if (i0->vertex_idx != i1->vertex_idx)
1915 return i0->vertex_idx - i1->vertex_idx;
1916 if (i0->t != i1->t)
1917 return i0->t > i1->t ? 1 : -1;
1918 return 0;
1921 static BOOL d2d_geometry_intersect_line_line(struct d2d_geometry *geometry,
1922 struct d2d_geometry_intersections *intersections, const struct d2d_segment_idx *idx_p,
1923 const struct d2d_segment_idx *idx_q)
1925 D2D1_POINT_2F v_p, v_q, v_qp, intersection;
1926 const D2D1_POINT_2F *p[2], *q[2];
1927 const struct d2d_figure *figure;
1928 float s, t, det;
1929 size_t next;
1931 figure = &geometry->u.path.figures[idx_p->figure_idx];
1932 p[0] = &figure->vertices[idx_p->vertex_idx];
1933 next = idx_p->vertex_idx + 1;
1934 if (next == figure->vertex_count)
1935 next = 0;
1936 p[1] = &figure->vertices[next];
1938 figure = &geometry->u.path.figures[idx_q->figure_idx];
1939 q[0] = &figure->vertices[idx_q->vertex_idx];
1940 next = idx_q->vertex_idx + 1;
1941 if (next == figure->vertex_count)
1942 next = 0;
1943 q[1] = &figure->vertices[next];
1945 d2d_point_subtract(&v_p, p[1], p[0]);
1946 d2d_point_subtract(&v_q, q[1], q[0]);
1947 d2d_point_subtract(&v_qp, p[0], q[0]);
1949 det = v_p.x * v_q.y - v_p.y * v_q.x;
1950 if (det == 0.0f)
1951 return TRUE;
1953 s = (v_q.x * v_qp.y - v_q.y * v_qp.x) / det;
1954 t = (v_p.x * v_qp.y - v_p.y * v_qp.x) / det;
1956 if (s < 0.0f || s > 1.0f || t < 0.0f || t > 1.0f)
1957 return TRUE;
1959 intersection.x = p[0]->x + v_p.x * s;
1960 intersection.y = p[0]->y + v_p.y * s;
1962 if (s > 0.0f && s < 1.0f && !d2d_geometry_intersections_add(intersections, idx_p, s, intersection))
1963 return FALSE;
1965 if (t > 0.0f && t < 1.0f && !d2d_geometry_intersections_add(intersections, idx_q, t, intersection))
1966 return FALSE;
1968 return TRUE;
1971 static BOOL d2d_geometry_add_bezier_line_intersections(struct d2d_geometry *geometry,
1972 struct d2d_geometry_intersections *intersections, const struct d2d_segment_idx *idx_p,
1973 const D2D1_POINT_2F **p, const struct d2d_segment_idx *idx_q, const D2D1_POINT_2F **q, float s)
1975 D2D1_POINT_2F intersection;
1976 float t;
1978 d2d_point_calculate_bezier(&intersection, p[0], p[1], p[2], s);
1979 if (fabsf(q[1]->x - q[0]->x) > fabsf(q[1]->y - q[0]->y))
1980 t = (intersection.x - q[0]->x) / (q[1]->x - q[0]->x);
1981 else
1982 t = (intersection.y - q[0]->y) / (q[1]->y - q[0]->y);
1983 if (t < 0.0f || t > 1.0f)
1984 return TRUE;
1986 d2d_point_lerp(&intersection, q[0], q[1], t);
1988 if (s > 0.0f && s < 1.0f && !d2d_geometry_intersections_add(intersections, idx_p, s, intersection))
1989 return FALSE;
1991 if (t > 0.0f && t < 1.0f && !d2d_geometry_intersections_add(intersections, idx_q, t, intersection))
1992 return FALSE;
1994 return TRUE;
1997 static BOOL d2d_geometry_intersect_bezier_line(struct d2d_geometry *geometry,
1998 struct d2d_geometry_intersections *intersections,
1999 const struct d2d_segment_idx *idx_p, const struct d2d_segment_idx *idx_q)
2001 const D2D1_POINT_2F *p[3], *q[2];
2002 const struct d2d_figure *figure;
2003 float y[3], root, theta, d, e;
2004 size_t next;
2006 figure = &geometry->u.path.figures[idx_p->figure_idx];
2007 p[0] = &figure->vertices[idx_p->vertex_idx];
2008 p[1] = &figure->bezier_controls[idx_p->control_idx];
2009 next = idx_p->vertex_idx + 1;
2010 p[2] = &figure->vertices[next];
2012 figure = &geometry->u.path.figures[idx_q->figure_idx];
2013 q[0] = &figure->vertices[idx_q->vertex_idx];
2014 next = idx_q->vertex_idx + 1;
2015 if (next == figure->vertex_count)
2016 next = 0;
2017 q[1] = &figure->vertices[next];
2019 /* Align the line with x-axis. */
2020 theta = -atan2f(q[1]->y - q[0]->y, q[1]->x - q[0]->x);
2021 y[0] = (p[0]->x - q[0]->x) * sinf(theta) + (p[0]->y - q[0]->y) * cosf(theta);
2022 y[1] = (p[1]->x - q[0]->x) * sinf(theta) + (p[1]->y - q[0]->y) * cosf(theta);
2023 y[2] = (p[2]->x - q[0]->x) * sinf(theta) + (p[2]->y - q[0]->y) * cosf(theta);
2025 /* Intersect the transformed curve with the x-axis.
2027 * f(t) = (1 - t)²P₀ + 2(1 - t)tP₁ + t²P₂
2028 * = (P₀ - 2P₁ + P₂)t² + 2(P₁ - P₀)t + P₀
2030 * a = P₀ - 2P₁ + P₂
2031 * b = 2(P₁ - P₀)
2032 * c = P₀
2034 * f(t) = 0
2035 * t = (-b ± √(b² - 4ac)) / 2a
2036 * = (-2(P₁ - P₀) ± √((2(P₁ - P₀))² - 4((P₀ - 2P₁ + P₂)P₀))) / 2(P₀ - 2P₁ + P₂)
2037 * = (2P₀ - 2P₁ ± √(4P₀² + 4P₁² - 8P₀P₁ - 4P₀² + 8P₀P₁ - 4P₀P₂)) / (2P₀ - 4P₁ + 2P₂)
2038 * = (P₀ - P₁ ± √(P₁² - P₀P₂)) / (P₀ - 2P₁ + P₂) */
2040 d = y[0] - 2 * y[1] + y[2];
2041 if (d == 0.0f)
2043 /* P₀ - 2P₁ + P₂ = 0
2044 * f(t) = (P₀ - 2P₁ + P₂)t² + 2(P₁ - P₀)t + P₀ = 0
2045 * t = -P₀ / 2(P₁ - P₀) */
2046 root = -y[0] / (2.0f * (y[1] - y[0]));
2047 if (root < 0.0f || root > 1.0f)
2048 return TRUE;
2050 return d2d_geometry_add_bezier_line_intersections(geometry, intersections, idx_p, p, idx_q, q, root);
2053 e = y[1] * y[1] - y[0] * y[2];
2054 if (e < 0.0f)
2055 return TRUE;
2057 root = (y[0] - y[1] + sqrtf(e)) / d;
2058 if (root >= 0.0f && root <= 1.0f && !d2d_geometry_add_bezier_line_intersections(geometry,
2059 intersections, idx_p, p, idx_q, q, root))
2060 return FALSE;
2062 root = (y[0] - y[1] - sqrtf(e)) / d;
2063 if (root >= 0.0f && root <= 1.0f && !d2d_geometry_add_bezier_line_intersections(geometry,
2064 intersections, idx_p, p, idx_q, q, root))
2065 return FALSE;
2067 return TRUE;
2070 static BOOL d2d_geometry_intersect_bezier_bezier(struct d2d_geometry *geometry,
2071 struct d2d_geometry_intersections *intersections,
2072 const struct d2d_segment_idx *idx_p, float start_p, float end_p,
2073 const struct d2d_segment_idx *idx_q, float start_q, float end_q)
2075 const D2D1_POINT_2F *p[3], *q[3];
2076 const struct d2d_figure *figure;
2077 D2D_RECT_F p_bounds, q_bounds;
2078 D2D1_POINT_2F intersection;
2079 float centre_p, centre_q;
2080 size_t next;
2082 figure = &geometry->u.path.figures[idx_p->figure_idx];
2083 p[0] = &figure->vertices[idx_p->vertex_idx];
2084 p[1] = &figure->bezier_controls[idx_p->control_idx];
2085 next = idx_p->vertex_idx + 1;
2086 p[2] = &figure->vertices[next];
2088 figure = &geometry->u.path.figures[idx_q->figure_idx];
2089 q[0] = &figure->vertices[idx_q->vertex_idx];
2090 q[1] = &figure->bezier_controls[idx_q->control_idx];
2091 next = idx_q->vertex_idx + 1;
2092 q[2] = &figure->vertices[next];
2094 d2d_rect_get_bezier_segment_bounds(&p_bounds, p[0], p[1], p[2], start_p, end_p);
2095 d2d_rect_get_bezier_segment_bounds(&q_bounds, q[0], q[1], q[2], start_q, end_q);
2097 if (!d2d_rect_check_overlap(&p_bounds, &q_bounds))
2098 return TRUE;
2100 centre_p = (start_p + end_p) / 2.0f;
2101 centre_q = (start_q + end_q) / 2.0f;
2103 if (end_p - start_p < 1e-3f)
2105 d2d_point_calculate_bezier(&intersection, p[0], p[1], p[2], centre_p);
2106 if (start_p > 0.0f && end_p < 1.0f && !d2d_geometry_intersections_add(intersections,
2107 idx_p, centre_p, intersection))
2108 return FALSE;
2109 if (start_q > 0.0f && end_q < 1.0f && !d2d_geometry_intersections_add(intersections,
2110 idx_q, centre_q, intersection))
2111 return FALSE;
2112 return TRUE;
2115 if (!d2d_geometry_intersect_bezier_bezier(geometry, intersections,
2116 idx_p, start_p, centre_p, idx_q, start_q, centre_q))
2117 return FALSE;
2118 if (!d2d_geometry_intersect_bezier_bezier(geometry, intersections,
2119 idx_p, start_p, centre_p, idx_q, centre_q, end_q))
2120 return FALSE;
2121 if (!d2d_geometry_intersect_bezier_bezier(geometry, intersections,
2122 idx_p, centre_p, end_p, idx_q, start_q, centre_q))
2123 return FALSE;
2124 if (!d2d_geometry_intersect_bezier_bezier(geometry, intersections,
2125 idx_p, centre_p, end_p, idx_q, centre_q, end_q))
2126 return FALSE;
2128 return TRUE;
2131 static BOOL d2d_geometry_apply_intersections(struct d2d_geometry *geometry,
2132 struct d2d_geometry_intersections *intersections)
2134 size_t vertex_offset, control_offset, next, i;
2135 struct d2d_geometry_intersection *inter;
2136 enum d2d_vertex_type vertex_type;
2137 const D2D1_POINT_2F *p[3];
2138 struct d2d_figure *figure;
2139 D2D1_POINT_2F q[2];
2140 float t, t_prev;
2142 for (i = 0; i < intersections->intersection_count; ++i)
2144 inter = &intersections->intersections[i];
2145 if (!i || inter->figure_idx != intersections->intersections[i - 1].figure_idx)
2146 vertex_offset = control_offset = 0;
2148 figure = &geometry->u.path.figures[inter->figure_idx];
2149 vertex_type = figure->vertex_types[inter->vertex_idx + vertex_offset];
2150 if (!d2d_vertex_type_is_bezier(vertex_type))
2152 if (!d2d_figure_insert_vertex(&geometry->u.path.figures[inter->figure_idx],
2153 inter->vertex_idx + vertex_offset + 1, inter->p))
2154 return FALSE;
2155 ++vertex_offset;
2156 continue;
2159 t = inter->t;
2160 if (i && inter->figure_idx == intersections->intersections[i - 1].figure_idx
2161 && inter->vertex_idx == intersections->intersections[i - 1].vertex_idx)
2163 t_prev = intersections->intersections[i - 1].t;
2164 if (t - t_prev < 1e-3f)
2166 inter->t = intersections->intersections[i - 1].t;
2167 continue;
2169 t = (t - t_prev) / (1.0f - t_prev);
2172 p[0] = &figure->vertices[inter->vertex_idx + vertex_offset];
2173 p[1] = &figure->bezier_controls[inter->control_idx + control_offset];
2174 next = inter->vertex_idx + vertex_offset + 1;
2175 p[2] = &figure->vertices[next];
2177 d2d_point_lerp(&q[0], p[0], p[1], t);
2178 d2d_point_lerp(&q[1], p[1], p[2], t);
2180 figure->bezier_controls[inter->control_idx + control_offset] = q[0];
2181 if (!(d2d_figure_insert_bezier_controls(figure, inter->control_idx + control_offset + 1, 1, &q[1])))
2182 return FALSE;
2183 ++control_offset;
2185 if (!(d2d_figure_insert_vertex(figure, inter->vertex_idx + vertex_offset + 1, inter->p)))
2186 return FALSE;
2187 figure->vertex_types[inter->vertex_idx + vertex_offset + 1] = D2D_VERTEX_TYPE_SPLIT_BEZIER;
2188 ++vertex_offset;
2191 return TRUE;
2194 /* Intersect the geometry's segments with themselves. This uses the
2195 * straightforward approach of testing everything against everything, but
2196 * there certainly exist more scalable algorithms for this. */
2197 static BOOL d2d_geometry_intersect_self(struct d2d_geometry *geometry)
2199 struct d2d_geometry_intersections intersections = {0};
2200 const struct d2d_figure *figure_p, *figure_q;
2201 struct d2d_segment_idx idx_p, idx_q;
2202 enum d2d_vertex_type type_p, type_q;
2203 BOOL ret = FALSE;
2204 size_t max_q;
2206 if (!geometry->u.path.figure_count)
2207 return TRUE;
2209 for (idx_p.figure_idx = 0; idx_p.figure_idx < geometry->u.path.figure_count; ++idx_p.figure_idx)
2211 figure_p = &geometry->u.path.figures[idx_p.figure_idx];
2212 idx_p.control_idx = 0;
2213 for (idx_p.vertex_idx = 0; idx_p.vertex_idx < figure_p->vertex_count; ++idx_p.vertex_idx)
2215 if ((type_p = figure_p->vertex_types[idx_p.vertex_idx]) == D2D_VERTEX_TYPE_END)
2216 continue;
2218 for (idx_q.figure_idx = 0; idx_q.figure_idx <= idx_p.figure_idx; ++idx_q.figure_idx)
2220 figure_q = &geometry->u.path.figures[idx_q.figure_idx];
2221 if (idx_q.figure_idx != idx_p.figure_idx)
2223 if (!d2d_rect_check_overlap(&figure_p->bounds, &figure_q->bounds))
2224 continue;
2225 if ((max_q = figure_q->vertex_count)
2226 && figure_q->vertex_types[max_q - 1] == D2D_VERTEX_TYPE_END)
2227 --max_q;
2229 else
2231 max_q = idx_p.vertex_idx;
2234 idx_q.control_idx = 0;
2235 for (idx_q.vertex_idx = 0; idx_q.vertex_idx < max_q; ++idx_q.vertex_idx)
2237 type_q = figure_q->vertex_types[idx_q.vertex_idx];
2238 if (d2d_vertex_type_is_bezier(type_q))
2240 if (d2d_vertex_type_is_bezier(type_p))
2242 if (!d2d_geometry_intersect_bezier_bezier(geometry, &intersections,
2243 &idx_p, 0.0f, 1.0f, &idx_q, 0.0f, 1.0f))
2244 goto done;
2246 else
2248 if (!d2d_geometry_intersect_bezier_line(geometry, &intersections, &idx_q, &idx_p))
2249 goto done;
2251 ++idx_q.control_idx;
2253 else
2255 if (d2d_vertex_type_is_bezier(type_p))
2257 if (!d2d_geometry_intersect_bezier_line(geometry, &intersections, &idx_p, &idx_q))
2258 goto done;
2260 else
2262 if (!d2d_geometry_intersect_line_line(geometry, &intersections, &idx_p, &idx_q))
2263 goto done;
2268 if (d2d_vertex_type_is_bezier(type_p))
2269 ++idx_p.control_idx;
2273 qsort(intersections.intersections, intersections.intersection_count,
2274 sizeof(*intersections.intersections), d2d_geometry_intersections_compare);
2275 ret = d2d_geometry_apply_intersections(geometry, &intersections);
2277 done:
2278 heap_free(intersections.intersections);
2279 return ret;
2282 static HRESULT d2d_path_geometry_triangulate(struct d2d_geometry *geometry)
2284 struct d2d_cdt_edge_ref left_edge, right_edge;
2285 size_t vertex_count, i, j;
2286 struct d2d_cdt cdt = {0};
2287 D2D1_POINT_2F *vertices;
2289 for (i = 0, vertex_count = 0; i < geometry->u.path.figure_count; ++i)
2291 if (geometry->u.path.figures[i].flags & D2D_FIGURE_FLAG_HOLLOW)
2292 continue;
2293 vertex_count += geometry->u.path.figures[i].vertex_count;
2296 if (vertex_count < 3)
2298 WARN("Geometry has %lu vertices.\n", (long)vertex_count);
2299 return S_OK;
2302 if (!(vertices = heap_calloc(vertex_count, sizeof(*vertices))))
2303 return E_OUTOFMEMORY;
2305 for (i = 0, j = 0; i < geometry->u.path.figure_count; ++i)
2307 if (geometry->u.path.figures[i].flags & D2D_FIGURE_FLAG_HOLLOW)
2308 continue;
2309 memcpy(&vertices[j], geometry->u.path.figures[i].vertices,
2310 geometry->u.path.figures[i].vertex_count * sizeof(*vertices));
2311 j += geometry->u.path.figures[i].vertex_count;
2314 /* Sort vertices, eliminate duplicates. */
2315 qsort(vertices, vertex_count, sizeof(*vertices), d2d_cdt_compare_vertices);
2316 for (i = 1; i < vertex_count; ++i)
2318 if (!memcmp(&vertices[i - 1], &vertices[i], sizeof(*vertices)))
2320 --vertex_count;
2321 memmove(&vertices[i], &vertices[i + 1], (vertex_count - i) * sizeof(*vertices));
2322 --i;
2326 if (vertex_count < 3)
2328 WARN("Geometry has %lu vertices after eliminating duplicates.\n", (long)vertex_count);
2329 heap_free(vertices);
2330 return S_OK;
2333 geometry->fill.vertices = vertices;
2334 geometry->fill.vertex_count = vertex_count;
2336 cdt.free_edge = ~0u;
2337 cdt.vertices = vertices;
2338 if (!d2d_cdt_triangulate(&cdt, 0, vertex_count, &left_edge, &right_edge))
2339 goto fail;
2340 if (!d2d_cdt_insert_segments(&cdt, geometry))
2341 goto fail;
2342 if (!d2d_cdt_generate_faces(&cdt, geometry))
2343 goto fail;
2345 heap_free(cdt.edges);
2346 return S_OK;
2348 fail:
2349 geometry->fill.vertices = NULL;
2350 geometry->fill.vertex_count = 0;
2351 heap_free(vertices);
2352 heap_free(cdt.edges);
2353 return E_FAIL;
2356 static BOOL d2d_path_geometry_add_figure(struct d2d_geometry *geometry)
2358 struct d2d_figure *figure;
2360 if (!d2d_array_reserve((void **)&geometry->u.path.figures, &geometry->u.path.figures_size,
2361 geometry->u.path.figure_count + 1, sizeof(*geometry->u.path.figures)))
2363 ERR("Failed to grow figures array.\n");
2364 return FALSE;
2367 figure = &geometry->u.path.figures[geometry->u.path.figure_count];
2368 memset(figure, 0, sizeof(*figure));
2369 figure->bounds.left = FLT_MAX;
2370 figure->bounds.top = FLT_MAX;
2371 figure->bounds.right = -FLT_MAX;
2372 figure->bounds.bottom = -FLT_MAX;
2374 ++geometry->u.path.figure_count;
2375 return TRUE;
2378 static BOOL d2d_geometry_outline_add_join(struct d2d_geometry *geometry,
2379 const D2D1_POINT_2F *prev, const D2D1_POINT_2F *p0, const D2D1_POINT_2F *next)
2381 static const D2D1_POINT_2F origin = {0.0f, 0.0f};
2382 struct d2d_outline_vertex *v;
2383 struct d2d_face *f;
2384 size_t base_idx;
2385 float ccw;
2387 if (!d2d_array_reserve((void **)&geometry->outline.vertices, &geometry->outline.vertices_size,
2388 geometry->outline.vertex_count + 4, sizeof(*geometry->outline.vertices)))
2390 ERR("Failed to grow outline vertices array.\n");
2391 return FALSE;
2393 base_idx = geometry->outline.vertex_count;
2394 v = &geometry->outline.vertices[base_idx];
2396 if (!d2d_array_reserve((void **)&geometry->outline.faces, &geometry->outline.faces_size,
2397 geometry->outline.face_count + 2, sizeof(*geometry->outline.faces)))
2399 ERR("Failed to grow outline faces array.\n");
2400 return FALSE;
2402 f = &geometry->outline.faces[geometry->outline.face_count];
2404 ccw = d2d_point_ccw(&origin, prev, next);
2405 if (ccw == 0.0f)
2407 d2d_outline_vertex_set(&v[0], p0->x, p0->y, -prev->x, -prev->y, -prev->x, -prev->y);
2408 d2d_outline_vertex_set(&v[1], p0->x, p0->y, prev->x, prev->y, prev->x, prev->y);
2409 d2d_outline_vertex_set(&v[2], p0->x + 25.0f * -prev->x, p0->y + 25.0f * -prev->y,
2410 prev->x, prev->y, prev->x, prev->y);
2411 d2d_outline_vertex_set(&v[3], p0->x + 25.0f * -prev->x, p0->y + 25.0f * -prev->y,
2412 -prev->x, -prev->y, -prev->x, -prev->y);
2414 else if (ccw < 0.0f)
2416 d2d_outline_vertex_set(&v[0], p0->x, p0->y, next->x, next->y, -prev->x, -prev->y);
2417 d2d_outline_vertex_set(&v[1], p0->x, p0->y, -next->x, -next->y, -next->x, -next->y);
2418 d2d_outline_vertex_set(&v[2], p0->x, p0->y, -next->x, -next->y, prev->x, prev->y);
2419 d2d_outline_vertex_set(&v[3], p0->x, p0->y, prev->x, prev->y, prev->x, prev->y);
2421 else
2423 d2d_outline_vertex_set(&v[0], p0->x, p0->y, prev->x, prev->y, -next->x, -next->y);
2424 d2d_outline_vertex_set(&v[1], p0->x, p0->y, -prev->x, -prev->y, -prev->x, -prev->y);
2425 d2d_outline_vertex_set(&v[2], p0->x, p0->y, -prev->x, -prev->y, next->x, next->y);
2426 d2d_outline_vertex_set(&v[3], p0->x, p0->y, next->x, next->y, next->x, next->y);
2428 geometry->outline.vertex_count += 4;
2430 d2d_face_set(&f[0], base_idx + 1, base_idx + 0, base_idx + 2);
2431 d2d_face_set(&f[1], base_idx + 2, base_idx + 0, base_idx + 3);
2432 geometry->outline.face_count += 2;
2434 return TRUE;
2437 static BOOL d2d_geometry_outline_add_line_segment(struct d2d_geometry *geometry,
2438 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *next)
2440 struct d2d_outline_vertex *v;
2441 D2D1_POINT_2F q_next;
2442 struct d2d_face *f;
2443 size_t base_idx;
2445 if (!d2d_array_reserve((void **)&geometry->outline.vertices, &geometry->outline.vertices_size,
2446 geometry->outline.vertex_count + 4, sizeof(*geometry->outline.vertices)))
2448 ERR("Failed to grow outline vertices array.\n");
2449 return FALSE;
2451 base_idx = geometry->outline.vertex_count;
2452 v = &geometry->outline.vertices[base_idx];
2454 if (!d2d_array_reserve((void **)&geometry->outline.faces, &geometry->outline.faces_size,
2455 geometry->outline.face_count + 2, sizeof(*geometry->outline.faces)))
2457 ERR("Failed to grow outline faces array.\n");
2458 return FALSE;
2460 f = &geometry->outline.faces[geometry->outline.face_count];
2462 d2d_point_subtract(&q_next, next, p0);
2463 d2d_point_normalise(&q_next);
2465 d2d_outline_vertex_set(&v[0], p0->x, p0->y, q_next.x, q_next.y, q_next.x, q_next.y);
2466 d2d_outline_vertex_set(&v[1], p0->x, p0->y, -q_next.x, -q_next.y, -q_next.x, -q_next.y);
2467 d2d_outline_vertex_set(&v[2], next->x, next->y, q_next.x, q_next.y, q_next.x, q_next.y);
2468 d2d_outline_vertex_set(&v[3], next->x, next->y, -q_next.x, -q_next.y, -q_next.x, -q_next.y);
2469 geometry->outline.vertex_count += 4;
2471 d2d_face_set(&f[0], base_idx + 0, base_idx + 1, base_idx + 2);
2472 d2d_face_set(&f[1], base_idx + 2, base_idx + 1, base_idx + 3);
2473 geometry->outline.face_count += 2;
2475 return TRUE;
2478 static BOOL d2d_geometry_outline_add_bezier_segment(struct d2d_geometry *geometry,
2479 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2)
2481 struct d2d_curve_outline_vertex *b;
2482 D2D1_POINT_2F r0, r1, r2;
2483 D2D1_POINT_2F q0, q1, q2;
2484 struct d2d_face *f;
2485 size_t base_idx;
2487 if (!d2d_array_reserve((void **)&geometry->outline.beziers, &geometry->outline.beziers_size,
2488 geometry->outline.bezier_count + 7, sizeof(*geometry->outline.beziers)))
2490 ERR("Failed to grow outline beziers array.\n");
2491 return FALSE;
2493 base_idx = geometry->outline.bezier_count;
2494 b = &geometry->outline.beziers[base_idx];
2496 if (!d2d_array_reserve((void **)&geometry->outline.bezier_faces, &geometry->outline.bezier_faces_size,
2497 geometry->outline.bezier_face_count + 5, sizeof(*geometry->outline.bezier_faces)))
2499 ERR("Failed to grow outline faces array.\n");
2500 return FALSE;
2502 f = &geometry->outline.bezier_faces[geometry->outline.bezier_face_count];
2504 d2d_point_lerp(&q0, p0, p1, 0.5f);
2505 d2d_point_lerp(&q1, p1, p2, 0.5f);
2506 d2d_point_lerp(&q2, &q0, &q1, 0.5f);
2508 d2d_point_subtract(&r0, &q0, p0);
2509 d2d_point_subtract(&r1, &q1, &q0);
2510 d2d_point_subtract(&r2, p2, &q1);
2512 d2d_point_normalise(&r0);
2513 d2d_point_normalise(&r1);
2514 d2d_point_normalise(&r2);
2516 if (d2d_point_ccw(p0, p1, p2) > 0.0f)
2518 d2d_point_scale(&r0, -1.0f);
2519 d2d_point_scale(&r1, -1.0f);
2520 d2d_point_scale(&r2, -1.0f);
2523 d2d_curve_outline_vertex_set(&b[0], p0, p0, p1, p2, r0.x, r0.y, r0.x, r0.y);
2524 d2d_curve_outline_vertex_set(&b[1], p0, p0, p1, p2, -r0.x, -r0.y, -r0.x, -r0.y);
2525 d2d_curve_outline_vertex_set(&b[2], &q0, p0, p1, p2, r0.x, r0.y, r1.x, r1.y);
2526 d2d_curve_outline_vertex_set(&b[3], &q2, p0, p1, p2, -r1.x, -r1.y, -r1.x, -r1.y);
2527 d2d_curve_outline_vertex_set(&b[4], &q1, p0, p1, p2, r1.x, r1.y, r2.x, r2.y);
2528 d2d_curve_outline_vertex_set(&b[5], p2, p0, p1, p2, -r2.x, -r2.y, -r2.x, -r2.y);
2529 d2d_curve_outline_vertex_set(&b[6], p2, p0, p1, p2, r2.x, r2.y, r2.x, r2.y);
2530 geometry->outline.bezier_count += 7;
2532 d2d_face_set(&f[0], base_idx + 0, base_idx + 1, base_idx + 2);
2533 d2d_face_set(&f[1], base_idx + 2, base_idx + 1, base_idx + 3);
2534 d2d_face_set(&f[2], base_idx + 3, base_idx + 4, base_idx + 2);
2535 d2d_face_set(&f[3], base_idx + 5, base_idx + 4, base_idx + 3);
2536 d2d_face_set(&f[4], base_idx + 5, base_idx + 6, base_idx + 4);
2537 geometry->outline.bezier_face_count += 5;
2539 return TRUE;
2542 static BOOL d2d_geometry_outline_add_arc_quadrant(struct d2d_geometry *geometry,
2543 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2)
2545 struct d2d_curve_outline_vertex *a;
2546 D2D1_POINT_2F r0, r1;
2547 struct d2d_face *f;
2548 size_t base_idx;
2550 if (!d2d_array_reserve((void **)&geometry->outline.arcs, &geometry->outline.arcs_size,
2551 geometry->outline.arc_count + 5, sizeof(*geometry->outline.arcs)))
2553 ERR("Failed to grow outline arcs array.\n");
2554 return FALSE;
2556 base_idx = geometry->outline.arc_count;
2557 a = &geometry->outline.arcs[base_idx];
2559 if (!d2d_array_reserve((void **)&geometry->outline.arc_faces, &geometry->outline.arc_faces_size,
2560 geometry->outline.arc_face_count + 3, sizeof(*geometry->outline.arc_faces)))
2562 ERR("Failed to grow outline faces array.\n");
2563 return FALSE;
2565 f = &geometry->outline.arc_faces[geometry->outline.arc_face_count];
2567 d2d_point_subtract(&r0, p1, p0);
2568 d2d_point_subtract(&r1, p2, p1);
2570 d2d_point_normalise(&r0);
2571 d2d_point_normalise(&r1);
2573 if (d2d_point_ccw(p0, p1, p2) > 0.0f)
2575 d2d_point_scale(&r0, -1.0f);
2576 d2d_point_scale(&r1, -1.0f);
2579 d2d_curve_outline_vertex_set(&a[0], p0, p0, p1, p2, r0.x, r0.y, r0.x, r0.y);
2580 d2d_curve_outline_vertex_set(&a[1], p0, p0, p1, p2, -r0.x, -r0.y, -r0.x, -r0.y);
2581 d2d_curve_outline_vertex_set(&a[2], p1, p0, p1, p2, r0.x, r0.y, r1.x, r1.y);
2582 d2d_curve_outline_vertex_set(&a[3], p2, p0, p1, p2, -r1.x, -r1.y, -r1.x, -r1.y);
2583 d2d_curve_outline_vertex_set(&a[4], p2, p0, p1, p2, r1.x, r1.y, r1.x, r1.y);
2584 geometry->outline.arc_count += 5;
2586 d2d_face_set(&f[0], base_idx + 0, base_idx + 1, base_idx + 2);
2587 d2d_face_set(&f[1], base_idx + 2, base_idx + 1, base_idx + 3);
2588 d2d_face_set(&f[2], base_idx + 2, base_idx + 4, base_idx + 3);
2589 geometry->outline.arc_face_count += 3;
2591 return TRUE;
2594 static BOOL d2d_geometry_add_figure_outline(struct d2d_geometry *geometry,
2595 struct d2d_figure *figure, D2D1_FIGURE_END figure_end)
2597 const D2D1_POINT_2F *prev, *p0, *p1, *next, *next_prev;
2598 size_t bezier_idx, i, vertex_count;
2599 enum d2d_vertex_type type;
2601 if (!(vertex_count = figure->vertex_count))
2602 return TRUE;
2604 p0 = &figure->vertices[0];
2605 if (figure_end == D2D1_FIGURE_END_CLOSED)
2607 if (figure->vertex_types[vertex_count - 1] == D2D_VERTEX_TYPE_END && !--vertex_count)
2608 return TRUE;
2610 /* In case of a CLOSED path, a join between first and last vertex is
2611 * required. */
2612 if (d2d_vertex_type_is_bezier(figure->vertex_types[vertex_count - 1]))
2613 prev = &figure->bezier_controls[figure->bezier_control_count - 1];
2614 else
2615 prev = &figure->vertices[vertex_count - 1];
2617 else
2619 if (!--vertex_count)
2620 return TRUE;
2621 prev = p0;
2624 for (i = 0, bezier_idx = 0; i < vertex_count; ++i)
2626 if ((type = figure->vertex_types[i]) == D2D_VERTEX_TYPE_NONE)
2628 prev = next_prev = &figure->vertices[i];
2629 continue;
2632 /* next: tangent along next segment, at p0.
2633 * p1: next vertex. */
2634 if (d2d_vertex_type_is_bezier(type))
2636 next_prev = next = &figure->bezier_controls[bezier_idx++];
2637 /* type BEZIER implies i + 1 < figure->vertex_count. */
2638 p1 = &figure->vertices[i + 1];
2640 if (!d2d_geometry_outline_add_bezier_segment(geometry, p0, next, p1))
2642 ERR("Failed to add bezier segment.\n");
2643 return FALSE;
2646 else
2648 if (i + 1 == figure->vertex_count)
2649 next = p1 = &figure->vertices[0];
2650 else
2651 next = p1 = &figure->vertices[i + 1];
2652 next_prev = p0;
2654 if (!d2d_geometry_outline_add_line_segment(geometry, p0, p1))
2656 ERR("Failed to add line segment.\n");
2657 return FALSE;
2661 if (i || figure_end == D2D1_FIGURE_END_CLOSED)
2663 D2D1_POINT_2F q_next, q_prev;
2665 d2d_point_subtract(&q_prev, prev, p0);
2666 d2d_point_subtract(&q_next, next, p0);
2668 d2d_point_normalise(&q_prev);
2669 d2d_point_normalise(&q_next);
2671 if (!d2d_geometry_outline_add_join(geometry, &q_prev, p0, &q_next))
2673 ERR("Failed to add join.\n");
2674 return FALSE;
2678 p0 = p1;
2679 prev = next_prev;
2682 return TRUE;
2685 static BOOL d2d_geometry_fill_add_arc_triangle(struct d2d_geometry *geometry,
2686 const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2)
2688 struct d2d_curve_vertex *a;
2690 if (!d2d_array_reserve((void **)&geometry->fill.arc_vertices, &geometry->fill.arc_vertices_size,
2691 geometry->fill.arc_vertex_count + 3, sizeof(*geometry->fill.arc_vertices)))
2692 return FALSE;
2694 a = &geometry->fill.arc_vertices[geometry->fill.arc_vertex_count];
2695 d2d_curve_vertex_set(&a[0], p0, 0.0f, 1.0f, -1.0f);
2696 d2d_curve_vertex_set(&a[1], p1, 1.0f, 1.0f, -1.0f);
2697 d2d_curve_vertex_set(&a[2], p2, 1.0f, 0.0f, -1.0f);
2698 geometry->fill.arc_vertex_count += 3;
2700 return TRUE;
2703 static void d2d_geometry_cleanup(struct d2d_geometry *geometry)
2705 heap_free(geometry->outline.arc_faces);
2706 heap_free(geometry->outline.arcs);
2707 heap_free(geometry->outline.bezier_faces);
2708 heap_free(geometry->outline.beziers);
2709 heap_free(geometry->outline.faces);
2710 heap_free(geometry->outline.vertices);
2711 heap_free(geometry->fill.arc_vertices);
2712 heap_free(geometry->fill.bezier_vertices);
2713 heap_free(geometry->fill.faces);
2714 heap_free(geometry->fill.vertices);
2715 ID2D1Factory_Release(geometry->factory);
2718 static void d2d_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
2719 const D2D1_MATRIX_3X2_F *transform, const struct ID2D1GeometryVtbl *vtbl)
2721 geometry->ID2D1Geometry_iface.lpVtbl = vtbl;
2722 geometry->refcount = 1;
2723 ID2D1Factory_AddRef(geometry->factory = factory);
2724 geometry->transform = *transform;
2727 static inline struct d2d_geometry *impl_from_ID2D1GeometrySink(ID2D1GeometrySink *iface)
2729 return CONTAINING_RECORD(iface, struct d2d_geometry, u.path.ID2D1GeometrySink_iface);
2732 static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_QueryInterface(ID2D1GeometrySink *iface, REFIID iid, void **out)
2734 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
2736 if (IsEqualGUID(iid, &IID_ID2D1GeometrySink)
2737 || IsEqualGUID(iid, &IID_ID2D1SimplifiedGeometrySink)
2738 || IsEqualGUID(iid, &IID_IUnknown))
2740 ID2D1GeometrySink_AddRef(iface);
2741 *out = iface;
2742 return S_OK;
2745 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
2747 *out = NULL;
2748 return E_NOINTERFACE;
2751 static ULONG STDMETHODCALLTYPE d2d_geometry_sink_AddRef(ID2D1GeometrySink *iface)
2753 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2755 TRACE("iface %p.\n", iface);
2757 return ID2D1Geometry_AddRef(&geometry->ID2D1Geometry_iface);
2760 static ULONG STDMETHODCALLTYPE d2d_geometry_sink_Release(ID2D1GeometrySink *iface)
2762 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2764 TRACE("iface %p.\n", iface);
2766 return ID2D1Geometry_Release(&geometry->ID2D1Geometry_iface);
2769 static void STDMETHODCALLTYPE d2d_geometry_sink_SetFillMode(ID2D1GeometrySink *iface, D2D1_FILL_MODE mode)
2771 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2773 TRACE("iface %p, mode %#x.\n", iface, mode);
2775 if (geometry->u.path.state == D2D_GEOMETRY_STATE_CLOSED)
2776 return;
2777 geometry->u.path.fill_mode = mode;
2780 static void STDMETHODCALLTYPE d2d_geometry_sink_SetSegmentFlags(ID2D1GeometrySink *iface, D2D1_PATH_SEGMENT flags)
2782 TRACE("iface %p, flags %#x.\n", iface, flags);
2784 if (flags != D2D1_PATH_SEGMENT_NONE)
2785 FIXME("Ignoring flags %#x.\n", flags);
2788 static void STDMETHODCALLTYPE d2d_geometry_sink_BeginFigure(ID2D1GeometrySink *iface,
2789 D2D1_POINT_2F start_point, D2D1_FIGURE_BEGIN figure_begin)
2791 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2792 struct d2d_figure *figure;
2794 TRACE("iface %p, start_point %s, figure_begin %#x.\n",
2795 iface, debug_d2d_point_2f(&start_point), figure_begin);
2797 if (geometry->u.path.state != D2D_GEOMETRY_STATE_OPEN)
2799 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2800 return;
2803 if (!d2d_path_geometry_add_figure(geometry))
2805 ERR("Failed to add figure.\n");
2806 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2807 return;
2810 figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2811 if (figure_begin == D2D1_FIGURE_BEGIN_HOLLOW)
2812 figure->flags |= D2D_FIGURE_FLAG_HOLLOW;
2814 if (!d2d_figure_add_vertex(figure, start_point))
2816 ERR("Failed to add vertex.\n");
2817 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2818 return;
2821 geometry->u.path.state = D2D_GEOMETRY_STATE_FIGURE;
2824 static void STDMETHODCALLTYPE d2d_geometry_sink_AddLines(ID2D1GeometrySink *iface,
2825 const D2D1_POINT_2F *points, UINT32 count)
2827 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2828 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2829 unsigned int i;
2831 TRACE("iface %p, points %p, count %u.\n", iface, points, count);
2833 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2835 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2836 return;
2839 for (i = 0; i < count; ++i)
2841 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_LINE;
2842 if (!d2d_figure_add_vertex(figure, points[i]))
2844 ERR("Failed to add vertex.\n");
2845 return;
2849 geometry->u.path.segment_count += count;
2852 static void STDMETHODCALLTYPE d2d_geometry_sink_AddBeziers(ID2D1GeometrySink *iface,
2853 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
2855 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2856 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2857 D2D1_POINT_2F p;
2858 unsigned int i;
2860 TRACE("iface %p, beziers %p, count %u.\n", iface, beziers, count);
2862 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2864 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2865 return;
2868 for (i = 0; i < count; ++i)
2870 D2D1_RECT_F bezier_bounds;
2872 if (!d2d_figure_add_original_bezier_controls(figure, 1, &beziers[i].point1)
2873 || !d2d_figure_add_original_bezier_controls(figure, 1, &beziers[i].point2))
2875 ERR("Failed to add cubic Bézier controls.\n");
2876 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2877 return;
2880 /* FIXME: This tries to approximate a cubic Bézier with a quadratic one. */
2881 p.x = (beziers[i].point1.x + beziers[i].point2.x) * 0.75f;
2882 p.y = (beziers[i].point1.y + beziers[i].point2.y) * 0.75f;
2883 p.x -= (figure->vertices[figure->vertex_count - 1].x + beziers[i].point3.x) * 0.25f;
2884 p.y -= (figure->vertices[figure->vertex_count - 1].y + beziers[i].point3.y) * 0.25f;
2885 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_BEZIER;
2887 d2d_rect_get_bezier_bounds(&bezier_bounds, &figure->vertices[figure->vertex_count - 1],
2888 &p, &beziers[i].point3);
2890 if (!d2d_figure_add_bezier_controls(figure, 1, &p))
2892 ERR("Failed to add bezier control.\n");
2893 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2894 return;
2897 if (!d2d_figure_add_vertex(figure, beziers[i].point3))
2899 ERR("Failed to add bezier vertex.\n");
2900 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2901 return;
2904 d2d_rect_union(&figure->bounds, &bezier_bounds);
2907 geometry->u.path.segment_count += count;
2910 static void STDMETHODCALLTYPE d2d_geometry_sink_EndFigure(ID2D1GeometrySink *iface, D2D1_FIGURE_END figure_end)
2912 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
2913 struct d2d_figure *figure;
2915 TRACE("iface %p, figure_end %#x.\n", iface, figure_end);
2917 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
2919 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2920 return;
2923 figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
2924 if (memcmp(&figure->vertices[0], &figure->vertices[figure->vertex_count - 1], sizeof(*figure->vertices)))
2925 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_LINE;
2926 else
2927 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_END;
2928 if (figure_end == D2D1_FIGURE_END_CLOSED)
2930 ++geometry->u.path.segment_count;
2931 figure->flags |= D2D_FIGURE_FLAG_CLOSED;
2934 if (!d2d_geometry_add_figure_outline(geometry, figure, figure_end))
2936 ERR("Failed to add figure outline.\n");
2937 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
2938 return;
2941 geometry->u.path.state = D2D_GEOMETRY_STATE_OPEN;
2944 static void d2d_path_geometry_free_figures(struct d2d_geometry *geometry)
2946 size_t i;
2948 if (!geometry->u.path.figures)
2949 return;
2951 for (i = 0; i < geometry->u.path.figure_count; ++i)
2953 heap_free(geometry->u.path.figures[i].original_bezier_controls);
2954 heap_free(geometry->u.path.figures[i].bezier_controls);
2955 heap_free(geometry->u.path.figures[i].vertices);
2957 heap_free(geometry->u.path.figures);
2958 geometry->u.path.figures = NULL;
2959 geometry->u.path.figures_size = 0;
2962 static BOOL d2d_geometry_get_bezier_segment_idx(struct d2d_geometry *geometry, struct d2d_segment_idx *idx, BOOL next)
2964 if (next)
2966 ++idx->vertex_idx;
2967 ++idx->control_idx;
2970 for (; idx->figure_idx < geometry->u.path.figure_count; ++idx->figure_idx, idx->vertex_idx = idx->control_idx = 0)
2972 struct d2d_figure *figure = &geometry->u.path.figures[idx->figure_idx];
2974 if (!figure->bezier_control_count || figure->flags & D2D_FIGURE_FLAG_HOLLOW)
2975 continue;
2977 for (; idx->vertex_idx < figure->vertex_count; ++idx->vertex_idx)
2979 if (d2d_vertex_type_is_bezier(figure->vertex_types[idx->vertex_idx]))
2980 return TRUE;
2984 return FALSE;
2987 static BOOL d2d_geometry_get_first_bezier_segment_idx(struct d2d_geometry *geometry, struct d2d_segment_idx *idx)
2989 memset(idx, 0, sizeof(*idx));
2991 return d2d_geometry_get_bezier_segment_idx(geometry, idx, FALSE);
2994 static BOOL d2d_geometry_get_next_bezier_segment_idx(struct d2d_geometry *geometry, struct d2d_segment_idx *idx)
2996 return d2d_geometry_get_bezier_segment_idx(geometry, idx, TRUE);
2999 static BOOL d2d_geometry_check_bezier_overlap(struct d2d_geometry *geometry,
3000 const struct d2d_segment_idx *idx_p, const struct d2d_segment_idx *idx_q)
3002 const D2D1_POINT_2F *a[3], *b[3], *p[2], *q;
3003 const struct d2d_figure *figure;
3004 D2D1_POINT_2F v_q[3], v_p, v_qp;
3005 unsigned int i, j, score;
3006 float det, t;
3008 figure = &geometry->u.path.figures[idx_p->figure_idx];
3009 a[0] = &figure->vertices[idx_p->vertex_idx];
3010 a[1] = &figure->bezier_controls[idx_p->control_idx];
3011 a[2] = &figure->vertices[idx_p->vertex_idx + 1];
3013 figure = &geometry->u.path.figures[idx_q->figure_idx];
3014 b[0] = &figure->vertices[idx_q->vertex_idx];
3015 b[1] = &figure->bezier_controls[idx_q->control_idx];
3016 b[2] = &figure->vertices[idx_q->vertex_idx + 1];
3018 if (d2d_point_ccw(a[0], a[1], a[2]) == 0.0f || d2d_point_ccw(b[0], b[1], b[2]) == 0.0f)
3019 return FALSE;
3021 d2d_point_subtract(&v_q[0], b[1], b[0]);
3022 d2d_point_subtract(&v_q[1], b[2], b[0]);
3023 d2d_point_subtract(&v_q[2], b[1], b[2]);
3025 /* Check for intersections between the edges. Strictly speaking we'd only
3026 * need to check 8 of the 9 possible intersections, since if there's any
3027 * intersection there has to be a second intersection as well. */
3028 for (i = 0; i < 3; ++i)
3030 d2d_point_subtract(&v_p, a[(i & 1) + 1], a[i & 2]);
3031 for (j = 0; j < 3; ++j)
3033 det = v_p.x * v_q[j].y - v_p.y * v_q[j].x;
3034 if (det == 0.0f)
3035 continue;
3037 d2d_point_subtract(&v_qp, a[i & 2], b[j & 2]);
3038 t = (v_q[j].x * v_qp.y - v_q[j].y * v_qp.x) / det;
3039 if (t <= 0.0f || t >= 1.0f)
3040 continue;
3042 t = (v_p.x * v_qp.y - v_p.y * v_qp.x) / det;
3043 if (t <= 0.0f || t >= 1.0f)
3044 continue;
3046 return TRUE;
3050 /* Check if one triangle is contained within the other. */
3051 for (j = 0, score = 0, q = a[1], p[0] = b[2]; j < 3; ++j)
3053 p[1] = b[j];
3054 d2d_point_subtract(&v_p, p[1], p[0]);
3055 d2d_point_subtract(&v_qp, q, p[0]);
3057 if ((q->y < p[0]->y) != (q->y < p[1]->y) && v_qp.x < v_p.x * (v_qp.y / v_p.y))
3058 ++score;
3060 p[0] = p[1];
3063 if (score & 1)
3064 return TRUE;
3066 for (j = 0, score = 0, q = b[1], p[0] = a[2]; j < 3; ++j)
3068 p[1] = a[j];
3069 d2d_point_subtract(&v_p, p[1], p[0]);
3070 d2d_point_subtract(&v_qp, q, p[0]);
3072 if ((q->y < p[0]->y) != (q->y < p[1]->y) && v_qp.x < v_p.x * (v_qp.y / v_p.y))
3073 ++score;
3075 p[0] = p[1];
3078 return score & 1;
3081 static float d2d_geometry_bezier_ccw(struct d2d_geometry *geometry, const struct d2d_segment_idx *idx)
3083 const struct d2d_figure *figure = &geometry->u.path.figures[idx->figure_idx];
3084 size_t next = idx->vertex_idx + 1;
3086 return d2d_point_ccw(&figure->vertices[idx->vertex_idx],
3087 &figure->bezier_controls[idx->control_idx], &figure->vertices[next]);
3090 static BOOL d2d_geometry_split_bezier(struct d2d_geometry *geometry, const struct d2d_segment_idx *idx)
3092 const D2D1_POINT_2F *p[3];
3093 struct d2d_figure *figure;
3094 D2D1_POINT_2F q[3];
3095 size_t next;
3097 figure = &geometry->u.path.figures[idx->figure_idx];
3098 p[0] = &figure->vertices[idx->vertex_idx];
3099 p[1] = &figure->bezier_controls[idx->control_idx];
3100 next = idx->vertex_idx + 1;
3101 p[2] = &figure->vertices[next];
3103 d2d_point_lerp(&q[0], p[0], p[1], 0.5f);
3104 d2d_point_lerp(&q[1], p[1], p[2], 0.5f);
3105 d2d_point_lerp(&q[2], &q[0], &q[1], 0.5f);
3107 figure->bezier_controls[idx->control_idx] = q[0];
3108 if (!(d2d_figure_insert_bezier_controls(figure, idx->control_idx + 1, 1, &q[1])))
3109 return FALSE;
3110 if (!(d2d_figure_insert_vertex(figure, idx->vertex_idx + 1, q[2])))
3111 return FALSE;
3112 figure->vertex_types[idx->vertex_idx + 1] = D2D_VERTEX_TYPE_SPLIT_BEZIER;
3114 return TRUE;
3117 static HRESULT d2d_geometry_resolve_beziers(struct d2d_geometry *geometry)
3119 struct d2d_segment_idx idx_p, idx_q;
3120 struct d2d_curve_vertex *b;
3121 const D2D1_POINT_2F *p[3];
3122 struct d2d_figure *figure;
3123 size_t bezier_idx, i;
3125 if (!d2d_geometry_get_first_bezier_segment_idx(geometry, &idx_p))
3126 return S_OK;
3128 /* Split overlapping bezier control triangles. */
3129 while (d2d_geometry_get_next_bezier_segment_idx(geometry, &idx_p))
3131 d2d_geometry_get_first_bezier_segment_idx(geometry, &idx_q);
3132 while (idx_q.figure_idx < idx_p.figure_idx || idx_q.vertex_idx < idx_p.vertex_idx)
3134 while (d2d_geometry_check_bezier_overlap(geometry, &idx_p, &idx_q))
3136 if (fabsf(d2d_geometry_bezier_ccw(geometry, &idx_q)) > fabsf(d2d_geometry_bezier_ccw(geometry, &idx_p)))
3138 if (!d2d_geometry_split_bezier(geometry, &idx_q))
3139 return E_OUTOFMEMORY;
3140 if (idx_p.figure_idx == idx_q.figure_idx)
3142 ++idx_p.vertex_idx;
3143 ++idx_p.control_idx;
3146 else
3148 if (!d2d_geometry_split_bezier(geometry, &idx_p))
3149 return E_OUTOFMEMORY;
3152 d2d_geometry_get_next_bezier_segment_idx(geometry, &idx_q);
3156 for (i = 0; i < geometry->u.path.figure_count; ++i)
3158 if (geometry->u.path.figures[i].flags & D2D_FIGURE_FLAG_HOLLOW)
3159 continue;
3160 geometry->fill.bezier_vertex_count += 3 * geometry->u.path.figures[i].bezier_control_count;
3163 if (!(geometry->fill.bezier_vertices = heap_calloc(geometry->fill.bezier_vertex_count,
3164 sizeof(*geometry->fill.bezier_vertices))))
3166 ERR("Failed to allocate bezier vertices array.\n");
3167 geometry->fill.bezier_vertex_count = 0;
3168 return E_OUTOFMEMORY;
3171 bezier_idx = 0;
3172 d2d_geometry_get_first_bezier_segment_idx(geometry, &idx_p);
3173 for (;;)
3175 float sign = -1.0f;
3177 figure = &geometry->u.path.figures[idx_p.figure_idx];
3178 p[0] = &figure->vertices[idx_p.vertex_idx];
3179 p[1] = &figure->bezier_controls[idx_p.control_idx];
3181 i = idx_p.vertex_idx + 1;
3182 if (d2d_path_geometry_point_inside(geometry, p[1], FALSE))
3184 sign = 1.0f;
3185 d2d_figure_insert_vertex(figure, i, *p[1]);
3186 /* Inserting a vertex potentially invalidates p[0]. */
3187 p[0] = &figure->vertices[idx_p.vertex_idx];
3188 ++i;
3191 if (i == figure->vertex_count)
3192 i = 0;
3193 p[2] = &figure->vertices[i];
3195 b = &geometry->fill.bezier_vertices[bezier_idx * 3];
3196 d2d_curve_vertex_set(&b[0], p[0], 0.0f, 0.0f, sign);
3197 d2d_curve_vertex_set(&b[1], p[1], 0.5f, 0.0f, sign);
3198 d2d_curve_vertex_set(&b[2], p[2], 1.0f, 1.0f, sign);
3200 if (!d2d_geometry_get_next_bezier_segment_idx(geometry, &idx_p))
3201 break;
3202 ++bezier_idx;
3205 return S_OK;
3208 static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_Close(ID2D1GeometrySink *iface)
3210 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
3211 HRESULT hr = E_FAIL;
3213 TRACE("iface %p.\n", iface);
3215 if (geometry->u.path.state != D2D_GEOMETRY_STATE_OPEN)
3217 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
3218 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3219 return D2DERR_WRONG_STATE;
3221 geometry->u.path.state = D2D_GEOMETRY_STATE_CLOSED;
3223 if (!d2d_geometry_intersect_self(geometry))
3224 goto done;
3225 if (FAILED(hr = d2d_geometry_resolve_beziers(geometry)))
3226 goto done;
3227 if (FAILED(hr = d2d_path_geometry_triangulate(geometry)))
3228 goto done;
3230 done:
3231 if (FAILED(hr))
3233 heap_free(geometry->fill.bezier_vertices);
3234 geometry->fill.bezier_vertex_count = 0;
3235 d2d_path_geometry_free_figures(geometry);
3236 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3238 return hr;
3241 static void STDMETHODCALLTYPE d2d_geometry_sink_AddLine(ID2D1GeometrySink *iface, D2D1_POINT_2F point)
3243 TRACE("iface %p, point %s.\n", iface, debug_d2d_point_2f(&point));
3245 d2d_geometry_sink_AddLines(iface, &point, 1);
3248 static void STDMETHODCALLTYPE d2d_geometry_sink_AddBezier(ID2D1GeometrySink *iface, const D2D1_BEZIER_SEGMENT *bezier)
3250 TRACE("iface %p, bezier %p.\n", iface, bezier);
3252 d2d_geometry_sink_AddBeziers(iface, bezier, 1);
3255 static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBezier(ID2D1GeometrySink *iface,
3256 const D2D1_QUADRATIC_BEZIER_SEGMENT *bezier)
3258 TRACE("iface %p, bezier %p.\n", iface, bezier);
3260 ID2D1GeometrySink_AddQuadraticBeziers(iface, bezier, 1);
3263 static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBeziers(ID2D1GeometrySink *iface,
3264 const D2D1_QUADRATIC_BEZIER_SEGMENT *beziers, UINT32 bezier_count)
3266 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
3267 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
3268 unsigned int i;
3270 TRACE("iface %p, beziers %p, bezier_count %u.\n", iface, beziers, bezier_count);
3272 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
3274 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3275 return;
3278 for (i = 0; i < bezier_count; ++i)
3280 D2D1_RECT_F bezier_bounds;
3281 D2D1_POINT_2F p[2];
3283 /* Construct a cubic curve. */
3284 d2d_point_lerp(&p[0], &figure->vertices[figure->vertex_count - 1], &beziers[i].point1, 2.0f / 3.0f);
3285 d2d_point_lerp(&p[1], &beziers[i].point2, &beziers[i].point1, 2.0f / 3.0f);
3286 if (!d2d_figure_add_original_bezier_controls(figure, 2, p))
3288 ERR("Failed to add cubic Bézier controls.\n");
3289 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3290 return;
3293 d2d_rect_get_bezier_bounds(&bezier_bounds, &figure->vertices[figure->vertex_count - 1],
3294 &beziers[i].point1, &beziers[i].point2);
3296 figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_BEZIER;
3297 if (!d2d_figure_add_bezier_controls(figure, 1, &beziers[i].point1))
3299 ERR("Failed to add bezier.\n");
3300 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3301 return;
3304 if (!d2d_figure_add_vertex(figure, beziers[i].point2))
3306 ERR("Failed to add bezier vertex.\n");
3307 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3308 return;
3311 d2d_rect_union(&figure->bounds, &bezier_bounds);
3314 geometry->u.path.segment_count += bezier_count;
3317 static void STDMETHODCALLTYPE d2d_geometry_sink_AddArc(ID2D1GeometrySink *iface, const D2D1_ARC_SEGMENT *arc)
3319 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
3321 FIXME("iface %p, arc %p stub!\n", iface, arc);
3323 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
3325 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
3326 return;
3329 if (!d2d_figure_add_vertex(&geometry->u.path.figures[geometry->u.path.figure_count - 1], arc->point))
3331 ERR("Failed to add vertex.\n");
3332 return;
3335 ++geometry->u.path.segment_count;
3338 static const struct ID2D1GeometrySinkVtbl d2d_geometry_sink_vtbl =
3340 d2d_geometry_sink_QueryInterface,
3341 d2d_geometry_sink_AddRef,
3342 d2d_geometry_sink_Release,
3343 d2d_geometry_sink_SetFillMode,
3344 d2d_geometry_sink_SetSegmentFlags,
3345 d2d_geometry_sink_BeginFigure,
3346 d2d_geometry_sink_AddLines,
3347 d2d_geometry_sink_AddBeziers,
3348 d2d_geometry_sink_EndFigure,
3349 d2d_geometry_sink_Close,
3350 d2d_geometry_sink_AddLine,
3351 d2d_geometry_sink_AddBezier,
3352 d2d_geometry_sink_AddQuadraticBezier,
3353 d2d_geometry_sink_AddQuadraticBeziers,
3354 d2d_geometry_sink_AddArc,
3357 static inline struct d2d_geometry *impl_from_ID2D1PathGeometry1(ID2D1PathGeometry1 *iface)
3359 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
3362 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_QueryInterface(ID2D1PathGeometry1 *iface, REFIID iid, void **out)
3364 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
3366 if (IsEqualGUID(iid, &IID_ID2D1PathGeometry1)
3367 || IsEqualGUID(iid, &IID_ID2D1PathGeometry)
3368 || IsEqualGUID(iid, &IID_ID2D1Geometry)
3369 || IsEqualGUID(iid, &IID_ID2D1Resource)
3370 || IsEqualGUID(iid, &IID_IUnknown))
3372 ID2D1PathGeometry1_AddRef(iface);
3373 *out = iface;
3374 return S_OK;
3377 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
3379 *out = NULL;
3380 return E_NOINTERFACE;
3383 static ULONG STDMETHODCALLTYPE d2d_path_geometry_AddRef(ID2D1PathGeometry1 *iface)
3385 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface);
3386 ULONG refcount = InterlockedIncrement(&geometry->refcount);
3388 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
3390 return refcount;
3393 static ULONG STDMETHODCALLTYPE d2d_path_geometry_Release(ID2D1PathGeometry1 *iface)
3395 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface);
3396 ULONG refcount = InterlockedDecrement(&geometry->refcount);
3398 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
3400 if (!refcount)
3402 d2d_path_geometry_free_figures(geometry);
3403 d2d_geometry_cleanup(geometry);
3404 heap_free(geometry);
3407 return refcount;
3410 static void STDMETHODCALLTYPE d2d_path_geometry_GetFactory(ID2D1PathGeometry1 *iface, ID2D1Factory **factory)
3412 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface);
3414 TRACE("iface %p, factory %p.\n", iface, factory);
3416 ID2D1Factory_AddRef(*factory = geometry->factory);
3419 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetBounds(ID2D1PathGeometry1 *iface,
3420 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
3422 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface);
3423 size_t i;
3425 TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
3427 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
3428 return D2DERR_WRONG_STATE;
3430 bounds->left = FLT_MAX;
3431 bounds->top = FLT_MAX;
3432 bounds->right = -FLT_MAX;
3433 bounds->bottom = -FLT_MAX;
3435 if (!transform)
3437 if (geometry->u.path.bounds.left > geometry->u.path.bounds.right
3438 && !isinf(geometry->u.path.bounds.left))
3440 for (i = 0; i < geometry->u.path.figure_count; ++i)
3442 if (geometry->u.path.figures[i].flags & D2D_FIGURE_FLAG_HOLLOW)
3443 continue;
3444 d2d_rect_union(&geometry->u.path.bounds, &geometry->u.path.figures[i].bounds);
3446 if (geometry->u.path.bounds.left > geometry->u.path.bounds.right)
3448 geometry->u.path.bounds.left = INFINITY;
3449 geometry->u.path.bounds.right = FLT_MAX;
3450 geometry->u.path.bounds.top = INFINITY;
3451 geometry->u.path.bounds.bottom = FLT_MAX;
3455 *bounds = geometry->u.path.bounds;
3456 return S_OK;
3459 for (i = 0; i < geometry->u.path.figure_count; ++i)
3461 const struct d2d_figure *figure = &geometry->u.path.figures[i];
3462 enum d2d_vertex_type type = D2D_VERTEX_TYPE_NONE;
3463 D2D1_RECT_F bezier_bounds;
3464 D2D1_POINT_2F p, p1, p2;
3465 size_t j, bezier_idx;
3467 if (figure->flags & D2D_FIGURE_FLAG_HOLLOW)
3468 continue;
3470 for (j = 0; j < figure->vertex_count; ++j)
3472 if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
3473 continue;
3475 p = figure->vertices[j];
3476 type = figure->vertex_types[j];
3477 d2d_point_transform(&p, transform, p.x, p.y);
3478 d2d_rect_expand(bounds, &p);
3479 break;
3482 for (bezier_idx = 0, ++j; j < figure->vertex_count; ++j)
3484 enum d2d_vertex_type next_type;
3486 if ((next_type = figure->vertex_types[j]) == D2D_VERTEX_TYPE_NONE
3487 || d2d_vertex_type_is_split_bezier(next_type))
3488 continue;
3490 switch (type)
3492 case D2D_VERTEX_TYPE_LINE:
3493 p = figure->vertices[j];
3494 d2d_point_transform(&p, transform, p.x, p.y);
3495 d2d_rect_expand(bounds, &p);
3496 break;
3498 case D2D_VERTEX_TYPE_BEZIER:
3499 /* FIXME: This attempts to approximate a cubic Bézier with
3500 * a quadratic one. */
3501 p1 = figure->original_bezier_controls[bezier_idx++];
3502 d2d_point_transform(&p1, transform, p1.x, p1.y);
3503 p2 = figure->original_bezier_controls[bezier_idx++];
3504 d2d_point_transform(&p2, transform, p2.x, p2.y);
3505 p1.x = (p1.x + p2.x) * 0.75f;
3506 p1.y = (p1.y + p2.y) * 0.75f;
3507 p2 = figure->vertices[j];
3508 d2d_point_transform(&p2, transform, p2.x, p2.y);
3509 p1.x -= (p.x + p2.x) * 0.25f;
3510 p1.y -= (p.y + p2.y) * 0.25f;
3512 d2d_rect_get_bezier_bounds(&bezier_bounds, &p, &p1, &p2);
3513 d2d_rect_union(bounds, &bezier_bounds);
3514 p = p2;
3515 break;
3517 default:
3518 FIXME("Unhandled vertex type %#x.\n", type);
3519 p = figure->vertices[j];
3520 d2d_point_transform(&p, transform, p.x, p.y);
3521 d2d_rect_expand(bounds, &p);
3522 break;
3525 type = next_type;
3529 if (bounds->left > bounds->right)
3531 bounds->left = INFINITY;
3532 bounds->right = FLT_MAX;
3533 bounds->top = INFINITY;
3534 bounds->bottom = FLT_MAX;
3537 return S_OK;
3540 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetWidenedBounds(ID2D1PathGeometry1 *iface, float stroke_width,
3541 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_RECT_F *bounds)
3543 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
3544 iface, stroke_width, stroke_style, transform, tolerance, bounds);
3546 return E_NOTIMPL;
3549 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_StrokeContainsPoint(ID2D1PathGeometry1 *iface,
3550 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
3551 float tolerance, BOOL *contains)
3553 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface);
3554 enum d2d_vertex_type type = D2D_VERTEX_TYPE_NONE;
3555 unsigned int i, j, bezier_idx;
3556 D2D1_BEZIER_SEGMENT b;
3557 D2D1_POINT_2F p, p1;
3559 TRACE("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p.\n",
3560 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
3562 if (stroke_style)
3563 FIXME("Ignoring stroke style %p.\n", stroke_style);
3565 if (!transform)
3566 transform = &identity;
3568 if (tolerance <= 0.0f)
3569 tolerance = D2D1_DEFAULT_FLATTENING_TOLERANCE;
3571 *contains = FALSE;
3572 for (i = 0; i < geometry->u.path.figure_count; ++i)
3574 const struct d2d_figure *figure = &geometry->u.path.figures[i];
3576 for (j = 0; j < figure->vertex_count; ++j)
3578 if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
3579 continue;
3581 p = figure->vertices[j];
3582 type = figure->vertex_types[j];
3583 break;
3586 for (bezier_idx = 0, ++j; j < figure->vertex_count; ++j)
3588 enum d2d_vertex_type next_type;
3590 if ((next_type = figure->vertex_types[j]) == D2D_VERTEX_TYPE_NONE
3591 || d2d_vertex_type_is_split_bezier(next_type))
3592 continue;
3594 switch (type)
3596 case D2D_VERTEX_TYPE_LINE:
3597 p1 = figure->vertices[j];
3598 *contains = d2d_point_on_line_segment(&point, &p, &p1, transform, stroke_width * 0.5f, tolerance);
3599 p = p1;
3600 break;
3602 case D2D_VERTEX_TYPE_BEZIER:
3603 b.point1 = figure->original_bezier_controls[bezier_idx++];
3604 b.point2 = figure->original_bezier_controls[bezier_idx++];
3605 b.point3 = figure->vertices[j];
3606 *contains = d2d_point_on_bezier_segment(&point, &p, &b, transform, stroke_width, tolerance);
3607 p = b.point3;
3608 break;
3610 default:
3611 FIXME("Unhandled vertex type %#x.\n", type);
3612 p = figure->vertices[j];
3613 break;
3615 if (*contains)
3616 return S_OK;
3617 type = next_type;
3620 if (type == D2D_VERTEX_TYPE_LINE)
3622 p1 = figure->vertices[0];
3623 if (figure->flags & D2D_FIGURE_FLAG_CLOSED)
3624 *contains = d2d_point_on_line_segment(&point, &p, &p1, transform, stroke_width * 0.5f, tolerance);
3627 if (*contains)
3628 return S_OK;
3631 return S_OK;
3634 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_FillContainsPoint(ID2D1PathGeometry1 *iface,
3635 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
3637 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface);
3638 D2D1_MATRIX_3X2_F g_i;
3640 TRACE("iface %p, point %s, transform %p, tolerance %.8e, contains %p.\n",
3641 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
3643 if (transform)
3645 if (!d2d_matrix_invert(&g_i, transform))
3646 return D2DERR_UNSUPPORTED_OPERATION;
3647 d2d_point_transform(&point, &g_i, point.x, point.y);
3650 *contains = !!d2d_path_geometry_point_inside(geometry, &point, FALSE);
3652 TRACE("-> %#x.\n", *contains);
3654 return S_OK;
3657 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_CompareWithGeometry(ID2D1PathGeometry1 *iface,
3658 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
3660 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
3661 iface, geometry, transform, tolerance, relation);
3663 return E_NOTIMPL;
3666 static void d2d_geometry_flatten_cubic(ID2D1SimplifiedGeometrySink *sink, const D2D1_POINT_2F *p0,
3667 const D2D1_BEZIER_SEGMENT *b, float tolerance)
3669 D2D1_BEZIER_SEGMENT b0, b1;
3670 D2D1_POINT_2F q;
3671 float d;
3673 /* It's certainly possible to calculate the maximum deviation of the
3674 * approximation from the curve, but it's a little involved. Instead, note
3675 * that if the control points were evenly spaced and collinear, p1 would
3676 * be exactly between p0 and p2, and p2 would be exactly between p1 and
3677 * p3. The deviation is a decent enough approximation, and much easier to
3678 * calculate.
3680 * p1' = (p0 + p2) / 2
3681 * p2' = (p1 + p3) / 2
3682 * d = ‖p1 - p1'‖₁ + ‖p2 - p2'‖₁ */
3683 d2d_point_lerp(&q, p0, &b->point2, 0.5f);
3684 d2d_point_subtract(&q, &b->point1, &q);
3685 d = fabsf(q.x) + fabsf(q.y);
3686 d2d_point_lerp(&q, &b->point1, &b->point3, 0.5f);
3687 d2d_point_subtract(&q, &b->point2, &q);
3688 d += fabsf(q.x) + fabsf(q.y);
3689 if (d < tolerance)
3691 ID2D1SimplifiedGeometrySink_AddLines(sink, &b->point3, 1);
3692 return;
3695 d2d_point_lerp(&q, &b->point1, &b->point2, 0.5f);
3697 b1.point3 = b->point3;
3698 d2d_point_lerp(&b1.point2, &b1.point3, &b->point2, 0.5f);
3699 d2d_point_lerp(&b1.point1, &b1.point2, &q, 0.5f);
3701 d2d_point_lerp(&b0.point1, p0, &b->point1, 0.5f);
3702 d2d_point_lerp(&b0.point2, &b0.point1, &q, 0.5f);
3703 d2d_point_lerp(&b0.point3, &b0.point2, &b1.point1, 0.5f);
3705 d2d_geometry_flatten_cubic(sink, p0, &b0, tolerance);
3706 ID2D1SimplifiedGeometrySink_SetSegmentFlags(sink, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN);
3707 d2d_geometry_flatten_cubic(sink, &b0.point3, &b1, tolerance);
3708 ID2D1SimplifiedGeometrySink_SetSegmentFlags(sink, D2D1_PATH_SEGMENT_NONE);
3711 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry1 *iface,
3712 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
3713 ID2D1SimplifiedGeometrySink *sink)
3715 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface);
3716 enum d2d_vertex_type type = D2D_VERTEX_TYPE_NONE;
3717 unsigned int i, j, bezier_idx;
3718 D2D1_FIGURE_BEGIN begin;
3719 D2D1_BEZIER_SEGMENT b;
3720 D2D1_FIGURE_END end;
3721 D2D1_POINT_2F p;
3723 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
3724 iface, option, transform, tolerance, sink);
3726 ID2D1SimplifiedGeometrySink_SetFillMode(sink, geometry->u.path.fill_mode);
3727 for (i = 0; i < geometry->u.path.figure_count; ++i)
3729 const struct d2d_figure *figure = &geometry->u.path.figures[i];
3731 for (j = 0; j < figure->vertex_count; ++j)
3733 if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
3734 continue;
3736 p = figure->vertices[j];
3737 if (transform)
3738 d2d_point_transform(&p, transform, p.x, p.y);
3739 begin = figure->flags & D2D_FIGURE_FLAG_HOLLOW ? D2D1_FIGURE_BEGIN_HOLLOW : D2D1_FIGURE_BEGIN_FILLED;
3740 ID2D1SimplifiedGeometrySink_BeginFigure(sink, p, begin);
3741 type = figure->vertex_types[j];
3742 break;
3745 for (bezier_idx = 0, ++j; j < figure->vertex_count; ++j)
3747 enum d2d_vertex_type next_type;
3749 if ((next_type = figure->vertex_types[j]) == D2D_VERTEX_TYPE_NONE
3750 || d2d_vertex_type_is_split_bezier(next_type))
3751 continue;
3753 switch (type)
3755 case D2D_VERTEX_TYPE_LINE:
3756 p = figure->vertices[j];
3757 if (transform)
3758 d2d_point_transform(&p, transform, p.x, p.y);
3759 ID2D1SimplifiedGeometrySink_AddLines(sink, &p, 1);
3760 break;
3762 case D2D_VERTEX_TYPE_BEZIER:
3763 b.point1 = figure->original_bezier_controls[bezier_idx++];
3764 b.point2 = figure->original_bezier_controls[bezier_idx++];
3765 b.point3 = figure->vertices[j];
3766 if (transform)
3768 d2d_point_transform(&b.point1, transform, b.point1.x, b.point1.y);
3769 d2d_point_transform(&b.point2, transform, b.point2.x, b.point2.y);
3770 d2d_point_transform(&b.point3, transform, b.point3.x, b.point3.y);
3773 if (option == D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES)
3774 d2d_geometry_flatten_cubic(sink, &p, &b, tolerance);
3775 else
3776 ID2D1SimplifiedGeometrySink_AddBeziers(sink, &b, 1);
3777 p = b.point3;
3778 break;
3780 default:
3781 FIXME("Unhandled vertex type %#x.\n", type);
3782 p = figure->vertices[j];
3783 if (transform)
3784 d2d_point_transform(&p, transform, p.x, p.y);
3785 ID2D1SimplifiedGeometrySink_AddLines(sink, &p, 1);
3786 break;
3789 type = next_type;
3792 end = figure->flags & D2D_FIGURE_FLAG_CLOSED ? D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN;
3793 ID2D1SimplifiedGeometrySink_EndFigure(sink, end);
3796 return S_OK;
3799 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Tessellate(ID2D1PathGeometry1 *iface,
3800 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
3802 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
3804 return E_NOTIMPL;
3807 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_CombineWithGeometry(ID2D1PathGeometry1 *iface,
3808 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
3809 float tolerance, ID2D1SimplifiedGeometrySink *sink)
3811 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
3812 iface, geometry, combine_mode, transform, tolerance, sink);
3814 return E_NOTIMPL;
3817 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Outline(ID2D1PathGeometry1 *iface,
3818 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
3820 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
3822 return E_NOTIMPL;
3825 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeArea(ID2D1PathGeometry1 *iface,
3826 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
3828 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
3830 return E_NOTIMPL;
3833 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeLength(ID2D1PathGeometry1 *iface,
3834 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
3836 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
3838 return E_NOTIMPL;
3841 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputePointAtLength(ID2D1PathGeometry1 *iface, float length,
3842 const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point, D2D1_POINT_2F *tangent)
3844 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
3845 iface, length, transform, tolerance, point, tangent);
3847 return E_NOTIMPL;
3850 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Widen(ID2D1PathGeometry1 *iface, float stroke_width,
3851 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
3852 ID2D1SimplifiedGeometrySink *sink)
3854 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
3855 iface, stroke_width, stroke_style, transform, tolerance, sink);
3857 return E_NOTIMPL;
3860 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Open(ID2D1PathGeometry1 *iface, ID2D1GeometrySink **sink)
3862 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface);
3864 TRACE("iface %p, sink %p.\n", iface, sink);
3866 if (geometry->u.path.state != D2D_GEOMETRY_STATE_INITIAL)
3867 return D2DERR_WRONG_STATE;
3869 *sink = &geometry->u.path.ID2D1GeometrySink_iface;
3870 ID2D1GeometrySink_AddRef(*sink);
3872 geometry->u.path.state = D2D_GEOMETRY_STATE_OPEN;
3874 return S_OK;
3877 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Stream(ID2D1PathGeometry1 *iface, ID2D1GeometrySink *sink)
3879 FIXME("iface %p, sink %p stub!\n", iface, sink);
3881 return E_NOTIMPL;
3884 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetSegmentCount(ID2D1PathGeometry1 *iface, UINT32 *count)
3886 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface);
3888 TRACE("iface %p, count %p.\n", iface, count);
3890 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
3891 return D2DERR_WRONG_STATE;
3893 *count = geometry->u.path.segment_count;
3895 return S_OK;
3898 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetFigureCount(ID2D1PathGeometry1 *iface, UINT32 *count)
3900 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface);
3902 TRACE("iface %p, count %p.\n", iface, count);
3904 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
3905 return D2DERR_WRONG_STATE;
3907 *count = geometry->u.path.figure_count;
3909 return S_OK;
3912 static HRESULT STDMETHODCALLTYPE d2d_path_geometry1_ComputePointAndSegmentAtLength(ID2D1PathGeometry1 *iface,
3913 float length, UINT32 start_segment, const D2D1_MATRIX_3X2_F *transform, float tolerance,
3914 D2D1_POINT_DESCRIPTION *point_desc)
3916 FIXME("iface %p, length %.8e, start_segment %u, transform %p, tolerance %.8e, point_desc %p.\n",
3917 iface, length, start_segment, transform, tolerance, point_desc);
3919 return E_NOTIMPL;
3922 static const struct ID2D1PathGeometry1Vtbl d2d_path_geometry_vtbl =
3924 d2d_path_geometry_QueryInterface,
3925 d2d_path_geometry_AddRef,
3926 d2d_path_geometry_Release,
3927 d2d_path_geometry_GetFactory,
3928 d2d_path_geometry_GetBounds,
3929 d2d_path_geometry_GetWidenedBounds,
3930 d2d_path_geometry_StrokeContainsPoint,
3931 d2d_path_geometry_FillContainsPoint,
3932 d2d_path_geometry_CompareWithGeometry,
3933 d2d_path_geometry_Simplify,
3934 d2d_path_geometry_Tessellate,
3935 d2d_path_geometry_CombineWithGeometry,
3936 d2d_path_geometry_Outline,
3937 d2d_path_geometry_ComputeArea,
3938 d2d_path_geometry_ComputeLength,
3939 d2d_path_geometry_ComputePointAtLength,
3940 d2d_path_geometry_Widen,
3941 d2d_path_geometry_Open,
3942 d2d_path_geometry_Stream,
3943 d2d_path_geometry_GetSegmentCount,
3944 d2d_path_geometry_GetFigureCount,
3945 d2d_path_geometry1_ComputePointAndSegmentAtLength,
3948 void d2d_path_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory)
3950 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl);
3951 geometry->u.path.ID2D1GeometrySink_iface.lpVtbl = &d2d_geometry_sink_vtbl;
3952 geometry->u.path.bounds.left = FLT_MAX;
3953 geometry->u.path.bounds.right = -FLT_MAX;
3954 geometry->u.path.bounds.top = FLT_MAX;
3955 geometry->u.path.bounds.bottom = -FLT_MAX;
3958 static inline struct d2d_geometry *impl_from_ID2D1EllipseGeometry(ID2D1EllipseGeometry *iface)
3960 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
3963 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_QueryInterface(ID2D1EllipseGeometry *iface,
3964 REFIID iid, void **out)
3966 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
3968 if (IsEqualGUID(iid, &IID_ID2D1EllipseGeometry)
3969 || IsEqualGUID(iid, &IID_ID2D1Geometry)
3970 || IsEqualGUID(iid, &IID_ID2D1Resource)
3971 || IsEqualGUID(iid, &IID_IUnknown))
3973 ID2D1EllipseGeometry_AddRef(iface);
3974 *out = iface;
3975 return S_OK;
3978 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
3980 *out = NULL;
3981 return E_NOINTERFACE;
3984 static ULONG STDMETHODCALLTYPE d2d_ellipse_geometry_AddRef(ID2D1EllipseGeometry *iface)
3986 struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface);
3987 ULONG refcount = InterlockedIncrement(&geometry->refcount);
3989 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
3991 return refcount;
3994 static ULONG STDMETHODCALLTYPE d2d_ellipse_geometry_Release(ID2D1EllipseGeometry *iface)
3996 struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface);
3997 ULONG refcount = InterlockedDecrement(&geometry->refcount);
3999 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
4001 if (!refcount)
4003 d2d_geometry_cleanup(geometry);
4004 heap_free(geometry);
4007 return refcount;
4010 static void STDMETHODCALLTYPE d2d_ellipse_geometry_GetFactory(ID2D1EllipseGeometry *iface, ID2D1Factory **factory)
4012 struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface);
4014 TRACE("iface %p, factory %p.\n", iface, factory);
4016 ID2D1Factory_AddRef(*factory = geometry->factory);
4019 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_GetBounds(ID2D1EllipseGeometry *iface,
4020 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
4022 FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
4024 return E_NOTIMPL;
4027 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_GetWidenedBounds(ID2D1EllipseGeometry *iface,
4028 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4029 float tolerance, D2D1_RECT_F *bounds)
4031 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
4032 iface, stroke_width, stroke_style, transform, tolerance, bounds);
4034 return E_NOTIMPL;
4037 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_StrokeContainsPoint(ID2D1EllipseGeometry *iface,
4038 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4039 float tolerance, BOOL *contains)
4041 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p stub!\n",
4042 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
4044 return E_NOTIMPL;
4047 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_FillContainsPoint(ID2D1EllipseGeometry *iface,
4048 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
4050 FIXME("iface %p, point %s, transform %p, tolerance %.8e, contains %p stub!\n",
4051 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
4053 return E_NOTIMPL;
4056 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_CompareWithGeometry(ID2D1EllipseGeometry *iface,
4057 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
4059 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
4060 iface, geometry, transform, tolerance, relation);
4062 return E_NOTIMPL;
4065 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Simplify(ID2D1EllipseGeometry *iface,
4066 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4067 ID2D1SimplifiedGeometrySink *sink)
4069 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4070 iface, option, transform, tolerance, sink);
4072 return E_NOTIMPL;
4075 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Tessellate(ID2D1EllipseGeometry *iface,
4076 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
4078 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4080 return E_NOTIMPL;
4083 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_CombineWithGeometry(ID2D1EllipseGeometry *iface,
4084 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
4085 float tolerance, ID2D1SimplifiedGeometrySink *sink)
4087 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4088 iface, geometry, combine_mode, transform, tolerance, sink);
4090 return E_NOTIMPL;
4093 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Outline(ID2D1EllipseGeometry *iface,
4094 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
4096 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4098 return E_NOTIMPL;
4101 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_ComputeArea(ID2D1EllipseGeometry *iface,
4102 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
4104 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
4106 return E_NOTIMPL;
4109 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_ComputeLength(ID2D1EllipseGeometry *iface,
4110 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
4112 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
4114 return E_NOTIMPL;
4117 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_ComputePointAtLength(ID2D1EllipseGeometry *iface,
4118 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
4119 D2D1_POINT_2F *tangent)
4121 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
4122 iface, length, transform, tolerance, point, tangent);
4124 return E_NOTIMPL;
4127 static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Widen(ID2D1EllipseGeometry *iface, float stroke_width,
4128 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4129 ID2D1SimplifiedGeometrySink *sink)
4131 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
4132 iface, stroke_width, stroke_style, transform, tolerance, sink);
4134 return E_NOTIMPL;
4137 static void STDMETHODCALLTYPE d2d_ellipse_geometry_GetEllipse(ID2D1EllipseGeometry *iface, D2D1_ELLIPSE *ellipse)
4139 struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface);
4141 TRACE("iface %p, ellipse %p.\n", iface, ellipse);
4143 *ellipse = geometry->u.ellipse.ellipse;
4146 static const struct ID2D1EllipseGeometryVtbl d2d_ellipse_geometry_vtbl =
4148 d2d_ellipse_geometry_QueryInterface,
4149 d2d_ellipse_geometry_AddRef,
4150 d2d_ellipse_geometry_Release,
4151 d2d_ellipse_geometry_GetFactory,
4152 d2d_ellipse_geometry_GetBounds,
4153 d2d_ellipse_geometry_GetWidenedBounds,
4154 d2d_ellipse_geometry_StrokeContainsPoint,
4155 d2d_ellipse_geometry_FillContainsPoint,
4156 d2d_ellipse_geometry_CompareWithGeometry,
4157 d2d_ellipse_geometry_Simplify,
4158 d2d_ellipse_geometry_Tessellate,
4159 d2d_ellipse_geometry_CombineWithGeometry,
4160 d2d_ellipse_geometry_Outline,
4161 d2d_ellipse_geometry_ComputeArea,
4162 d2d_ellipse_geometry_ComputeLength,
4163 d2d_ellipse_geometry_ComputePointAtLength,
4164 d2d_ellipse_geometry_Widen,
4165 d2d_ellipse_geometry_GetEllipse,
4168 HRESULT d2d_ellipse_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_ELLIPSE *ellipse)
4170 D2D1_POINT_2F *v, v1, v2, v3, v4;
4171 struct d2d_face *f;
4172 float l, r, t, b;
4174 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_ellipse_geometry_vtbl);
4175 geometry->u.ellipse.ellipse = *ellipse;
4177 if (!(geometry->fill.vertices = heap_alloc(4 * sizeof(*geometry->fill.vertices))))
4178 goto fail;
4179 if (!d2d_array_reserve((void **)&geometry->fill.faces,
4180 &geometry->fill.faces_size, 2, sizeof(*geometry->fill.faces)))
4181 goto fail;
4183 l = ellipse->point.x - ellipse->radiusX;
4184 r = ellipse->point.x + ellipse->radiusX;
4185 t = ellipse->point.y - ellipse->radiusY;
4186 b = ellipse->point.y + ellipse->radiusY;
4188 d2d_point_set(&v1, r, t);
4189 d2d_point_set(&v2, r, b);
4190 d2d_point_set(&v3, l, b);
4191 d2d_point_set(&v4, l, t);
4193 v = geometry->fill.vertices;
4194 d2d_point_set(&v[0], ellipse->point.x, t);
4195 d2d_point_set(&v[1], r, ellipse->point.y);
4196 d2d_point_set(&v[2], ellipse->point.x, b);
4197 d2d_point_set(&v[3], l, ellipse->point.y);
4198 geometry->fill.vertex_count = 4;
4200 f = geometry->fill.faces;
4201 d2d_face_set(&f[0], 0, 3, 2);
4202 d2d_face_set(&f[1], 0, 2, 1);
4203 geometry->fill.face_count = 2;
4205 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[0], &v1, &v[1]))
4206 goto fail;
4207 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[1], &v2, &v[2]))
4208 goto fail;
4209 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[2], &v3, &v[3]))
4210 goto fail;
4211 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[3], &v4, &v[0]))
4212 goto fail;
4214 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[0], &v1, &v[1]))
4215 goto fail;
4216 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[1], &v2, &v[2]))
4217 goto fail;
4218 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[2], &v3, &v[3]))
4219 goto fail;
4220 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[3], &v4, &v[0]))
4221 goto fail;
4223 return S_OK;
4225 fail:
4226 d2d_geometry_cleanup(geometry);
4227 return E_OUTOFMEMORY;
4230 static inline struct d2d_geometry *impl_from_ID2D1RectangleGeometry(ID2D1RectangleGeometry *iface)
4232 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
4235 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_QueryInterface(ID2D1RectangleGeometry *iface,
4236 REFIID iid, void **out)
4238 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
4240 if (IsEqualGUID(iid, &IID_ID2D1RectangleGeometry)
4241 || IsEqualGUID(iid, &IID_ID2D1Geometry)
4242 || IsEqualGUID(iid, &IID_ID2D1Resource)
4243 || IsEqualGUID(iid, &IID_IUnknown))
4245 ID2D1RectangleGeometry_AddRef(iface);
4246 *out = iface;
4247 return S_OK;
4250 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
4252 *out = NULL;
4253 return E_NOINTERFACE;
4256 static ULONG STDMETHODCALLTYPE d2d_rectangle_geometry_AddRef(ID2D1RectangleGeometry *iface)
4258 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4259 ULONG refcount = InterlockedIncrement(&geometry->refcount);
4261 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
4263 return refcount;
4266 static ULONG STDMETHODCALLTYPE d2d_rectangle_geometry_Release(ID2D1RectangleGeometry *iface)
4268 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4269 ULONG refcount = InterlockedDecrement(&geometry->refcount);
4271 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
4273 if (!refcount)
4275 d2d_geometry_cleanup(geometry);
4276 heap_free(geometry);
4279 return refcount;
4282 static void STDMETHODCALLTYPE d2d_rectangle_geometry_GetFactory(ID2D1RectangleGeometry *iface, ID2D1Factory **factory)
4284 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4286 TRACE("iface %p, factory %p.\n", iface, factory);
4288 ID2D1Factory_AddRef(*factory = geometry->factory);
4291 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_GetBounds(ID2D1RectangleGeometry *iface,
4292 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
4294 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4295 D2D1_RECT_F *rect;
4296 D2D1_POINT_2F p;
4298 TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
4300 rect = &geometry->u.rectangle.rect;
4301 if (!transform)
4303 *bounds = *rect;
4304 return S_OK;
4307 bounds->left = FLT_MAX;
4308 bounds->top = FLT_MAX;
4309 bounds->right = -FLT_MAX;
4310 bounds->bottom = -FLT_MAX;
4312 d2d_point_transform(&p, transform, rect->left, rect->top);
4313 d2d_rect_expand(bounds, &p);
4314 d2d_point_transform(&p, transform, rect->left, rect->bottom);
4315 d2d_rect_expand(bounds, &p);
4316 d2d_point_transform(&p, transform, rect->right, rect->bottom);
4317 d2d_rect_expand(bounds, &p);
4318 d2d_point_transform(&p, transform, rect->right, rect->top);
4319 d2d_rect_expand(bounds, &p);
4321 return S_OK;
4324 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_GetWidenedBounds(ID2D1RectangleGeometry *iface,
4325 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4326 float tolerance, D2D1_RECT_F *bounds)
4328 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
4329 iface, stroke_width, stroke_style, transform, tolerance, bounds);
4331 return E_NOTIMPL;
4334 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_StrokeContainsPoint(ID2D1RectangleGeometry *iface,
4335 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4336 float tolerance, BOOL *contains)
4338 const struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4339 const D2D1_RECT_F *rect = &geometry->u.rectangle.rect;
4340 unsigned int i;
4341 struct
4343 D2D1_POINT_2F s, e;
4345 segments[4];
4347 TRACE("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p.\n",
4348 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
4350 if (stroke_style)
4351 FIXME("Ignoring stroke style %p.\n", stroke_style);
4353 tolerance = fabsf(tolerance);
4355 if (!transform)
4357 D2D1_POINT_2F d, s;
4359 s.x = rect->right - rect->left;
4360 s.y = rect->bottom - rect->top;
4361 d.x = fabsf((rect->right + rect->left) * 0.5f - point.x);
4362 d.y = fabsf((rect->bottom + rect->top) * 0.5f - point.y);
4364 /* Inside test. */
4365 if (d.x <= (s.x - stroke_width) * 0.5f - tolerance && d.y <= (s.y - stroke_width) * 0.5f - tolerance)
4367 *contains = FALSE;
4368 return S_OK;
4371 if (tolerance == 0.0f)
4373 *contains = d.x < (s.x + stroke_width) * 0.5f && d.y < (s.y + stroke_width) * 0.5f;
4375 else
4377 d.x = max(d.x - (s.x + stroke_width) * 0.5f, 0.0f);
4378 d.y = max(d.y - (s.y + stroke_width) * 0.5f, 0.0f);
4380 *contains = d2d_point_dot(&d, &d) < tolerance * tolerance;
4383 return S_OK;
4386 stroke_width *= 0.5f;
4388 d2d_point_set(&segments[0].s, rect->left - stroke_width, rect->bottom);
4389 d2d_point_set(&segments[0].e, rect->right + stroke_width, rect->bottom);
4390 d2d_point_set(&segments[1].s, rect->right, rect->bottom + stroke_width);
4391 d2d_point_set(&segments[1].e, rect->right, rect->top - stroke_width);
4392 d2d_point_set(&segments[2].s, rect->right + stroke_width, rect->top);
4393 d2d_point_set(&segments[2].e, rect->left - stroke_width, rect->top);
4394 d2d_point_set(&segments[3].s, rect->left, rect->top - stroke_width);
4395 d2d_point_set(&segments[3].e, rect->left, rect->bottom + stroke_width);
4397 *contains = FALSE;
4398 for (i = 0; i < ARRAY_SIZE(segments); ++i)
4400 if (d2d_point_on_line_segment(&point, &segments[i].s, &segments[i].e, transform, stroke_width, tolerance))
4402 *contains = TRUE;
4403 break;
4407 return S_OK;
4410 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_FillContainsPoint(ID2D1RectangleGeometry *iface,
4411 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
4413 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4414 D2D1_RECT_F *rect = &geometry->u.rectangle.rect;
4415 float dx, dy;
4417 TRACE("iface %p, point %s, transform %p, tolerance %.8e, contains %p.\n",
4418 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
4420 if (transform)
4422 D2D1_MATRIX_3X2_F g_i;
4424 if (!d2d_matrix_invert(&g_i, transform))
4425 return D2DERR_UNSUPPORTED_OPERATION;
4426 d2d_point_transform(&point, &g_i, point.x, point.y);
4429 if (tolerance == 0.0f)
4430 tolerance = D2D1_DEFAULT_FLATTENING_TOLERANCE;
4432 dx = max(fabsf((rect->right + rect->left) / 2.0f - point.x) - (rect->right - rect->left) / 2.0f, 0.0f);
4433 dy = max(fabsf((rect->bottom + rect->top) / 2.0f - point.y) - (rect->bottom - rect->top) / 2.0f, 0.0f);
4435 *contains = tolerance * tolerance > (dx * dx + dy * dy);
4436 return S_OK;
4439 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_CompareWithGeometry(ID2D1RectangleGeometry *iface,
4440 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
4442 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
4443 iface, geometry, transform, tolerance, relation);
4445 return E_NOTIMPL;
4448 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Simplify(ID2D1RectangleGeometry *iface,
4449 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4450 ID2D1SimplifiedGeometrySink *sink)
4452 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4453 D2D1_RECT_F *rect = &geometry->u.rectangle.rect;
4454 D2D1_POINT_2F p[4];
4455 unsigned int i;
4457 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
4458 iface, option, transform, tolerance, sink);
4460 d2d_point_set(&p[0], rect->left, rect->top);
4461 d2d_point_set(&p[1], rect->right, rect->top);
4462 d2d_point_set(&p[2], rect->right, rect->bottom);
4463 d2d_point_set(&p[3], rect->left, rect->bottom);
4465 if (transform)
4467 for (i = 0; i < ARRAY_SIZE(p); ++i)
4469 d2d_point_transform(&p[i], transform, p[i].x, p[i].y);
4473 ID2D1SimplifiedGeometrySink_SetFillMode(sink, D2D1_FILL_MODE_ALTERNATE);
4474 ID2D1SimplifiedGeometrySink_BeginFigure(sink, p[0], D2D1_FIGURE_BEGIN_FILLED);
4475 ID2D1SimplifiedGeometrySink_AddLines(sink, &p[1], 3);
4476 ID2D1SimplifiedGeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
4478 return S_OK;
4481 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Tessellate(ID2D1RectangleGeometry *iface,
4482 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
4484 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4486 return E_NOTIMPL;
4489 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_CombineWithGeometry(ID2D1RectangleGeometry *iface,
4490 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
4491 float tolerance, ID2D1SimplifiedGeometrySink *sink)
4493 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4494 iface, geometry, combine_mode, transform, tolerance, sink);
4496 return E_NOTIMPL;
4499 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Outline(ID2D1RectangleGeometry *iface,
4500 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
4502 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4504 return E_NOTIMPL;
4507 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputeArea(ID2D1RectangleGeometry *iface,
4508 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
4510 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
4512 return E_NOTIMPL;
4515 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputeLength(ID2D1RectangleGeometry *iface,
4516 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
4518 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
4520 return E_NOTIMPL;
4523 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputePointAtLength(ID2D1RectangleGeometry *iface,
4524 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
4525 D2D1_POINT_2F *tangent)
4527 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
4528 iface, length, transform, tolerance, point, tangent);
4530 return E_NOTIMPL;
4533 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Widen(ID2D1RectangleGeometry *iface, float stroke_width,
4534 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4535 ID2D1SimplifiedGeometrySink *sink)
4537 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
4538 iface, stroke_width, stroke_style, transform, tolerance, sink);
4540 return E_NOTIMPL;
4543 static void STDMETHODCALLTYPE d2d_rectangle_geometry_GetRect(ID2D1RectangleGeometry *iface, D2D1_RECT_F *rect)
4545 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
4547 TRACE("iface %p, rect %p.\n", iface, rect);
4549 *rect = geometry->u.rectangle.rect;
4552 static const struct ID2D1RectangleGeometryVtbl d2d_rectangle_geometry_vtbl =
4554 d2d_rectangle_geometry_QueryInterface,
4555 d2d_rectangle_geometry_AddRef,
4556 d2d_rectangle_geometry_Release,
4557 d2d_rectangle_geometry_GetFactory,
4558 d2d_rectangle_geometry_GetBounds,
4559 d2d_rectangle_geometry_GetWidenedBounds,
4560 d2d_rectangle_geometry_StrokeContainsPoint,
4561 d2d_rectangle_geometry_FillContainsPoint,
4562 d2d_rectangle_geometry_CompareWithGeometry,
4563 d2d_rectangle_geometry_Simplify,
4564 d2d_rectangle_geometry_Tessellate,
4565 d2d_rectangle_geometry_CombineWithGeometry,
4566 d2d_rectangle_geometry_Outline,
4567 d2d_rectangle_geometry_ComputeArea,
4568 d2d_rectangle_geometry_ComputeLength,
4569 d2d_rectangle_geometry_ComputePointAtLength,
4570 d2d_rectangle_geometry_Widen,
4571 d2d_rectangle_geometry_GetRect,
4574 HRESULT d2d_rectangle_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_RECT_F *rect)
4576 struct d2d_face *f;
4577 D2D1_POINT_2F *v;
4578 float l, r, t, b;
4580 static const D2D1_POINT_2F prev[] =
4582 { 1.0f, 0.0f},
4583 { 0.0f, -1.0f},
4584 {-1.0f, 0.0f},
4585 { 0.0f, 1.0f},
4587 static const D2D1_POINT_2F next[] =
4589 { 0.0f, 1.0f},
4590 { 1.0f, 0.0f},
4591 { 0.0f, -1.0f},
4592 {-1.0f, 0.0f},
4595 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl);
4596 geometry->u.rectangle.rect = *rect;
4598 if (!(geometry->fill.vertices = heap_alloc(4 * sizeof(*geometry->fill.vertices))))
4599 goto fail;
4600 if (!d2d_array_reserve((void **)&geometry->fill.faces,
4601 &geometry->fill.faces_size, 2, sizeof(*geometry->fill.faces)))
4602 goto fail;
4604 l = min(rect->left, rect->right);
4605 r = max(rect->left, rect->right);
4606 t = min(rect->top, rect->bottom);
4607 b = max(rect->top, rect->bottom);
4609 v = geometry->fill.vertices;
4610 d2d_point_set(&v[0], l, t);
4611 d2d_point_set(&v[1], l, b);
4612 d2d_point_set(&v[2], r, b);
4613 d2d_point_set(&v[3], r, t);
4614 geometry->fill.vertex_count = 4;
4616 f = geometry->fill.faces;
4617 d2d_face_set(&f[0], 1, 2, 0);
4618 d2d_face_set(&f[1], 0, 2, 3);
4619 geometry->fill.face_count = 2;
4621 if (!d2d_geometry_outline_add_line_segment(geometry, &v[0], &v[1]))
4622 goto fail;
4623 if (!d2d_geometry_outline_add_line_segment(geometry, &v[1], &v[2]))
4624 goto fail;
4625 if (!d2d_geometry_outline_add_line_segment(geometry, &v[2], &v[3]))
4626 goto fail;
4627 if (!d2d_geometry_outline_add_line_segment(geometry, &v[3], &v[0]))
4628 goto fail;
4630 if (!d2d_geometry_outline_add_join(geometry, &prev[0], &v[0], &next[0]))
4631 goto fail;
4632 if (!d2d_geometry_outline_add_join(geometry, &prev[1], &v[1], &next[1]))
4633 goto fail;
4634 if (!d2d_geometry_outline_add_join(geometry, &prev[2], &v[2], &next[2]))
4635 goto fail;
4636 if (!d2d_geometry_outline_add_join(geometry, &prev[3], &v[3], &next[3]))
4637 goto fail;
4639 return S_OK;
4641 fail:
4642 d2d_geometry_cleanup(geometry);
4643 return E_OUTOFMEMORY;
4646 static inline struct d2d_geometry *impl_from_ID2D1RoundedRectangleGeometry(ID2D1RoundedRectangleGeometry *iface)
4648 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
4651 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_QueryInterface(ID2D1RoundedRectangleGeometry *iface,
4652 REFIID iid, void **out)
4654 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
4656 if (IsEqualGUID(iid, &IID_ID2D1RoundedRectangleGeometry)
4657 || IsEqualGUID(iid, &IID_ID2D1Geometry)
4658 || IsEqualGUID(iid, &IID_ID2D1Resource)
4659 || IsEqualGUID(iid, &IID_IUnknown))
4661 ID2D1RoundedRectangleGeometry_AddRef(iface);
4662 *out = iface;
4663 return S_OK;
4666 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
4668 *out = NULL;
4669 return E_NOINTERFACE;
4672 static ULONG STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_AddRef(ID2D1RoundedRectangleGeometry *iface)
4674 struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface);
4675 ULONG refcount = InterlockedIncrement(&geometry->refcount);
4677 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
4679 return refcount;
4682 static ULONG STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Release(ID2D1RoundedRectangleGeometry *iface)
4684 struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface);
4685 ULONG refcount = InterlockedDecrement(&geometry->refcount);
4687 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
4689 if (!refcount)
4691 d2d_geometry_cleanup(geometry);
4692 heap_free(geometry);
4695 return refcount;
4698 static void STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetFactory(ID2D1RoundedRectangleGeometry *iface,
4699 ID2D1Factory **factory)
4701 struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface);
4703 TRACE("iface %p, factory %p.\n", iface, factory);
4705 ID2D1Factory_AddRef(*factory = geometry->factory);
4708 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetBounds(ID2D1RoundedRectangleGeometry *iface,
4709 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
4711 FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
4713 return E_NOTIMPL;
4716 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetWidenedBounds(ID2D1RoundedRectangleGeometry *iface,
4717 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4718 float tolerance, D2D1_RECT_F *bounds)
4720 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
4721 iface, stroke_width, stroke_style, transform, tolerance, bounds);
4723 return E_NOTIMPL;
4726 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_StrokeContainsPoint(
4727 ID2D1RoundedRectangleGeometry *iface, D2D1_POINT_2F point, float stroke_width,
4728 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
4730 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p stub!\n",
4731 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
4733 return E_NOTIMPL;
4736 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_FillContainsPoint(ID2D1RoundedRectangleGeometry *iface,
4737 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
4739 FIXME("iface %p, point %s, transform %p, tolerance %.8e, contains %p stub!\n",
4740 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
4742 return E_NOTIMPL;
4745 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_CompareWithGeometry(
4746 ID2D1RoundedRectangleGeometry *iface, ID2D1Geometry *geometry,
4747 const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
4749 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
4750 iface, geometry, transform, tolerance, relation);
4752 return E_NOTIMPL;
4755 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Simplify(ID2D1RoundedRectangleGeometry *iface,
4756 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
4757 ID2D1SimplifiedGeometrySink *sink)
4759 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4760 iface, option, transform, tolerance, sink);
4762 return E_NOTIMPL;
4765 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Tessellate(ID2D1RoundedRectangleGeometry *iface,
4766 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
4768 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4770 return E_NOTIMPL;
4773 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_CombineWithGeometry(
4774 ID2D1RoundedRectangleGeometry *iface, ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode,
4775 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
4777 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4778 iface, geometry, combine_mode, transform, tolerance, sink);
4780 return E_NOTIMPL;
4783 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Outline(ID2D1RoundedRectangleGeometry *iface,
4784 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
4786 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
4788 return E_NOTIMPL;
4791 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_ComputeArea(ID2D1RoundedRectangleGeometry *iface,
4792 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
4794 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
4796 return E_NOTIMPL;
4799 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_ComputeLength(ID2D1RoundedRectangleGeometry *iface,
4800 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
4802 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
4804 return E_NOTIMPL;
4807 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_ComputePointAtLength(
4808 ID2D1RoundedRectangleGeometry *iface, float length, const D2D1_MATRIX_3X2_F *transform,
4809 float tolerance, D2D1_POINT_2F *point, D2D1_POINT_2F *tangent)
4811 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
4812 iface, length, transform, tolerance, point, tangent);
4814 return E_NOTIMPL;
4817 static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Widen(ID2D1RoundedRectangleGeometry *iface,
4818 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
4819 float tolerance, ID2D1SimplifiedGeometrySink *sink)
4821 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
4822 iface, stroke_width, stroke_style, transform, tolerance, sink);
4824 return E_NOTIMPL;
4827 static void STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_GetRoundedRect(ID2D1RoundedRectangleGeometry *iface,
4828 D2D1_ROUNDED_RECT *rounded_rect)
4830 struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface);
4832 TRACE("iface %p, rounded_rect %p.\n", iface, rounded_rect);
4834 *rounded_rect = geometry->u.rounded_rectangle.rounded_rect;
4837 static const struct ID2D1RoundedRectangleGeometryVtbl d2d_rounded_rectangle_geometry_vtbl =
4839 d2d_rounded_rectangle_geometry_QueryInterface,
4840 d2d_rounded_rectangle_geometry_AddRef,
4841 d2d_rounded_rectangle_geometry_Release,
4842 d2d_rounded_rectangle_geometry_GetFactory,
4843 d2d_rounded_rectangle_geometry_GetBounds,
4844 d2d_rounded_rectangle_geometry_GetWidenedBounds,
4845 d2d_rounded_rectangle_geometry_StrokeContainsPoint,
4846 d2d_rounded_rectangle_geometry_FillContainsPoint,
4847 d2d_rounded_rectangle_geometry_CompareWithGeometry,
4848 d2d_rounded_rectangle_geometry_Simplify,
4849 d2d_rounded_rectangle_geometry_Tessellate,
4850 d2d_rounded_rectangle_geometry_CombineWithGeometry,
4851 d2d_rounded_rectangle_geometry_Outline,
4852 d2d_rounded_rectangle_geometry_ComputeArea,
4853 d2d_rounded_rectangle_geometry_ComputeLength,
4854 d2d_rounded_rectangle_geometry_ComputePointAtLength,
4855 d2d_rounded_rectangle_geometry_Widen,
4856 d2d_rounded_rectangle_geometry_GetRoundedRect,
4859 HRESULT d2d_rounded_rectangle_geometry_init(struct d2d_geometry *geometry,
4860 ID2D1Factory *factory, const D2D1_ROUNDED_RECT *rounded_rect)
4862 D2D1_POINT_2F *v, v1, v2, v3, v4;
4863 struct d2d_face *f;
4864 float l, r, t, b;
4865 float rx, ry;
4867 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rounded_rectangle_geometry_vtbl);
4868 geometry->u.rounded_rectangle.rounded_rect = *rounded_rect;
4870 if (!(geometry->fill.vertices = heap_alloc(8 * sizeof(*geometry->fill.vertices))))
4871 goto fail;
4872 if (!d2d_array_reserve((void **)&geometry->fill.faces,
4873 &geometry->fill.faces_size, 6, sizeof(*geometry->fill.faces)))
4874 goto fail;
4876 l = min(rounded_rect->rect.left, rounded_rect->rect.right);
4877 r = max(rounded_rect->rect.left, rounded_rect->rect.right);
4878 t = min(rounded_rect->rect.top, rounded_rect->rect.bottom);
4879 b = max(rounded_rect->rect.top, rounded_rect->rect.bottom);
4881 rx = min(rounded_rect->radiusX, 0.5f * (r - l));
4882 ry = min(rounded_rect->radiusY, 0.5f * (b - t));
4884 d2d_point_set(&v1, r, t);
4885 d2d_point_set(&v2, r, b);
4886 d2d_point_set(&v3, l, b);
4887 d2d_point_set(&v4, l, t);
4889 v = geometry->fill.vertices;
4890 d2d_point_set(&v[0], l + rx, t);
4891 d2d_point_set(&v[1], r - rx, t);
4892 d2d_point_set(&v[2], r, t + ry);
4893 d2d_point_set(&v[3], r, b - ry);
4894 d2d_point_set(&v[4], r - rx, b);
4895 d2d_point_set(&v[5], l + rx, b);
4896 d2d_point_set(&v[6], l, b - ry);
4897 d2d_point_set(&v[7], l, t + ry);
4898 geometry->fill.vertex_count = 8;
4900 f = geometry->fill.faces;
4901 d2d_face_set(&f[0], 0, 7, 6);
4902 d2d_face_set(&f[1], 0, 6, 5);
4903 d2d_face_set(&f[2], 0, 5, 4);
4904 d2d_face_set(&f[3], 0, 4, 1);
4905 d2d_face_set(&f[4], 1, 4, 3);
4906 d2d_face_set(&f[5], 1, 3, 2);
4907 geometry->fill.face_count = 6;
4909 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[1], &v1, &v[2]))
4910 goto fail;
4911 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[3], &v2, &v[4]))
4912 goto fail;
4913 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[5], &v3, &v[6]))
4914 goto fail;
4915 if (!d2d_geometry_fill_add_arc_triangle(geometry, &v[7], &v4, &v[0]))
4916 goto fail;
4918 if (!d2d_geometry_outline_add_line_segment(geometry, &v[0], &v[1]))
4919 goto fail;
4920 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[1], &v1, &v[2]))
4921 goto fail;
4922 if (!d2d_geometry_outline_add_line_segment(geometry, &v[2], &v[3]))
4923 goto fail;
4924 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[3], &v2, &v[4]))
4925 goto fail;
4926 if (!d2d_geometry_outline_add_line_segment(geometry, &v[4], &v[5]))
4927 goto fail;
4928 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[5], &v3, &v[6]))
4929 goto fail;
4930 if (!d2d_geometry_outline_add_line_segment(geometry, &v[6], &v[7]))
4931 goto fail;
4932 if (!d2d_geometry_outline_add_arc_quadrant(geometry, &v[7], &v4, &v[0]))
4933 goto fail;
4935 return S_OK;
4937 fail:
4938 d2d_geometry_cleanup(geometry);
4939 return E_OUTOFMEMORY;
4942 static inline struct d2d_geometry *impl_from_ID2D1TransformedGeometry(ID2D1TransformedGeometry *iface)
4944 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
4947 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_QueryInterface(ID2D1TransformedGeometry *iface,
4948 REFIID iid, void **out)
4950 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
4952 if (IsEqualGUID(iid, &IID_ID2D1TransformedGeometry)
4953 || IsEqualGUID(iid, &IID_ID2D1Geometry)
4954 || IsEqualGUID(iid, &IID_ID2D1Resource)
4955 || IsEqualGUID(iid, &IID_IUnknown))
4957 ID2D1TransformedGeometry_AddRef(iface);
4958 *out = iface;
4959 return S_OK;
4962 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
4964 *out = NULL;
4965 return E_NOINTERFACE;
4968 static ULONG STDMETHODCALLTYPE d2d_transformed_geometry_AddRef(ID2D1TransformedGeometry *iface)
4970 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4971 ULONG refcount = InterlockedIncrement(&geometry->refcount);
4973 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
4975 return refcount;
4978 static ULONG STDMETHODCALLTYPE d2d_transformed_geometry_Release(ID2D1TransformedGeometry *iface)
4980 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
4981 ULONG refcount = InterlockedDecrement(&geometry->refcount);
4983 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
4985 if (!refcount)
4987 geometry->outline.arc_faces = NULL;
4988 geometry->outline.arcs = NULL;
4989 geometry->outline.bezier_faces = NULL;
4990 geometry->outline.beziers = NULL;
4991 geometry->outline.faces = NULL;
4992 geometry->outline.vertices = NULL;
4993 geometry->fill.arc_vertices = NULL;
4994 geometry->fill.bezier_vertices = NULL;
4995 geometry->fill.faces = NULL;
4996 geometry->fill.vertices = NULL;
4997 ID2D1Geometry_Release(geometry->u.transformed.src_geometry);
4998 d2d_geometry_cleanup(geometry);
4999 heap_free(geometry);
5002 return refcount;
5005 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetFactory(ID2D1TransformedGeometry *iface,
5006 ID2D1Factory **factory)
5008 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
5010 TRACE("iface %p, factory %p.\n", iface, factory);
5012 ID2D1Factory_AddRef(*factory = geometry->factory);
5015 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_GetBounds(ID2D1TransformedGeometry *iface,
5016 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
5018 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
5019 D2D1_MATRIX_3X2_F g;
5021 TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
5023 g = geometry->transform;
5024 if (transform)
5025 d2d_matrix_multiply(&g, transform);
5027 return ID2D1Geometry_GetBounds(geometry->u.transformed.src_geometry, &g, bounds);
5030 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_GetWidenedBounds(ID2D1TransformedGeometry *iface,
5031 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
5032 float tolerance, D2D1_RECT_F *bounds)
5034 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
5035 iface, stroke_width, stroke_style, transform, tolerance, bounds);
5037 return E_NOTIMPL;
5040 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_StrokeContainsPoint(ID2D1TransformedGeometry *iface,
5041 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
5042 float tolerance, BOOL *contains)
5044 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
5045 D2D1_MATRIX_3X2_F g;
5047 TRACE("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p.\n",
5048 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
5050 g = geometry->transform;
5051 stroke_width /= g.m11;
5052 if (transform)
5053 d2d_matrix_multiply(&g, transform);
5055 if (tolerance <= 0.0f)
5056 tolerance = D2D1_DEFAULT_FLATTENING_TOLERANCE;
5058 return ID2D1Geometry_StrokeContainsPoint(geometry->u.transformed.src_geometry, point, stroke_width, stroke_style,
5059 &g, tolerance, contains);
5062 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_FillContainsPoint(ID2D1TransformedGeometry *iface,
5063 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
5065 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
5066 D2D1_MATRIX_3X2_F g;
5068 TRACE("iface %p, point %s, transform %p, tolerance %.8e, contains %p.\n",
5069 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
5071 g = geometry->transform;
5072 if (transform)
5073 d2d_matrix_multiply(&g, transform);
5075 return ID2D1Geometry_FillContainsPoint(geometry->u.transformed.src_geometry, point, &g, tolerance, contains);
5078 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_CompareWithGeometry(ID2D1TransformedGeometry *iface,
5079 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
5081 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
5082 iface, geometry, transform, tolerance, relation);
5084 return E_NOTIMPL;
5087 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Simplify(ID2D1TransformedGeometry *iface,
5088 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
5089 ID2D1SimplifiedGeometrySink *sink)
5091 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
5092 D2D1_MATRIX_3X2_F g;
5094 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
5095 iface, option, transform, tolerance, sink);
5097 g = geometry->transform;
5098 if (transform)
5099 d2d_matrix_multiply(&g, transform);
5101 return ID2D1Geometry_Simplify(geometry->u.transformed.src_geometry, option, &g, tolerance, sink);
5104 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Tessellate(ID2D1TransformedGeometry *iface,
5105 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
5107 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
5109 return E_NOTIMPL;
5112 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_CombineWithGeometry(ID2D1TransformedGeometry *iface,
5113 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
5114 float tolerance, ID2D1SimplifiedGeometrySink *sink)
5116 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
5117 iface, geometry, combine_mode, transform, tolerance, sink);
5119 return E_NOTIMPL;
5122 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Outline(ID2D1TransformedGeometry *iface,
5123 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
5125 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
5127 return E_NOTIMPL;
5130 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputeArea(ID2D1TransformedGeometry *iface,
5131 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
5133 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
5135 return E_NOTIMPL;
5138 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputeLength(ID2D1TransformedGeometry *iface,
5139 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
5141 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
5143 return E_NOTIMPL;
5146 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_ComputePointAtLength(ID2D1TransformedGeometry *iface,
5147 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
5148 D2D1_POINT_2F *tangent)
5150 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
5151 iface, length, transform, tolerance, point, tangent);
5153 return E_NOTIMPL;
5156 static HRESULT STDMETHODCALLTYPE d2d_transformed_geometry_Widen(ID2D1TransformedGeometry *iface, float stroke_width,
5157 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
5158 ID2D1SimplifiedGeometrySink *sink)
5160 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
5161 iface, stroke_width, stroke_style, transform, tolerance, sink);
5163 return E_NOTIMPL;
5166 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetSourceGeometry(ID2D1TransformedGeometry *iface,
5167 ID2D1Geometry **src_geometry)
5169 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
5171 TRACE("iface %p, src_geometry %p.\n", iface, src_geometry);
5173 ID2D1Geometry_AddRef(*src_geometry = geometry->u.transformed.src_geometry);
5176 static void STDMETHODCALLTYPE d2d_transformed_geometry_GetTransform(ID2D1TransformedGeometry *iface,
5177 D2D1_MATRIX_3X2_F *transform)
5179 struct d2d_geometry *geometry = impl_from_ID2D1TransformedGeometry(iface);
5181 TRACE("iface %p, transform %p.\n", iface, transform);
5183 *transform = geometry->u.transformed.transform;
5186 static const struct ID2D1TransformedGeometryVtbl d2d_transformed_geometry_vtbl =
5188 d2d_transformed_geometry_QueryInterface,
5189 d2d_transformed_geometry_AddRef,
5190 d2d_transformed_geometry_Release,
5191 d2d_transformed_geometry_GetFactory,
5192 d2d_transformed_geometry_GetBounds,
5193 d2d_transformed_geometry_GetWidenedBounds,
5194 d2d_transformed_geometry_StrokeContainsPoint,
5195 d2d_transformed_geometry_FillContainsPoint,
5196 d2d_transformed_geometry_CompareWithGeometry,
5197 d2d_transformed_geometry_Simplify,
5198 d2d_transformed_geometry_Tessellate,
5199 d2d_transformed_geometry_CombineWithGeometry,
5200 d2d_transformed_geometry_Outline,
5201 d2d_transformed_geometry_ComputeArea,
5202 d2d_transformed_geometry_ComputeLength,
5203 d2d_transformed_geometry_ComputePointAtLength,
5204 d2d_transformed_geometry_Widen,
5205 d2d_transformed_geometry_GetSourceGeometry,
5206 d2d_transformed_geometry_GetTransform,
5209 void d2d_transformed_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
5210 ID2D1Geometry *src_geometry, const D2D_MATRIX_3X2_F *transform)
5212 struct d2d_geometry *src_impl;
5213 D2D_MATRIX_3X2_F g;
5215 src_impl = unsafe_impl_from_ID2D1Geometry(src_geometry);
5217 g = src_impl->transform;
5218 d2d_matrix_multiply(&g, transform);
5219 d2d_geometry_init(geometry, factory, &g, (ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl);
5220 ID2D1Geometry_AddRef(geometry->u.transformed.src_geometry = src_geometry);
5221 geometry->u.transformed.transform = *transform;
5222 geometry->fill = src_impl->fill;
5223 geometry->outline = src_impl->outline;
5226 static inline struct d2d_geometry *impl_from_ID2D1GeometryGroup(ID2D1GeometryGroup *iface)
5228 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
5231 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_QueryInterface(ID2D1GeometryGroup *iface,
5232 REFIID iid, void **out)
5234 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
5236 if (IsEqualGUID(iid, &IID_ID2D1GeometryGroup)
5237 || IsEqualGUID(iid, &IID_ID2D1Geometry)
5238 || IsEqualGUID(iid, &IID_ID2D1Resource)
5239 || IsEqualGUID(iid, &IID_IUnknown))
5241 ID2D1GeometryGroup_AddRef(iface);
5242 *out = iface;
5243 return S_OK;
5246 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
5248 *out = NULL;
5249 return E_NOINTERFACE;
5252 static ULONG STDMETHODCALLTYPE d2d_geometry_group_AddRef(ID2D1GeometryGroup *iface)
5254 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5255 ULONG refcount = InterlockedIncrement(&geometry->refcount);
5257 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
5259 return refcount;
5262 static ULONG STDMETHODCALLTYPE d2d_geometry_group_Release(ID2D1GeometryGroup *iface)
5264 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5265 ULONG refcount = InterlockedDecrement(&geometry->refcount);
5266 unsigned int i;
5268 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
5270 if (!refcount)
5272 for (i = 0; i < geometry->u.group.geometry_count; ++i)
5273 ID2D1Geometry_Release(geometry->u.group.src_geometries[i]);
5274 heap_free(geometry->u.group.src_geometries);
5275 d2d_geometry_cleanup(geometry);
5276 heap_free(geometry);
5279 return refcount;
5282 static void STDMETHODCALLTYPE d2d_geometry_group_GetFactory(ID2D1GeometryGroup *iface,
5283 ID2D1Factory **factory)
5285 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5287 TRACE("iface %p, factory %p.\n", iface, factory);
5289 ID2D1Factory_AddRef(*factory = geometry->factory);
5292 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_GetBounds(ID2D1GeometryGroup *iface,
5293 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
5295 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5296 D2D1_RECT_F rect;
5297 unsigned int i;
5299 TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
5301 bounds->left = FLT_MAX;
5302 bounds->top = FLT_MAX;
5303 bounds->right = -FLT_MAX;
5304 bounds->bottom = -FLT_MAX;
5306 for (i = 0; i < geometry->u.group.geometry_count; ++i)
5308 if (SUCCEEDED(ID2D1Geometry_GetBounds(geometry->u.group.src_geometries[i], transform, &rect)))
5309 d2d_rect_union(bounds, &rect);
5312 return S_OK;
5315 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_GetWidenedBounds(ID2D1GeometryGroup *iface,
5316 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
5317 float tolerance, D2D1_RECT_F *bounds)
5319 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
5320 iface, stroke_width, stroke_style, transform, tolerance, bounds);
5322 return E_NOTIMPL;
5325 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_StrokeContainsPoint(ID2D1GeometryGroup *iface,
5326 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
5327 float tolerance, BOOL *contains)
5329 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p.\n",
5330 iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
5332 return E_NOTIMPL;
5335 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_FillContainsPoint(ID2D1GeometryGroup *iface,
5336 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
5338 FIXME("iface %p, point %s, transform %p, tolerance %.8e, contains %p stub!.\n",
5339 iface, debug_d2d_point_2f(&point), transform, tolerance, contains);
5341 return E_NOTIMPL;
5344 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_CompareWithGeometry(ID2D1GeometryGroup *iface,
5345 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
5347 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
5348 iface, geometry, transform, tolerance, relation);
5350 return E_NOTIMPL;
5353 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_Simplify(ID2D1GeometryGroup *iface,
5354 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
5355 ID2D1SimplifiedGeometrySink *sink)
5357 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!.\n",
5358 iface, option, transform, tolerance, sink);
5360 return E_NOTIMPL;
5363 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_Tessellate(ID2D1GeometryGroup *iface,
5364 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
5366 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
5368 return E_NOTIMPL;
5371 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_CombineWithGeometry(ID2D1GeometryGroup *iface,
5372 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
5373 float tolerance, ID2D1SimplifiedGeometrySink *sink)
5375 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
5376 iface, geometry, combine_mode, transform, tolerance, sink);
5378 return E_NOTIMPL;
5381 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_Outline(ID2D1GeometryGroup *iface,
5382 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
5384 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
5386 return E_NOTIMPL;
5389 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_ComputeArea(ID2D1GeometryGroup *iface,
5390 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
5392 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
5394 return E_NOTIMPL;
5397 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_ComputeLength(ID2D1GeometryGroup *iface,
5398 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
5400 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
5402 return E_NOTIMPL;
5405 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_ComputePointAtLength(ID2D1GeometryGroup *iface,
5406 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
5407 D2D1_POINT_2F *tangent)
5409 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
5410 iface, length, transform, tolerance, point, tangent);
5412 return E_NOTIMPL;
5415 static HRESULT STDMETHODCALLTYPE d2d_geometry_group_Widen(ID2D1GeometryGroup *iface, float stroke_width,
5416 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
5417 ID2D1SimplifiedGeometrySink *sink)
5419 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
5420 iface, stroke_width, stroke_style, transform, tolerance, sink);
5422 return E_NOTIMPL;
5425 static D2D1_FILL_MODE STDMETHODCALLTYPE d2d_geometry_group_GetFillMode(ID2D1GeometryGroup *iface)
5427 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5429 TRACE("iface %p.\n", iface);
5431 return geometry->u.group.fill_mode;
5434 static UINT32 STDMETHODCALLTYPE d2d_geometry_group_GetSourceGeometryCount(ID2D1GeometryGroup *iface)
5436 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5438 TRACE("iface %p.\n", iface);
5440 return geometry->u.group.geometry_count;
5443 static void STDMETHODCALLTYPE d2d_geometry_group_GetSourceGeometries(ID2D1GeometryGroup *iface,
5444 ID2D1Geometry **geometries, UINT32 geometry_count)
5446 struct d2d_geometry *geometry = impl_from_ID2D1GeometryGroup(iface);
5447 unsigned int i;
5449 TRACE("iface %p, geometries %p, geometry_count %u.\n", iface, geometries, geometry_count);
5451 geometry_count = min(geometry_count, geometry->u.group.geometry_count);
5452 for (i = 0; i < geometry_count; ++i)
5453 ID2D1Geometry_AddRef(geometries[i] = geometry->u.group.src_geometries[i]);
5456 static const struct ID2D1GeometryGroupVtbl d2d_geometry_group_vtbl =
5458 d2d_geometry_group_QueryInterface,
5459 d2d_geometry_group_AddRef,
5460 d2d_geometry_group_Release,
5461 d2d_geometry_group_GetFactory,
5462 d2d_geometry_group_GetBounds,
5463 d2d_geometry_group_GetWidenedBounds,
5464 d2d_geometry_group_StrokeContainsPoint,
5465 d2d_geometry_group_FillContainsPoint,
5466 d2d_geometry_group_CompareWithGeometry,
5467 d2d_geometry_group_Simplify,
5468 d2d_geometry_group_Tessellate,
5469 d2d_geometry_group_CombineWithGeometry,
5470 d2d_geometry_group_Outline,
5471 d2d_geometry_group_ComputeArea,
5472 d2d_geometry_group_ComputeLength,
5473 d2d_geometry_group_ComputePointAtLength,
5474 d2d_geometry_group_Widen,
5475 d2d_geometry_group_GetFillMode,
5476 d2d_geometry_group_GetSourceGeometryCount,
5477 d2d_geometry_group_GetSourceGeometries,
5480 HRESULT d2d_geometry_group_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
5481 D2D1_FILL_MODE fill_mode, ID2D1Geometry **geometries, unsigned int geometry_count)
5483 unsigned int i;
5485 d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_geometry_group_vtbl);
5487 if (!(geometry->u.group.src_geometries = heap_calloc(geometry_count, sizeof(*geometries))))
5489 d2d_geometry_cleanup(geometry);
5490 return E_OUTOFMEMORY;
5493 for (i = 0; i < geometry_count; ++i)
5495 ID2D1Geometry_AddRef(geometry->u.group.src_geometries[i] = geometries[i]);
5497 geometry->u.group.geometry_count = geometry_count;
5498 geometry->u.group.fill_mode = fill_mode;
5500 return S_OK;
5503 struct d2d_geometry *unsafe_impl_from_ID2D1Geometry(ID2D1Geometry *iface)
5505 if (!iface)
5506 return NULL;
5507 assert(iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_ellipse_geometry_vtbl
5508 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl
5509 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl
5510 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_rounded_rectangle_geometry_vtbl
5511 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl
5512 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_geometry_group_vtbl);
5513 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);