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
20 #include "wine/port.h"
22 #include "d2d1_private.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(d2d
);
29 #define D2D_FIGURE_FLAG_CLOSED 0x00000001u
30 #define D2D_FIGURE_FLAG_HOLLOW 0x00000002u
32 #define D2D_CDT_EDGE_FLAG_FREED 0x80000000u
33 #define D2D_CDT_EDGE_FLAG_VISITED(r) (1u << (r))
35 #define D2D_FP_EPS (1.0f / (1 << FLT_MANT_DIG))
37 static const D2D1_MATRIX_3X2_F identity
=
44 enum d2d_cdt_edge_next
46 D2D_EDGE_NEXT_ORIGIN
= 0,
47 D2D_EDGE_NEXT_ROT
= 1,
48 D2D_EDGE_NEXT_SYM
= 2,
49 D2D_EDGE_NEXT_TOR
= 3,
56 D2D_VERTEX_TYPE_BEZIER
,
61 D2D1_POINT_2F
*vertices
;
63 enum d2d_vertex_type
*vertex_types
;
64 size_t vertex_types_size
;
67 D2D1_POINT_2F
*bezier_controls
;
68 size_t bezier_controls_size
;
69 size_t bezier_control_count
;
75 struct d2d_cdt_edge_ref
78 enum d2d_cdt_edge_next r
;
83 struct d2d_cdt_edge_ref next
[4];
90 struct d2d_cdt_edge
*edges
;
95 const D2D1_POINT_2F
*vertices
;
98 struct d2d_geometry_intersection
106 struct d2d_geometry_intersections
108 struct d2d_geometry_intersection
*intersections
;
109 size_t intersections_size
;
110 size_t intersection_count
;
113 struct d2d_fp_two_vec2
125 static void d2d_bezier_vertex_set(struct d2d_bezier_vertex
*b
,
126 const D2D1_POINT_2F
*p
, float u
, float v
, float sign
)
131 b
->texcoord
.sign
= sign
;
134 static void d2d_face_set(struct d2d_face
*f
, UINT16 v0
, UINT16 v1
, UINT16 v2
)
141 static void d2d_outline_vertex_set(struct d2d_outline_vertex
*v
, float x
, float y
,
142 float prev_x
, float prev_y
, float next_x
, float next_y
)
144 d2d_point_set(&v
->position
, x
, y
);
145 d2d_point_set(&v
->prev
, prev_x
, prev_y
);
146 d2d_point_set(&v
->next
, next_x
, next_y
);
149 static void d2d_bezier_outline_vertex_set(struct d2d_bezier_outline_vertex
*b
, const D2D1_POINT_2F
*position
,
150 const D2D1_POINT_2F
*p0
, const D2D1_POINT_2F
*p1
, const D2D1_POINT_2F
*p2
,
151 float prev_x
, float prev_y
, float next_x
, float next_y
)
153 b
->position
= *position
;
157 d2d_point_set(&b
->prev
, prev_x
, prev_y
);
158 d2d_point_set(&b
->next
, next_x
, next_y
);
161 static void d2d_fp_two_sum(float *out
, float a
, float b
)
163 float a_virt
, a_round
, b_virt
, b_round
;
167 a_virt
= out
[1] - b_virt
;
168 b_round
= b
- b_virt
;
169 a_round
= a
- a_virt
;
170 out
[0] = a_round
+ b_round
;
173 static void d2d_fp_fast_two_sum(float *out
, float a
, float b
)
182 static void d2d_fp_two_two_sum(float *out
, const float *a
, const float *b
)
186 d2d_fp_two_sum(out
, a
[0], b
[0]);
187 d2d_fp_two_sum(sum
, a
[1], out
[1]);
188 d2d_fp_two_sum(&out
[1], sum
[0], b
[1]);
189 d2d_fp_two_sum(&out
[2], sum
[1], out
[2]);
192 static void d2d_fp_two_diff_tail(float *out
, float a
, float b
, float x
)
194 float a_virt
, a_round
, b_virt
, b_round
;
198 b_round
= b_virt
- b
;
199 a_round
= a
- a_virt
;
200 *out
= a_round
+ b_round
;
203 static void d2d_fp_two_two_diff(float *out
, const float *a
, const float *b
)
208 d2d_fp_two_diff_tail(out
, a
[0], b
[0], diff
);
209 d2d_fp_two_sum(sum
, a
[1], diff
);
210 diff
= sum
[0] - b
[1];
211 d2d_fp_two_diff_tail(&out
[1], sum
[0], b
[1], diff
);
212 d2d_fp_two_sum(&out
[2], sum
[1], diff
);
215 static void d2d_fp_split(float *out
, float a
)
219 c
= a
* ((1 << (FLT_MANT_DIG
/ 2)) + 1.0f
);
225 static void d2d_fp_two_product_presplit(float *out
, float a
, float b
, const float *b_split
)
227 float a_split
[2], err1
, err2
, err3
;
230 d2d_fp_split(a_split
, a
);
231 err1
= out
[1] - (a_split
[1] * b_split
[1]);
232 err2
= err1
- (a_split
[0] * b_split
[1]);
233 err3
= err2
- (a_split
[1] * b_split
[0]);
234 out
[0] = (a_split
[0] * b_split
[0]) - err3
;
237 static void d2d_fp_two_product(float *out
, float a
, float b
)
241 d2d_fp_split(b_split
, b
);
242 d2d_fp_two_product_presplit(out
, a
, b
, b_split
);
245 static void d2d_fp_square(float *out
, float a
)
247 float a_split
[2], err1
, err2
;
250 d2d_fp_split(a_split
, a
);
251 err1
= out
[1] - (a_split
[1] * a_split
[1]);
252 err2
= err1
- ((a_split
[1] + a_split
[1]) * a_split
[0]);
253 out
[0] = (a_split
[0] * a_split
[0]) - err2
;
256 static float d2d_fp_estimate(float *a
, size_t len
)
267 static void d2d_fp_fast_expansion_sum_zeroelim(float *out
, size_t *out_len
,
268 const float *a
, size_t a_len
, const float *b
, size_t b_len
)
270 float sum
[2], q
, a_curr
, b_curr
;
271 size_t a_idx
, b_idx
, out_idx
;
276 if ((b_curr
> a_curr
) == (b_curr
> -a_curr
))
287 if (a_idx
< a_len
&& b_idx
< b_len
)
289 if ((b_curr
> a_curr
) == (b_curr
> -a_curr
))
291 d2d_fp_fast_two_sum(sum
, a_curr
, q
);
296 d2d_fp_fast_two_sum(sum
, b_curr
, q
);
300 out
[out_idx
++] = sum
[0];
302 while (a_idx
< a_len
&& b_idx
< b_len
)
304 if ((b_curr
> a_curr
) == (b_curr
> -a_curr
))
306 d2d_fp_two_sum(sum
, q
, a_curr
);
311 d2d_fp_two_sum(sum
, q
, b_curr
);
315 out
[out_idx
++] = sum
[0];
319 while (a_idx
< a_len
)
321 d2d_fp_two_sum(sum
, q
, a_curr
);
324 out
[out_idx
++] = sum
[0];
327 while (b_idx
< b_len
)
329 d2d_fp_two_sum(sum
, q
, b_curr
);
332 out
[out_idx
++] = sum
[0];
335 if (q
!= 0.0f
|| !out_idx
)
341 static void d2d_fp_scale_expansion_zeroelim(float *out
, size_t *out_len
, const float *a
, size_t a_len
, float b
)
343 float product
[2], sum
[2], b_split
[2], q
[2], a_curr
;
344 size_t a_idx
, out_idx
;
346 d2d_fp_split(b_split
, b
);
347 d2d_fp_two_product_presplit(q
, a
[0], b
, b_split
);
350 out
[out_idx
++] = q
[0];
351 for (a_idx
= 1; a_idx
< a_len
; ++a_idx
)
354 d2d_fp_two_product_presplit(product
, a_curr
, b
, b_split
);
355 d2d_fp_two_sum(sum
, q
[1], product
[0]);
357 out
[out_idx
++] = sum
[0];
358 d2d_fp_fast_two_sum(q
, product
[1], sum
[1]);
360 out
[out_idx
++] = q
[0];
362 if (q
[1] != 0.0f
|| !out_idx
)
363 out
[out_idx
++] = q
[1];
368 static void d2d_point_subtract(D2D1_POINT_2F
*out
,
369 const D2D1_POINT_2F
*a
, const D2D1_POINT_2F
*b
)
371 out
->x
= a
->x
- b
->x
;
372 out
->y
= a
->y
- b
->y
;
375 static void d2d_point_scale(D2D1_POINT_2F
*p
, float scale
)
381 static void d2d_point_lerp(D2D1_POINT_2F
*out
,
382 const D2D1_POINT_2F
*a
, const D2D1_POINT_2F
*b
, float t
)
384 out
->x
= a
->x
* (1.0f
- t
) + b
->x
* t
;
385 out
->y
= a
->y
* (1.0f
- t
) + b
->y
* t
;
388 static float d2d_point_dot(const D2D1_POINT_2F
*p0
, const D2D1_POINT_2F
*p1
)
390 return p0
->x
* p1
->x
+ p0
->y
* p1
->y
;
393 static void d2d_point_normalise(D2D1_POINT_2F
*p
)
397 if ((l
= sqrtf(d2d_point_dot(p
, p
))) != 0.0f
)
398 d2d_point_scale(p
, 1.0f
/ l
);
401 /* This implementation is based on the paper "Adaptive Precision
402 * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
403 * associated (Public Domain) code by Jonathan Richard Shewchuk. */
404 static float d2d_point_ccw(const D2D1_POINT_2F
*a
, const D2D1_POINT_2F
*b
, const D2D1_POINT_2F
*c
)
406 static const float err_bound_result
= (3.0f
+ 8.0f
* D2D_FP_EPS
) * D2D_FP_EPS
;
407 static const float err_bound_a
= (3.0f
+ 16.0f
* D2D_FP_EPS
) * D2D_FP_EPS
;
408 static const float err_bound_b
= (2.0f
+ 12.0f
* D2D_FP_EPS
) * D2D_FP_EPS
;
409 static const float err_bound_c
= (9.0f
+ 64.0f
* D2D_FP_EPS
) * D2D_FP_EPS
* D2D_FP_EPS
;
410 float det_d
[16], det_c2
[12], det_c1
[8], det_b
[4], temp4
[4], temp2a
[2], temp2b
[2], abxacy
[2], abyacx
[2];
411 size_t det_d_len
, det_c2_len
, det_c1_len
;
412 float det
, det_sum
, err_bound
;
413 struct d2d_fp_two_vec2 ab
, ac
;
415 ab
.x
[1] = b
->x
- a
->x
;
416 ab
.y
[1] = b
->y
- a
->y
;
417 ac
.x
[1] = c
->x
- a
->x
;
418 ac
.y
[1] = c
->y
- a
->y
;
420 abxacy
[1] = ab
.x
[1] * ac
.y
[1];
421 abyacx
[1] = ab
.y
[1] * ac
.x
[1];
422 det
= abxacy
[1] - abyacx
[1];
424 if (abxacy
[1] > 0.0f
)
426 if (abyacx
[1] <= 0.0f
)
428 det_sum
= abxacy
[1] + abyacx
[1];
430 else if (abxacy
[1] < 0.0f
)
432 if (abyacx
[1] >= 0.0f
)
434 det_sum
= -abxacy
[1] - abyacx
[1];
441 err_bound
= err_bound_a
* det_sum
;
442 if (det
>= err_bound
|| -det
>= err_bound
)
445 d2d_fp_two_product(abxacy
, ab
.x
[1], ac
.y
[1]);
446 d2d_fp_two_product(abyacx
, ab
.y
[1], ac
.x
[1]);
447 d2d_fp_two_two_diff(det_b
, abxacy
, abyacx
);
449 det
= d2d_fp_estimate(det_b
, 4);
450 err_bound
= err_bound_b
* det_sum
;
451 if (det
>= err_bound
|| -det
>= err_bound
)
454 d2d_fp_two_diff_tail(&ab
.x
[0], b
->x
, a
->x
, ab
.x
[1]);
455 d2d_fp_two_diff_tail(&ab
.y
[0], b
->y
, a
->y
, ab
.y
[1]);
456 d2d_fp_two_diff_tail(&ac
.x
[0], c
->x
, a
->x
, ac
.x
[1]);
457 d2d_fp_two_diff_tail(&ac
.y
[0], c
->y
, a
->y
, ac
.y
[1]);
459 if (ab
.x
[0] == 0.0f
&& ab
.y
[0] == 0.0f
&& ac
.x
[0] == 0.0f
&& ac
.y
[0] == 0.0f
)
462 err_bound
= err_bound_c
* det_sum
+ err_bound_result
* fabsf(det
);
463 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]);
464 if (det
>= err_bound
|| -det
>= err_bound
)
467 d2d_fp_two_product(temp2a
, ab
.x
[0], ac
.y
[1]);
468 d2d_fp_two_product(temp2b
, ab
.y
[0], ac
.x
[1]);
469 d2d_fp_two_two_diff(temp4
, temp2a
, temp2b
);
470 d2d_fp_fast_expansion_sum_zeroelim(det_c1
, &det_c1_len
, det_b
, 4, temp4
, 4);
472 d2d_fp_two_product(temp2a
, ab
.x
[1], ac
.y
[0]);
473 d2d_fp_two_product(temp2b
, ab
.y
[1], ac
.x
[0]);
474 d2d_fp_two_two_diff(temp4
, temp2a
, temp2b
);
475 d2d_fp_fast_expansion_sum_zeroelim(det_c2
, &det_c2_len
, det_c1
, det_c1_len
, temp4
, 4);
477 d2d_fp_two_product(temp2a
, ab
.x
[0], ac
.y
[0]);
478 d2d_fp_two_product(temp2b
, ab
.y
[0], ac
.x
[0]);
479 d2d_fp_two_two_diff(temp4
, temp2a
, temp2b
);
480 d2d_fp_fast_expansion_sum_zeroelim(det_d
, &det_d_len
, det_c2
, det_c2_len
, temp4
, 4);
482 return det_d
[det_d_len
- 1];
485 static BOOL
d2d_array_reserve(void **elements
, size_t *capacity
, size_t element_count
, size_t element_size
)
487 size_t new_capacity
, max_capacity
;
490 if (element_count
<= *capacity
)
493 max_capacity
= ~(size_t)0 / element_size
;
494 if (max_capacity
< element_count
)
497 new_capacity
= max(*capacity
, 4);
498 while (new_capacity
< element_count
&& new_capacity
<= max_capacity
/ 2)
501 if (new_capacity
< element_count
)
502 new_capacity
= max_capacity
;
505 new_elements
= HeapReAlloc(GetProcessHeap(), 0, *elements
, new_capacity
* element_size
);
507 new_elements
= HeapAlloc(GetProcessHeap(), 0, new_capacity
* element_size
);
512 *elements
= new_elements
;
513 *capacity
= new_capacity
;
517 static BOOL
d2d_figure_insert_vertex(struct d2d_figure
*figure
, size_t idx
, D2D1_POINT_2F vertex
)
519 if (!d2d_array_reserve((void **)&figure
->vertices
, &figure
->vertices_size
,
520 figure
->vertex_count
+ 1, sizeof(*figure
->vertices
)))
522 ERR("Failed to grow vertices array.\n");
526 if (!d2d_array_reserve((void **)&figure
->vertex_types
, &figure
->vertex_types_size
,
527 figure
->vertex_count
+ 1, sizeof(*figure
->vertex_types
)))
529 ERR("Failed to grow vertex types array.\n");
533 memmove(&figure
->vertices
[idx
+ 1], &figure
->vertices
[idx
],
534 (figure
->vertex_count
- idx
) * sizeof(*figure
->vertices
));
535 memmove(&figure
->vertex_types
[idx
+ 1], &figure
->vertex_types
[idx
],
536 (figure
->vertex_count
- idx
) * sizeof(*figure
->vertex_types
));
537 figure
->vertices
[idx
] = vertex
;
538 figure
->vertex_types
[idx
] = D2D_VERTEX_TYPE_NONE
;
539 d2d_rect_expand(&figure
->bounds
, &vertex
);
540 ++figure
->vertex_count
;
544 static BOOL
d2d_figure_add_vertex(struct d2d_figure
*figure
, D2D1_POINT_2F vertex
)
546 size_t last
= figure
->vertex_count
- 1;
548 if (figure
->vertex_count
&& figure
->vertex_types
[last
] == D2D_VERTEX_TYPE_LINE
549 && !memcmp(&figure
->vertices
[last
], &vertex
, sizeof(vertex
)))
552 if (!d2d_array_reserve((void **)&figure
->vertices
, &figure
->vertices_size
,
553 figure
->vertex_count
+ 1, sizeof(*figure
->vertices
)))
555 ERR("Failed to grow vertices array.\n");
559 if (!d2d_array_reserve((void **)&figure
->vertex_types
, &figure
->vertex_types_size
,
560 figure
->vertex_count
+ 1, sizeof(*figure
->vertex_types
)))
562 ERR("Failed to grow vertex types array.\n");
566 figure
->vertices
[figure
->vertex_count
] = vertex
;
567 figure
->vertex_types
[figure
->vertex_count
] = D2D_VERTEX_TYPE_NONE
;
568 d2d_rect_expand(&figure
->bounds
, &vertex
);
569 ++figure
->vertex_count
;
573 static BOOL
d2d_figure_add_bezier_control(struct d2d_figure
*figure
, const D2D1_POINT_2F
*p
)
575 if (!d2d_array_reserve((void **)&figure
->bezier_controls
, &figure
->bezier_controls_size
,
576 figure
->bezier_control_count
+ 1, sizeof(*figure
->bezier_controls
)))
578 ERR("Failed to grow bezier controls array.\n");
582 figure
->bezier_controls
[figure
->bezier_control_count
++] = *p
;
587 static void d2d_cdt_edge_rot(struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
590 dst
->r
= (src
->r
+ D2D_EDGE_NEXT_ROT
) & 3;
593 static void d2d_cdt_edge_sym(struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
596 dst
->r
= (src
->r
+ D2D_EDGE_NEXT_SYM
) & 3;
599 static void d2d_cdt_edge_tor(struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
602 dst
->r
= (src
->r
+ D2D_EDGE_NEXT_TOR
) & 3;
605 static void d2d_cdt_edge_next_left(const struct d2d_cdt
*cdt
,
606 struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
608 d2d_cdt_edge_rot(dst
, &cdt
->edges
[src
->idx
].next
[(src
->r
+ D2D_EDGE_NEXT_TOR
) & 3]);
611 static void d2d_cdt_edge_next_origin(const struct d2d_cdt
*cdt
,
612 struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
614 *dst
= cdt
->edges
[src
->idx
].next
[src
->r
];
617 static void d2d_cdt_edge_prev_origin(const struct d2d_cdt
*cdt
,
618 struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
620 d2d_cdt_edge_rot(dst
, &cdt
->edges
[src
->idx
].next
[(src
->r
+ D2D_EDGE_NEXT_ROT
) & 3]);
623 static size_t d2d_cdt_edge_origin(const struct d2d_cdt
*cdt
, const struct d2d_cdt_edge_ref
*e
)
625 return cdt
->edges
[e
->idx
].vertex
[e
->r
>> 1];
628 static size_t d2d_cdt_edge_destination(const struct d2d_cdt
*cdt
, const struct d2d_cdt_edge_ref
*e
)
630 return cdt
->edges
[e
->idx
].vertex
[!(e
->r
>> 1)];
633 static void d2d_cdt_edge_set_origin(const struct d2d_cdt
*cdt
,
634 const struct d2d_cdt_edge_ref
*e
, size_t vertex
)
636 cdt
->edges
[e
->idx
].vertex
[e
->r
>> 1] = vertex
;
639 static void d2d_cdt_edge_set_destination(const struct d2d_cdt
*cdt
,
640 const struct d2d_cdt_edge_ref
*e
, size_t vertex
)
642 cdt
->edges
[e
->idx
].vertex
[!(e
->r
>> 1)] = vertex
;
645 static float d2d_cdt_ccw(const struct d2d_cdt
*cdt
, size_t a
, size_t b
, size_t c
)
647 return d2d_point_ccw(&cdt
->vertices
[a
], &cdt
->vertices
[b
], &cdt
->vertices
[c
]);
650 static BOOL
d2d_cdt_rightof(const struct d2d_cdt
*cdt
, size_t p
, const struct d2d_cdt_edge_ref
*e
)
652 return d2d_cdt_ccw(cdt
, p
, d2d_cdt_edge_destination(cdt
, e
), d2d_cdt_edge_origin(cdt
, e
)) > 0.0f
;
655 static BOOL
d2d_cdt_leftof(const struct d2d_cdt
*cdt
, size_t p
, const struct d2d_cdt_edge_ref
*e
)
657 return d2d_cdt_ccw(cdt
, p
, d2d_cdt_edge_origin(cdt
, e
), d2d_cdt_edge_destination(cdt
, e
)) > 0.0f
;
662 static void d2d_fp_four_det2x2(float *out
, float ax
, float ay
, float bx
, float by
)
664 float axby
[2], aybx
[2];
666 d2d_fp_two_product(axby
, ax
, by
);
667 d2d_fp_two_product(aybx
, ay
, bx
);
668 d2d_fp_two_two_diff(out
, axby
, aybx
);
671 /* (a->x² + a->y²) * det2x2 */
672 static void d2d_fp_sub_det3x3(float *out
, size_t *out_len
, const struct d2d_fp_two_vec2
*a
, const float *det2x2
)
674 size_t axd_len
, ayd_len
, axxd_len
, ayyd_len
;
675 float axd
[8], ayd
[8], axxd
[16], ayyd
[16];
677 d2d_fp_scale_expansion_zeroelim(axd
, &axd_len
, det2x2
, 4, a
->x
[1]);
678 d2d_fp_scale_expansion_zeroelim(axxd
, &axxd_len
, axd
, axd_len
, a
->x
[1]);
679 d2d_fp_scale_expansion_zeroelim(ayd
, &ayd_len
, det2x2
, 4, a
->y
[1]);
680 d2d_fp_scale_expansion_zeroelim(ayyd
, &ayyd_len
, ayd
, ayd_len
, a
->y
[1]);
681 d2d_fp_fast_expansion_sum_zeroelim(out
, out_len
, axxd
, axxd_len
, ayyd
, ayyd_len
);
684 /* det_abt = det_ab * c[0]
685 * fin += c[0] * (az * b - bz * a + c[1] * det_ab * 2.0f) */
686 static void d2d_cdt_incircle_refine1(struct d2d_fp_fin
*fin
, float *det_abt
, size_t *det_abt_len
,
687 const float *det_ab
, float a
, const float *az
, float b
, const float *bz
, const float *c
)
689 size_t temp48_len
, temp32_len
, temp16a_len
, temp16b_len
, temp16c_len
, temp8_len
;
690 float temp48
[48], temp32
[32], temp16a
[16], temp16b
[16], temp16c
[16], temp8
[8];
693 d2d_fp_scale_expansion_zeroelim(det_abt
, det_abt_len
, det_ab
, 4, c
[0]);
694 d2d_fp_scale_expansion_zeroelim(temp16a
, &temp16a_len
, det_abt
, *det_abt_len
, 2.0f
* c
[1]);
695 d2d_fp_scale_expansion_zeroelim(temp8
, &temp8_len
, az
, 4, c
[0]);
696 d2d_fp_scale_expansion_zeroelim(temp16b
, &temp16b_len
, temp8
, temp8_len
, b
);
697 d2d_fp_scale_expansion_zeroelim(temp8
, &temp8_len
, bz
, 4, c
[0]);
698 d2d_fp_scale_expansion_zeroelim(temp16c
, &temp16c_len
, temp8
, temp8_len
, -a
);
699 d2d_fp_fast_expansion_sum_zeroelim(temp32
, &temp32_len
, temp16a
, temp16a_len
, temp16b
, temp16b_len
);
700 d2d_fp_fast_expansion_sum_zeroelim(temp48
, &temp48_len
, temp16c
, temp16c_len
, temp32
, temp32_len
);
701 d2d_fp_fast_expansion_sum_zeroelim(fin
->other
, &fin
->length
, fin
->now
, fin
->length
, temp48
, temp48_len
);
702 swap
= fin
->now
; fin
->now
= fin
->other
; fin
->other
= swap
;
705 static void d2d_cdt_incircle_refine2(struct d2d_fp_fin
*fin
, const struct d2d_fp_two_vec2
*a
,
706 const struct d2d_fp_two_vec2
*b
, const float *bz
, const struct d2d_fp_two_vec2
*c
, const float *cz
,
707 const float *axt_det_bc
, size_t axt_det_bc_len
, const float *ayt_det_bc
, size_t ayt_det_bc_len
)
709 size_t temp64_len
, temp48_len
, temp32a_len
, temp32b_len
, temp16a_len
, temp16b_len
, temp8_len
;
710 float temp64
[64], temp48
[48], temp32a
[32], temp32b
[32], temp16a
[16], temp16b
[16], temp8
[8];
711 float bct
[8], bctt
[4], temp4a
[4], temp4b
[4], temp2a
[2], temp2b
[2];
712 size_t bct_len
, bctt_len
;
715 /* 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]) */
716 /* bctt = b->x[0] * c->y[0] + c->x[0] * b->y[0] */
717 if (b
->x
[0] != 0.0f
|| b
->y
[0] != 0.0f
|| c
->x
[0] != 0.0f
|| c
->y
[0] != 0.0f
)
719 d2d_fp_two_product(temp2a
, b
->x
[0], c
->y
[1]);
720 d2d_fp_two_product(temp2b
, b
->x
[1], c
->y
[0]);
721 d2d_fp_two_two_sum(temp4a
, temp2a
, temp2b
);
722 d2d_fp_two_product(temp2a
, c
->x
[0], -b
->y
[1]);
723 d2d_fp_two_product(temp2b
, c
->x
[1], -b
->y
[0]);
724 d2d_fp_two_two_sum(temp4b
, temp2a
, temp2b
);
725 d2d_fp_fast_expansion_sum_zeroelim(bct
, &bct_len
, temp4a
, 4, temp4b
, 4);
727 d2d_fp_two_product(temp2a
, b
->x
[0], c
->y
[0]);
728 d2d_fp_two_product(temp2b
, c
->x
[0], b
->y
[0]);
729 d2d_fp_two_two_diff(bctt
, temp2a
, temp2b
);
742 size_t axt_bct_len
, axt_bctt_len
;
743 float axt_bct
[16], axt_bctt
[8];
745 /* fin += a->x[0] * (axt_det_bc + bct * 2.0f * a->x[1]) */
746 d2d_fp_scale_expansion_zeroelim(temp16a
, &temp16a_len
, axt_det_bc
, axt_det_bc_len
, a
->x
[0]);
747 d2d_fp_scale_expansion_zeroelim(axt_bct
, &axt_bct_len
, bct
, bct_len
, a
->x
[0]);
748 d2d_fp_scale_expansion_zeroelim(temp32a
, &temp32a_len
, axt_bct
, axt_bct_len
, 2.0f
* a
->x
[1]);
749 d2d_fp_fast_expansion_sum_zeroelim(temp48
, &temp48_len
, temp16a
, temp16a_len
, temp32a
, temp32a_len
);
750 d2d_fp_fast_expansion_sum_zeroelim(fin
->other
, &fin
->length
, fin
->now
, fin
->length
, temp48
, temp48_len
);
751 swap
= fin
->now
; fin
->now
= fin
->other
; fin
->other
= swap
;
755 /* fin += a->x[0] * cz * b->y[0] */
756 d2d_fp_scale_expansion_zeroelim(temp8
, &temp8_len
, cz
, 4, a
->x
[0]);
757 d2d_fp_scale_expansion_zeroelim(temp16a
, &temp16a_len
, temp8
, temp8_len
, b
->y
[0]);
758 d2d_fp_fast_expansion_sum_zeroelim(fin
->other
, &fin
->length
, fin
->now
, fin
->length
, temp16a
, temp16a_len
);
759 swap
= fin
->now
; fin
->now
= fin
->other
; fin
->other
= swap
;
764 /* fin -= a->x[0] * bz * c->y[0] */
765 d2d_fp_scale_expansion_zeroelim(temp8
, &temp8_len
, bz
, 4, -a
->x
[0]);
766 d2d_fp_scale_expansion_zeroelim(temp16a
, &temp16a_len
, temp8
, temp8_len
, c
->y
[0]);
767 d2d_fp_fast_expansion_sum_zeroelim(fin
->other
, &fin
->length
, fin
->now
, fin
->length
, temp16a
, temp16a_len
);
768 swap
= fin
->now
; fin
->now
= fin
->other
; fin
->other
= swap
;
771 /* fin += a->x[0] * (bct * a->x[0] + bctt * (2.0f * a->x[1] + a->x[0])) */
772 d2d_fp_scale_expansion_zeroelim(temp32a
, &temp32a_len
, axt_bct
, axt_bct_len
, a
->x
[0]);
773 d2d_fp_scale_expansion_zeroelim(axt_bctt
, &axt_bctt_len
, bctt
, bctt_len
, a
->x
[0]);
774 d2d_fp_scale_expansion_zeroelim(temp16a
, &temp16a_len
, axt_bctt
, axt_bctt_len
, 2.0f
* a
->x
[1]);
775 d2d_fp_scale_expansion_zeroelim(temp16b
, &temp16b_len
, axt_bctt
, axt_bctt_len
, a
->x
[0]);
776 d2d_fp_fast_expansion_sum_zeroelim(temp32b
, &temp32b_len
, temp16a
, temp16a_len
, temp16b
, temp16b_len
);
777 d2d_fp_fast_expansion_sum_zeroelim(temp64
, &temp64_len
, temp32a
, temp32a_len
, temp32b
, temp32b_len
);
778 d2d_fp_fast_expansion_sum_zeroelim(fin
->other
, &fin
->length
, fin
->now
, fin
->length
, temp64
, temp64_len
);
779 swap
= fin
->now
; fin
->now
= fin
->other
; fin
->other
= swap
;
784 size_t ayt_bct_len
, ayt_bctt_len
;
785 float ayt_bct
[16], ayt_bctt
[8];
787 /* fin += a->y[0] * (ayt_det_bc + bct * 2.0f * a->y[1]) */
788 d2d_fp_scale_expansion_zeroelim(temp16a
, &temp16a_len
, ayt_det_bc
, ayt_det_bc_len
, a
->y
[0]);
789 d2d_fp_scale_expansion_zeroelim(ayt_bct
, &ayt_bct_len
, bct
, bct_len
, a
->y
[0]);
790 d2d_fp_scale_expansion_zeroelim(temp32a
, &temp32a_len
, ayt_bct
, ayt_bct_len
, 2.0f
* a
->y
[1]);
791 d2d_fp_fast_expansion_sum_zeroelim(temp48
, &temp48_len
, temp16a
, temp16a_len
, temp32a
, temp32a_len
);
792 d2d_fp_fast_expansion_sum_zeroelim(fin
->other
, &fin
->length
, fin
->now
, fin
->length
, temp48
, temp48_len
);
793 swap
= fin
->now
; fin
->now
= fin
->other
; fin
->other
= swap
;
795 /* fin += a->y[0] * (bct * a->y[0] + bctt * (2.0f * a->y[1] + a->y[0])) */
796 d2d_fp_scale_expansion_zeroelim(temp32a
, &temp32a_len
, ayt_bct
, ayt_bct_len
, a
->y
[0]);
797 d2d_fp_scale_expansion_zeroelim(ayt_bctt
, &ayt_bctt_len
, bctt
, bctt_len
, a
->y
[0]);
798 d2d_fp_scale_expansion_zeroelim(temp16a
, &temp16a_len
, ayt_bctt
, ayt_bctt_len
, 2.0f
* a
->y
[1]);
799 d2d_fp_scale_expansion_zeroelim(temp16b
, &temp16b_len
, ayt_bctt
, ayt_bctt_len
, a
->y
[0]);
800 d2d_fp_fast_expansion_sum_zeroelim(temp32b
, &temp32b_len
, temp16a
, temp16a_len
, temp16b
, temp16b_len
);
801 d2d_fp_fast_expansion_sum_zeroelim(temp64
, &temp64_len
, temp32a
, temp32a_len
, temp32b
, temp32b_len
);
802 d2d_fp_fast_expansion_sum_zeroelim(fin
->other
, &fin
->length
, fin
->now
, fin
->length
, temp64
, temp64_len
);
803 swap
= fin
->now
; fin
->now
= fin
->other
; fin
->other
= swap
;
807 /* Determine if point D is inside or outside the circle defined by points A,
808 * B, C. As explained in the paper by Guibas and Stolfi, this is equivalent to
809 * calculating the signed volume of the tetrahedron defined by projecting the
810 * points onto the paraboloid of revolution x = x² + y²,
811 * λ:(x, y) → (x, y, x² + y²). I.e., D is inside the cirlce if
818 * After translating D to the origin, that becomes:
824 * This implementation is based on the paper "Adaptive Precision
825 * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
826 * associated (Public Domain) code by Jonathan Richard Shewchuk. */
827 static BOOL
d2d_cdt_incircle(const struct d2d_cdt
*cdt
, size_t a
, size_t b
, size_t c
, size_t d
)
829 static const float err_bound_result
= (3.0f
+ 8.0f
* D2D_FP_EPS
) * D2D_FP_EPS
;
830 static const float err_bound_a
= (10.0f
+ 96.0f
* D2D_FP_EPS
) * D2D_FP_EPS
;
831 static const float err_bound_b
= (4.0f
+ 48.0f
* D2D_FP_EPS
) * D2D_FP_EPS
;
832 static const float err_bound_c
= (44.0f
+ 576.0f
* D2D_FP_EPS
) * D2D_FP_EPS
* D2D_FP_EPS
;
834 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
;
835 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];
836 float fin1
[1152], fin2
[1152], temp64
[64], sub_det_a
[32], sub_det_b
[32], sub_det_c
[32];
837 float det_bc
[4], det_ca
[4], det_ab
[4], daz
[4], dbz
[4], dcz
[4], temp2a
[2], temp2b
[2];
838 size_t temp64_len
, sub_det_a_len
, sub_det_b_len
, sub_det_c_len
;
839 float dbxdcy
, dbydcx
, dcxday
, dcydax
, daxdby
, daydbx
;
840 const D2D1_POINT_2F
*p
= cdt
->vertices
;
841 struct d2d_fp_two_vec2 da
, db
, dc
;
842 float permanent
, err_bound
, det
;
843 struct d2d_fp_fin fin
;
845 da
.x
[1] = p
[a
].x
- p
[d
].x
;
846 da
.y
[1] = p
[a
].y
- p
[d
].y
;
847 db
.x
[1] = p
[b
].x
- p
[d
].x
;
848 db
.y
[1] = p
[b
].y
- p
[d
].y
;
849 dc
.x
[1] = p
[c
].x
- p
[d
].x
;
850 dc
.y
[1] = p
[c
].y
- p
[d
].y
;
852 daz
[3] = da
.x
[1] * da
.x
[1] + da
.y
[1] * da
.y
[1];
853 dbxdcy
= db
.x
[1] * dc
.y
[1];
854 dbydcx
= db
.y
[1] * dc
.x
[1];
856 dbz
[3] = db
.x
[1] * db
.x
[1] + db
.y
[1] * db
.y
[1];
857 dcxday
= dc
.x
[1] * da
.y
[1];
858 dcydax
= dc
.y
[1] * da
.x
[1];
860 dcz
[3] = dc
.x
[1] * dc
.x
[1] + dc
.y
[1] * dc
.y
[1];
861 daxdby
= da
.x
[1] * db
.y
[1];
862 daydbx
= da
.y
[1] * db
.x
[1];
864 det
= daz
[3] * (dbxdcy
- dbydcx
) + dbz
[3] * (dcxday
- dcydax
) + dcz
[3] * (daxdby
- daydbx
);
865 permanent
= daz
[3] * (fabsf(dbxdcy
) + fabsf(dbydcx
))
866 + dbz
[3] * (fabsf(dcxday
) + fabsf(dcydax
))
867 + dcz
[3] * (fabsf(daxdby
) + fabsf(daydbx
));
868 err_bound
= err_bound_a
* permanent
;
869 if (det
> err_bound
|| -det
> err_bound
)
875 d2d_fp_four_det2x2(det_bc
, db
.x
[1], db
.y
[1], dc
.x
[1], dc
.y
[1]);
876 d2d_fp_sub_det3x3(sub_det_a
, &sub_det_a_len
, &da
, det_bc
);
878 d2d_fp_four_det2x2(det_ca
, dc
.x
[1], dc
.y
[1], da
.x
[1], da
.y
[1]);
879 d2d_fp_sub_det3x3(sub_det_b
, &sub_det_b_len
, &db
, det_ca
);
881 d2d_fp_four_det2x2(det_ab
, da
.x
[1], da
.y
[1], db
.x
[1], db
.y
[1]);
882 d2d_fp_sub_det3x3(sub_det_c
, &sub_det_c_len
, &dc
, det_ab
);
884 d2d_fp_fast_expansion_sum_zeroelim(temp64
, &temp64_len
, sub_det_a
, sub_det_a_len
, sub_det_b
, sub_det_b_len
);
885 d2d_fp_fast_expansion_sum_zeroelim(fin
.now
, &fin
.length
, temp64
, temp64_len
, sub_det_c
, sub_det_c_len
);
886 det
= d2d_fp_estimate(fin
.now
, fin
.length
);
887 err_bound
= err_bound_b
* permanent
;
888 if (det
>= err_bound
|| -det
>= err_bound
)
891 d2d_fp_two_diff_tail(&da
.x
[0], p
[a
].x
, p
[d
].x
, da
.x
[1]);
892 d2d_fp_two_diff_tail(&da
.y
[0], p
[a
].y
, p
[d
].y
, da
.y
[1]);
893 d2d_fp_two_diff_tail(&db
.x
[0], p
[b
].x
, p
[d
].x
, db
.x
[1]);
894 d2d_fp_two_diff_tail(&db
.y
[0], p
[b
].y
, p
[d
].y
, db
.y
[1]);
895 d2d_fp_two_diff_tail(&dc
.x
[0], p
[c
].x
, p
[d
].x
, dc
.x
[1]);
896 d2d_fp_two_diff_tail(&dc
.y
[0], p
[c
].y
, p
[d
].y
, dc
.y
[1]);
897 if (da
.x
[0] == 0.0f
&& db
.x
[0] == 0.0f
&& dc
.x
[0] == 0.0f
898 && da
.y
[0] == 0.0f
&& db
.y
[0] == 0.0f
&& dc
.y
[0] == 0.0f
)
901 err_bound
= err_bound_c
* permanent
+ err_bound_result
* fabsf(det
);
902 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]))
903 + 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]))
904 + (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]))
905 + 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]))
906 + (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]))
907 + 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]));
908 if (det
>= err_bound
|| -det
>= err_bound
)
911 if (db
.x
[0] != 0.0f
|| db
.y
[0] != 0.0f
|| dc
.x
[0] != 0.0f
|| dc
.y
[0] != 0.0f
)
913 d2d_fp_square(temp2a
, da
.x
[1]);
914 d2d_fp_square(temp2b
, da
.y
[1]);
915 d2d_fp_two_two_sum(daz
, temp2a
, temp2b
);
917 if (dc
.x
[0] != 0.0f
|| dc
.y
[0] != 0.0f
|| da
.x
[0] != 0.0f
|| da
.y
[0] != 0.0f
)
919 d2d_fp_square(temp2a
, db
.x
[1]);
920 d2d_fp_square(temp2b
, db
.y
[1]);
921 d2d_fp_two_two_sum(dbz
, temp2a
, temp2b
);
923 if (da
.x
[0] != 0.0f
|| da
.y
[0] != 0.0f
|| db
.x
[0] != 0.0f
|| db
.y
[0] != 0.0f
)
925 d2d_fp_square(temp2a
, dc
.x
[1]);
926 d2d_fp_square(temp2b
, dc
.y
[1]);
927 d2d_fp_two_two_sum(dcz
, temp2a
, temp2b
);
931 d2d_cdt_incircle_refine1(&fin
, axt_det_bc
, &axt_det_bc_len
, det_bc
, dc
.y
[1], dcz
, db
.y
[1], dbz
, da
.x
);
933 d2d_cdt_incircle_refine1(&fin
, ayt_det_bc
, &ayt_det_bc_len
, det_bc
, db
.x
[1], dbz
, dc
.x
[1], dcz
, da
.y
);
935 d2d_cdt_incircle_refine1(&fin
, bxt_det_ca
, &bxt_det_ca_len
, det_ca
, da
.y
[1], daz
, dc
.y
[1], dcz
, db
.x
);
937 d2d_cdt_incircle_refine1(&fin
, byt_det_ca
, &byt_det_ca_len
, det_ca
, dc
.x
[1], dcz
, da
.x
[1], daz
, db
.y
);
939 d2d_cdt_incircle_refine1(&fin
, cxt_det_ab
, &cxt_det_ab_len
, det_ab
, db
.y
[1], dbz
, da
.y
[1], daz
, dc
.x
);
941 d2d_cdt_incircle_refine1(&fin
, cyt_det_ab
, &cyt_det_ab_len
, det_ab
, da
.x
[1], daz
, db
.x
[1], dbz
, dc
.y
);
943 if (da
.x
[0] != 0.0f
|| da
.y
[0] != 0.0f
)
944 d2d_cdt_incircle_refine2(&fin
, &da
, &db
, dbz
, &dc
, dcz
,
945 axt_det_bc
, axt_det_bc_len
, ayt_det_bc
, ayt_det_bc_len
);
946 if (db
.x
[0] != 0.0f
|| db
.y
[0] != 0.0f
)
947 d2d_cdt_incircle_refine2(&fin
, &db
, &dc
, dcz
, &da
, daz
,
948 bxt_det_ca
, bxt_det_ca_len
, byt_det_ca
, byt_det_ca_len
);
949 if (dc
.x
[0] != 0.0f
|| dc
.y
[0] != 0.0f
)
950 d2d_cdt_incircle_refine2(&fin
, &dc
, &da
, daz
, &db
, dbz
,
951 cxt_det_ab
, cxt_det_ab_len
, cyt_det_ab
, cyt_det_ab_len
);
953 return fin
.now
[fin
.length
- 1] > 0.0f
;
956 static void d2d_cdt_splice(const struct d2d_cdt
*cdt
, const struct d2d_cdt_edge_ref
*a
,
957 const struct d2d_cdt_edge_ref
*b
)
959 struct d2d_cdt_edge_ref ta
, tb
, alpha
, beta
;
961 ta
= cdt
->edges
[a
->idx
].next
[a
->r
];
962 tb
= cdt
->edges
[b
->idx
].next
[b
->r
];
963 cdt
->edges
[a
->idx
].next
[a
->r
] = tb
;
964 cdt
->edges
[b
->idx
].next
[b
->r
] = ta
;
966 d2d_cdt_edge_rot(&alpha
, &ta
);
967 d2d_cdt_edge_rot(&beta
, &tb
);
969 ta
= cdt
->edges
[alpha
.idx
].next
[alpha
.r
];
970 tb
= cdt
->edges
[beta
.idx
].next
[beta
.r
];
971 cdt
->edges
[alpha
.idx
].next
[alpha
.r
] = tb
;
972 cdt
->edges
[beta
.idx
].next
[beta
.r
] = ta
;
975 static BOOL
d2d_cdt_create_edge(struct d2d_cdt
*cdt
, struct d2d_cdt_edge_ref
*e
)
977 struct d2d_cdt_edge
*edge
;
979 if (cdt
->free_edge
!= ~0u)
981 e
->idx
= cdt
->free_edge
;
982 cdt
->free_edge
= cdt
->edges
[e
->idx
].next
[D2D_EDGE_NEXT_ORIGIN
].idx
;
986 if (!d2d_array_reserve((void **)&cdt
->edges
, &cdt
->edges_size
, cdt
->edge_count
+ 1, sizeof(*cdt
->edges
)))
988 ERR("Failed to grow edges array.\n");
991 e
->idx
= cdt
->edge_count
++;
995 edge
= &cdt
->edges
[e
->idx
];
996 edge
->next
[D2D_EDGE_NEXT_ORIGIN
] = *e
;
997 d2d_cdt_edge_tor(&edge
->next
[D2D_EDGE_NEXT_ROT
], e
);
998 d2d_cdt_edge_sym(&edge
->next
[D2D_EDGE_NEXT_SYM
], e
);
999 d2d_cdt_edge_rot(&edge
->next
[D2D_EDGE_NEXT_TOR
], e
);
1005 static void d2d_cdt_destroy_edge(struct d2d_cdt
*cdt
, const struct d2d_cdt_edge_ref
*e
)
1007 struct d2d_cdt_edge_ref next
, sym
, prev
;
1009 d2d_cdt_edge_next_origin(cdt
, &next
, e
);
1010 if (next
.idx
!= e
->idx
|| next
.r
!= e
->r
)
1012 d2d_cdt_edge_prev_origin(cdt
, &prev
, e
);
1013 d2d_cdt_splice(cdt
, e
, &prev
);
1016 d2d_cdt_edge_sym(&sym
, e
);
1018 d2d_cdt_edge_next_origin(cdt
, &next
, &sym
);
1019 if (next
.idx
!= sym
.idx
|| next
.r
!= sym
.r
)
1021 d2d_cdt_edge_prev_origin(cdt
, &prev
, &sym
);
1022 d2d_cdt_splice(cdt
, &sym
, &prev
);
1025 cdt
->edges
[e
->idx
].flags
|= D2D_CDT_EDGE_FLAG_FREED
;
1026 cdt
->edges
[e
->idx
].next
[D2D_EDGE_NEXT_ORIGIN
].idx
= cdt
->free_edge
;
1027 cdt
->free_edge
= e
->idx
;
1030 static BOOL
d2d_cdt_connect(struct d2d_cdt
*cdt
, struct d2d_cdt_edge_ref
*e
,
1031 const struct d2d_cdt_edge_ref
*a
, const struct d2d_cdt_edge_ref
*b
)
1033 struct d2d_cdt_edge_ref tmp
;
1035 if (!d2d_cdt_create_edge(cdt
, e
))
1037 d2d_cdt_edge_set_origin(cdt
, e
, d2d_cdt_edge_destination(cdt
, a
));
1038 d2d_cdt_edge_set_destination(cdt
, e
, d2d_cdt_edge_origin(cdt
, b
));
1039 d2d_cdt_edge_next_left(cdt
, &tmp
, a
);
1040 d2d_cdt_splice(cdt
, e
, &tmp
);
1041 d2d_cdt_edge_sym(&tmp
, e
);
1042 d2d_cdt_splice(cdt
, &tmp
, b
);
1047 static BOOL
d2d_cdt_merge(struct d2d_cdt
*cdt
, struct d2d_cdt_edge_ref
*left_outer
,
1048 struct d2d_cdt_edge_ref
*left_inner
, struct d2d_cdt_edge_ref
*right_inner
,
1049 struct d2d_cdt_edge_ref
*right_outer
)
1051 struct d2d_cdt_edge_ref base_edge
, tmp
;
1053 /* Create the base edge between both parts. */
1056 if (d2d_cdt_leftof(cdt
, d2d_cdt_edge_origin(cdt
, right_inner
), left_inner
))
1058 d2d_cdt_edge_next_left(cdt
, left_inner
, left_inner
);
1060 else if (d2d_cdt_rightof(cdt
, d2d_cdt_edge_origin(cdt
, left_inner
), right_inner
))
1062 d2d_cdt_edge_sym(&tmp
, right_inner
);
1063 d2d_cdt_edge_next_origin(cdt
, right_inner
, &tmp
);
1071 d2d_cdt_edge_sym(&tmp
, right_inner
);
1072 if (!d2d_cdt_connect(cdt
, &base_edge
, &tmp
, left_inner
))
1074 if (d2d_cdt_edge_origin(cdt
, left_inner
) == d2d_cdt_edge_origin(cdt
, left_outer
))
1075 d2d_cdt_edge_sym(left_outer
, &base_edge
);
1076 if (d2d_cdt_edge_origin(cdt
, right_inner
) == d2d_cdt_edge_origin(cdt
, right_outer
))
1077 *right_outer
= base_edge
;
1081 struct d2d_cdt_edge_ref left_candidate
, right_candidate
, sym_base_edge
;
1082 BOOL left_valid
, right_valid
;
1084 /* Find the left candidate. */
1085 d2d_cdt_edge_sym(&sym_base_edge
, &base_edge
);
1086 d2d_cdt_edge_next_origin(cdt
, &left_candidate
, &sym_base_edge
);
1087 if ((left_valid
= d2d_cdt_leftof(cdt
, d2d_cdt_edge_destination(cdt
, &left_candidate
), &sym_base_edge
)))
1089 d2d_cdt_edge_next_origin(cdt
, &tmp
, &left_candidate
);
1090 while (d2d_cdt_edge_destination(cdt
, &tmp
) != d2d_cdt_edge_destination(cdt
, &sym_base_edge
)
1091 && d2d_cdt_incircle(cdt
,
1092 d2d_cdt_edge_origin(cdt
, &sym_base_edge
), d2d_cdt_edge_destination(cdt
, &sym_base_edge
),
1093 d2d_cdt_edge_destination(cdt
, &left_candidate
), d2d_cdt_edge_destination(cdt
, &tmp
)))
1095 d2d_cdt_destroy_edge(cdt
, &left_candidate
);
1096 left_candidate
= tmp
;
1097 d2d_cdt_edge_next_origin(cdt
, &tmp
, &left_candidate
);
1100 d2d_cdt_edge_sym(&left_candidate
, &left_candidate
);
1102 /* Find the right candidate. */
1103 d2d_cdt_edge_prev_origin(cdt
, &right_candidate
, &base_edge
);
1104 if ((right_valid
= d2d_cdt_rightof(cdt
, d2d_cdt_edge_destination(cdt
, &right_candidate
), &base_edge
)))
1106 d2d_cdt_edge_prev_origin(cdt
, &tmp
, &right_candidate
);
1107 while (d2d_cdt_edge_destination(cdt
, &tmp
) != d2d_cdt_edge_destination(cdt
, &base_edge
)
1108 && d2d_cdt_incircle(cdt
,
1109 d2d_cdt_edge_origin(cdt
, &sym_base_edge
), d2d_cdt_edge_destination(cdt
, &sym_base_edge
),
1110 d2d_cdt_edge_destination(cdt
, &right_candidate
), d2d_cdt_edge_destination(cdt
, &tmp
)))
1112 d2d_cdt_destroy_edge(cdt
, &right_candidate
);
1113 right_candidate
= tmp
;
1114 d2d_cdt_edge_prev_origin(cdt
, &tmp
, &right_candidate
);
1118 if (!left_valid
&& !right_valid
)
1121 /* Connect the appropriate candidate with the base edge. */
1122 if (!left_valid
|| (right_valid
&& d2d_cdt_incircle(cdt
,
1123 d2d_cdt_edge_origin(cdt
, &left_candidate
), d2d_cdt_edge_destination(cdt
, &left_candidate
),
1124 d2d_cdt_edge_origin(cdt
, &right_candidate
), d2d_cdt_edge_destination(cdt
, &right_candidate
))))
1126 if (!d2d_cdt_connect(cdt
, &base_edge
, &right_candidate
, &sym_base_edge
))
1131 if (!d2d_cdt_connect(cdt
, &base_edge
, &sym_base_edge
, &left_candidate
))
1139 /* Create a Delaunay triangulation from a set of vertices. This is an
1140 * implementation of the divide-and-conquer algorithm described by Guibas and
1141 * Stolfi. Should be called with at least two vertices. */
1142 static BOOL
d2d_cdt_triangulate(struct d2d_cdt
*cdt
, size_t start_vertex
, size_t vertex_count
,
1143 struct d2d_cdt_edge_ref
*left_edge
, struct d2d_cdt_edge_ref
*right_edge
)
1145 struct d2d_cdt_edge_ref left_inner
, left_outer
, right_inner
, right_outer
, tmp
;
1148 /* Only two vertices, create a single edge. */
1149 if (vertex_count
== 2)
1151 struct d2d_cdt_edge_ref a
;
1153 if (!d2d_cdt_create_edge(cdt
, &a
))
1155 d2d_cdt_edge_set_origin(cdt
, &a
, start_vertex
);
1156 d2d_cdt_edge_set_destination(cdt
, &a
, start_vertex
+ 1);
1159 d2d_cdt_edge_sym(right_edge
, &a
);
1164 /* Three vertices, create a triangle. */
1165 if (vertex_count
== 3)
1167 struct d2d_cdt_edge_ref a
, b
, c
;
1170 if (!d2d_cdt_create_edge(cdt
, &a
))
1172 if (!d2d_cdt_create_edge(cdt
, &b
))
1174 d2d_cdt_edge_sym(&tmp
, &a
);
1175 d2d_cdt_splice(cdt
, &tmp
, &b
);
1177 d2d_cdt_edge_set_origin(cdt
, &a
, start_vertex
);
1178 d2d_cdt_edge_set_destination(cdt
, &a
, start_vertex
+ 1);
1179 d2d_cdt_edge_set_origin(cdt
, &b
, start_vertex
+ 1);
1180 d2d_cdt_edge_set_destination(cdt
, &b
, start_vertex
+ 2);
1182 det
= d2d_cdt_ccw(cdt
, start_vertex
, start_vertex
+ 1, start_vertex
+ 2);
1183 if (det
!= 0.0f
&& !d2d_cdt_connect(cdt
, &c
, &b
, &a
))
1188 d2d_cdt_edge_sym(left_edge
, &c
);
1194 d2d_cdt_edge_sym(right_edge
, &b
);
1200 /* More than tree vertices, divide. */
1201 cut
= vertex_count
/ 2;
1202 if (!d2d_cdt_triangulate(cdt
, start_vertex
, cut
, &left_outer
, &left_inner
))
1204 if (!d2d_cdt_triangulate(cdt
, start_vertex
+ cut
, vertex_count
- cut
, &right_inner
, &right_outer
))
1206 /* Merge the left and right parts. */
1207 if (!d2d_cdt_merge(cdt
, &left_outer
, &left_inner
, &right_inner
, &right_outer
))
1210 *left_edge
= left_outer
;
1211 *right_edge
= right_outer
;
1215 static int d2d_cdt_compare_vertices(const void *a
, const void *b
)
1217 const D2D1_POINT_2F
*p0
= a
;
1218 const D2D1_POINT_2F
*p1
= b
;
1219 float diff
= p0
->x
- p1
->x
;
1222 diff
= p0
->y
- p1
->y
;
1224 return diff
== 0.0f
? 0 : (diff
> 0.0f
? 1 : -1);
1227 /* Determine whether a given point is inside the geometry, using the current
1228 * fill mode rule. */
1229 static BOOL
d2d_path_geometry_point_inside(const struct d2d_geometry
*geometry
,
1230 const D2D1_POINT_2F
*probe
, BOOL triangles_only
)
1232 const D2D1_POINT_2F
*p0
, *p1
;
1233 D2D1_POINT_2F v_p
, v_probe
;
1237 for (i
= 0, score
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
1239 const struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[i
];
1241 if (probe
->x
< figure
->bounds
.left
|| probe
->x
> figure
->bounds
.right
1242 || probe
->y
< figure
->bounds
.top
|| probe
->y
> figure
->bounds
.bottom
)
1245 last
= figure
->vertex_count
- 1;
1246 if (!triangles_only
)
1248 while (last
&& figure
->vertex_types
[last
] == D2D_VERTEX_TYPE_NONE
)
1251 p0
= &figure
->vertices
[last
];
1252 for (j
= 0; j
<= last
; ++j
)
1254 if (!triangles_only
&& figure
->vertex_types
[j
] == D2D_VERTEX_TYPE_NONE
)
1257 p1
= &figure
->vertices
[j
];
1258 d2d_point_subtract(&v_p
, p1
, p0
);
1259 d2d_point_subtract(&v_probe
, probe
, p0
);
1261 if ((probe
->y
< p0
->y
) != (probe
->y
< p1
->y
) && v_probe
.x
< v_p
.x
* (v_probe
.y
/ v_p
.y
))
1263 if (geometry
->u
.path
.fill_mode
== D2D1_FILL_MODE_ALTERNATE
|| (probe
->y
< p0
->y
))
1273 return geometry
->u
.path
.fill_mode
== D2D1_FILL_MODE_ALTERNATE
? score
& 1 : score
;
1276 static BOOL
d2d_path_geometry_add_fill_face(struct d2d_geometry
*geometry
, const struct d2d_cdt
*cdt
,
1277 const struct d2d_cdt_edge_ref
*base_edge
)
1279 struct d2d_cdt_edge_ref tmp
;
1280 struct d2d_face
*face
;
1281 D2D1_POINT_2F probe
;
1283 if (cdt
->edges
[base_edge
->idx
].flags
& D2D_CDT_EDGE_FLAG_VISITED(base_edge
->r
))
1286 if (!d2d_array_reserve((void **)&geometry
->fill
.faces
, &geometry
->fill
.faces_size
,
1287 geometry
->fill
.face_count
+ 1, sizeof(*geometry
->fill
.faces
)))
1289 ERR("Failed to grow faces array.\n");
1293 face
= &geometry
->fill
.faces
[geometry
->fill
.face_count
];
1295 /* It may seem tempting to use the center of the face as probe origin, but
1296 * multiplying by powers of two works much better for preserving accuracy. */
1299 cdt
->edges
[tmp
.idx
].flags
|= D2D_CDT_EDGE_FLAG_VISITED(tmp
.r
);
1300 face
->v
[0] = d2d_cdt_edge_origin(cdt
, &tmp
);
1301 probe
.x
= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].x
* 0.25f
;
1302 probe
.y
= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].y
* 0.25f
;
1304 d2d_cdt_edge_next_left(cdt
, &tmp
, &tmp
);
1305 cdt
->edges
[tmp
.idx
].flags
|= D2D_CDT_EDGE_FLAG_VISITED(tmp
.r
);
1306 face
->v
[1] = d2d_cdt_edge_origin(cdt
, &tmp
);
1307 probe
.x
+= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].x
* 0.25f
;
1308 probe
.y
+= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].y
* 0.25f
;
1310 d2d_cdt_edge_next_left(cdt
, &tmp
, &tmp
);
1311 cdt
->edges
[tmp
.idx
].flags
|= D2D_CDT_EDGE_FLAG_VISITED(tmp
.r
);
1312 face
->v
[2] = d2d_cdt_edge_origin(cdt
, &tmp
);
1313 probe
.x
+= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].x
* 0.50f
;
1314 probe
.y
+= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].y
* 0.50f
;
1316 if (d2d_cdt_leftof(cdt
, face
->v
[2], base_edge
) && d2d_path_geometry_point_inside(geometry
, &probe
, TRUE
))
1317 ++geometry
->fill
.face_count
;
1322 static BOOL
d2d_cdt_generate_faces(const struct d2d_cdt
*cdt
, struct d2d_geometry
*geometry
)
1324 struct d2d_cdt_edge_ref base_edge
;
1327 for (i
= 0; i
< cdt
->edge_count
; ++i
)
1329 if (cdt
->edges
[i
].flags
& D2D_CDT_EDGE_FLAG_FREED
)
1334 if (!d2d_path_geometry_add_fill_face(geometry
, cdt
, &base_edge
))
1336 d2d_cdt_edge_sym(&base_edge
, &base_edge
);
1337 if (!d2d_path_geometry_add_fill_face(geometry
, cdt
, &base_edge
))
1344 HeapFree(GetProcessHeap(), 0, geometry
->fill
.faces
);
1345 geometry
->fill
.faces
= NULL
;
1346 geometry
->fill
.faces_size
= 0;
1347 geometry
->fill
.face_count
= 0;
1351 static BOOL
d2d_cdt_fixup(struct d2d_cdt
*cdt
, const struct d2d_cdt_edge_ref
*base_edge
)
1353 struct d2d_cdt_edge_ref candidate
, next
, new_base
;
1354 unsigned int count
= 0;
1356 d2d_cdt_edge_next_left(cdt
, &next
, base_edge
);
1357 if (next
.idx
== base_edge
->idx
)
1359 ERR("Degenerate face.\n");
1364 while (d2d_cdt_edge_destination(cdt
, &next
) != d2d_cdt_edge_origin(cdt
, base_edge
))
1366 if (d2d_cdt_incircle(cdt
, d2d_cdt_edge_origin(cdt
, base_edge
), d2d_cdt_edge_destination(cdt
, base_edge
),
1367 d2d_cdt_edge_destination(cdt
, &candidate
), d2d_cdt_edge_destination(cdt
, &next
)))
1369 d2d_cdt_edge_next_left(cdt
, &next
, &next
);
1375 d2d_cdt_edge_next_left(cdt
, &next
, &candidate
);
1376 if (d2d_cdt_edge_destination(cdt
, &next
) == d2d_cdt_edge_origin(cdt
, base_edge
))
1377 d2d_cdt_edge_next_left(cdt
, &next
, base_edge
);
1380 if (!d2d_cdt_connect(cdt
, &new_base
, &candidate
, &next
))
1382 if (!d2d_cdt_fixup(cdt
, &new_base
))
1384 d2d_cdt_edge_sym(&new_base
, &new_base
);
1385 if (!d2d_cdt_fixup(cdt
, &new_base
))
1392 static void d2d_cdt_cut_edges(struct d2d_cdt
*cdt
, struct d2d_cdt_edge_ref
*end_edge
,
1393 const struct d2d_cdt_edge_ref
*base_edge
, size_t start_vertex
, size_t end_vertex
)
1395 struct d2d_cdt_edge_ref next
;
1398 d2d_cdt_edge_next_left(cdt
, &next
, base_edge
);
1399 if (d2d_cdt_edge_destination(cdt
, &next
) == end_vertex
)
1405 ccw
= d2d_cdt_ccw(cdt
, d2d_cdt_edge_destination(cdt
, &next
), end_vertex
, start_vertex
);
1413 d2d_cdt_edge_next_left(cdt
, &next
, &next
);
1415 d2d_cdt_edge_sym(&next
, &next
);
1416 d2d_cdt_cut_edges(cdt
, end_edge
, &next
, start_vertex
, end_vertex
);
1417 d2d_cdt_destroy_edge(cdt
, &next
);
1420 static BOOL
d2d_cdt_insert_segment(struct d2d_cdt
*cdt
, struct d2d_geometry
*geometry
,
1421 const struct d2d_cdt_edge_ref
*origin
, struct d2d_cdt_edge_ref
*edge
, size_t end_vertex
)
1423 struct d2d_cdt_edge_ref base_edge
, current
, new_origin
, next
, target
;
1424 size_t current_destination
, current_origin
;
1426 for (current
= *origin
;; current
= next
)
1428 d2d_cdt_edge_next_origin(cdt
, &next
, ¤t
);
1430 current_destination
= d2d_cdt_edge_destination(cdt
, ¤t
);
1431 if (current_destination
== end_vertex
)
1433 d2d_cdt_edge_sym(edge
, ¤t
);
1437 current_origin
= d2d_cdt_edge_origin(cdt
, ¤t
);
1438 if (d2d_cdt_ccw(cdt
, end_vertex
, current_origin
, current_destination
) == 0.0f
1439 && (cdt
->vertices
[current_destination
].x
> cdt
->vertices
[current_origin
].x
)
1440 == (cdt
->vertices
[end_vertex
].x
> cdt
->vertices
[current_origin
].x
)
1441 && (cdt
->vertices
[current_destination
].y
> cdt
->vertices
[current_origin
].y
)
1442 == (cdt
->vertices
[end_vertex
].y
> cdt
->vertices
[current_origin
].y
))
1444 d2d_cdt_edge_sym(&new_origin
, ¤t
);
1445 return d2d_cdt_insert_segment(cdt
, geometry
, &new_origin
, edge
, end_vertex
);
1448 if (d2d_cdt_rightof(cdt
, end_vertex
, &next
) && d2d_cdt_leftof(cdt
, end_vertex
, ¤t
))
1450 d2d_cdt_edge_next_left(cdt
, &base_edge
, ¤t
);
1452 d2d_cdt_edge_sym(&base_edge
, &base_edge
);
1453 d2d_cdt_cut_edges(cdt
, &target
, &base_edge
, d2d_cdt_edge_origin(cdt
, origin
), end_vertex
);
1454 d2d_cdt_destroy_edge(cdt
, &base_edge
);
1456 if (!d2d_cdt_connect(cdt
, &base_edge
, &target
, ¤t
))
1459 if (!d2d_cdt_fixup(cdt
, &base_edge
))
1461 d2d_cdt_edge_sym(&base_edge
, &base_edge
);
1462 if (!d2d_cdt_fixup(cdt
, &base_edge
))
1465 if (d2d_cdt_edge_origin(cdt
, edge
) == end_vertex
)
1468 return d2d_cdt_insert_segment(cdt
, geometry
, &new_origin
, edge
, end_vertex
);
1471 if (next
.idx
== origin
->idx
)
1473 ERR("Triangle not found.\n");
1479 static BOOL
d2d_cdt_insert_segments(struct d2d_cdt
*cdt
, struct d2d_geometry
*geometry
)
1481 size_t start_vertex
, end_vertex
, i
, j
, k
;
1482 struct d2d_cdt_edge_ref edge
, new_edge
;
1483 const struct d2d_figure
*figure
;
1484 const D2D1_POINT_2F
*p
;
1487 for (i
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
1489 figure
= &geometry
->u
.path
.figures
[i
];
1491 /* Degenerate figure. */
1492 if (figure
->vertex_count
< 2)
1495 p
= bsearch(&figure
->vertices
[figure
->vertex_count
- 1], cdt
->vertices
,
1496 geometry
->fill
.vertex_count
, sizeof(*p
), d2d_cdt_compare_vertices
);
1497 start_vertex
= p
- cdt
->vertices
;
1499 for (k
= 0, found
= FALSE
; k
< cdt
->edge_count
; ++k
)
1501 if (cdt
->edges
[k
].flags
& D2D_CDT_EDGE_FLAG_FREED
)
1507 if (d2d_cdt_edge_origin(cdt
, &edge
) == start_vertex
)
1512 d2d_cdt_edge_sym(&edge
, &edge
);
1513 if (d2d_cdt_edge_origin(cdt
, &edge
) == start_vertex
)
1522 ERR("Edge not found.\n");
1526 for (j
= 0; j
< figure
->vertex_count
; start_vertex
= end_vertex
, ++j
)
1528 p
= bsearch(&figure
->vertices
[j
], cdt
->vertices
,
1529 geometry
->fill
.vertex_count
, sizeof(*p
), d2d_cdt_compare_vertices
);
1530 end_vertex
= p
- cdt
->vertices
;
1532 if (start_vertex
== end_vertex
)
1535 if (!d2d_cdt_insert_segment(cdt
, geometry
, &edge
, &new_edge
, end_vertex
))
1544 static BOOL
d2d_geometry_intersections_add(struct d2d_geometry_intersections
*i
,
1545 size_t figure_idx
, size_t segment_idx
, float t
, D2D1_POINT_2F p
)
1547 struct d2d_geometry_intersection
*intersection
;
1549 if (!d2d_array_reserve((void **)&i
->intersections
, &i
->intersections_size
,
1550 i
->intersection_count
+ 1, sizeof(*i
->intersections
)))
1552 ERR("Failed to grow intersections array.\n");
1556 intersection
= &i
->intersections
[i
->intersection_count
++];
1557 intersection
->figure_idx
= figure_idx
;
1558 intersection
->segment_idx
= segment_idx
;
1559 intersection
->t
= t
;
1560 intersection
->p
= p
;
1565 static int d2d_geometry_intersections_compare(const void *a
, const void *b
)
1567 const struct d2d_geometry_intersection
*i0
= a
;
1568 const struct d2d_geometry_intersection
*i1
= b
;
1570 if (i0
->figure_idx
!= i1
->figure_idx
)
1571 return i0
->figure_idx
- i1
->figure_idx
;
1572 if (i0
->segment_idx
!= i1
->segment_idx
)
1573 return i0
->segment_idx
- i1
->segment_idx
;
1575 return i0
->t
> i1
->t
? 1 : -1;
1579 /* Intersect the geometry's segments with themselves. This uses the
1580 * straightforward approach of testing everything against everything, but
1581 * there certainly exist more scalable algorithms for this. */
1582 /* FIXME: Beziers can't currently self-intersect. */
1583 static BOOL
d2d_geometry_intersect_self(struct d2d_geometry
*geometry
)
1585 D2D1_POINT_2F p0
, p1
, q0
, q1
, v_p
, v_q
, v_qp
, intersection
;
1586 struct d2d_geometry_intersections intersections
= {0};
1587 struct d2d_figure
*figure_p
, *figure_q
;
1588 size_t i
, j
, k
, l
, max_l
;
1592 for (i
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
1594 figure_p
= &geometry
->u
.path
.figures
[i
];
1595 p0
= figure_p
->vertices
[figure_p
->vertex_count
- 1];
1596 for (k
= 0; k
< figure_p
->vertex_count
; p0
= p1
, ++k
)
1598 p1
= figure_p
->vertices
[k
];
1599 d2d_point_subtract(&v_p
, &p1
, &p0
);
1600 for (j
= 0; j
< i
|| (j
== i
&& k
); ++j
)
1602 figure_q
= &geometry
->u
.path
.figures
[j
];
1604 if (figure_p
->bounds
.left
> figure_q
->bounds
.right
1605 || figure_q
->bounds
.left
> figure_p
->bounds
.right
1606 || figure_p
->bounds
.top
> figure_q
->bounds
.bottom
1607 || figure_q
->bounds
.top
> figure_p
->bounds
.bottom
)
1610 max_l
= j
== i
? k
- 1 : figure_q
->vertex_count
;
1611 q0
= figure_q
->vertices
[figure_q
->vertex_count
- 1];
1612 for (l
= 0; l
< max_l
; q0
= q1
, ++l
)
1614 q1
= figure_q
->vertices
[l
];
1615 d2d_point_subtract(&v_q
, &q1
, &q0
);
1616 d2d_point_subtract(&v_qp
, &p0
, &q0
);
1618 det
= v_p
.x
* v_q
.y
- v_p
.y
* v_q
.x
;
1622 s
= (v_q
.x
* v_qp
.y
- v_q
.y
* v_qp
.x
) / det
;
1623 t
= (v_p
.x
* v_qp
.y
- v_p
.y
* v_qp
.x
) / det
;
1625 if (s
< 0.0f
|| s
> 1.0f
|| t
< 0.0f
|| t
> 1.0f
)
1628 intersection
.x
= p0
.x
+ v_p
.x
* s
;
1629 intersection
.y
= p0
.y
+ v_p
.y
* s
;
1631 if (t
> 0.0f
&& t
< 1.0f
1632 && !d2d_geometry_intersections_add(&intersections
, j
, l
, t
, intersection
))
1635 if (s
> 0.0f
&& s
< 1.0f
1636 && !d2d_geometry_intersections_add(&intersections
, i
, k
, s
, intersection
))
1643 qsort(intersections
.intersections
, intersections
.intersection_count
,
1644 sizeof(*intersections
.intersections
), d2d_geometry_intersections_compare
);
1645 for (i
= 0; i
< intersections
.intersection_count
; ++i
)
1647 const struct d2d_geometry_intersection
*inter
= &intersections
.intersections
[i
];
1649 if (!i
|| inter
->figure_idx
!= intersections
.intersections
[i
- 1].figure_idx
)
1652 if (!d2d_figure_insert_vertex(&geometry
->u
.path
.figures
[inter
->figure_idx
],
1653 inter
->segment_idx
+ j
, inter
->p
))
1661 HeapFree(GetProcessHeap(), 0, intersections
.intersections
);
1665 static HRESULT
d2d_path_geometry_triangulate(struct d2d_geometry
*geometry
)
1667 struct d2d_cdt_edge_ref left_edge
, right_edge
;
1668 size_t vertex_count
, i
, j
;
1669 struct d2d_cdt cdt
= {0};
1670 D2D1_POINT_2F
*vertices
;
1672 for (i
= 0, vertex_count
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
1674 vertex_count
+= geometry
->u
.path
.figures
[i
].vertex_count
;
1677 if (vertex_count
< 3)
1679 WARN("Geometry has %lu vertices.\n", (long)vertex_count
);
1683 if (!(vertices
= HeapAlloc(GetProcessHeap(), 0, vertex_count
* sizeof(*vertices
))))
1684 return E_OUTOFMEMORY
;
1686 for (i
= 0, j
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
1688 memcpy(&vertices
[j
], geometry
->u
.path
.figures
[i
].vertices
,
1689 geometry
->u
.path
.figures
[i
].vertex_count
* sizeof(*vertices
));
1690 j
+= geometry
->u
.path
.figures
[i
].vertex_count
;
1693 /* Sort vertices, eliminate duplicates. */
1694 qsort(vertices
, vertex_count
, sizeof(*vertices
), d2d_cdt_compare_vertices
);
1695 for (i
= 1; i
< vertex_count
; ++i
)
1697 if (!memcmp(&vertices
[i
- 1], &vertices
[i
], sizeof(*vertices
)))
1700 memmove(&vertices
[i
], &vertices
[i
+ 1], (vertex_count
- i
) * sizeof(*vertices
));
1705 geometry
->fill
.vertices
= vertices
;
1706 geometry
->fill
.vertex_count
= vertex_count
;
1708 cdt
.free_edge
= ~0u;
1709 cdt
.vertices
= vertices
;
1710 if (!d2d_cdt_triangulate(&cdt
, 0, vertex_count
, &left_edge
, &right_edge
))
1712 if (!d2d_cdt_insert_segments(&cdt
, geometry
))
1714 if (!d2d_cdt_generate_faces(&cdt
, geometry
))
1717 HeapFree(GetProcessHeap(), 0, cdt
.edges
);
1721 geometry
->fill
.vertices
= NULL
;
1722 geometry
->fill
.vertex_count
= 0;
1723 HeapFree(GetProcessHeap(), 0, vertices
);
1724 HeapFree(GetProcessHeap(), 0, cdt
.edges
);
1728 static BOOL
d2d_path_geometry_add_figure(struct d2d_geometry
*geometry
)
1730 struct d2d_figure
*figure
;
1732 if (!d2d_array_reserve((void **)&geometry
->u
.path
.figures
, &geometry
->u
.path
.figures_size
,
1733 geometry
->u
.path
.figure_count
+ 1, sizeof(*geometry
->u
.path
.figures
)))
1735 ERR("Failed to grow figures array.\n");
1739 figure
= &geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
];
1740 memset(figure
, 0, sizeof(*figure
));
1741 figure
->bounds
.left
= FLT_MAX
;
1742 figure
->bounds
.top
= FLT_MAX
;
1743 figure
->bounds
.right
= -FLT_MAX
;
1744 figure
->bounds
.bottom
= -FLT_MAX
;
1746 ++geometry
->u
.path
.figure_count
;
1750 static BOOL
d2d_geometry_outline_add_join(struct d2d_geometry
*geometry
,
1751 const D2D1_POINT_2F
*prev
, const D2D1_POINT_2F
*p0
, const D2D1_POINT_2F
*next
)
1753 D2D1_POINT_2F q_prev
, q_next
;
1754 struct d2d_outline_vertex
*v
;
1759 if (!d2d_array_reserve((void **)&geometry
->outline
.vertices
, &geometry
->outline
.vertices_size
,
1760 geometry
->outline
.vertex_count
+ 4, sizeof(*geometry
->outline
.vertices
)))
1762 ERR("Failed to grow outline vertices array.\n");
1765 base_idx
= geometry
->outline
.vertex_count
;
1766 v
= &geometry
->outline
.vertices
[base_idx
];
1768 if (!d2d_array_reserve((void **)&geometry
->outline
.faces
, &geometry
->outline
.faces_size
,
1769 geometry
->outline
.face_count
+ 2, sizeof(*geometry
->outline
.faces
)))
1771 ERR("Failed to grow outline faces array.\n");
1774 f
= &geometry
->outline
.faces
[geometry
->outline
.face_count
];
1776 d2d_point_subtract(&q_prev
, p0
, prev
);
1777 d2d_point_subtract(&q_next
, next
, p0
);
1779 d2d_point_normalise(&q_prev
);
1780 d2d_point_normalise(&q_next
);
1782 ccw
= d2d_point_ccw(p0
, prev
, next
);
1785 d2d_outline_vertex_set(&v
[0], p0
->x
, p0
->y
, q_prev
.x
, q_prev
.y
, q_prev
.x
, q_prev
.y
);
1786 d2d_outline_vertex_set(&v
[1], p0
->x
, p0
->y
, -q_prev
.x
, -q_prev
.y
, -q_prev
.x
, -q_prev
.y
);
1787 d2d_outline_vertex_set(&v
[2], p0
->x
+ 25.0f
* q_prev
.x
, p0
->y
+ 25.0f
* q_prev
.y
,
1788 -q_prev
.x
, -q_prev
.y
, -q_prev
.x
, -q_prev
.y
);
1789 d2d_outline_vertex_set(&v
[3], p0
->x
+ 25.0f
* q_prev
.x
, p0
->y
+ 25.0f
* q_prev
.y
,
1790 q_prev
.x
, q_prev
.y
, q_prev
.x
, q_prev
.y
);
1792 else if (ccw
< 0.0f
)
1794 d2d_outline_vertex_set(&v
[0], p0
->x
, p0
->y
, 0.0f
, 0.0f
, 0.0f
, 0.0f
);
1795 d2d_outline_vertex_set(&v
[1], p0
->x
, p0
->y
, -q_next
.x
, -q_next
.y
, -q_next
.x
, -q_next
.y
);
1796 d2d_outline_vertex_set(&v
[2], p0
->x
, p0
->y
, -q_next
.x
, -q_next
.y
, -q_prev
.x
, -q_prev
.y
);
1797 d2d_outline_vertex_set(&v
[3], p0
->x
, p0
->y
, -q_prev
.x
, -q_prev
.y
, -q_prev
.x
, -q_prev
.y
);
1801 d2d_outline_vertex_set(&v
[0], p0
->x
, p0
->y
, 0.0f
, 0.0f
, 0.0f
, 0.0f
);
1802 d2d_outline_vertex_set(&v
[1], p0
->x
, p0
->y
, q_prev
.x
, q_prev
.y
, q_prev
.x
, q_prev
.y
);
1803 d2d_outline_vertex_set(&v
[2], p0
->x
, p0
->y
, q_prev
.x
, q_prev
.y
, q_next
.x
, q_next
.y
);
1804 d2d_outline_vertex_set(&v
[3], p0
->x
, p0
->y
, q_next
.x
, q_next
.y
, q_next
.x
, q_next
.y
);
1806 geometry
->outline
.vertex_count
+= 4;
1808 d2d_face_set(&f
[0], base_idx
+ 1, base_idx
+ 0, base_idx
+ 2);
1809 d2d_face_set(&f
[1], base_idx
+ 2, base_idx
+ 0, base_idx
+ 3);
1810 geometry
->outline
.face_count
+= 2;
1815 static BOOL
d2d_geometry_outline_add_line_segment(struct d2d_geometry
*geometry
,
1816 const D2D1_POINT_2F
*p0
, const D2D1_POINT_2F
*next
)
1818 struct d2d_outline_vertex
*v
;
1819 D2D1_POINT_2F q_next
;
1823 if (!d2d_array_reserve((void **)&geometry
->outline
.vertices
, &geometry
->outline
.vertices_size
,
1824 geometry
->outline
.vertex_count
+ 4, sizeof(*geometry
->outline
.vertices
)))
1826 ERR("Failed to grow outline vertices array.\n");
1829 base_idx
= geometry
->outline
.vertex_count
;
1830 v
= &geometry
->outline
.vertices
[base_idx
];
1832 if (!d2d_array_reserve((void **)&geometry
->outline
.faces
, &geometry
->outline
.faces_size
,
1833 geometry
->outline
.face_count
+ 2, sizeof(*geometry
->outline
.faces
)))
1835 ERR("Failed to grow outline faces array.\n");
1838 f
= &geometry
->outline
.faces
[geometry
->outline
.face_count
];
1840 d2d_point_subtract(&q_next
, next
, p0
);
1841 d2d_point_normalise(&q_next
);
1843 d2d_outline_vertex_set(&v
[0], p0
->x
, p0
->y
, q_next
.x
, q_next
.y
, q_next
.x
, q_next
.y
);
1844 d2d_outline_vertex_set(&v
[1], p0
->x
, p0
->y
, -q_next
.x
, -q_next
.y
, -q_next
.x
, -q_next
.y
);
1845 d2d_outline_vertex_set(&v
[2], next
->x
, next
->y
, q_next
.x
, q_next
.y
, q_next
.x
, q_next
.y
);
1846 d2d_outline_vertex_set(&v
[3], next
->x
, next
->y
, -q_next
.x
, -q_next
.y
, -q_next
.x
, -q_next
.y
);
1847 geometry
->outline
.vertex_count
+= 4;
1849 d2d_face_set(&f
[0], base_idx
+ 0, base_idx
+ 1, base_idx
+ 2);
1850 d2d_face_set(&f
[1], base_idx
+ 2, base_idx
+ 1, base_idx
+ 3);
1851 geometry
->outline
.face_count
+= 2;
1856 static BOOL
d2d_geometry_outline_add_bezier_segment(struct d2d_geometry
*geometry
,
1857 const D2D1_POINT_2F
*p0
, const D2D1_POINT_2F
*p1
, const D2D1_POINT_2F
*p2
)
1859 struct d2d_bezier_outline_vertex
*b
;
1860 D2D1_POINT_2F r0
, r1
, r2
;
1861 D2D1_POINT_2F q0
, q1
, q2
;
1865 if (!d2d_array_reserve((void **)&geometry
->outline
.beziers
, &geometry
->outline
.beziers_size
,
1866 geometry
->outline
.bezier_count
+ 7, sizeof(*geometry
->outline
.beziers
)))
1868 ERR("Failed to grow outline beziers array.\n");
1871 base_idx
= geometry
->outline
.bezier_count
;
1872 b
= &geometry
->outline
.beziers
[base_idx
];
1874 if (!d2d_array_reserve((void **)&geometry
->outline
.bezier_faces
, &geometry
->outline
.bezier_faces_size
,
1875 geometry
->outline
.bezier_face_count
+ 5, sizeof(*geometry
->outline
.bezier_faces
)))
1877 ERR("Failed to grow outline faces array.\n");
1880 f
= &geometry
->outline
.bezier_faces
[geometry
->outline
.bezier_face_count
];
1882 d2d_point_lerp(&q0
, p0
, p1
, 0.5f
);
1883 d2d_point_lerp(&q1
, p1
, p2
, 0.5f
);
1884 d2d_point_lerp(&q2
, &q0
, &q1
, 0.5f
);
1886 d2d_point_subtract(&r0
, &q0
, p0
);
1887 d2d_point_subtract(&r1
, &q1
, &q0
);
1888 d2d_point_subtract(&r2
, p2
, &q1
);
1890 d2d_point_normalise(&r0
);
1891 d2d_point_normalise(&r1
);
1892 d2d_point_normalise(&r2
);
1894 if (d2d_point_ccw(p0
, p1
, p2
) > 0.0f
)
1896 d2d_point_scale(&r0
, -1.0f
);
1897 d2d_point_scale(&r1
, -1.0f
);
1898 d2d_point_scale(&r2
, -1.0f
);
1901 d2d_bezier_outline_vertex_set(&b
[0], p0
, p0
, p1
, p2
, r0
.x
, r0
.y
, r0
.x
, r0
.y
);
1902 d2d_bezier_outline_vertex_set(&b
[1], p0
, p0
, p1
, p2
, -r0
.x
, -r0
.y
, -r0
.x
, -r0
.y
);
1903 d2d_bezier_outline_vertex_set(&b
[2], &q0
, p0
, p1
, p2
, r0
.x
, r0
.y
, r1
.x
, r1
.y
);
1904 d2d_bezier_outline_vertex_set(&b
[3], &q2
, p0
, p1
, p2
, -r1
.x
, -r1
.y
, -r1
.x
, -r1
.y
);
1905 d2d_bezier_outline_vertex_set(&b
[4], &q1
, p0
, p1
, p2
, r1
.x
, r1
.y
, r2
.x
, r2
.y
);
1906 d2d_bezier_outline_vertex_set(&b
[5], p2
, p0
, p1
, p2
, -r2
.x
, -r2
.y
, -r2
.x
, -r2
.y
);
1907 d2d_bezier_outline_vertex_set(&b
[6], p2
, p0
, p1
, p2
, r2
.x
, r2
.y
, r2
.x
, r2
.y
);
1908 geometry
->outline
.bezier_count
+= 7;
1910 d2d_face_set(&f
[0], base_idx
+ 0, base_idx
+ 1, base_idx
+ 2);
1911 d2d_face_set(&f
[1], base_idx
+ 2, base_idx
+ 1, base_idx
+ 3);
1912 d2d_face_set(&f
[2], base_idx
+ 3, base_idx
+ 4, base_idx
+ 2);
1913 d2d_face_set(&f
[3], base_idx
+ 5, base_idx
+ 4, base_idx
+ 3);
1914 d2d_face_set(&f
[4], base_idx
+ 5, base_idx
+ 6, base_idx
+ 4);
1915 geometry
->outline
.bezier_face_count
+= 5;
1920 static BOOL
d2d_geometry_add_figure_outline(struct d2d_geometry
*geometry
,
1921 struct d2d_figure
*figure
, D2D1_FIGURE_END figure_end
)
1923 const D2D1_POINT_2F
*prev
, *p0
, *next
;
1924 enum d2d_vertex_type prev_type
, type
;
1925 size_t bezier_idx
, i
;
1927 for (i
= 0, bezier_idx
= 0; i
< figure
->vertex_count
; ++i
)
1929 type
= figure
->vertex_types
[i
];
1930 if (type
== D2D_VERTEX_TYPE_NONE
)
1933 p0
= &figure
->vertices
[i
];
1937 prev_type
= figure
->vertex_types
[figure
->vertex_count
- 1];
1938 if (prev_type
== D2D_VERTEX_TYPE_BEZIER
)
1939 prev
= &figure
->bezier_controls
[figure
->bezier_control_count
- 1];
1941 prev
= &figure
->vertices
[figure
->vertex_count
- 1];
1945 prev_type
= figure
->vertex_types
[i
- 1];
1946 if (prev_type
== D2D_VERTEX_TYPE_BEZIER
)
1947 prev
= &figure
->bezier_controls
[bezier_idx
- 1];
1949 prev
= &figure
->vertices
[i
- 1];
1952 if (type
== D2D_VERTEX_TYPE_BEZIER
)
1953 next
= &figure
->bezier_controls
[bezier_idx
++];
1954 else if (i
== figure
->vertex_count
- 1)
1955 next
= &figure
->vertices
[0];
1957 next
= &figure
->vertices
[i
+ 1];
1959 if ((figure_end
== D2D1_FIGURE_END_CLOSED
|| (i
&& i
< figure
->vertex_count
- 1))
1960 && !d2d_geometry_outline_add_join(geometry
, prev
, p0
, next
))
1962 ERR("Failed to add join.\n");
1966 if (type
== D2D_VERTEX_TYPE_LINE
&& (figure_end
== D2D1_FIGURE_END_CLOSED
|| i
< figure
->vertex_count
- 1)
1967 && !d2d_geometry_outline_add_line_segment(geometry
, p0
, next
))
1969 ERR("Failed to add line segment.\n");
1972 else if (type
== D2D_VERTEX_TYPE_BEZIER
)
1974 const D2D1_POINT_2F
*p2
;
1976 if (i
== figure
->vertex_count
- 1)
1977 p2
= &figure
->vertices
[0];
1979 p2
= &figure
->vertices
[i
+ 1];
1981 if (!d2d_geometry_outline_add_bezier_segment(geometry
, p0
, next
, p2
))
1983 ERR("Failed to add bezier segment.\n");
1992 static void d2d_geometry_cleanup(struct d2d_geometry
*geometry
)
1994 HeapFree(GetProcessHeap(), 0, geometry
->outline
.bezier_faces
);
1995 HeapFree(GetProcessHeap(), 0, geometry
->outline
.beziers
);
1996 HeapFree(GetProcessHeap(), 0, geometry
->outline
.faces
);
1997 HeapFree(GetProcessHeap(), 0, geometry
->outline
.vertices
);
1998 HeapFree(GetProcessHeap(), 0, geometry
->fill
.bezier_vertices
);
1999 HeapFree(GetProcessHeap(), 0, geometry
->fill
.faces
);
2000 HeapFree(GetProcessHeap(), 0, geometry
->fill
.vertices
);
2001 ID2D1Factory_Release(geometry
->factory
);
2004 static void d2d_geometry_init(struct d2d_geometry
*geometry
, ID2D1Factory
*factory
,
2005 const D2D1_MATRIX_3X2_F
*transform
, const struct ID2D1GeometryVtbl
*vtbl
)
2007 geometry
->ID2D1Geometry_iface
.lpVtbl
= vtbl
;
2008 geometry
->refcount
= 1;
2009 ID2D1Factory_AddRef(geometry
->factory
= factory
);
2010 geometry
->transform
= *transform
;
2013 static inline struct d2d_geometry
*impl_from_ID2D1GeometrySink(ID2D1GeometrySink
*iface
)
2015 return CONTAINING_RECORD(iface
, struct d2d_geometry
, u
.path
.ID2D1GeometrySink_iface
);
2018 static HRESULT STDMETHODCALLTYPE
d2d_geometry_sink_QueryInterface(ID2D1GeometrySink
*iface
, REFIID iid
, void **out
)
2020 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
2022 if (IsEqualGUID(iid
, &IID_ID2D1GeometrySink
)
2023 || IsEqualGUID(iid
, &IID_ID2D1SimplifiedGeometrySink
)
2024 || IsEqualGUID(iid
, &IID_IUnknown
))
2026 ID2D1GeometrySink_AddRef(iface
);
2031 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
2034 return E_NOINTERFACE
;
2037 static ULONG STDMETHODCALLTYPE
d2d_geometry_sink_AddRef(ID2D1GeometrySink
*iface
)
2039 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
2041 TRACE("iface %p.\n", iface
);
2043 return ID2D1Geometry_AddRef(&geometry
->ID2D1Geometry_iface
);
2046 static ULONG STDMETHODCALLTYPE
d2d_geometry_sink_Release(ID2D1GeometrySink
*iface
)
2048 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
2050 TRACE("iface %p.\n", iface
);
2052 return ID2D1Geometry_Release(&geometry
->ID2D1Geometry_iface
);
2055 static void STDMETHODCALLTYPE
d2d_geometry_sink_SetFillMode(ID2D1GeometrySink
*iface
, D2D1_FILL_MODE mode
)
2057 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
2059 TRACE("iface %p, mode %#x.\n", iface
, mode
);
2061 if (geometry
->u
.path
.state
== D2D_GEOMETRY_STATE_CLOSED
)
2063 geometry
->u
.path
.fill_mode
= mode
;
2066 static void STDMETHODCALLTYPE
d2d_geometry_sink_SetSegmentFlags(ID2D1GeometrySink
*iface
, D2D1_PATH_SEGMENT flags
)
2068 FIXME("iface %p, flags %#x stub!\n", iface
, flags
);
2071 static void STDMETHODCALLTYPE
d2d_geometry_sink_BeginFigure(ID2D1GeometrySink
*iface
,
2072 D2D1_POINT_2F start_point
, D2D1_FIGURE_BEGIN figure_begin
)
2074 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
2075 struct d2d_figure
*figure
;
2077 TRACE("iface %p, start_point {%.8e, %.8e}, figure_begin %#x.\n",
2078 iface
, start_point
.x
, start_point
.y
, figure_begin
);
2080 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_OPEN
)
2082 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2086 if (figure_begin
!= D2D1_FIGURE_BEGIN_FILLED
)
2087 FIXME("Ignoring figure_begin %#x.\n", figure_begin
);
2089 if (!d2d_path_geometry_add_figure(geometry
))
2091 ERR("Failed to add figure.\n");
2092 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2096 figure
= &geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
- 1];
2097 if (figure_begin
== D2D1_FIGURE_BEGIN_HOLLOW
)
2098 figure
->flags
|= D2D_FIGURE_FLAG_HOLLOW
;
2100 if (!d2d_figure_add_vertex(figure
, start_point
))
2102 ERR("Failed to add vertex.\n");
2103 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2107 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_FIGURE
;
2110 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddLines(ID2D1GeometrySink
*iface
,
2111 const D2D1_POINT_2F
*points
, UINT32 count
)
2113 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
2114 struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
- 1];
2117 TRACE("iface %p, points %p, count %u.\n", iface
, points
, count
);
2119 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_FIGURE
)
2121 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2125 for (i
= 0; i
< count
; ++i
)
2127 figure
->vertex_types
[figure
->vertex_count
- 1] = D2D_VERTEX_TYPE_LINE
;
2128 if (!d2d_figure_add_vertex(figure
, points
[i
]))
2130 ERR("Failed to add vertex.\n");
2135 geometry
->u
.path
.segment_count
+= count
;
2138 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddBeziers(ID2D1GeometrySink
*iface
,
2139 const D2D1_BEZIER_SEGMENT
*beziers
, UINT32 count
)
2141 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
2142 struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
- 1];
2146 TRACE("iface %p, beziers %p, count %u.\n", iface
, beziers
, count
);
2148 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_FIGURE
)
2150 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2154 for (i
= 0; i
< count
; ++i
)
2156 /* FIXME: This tries to approximate a cubic bezier with a quadratic one. */
2157 p
.x
= (beziers
[i
].point1
.x
+ beziers
[i
].point2
.x
) * 0.75f
;
2158 p
.y
= (beziers
[i
].point1
.y
+ beziers
[i
].point2
.y
) * 0.75f
;
2159 p
.x
-= (figure
->vertices
[figure
->vertex_count
- 1].x
+ beziers
[i
].point3
.x
) * 0.25f
;
2160 p
.y
-= (figure
->vertices
[figure
->vertex_count
- 1].y
+ beziers
[i
].point3
.y
) * 0.25f
;
2161 figure
->vertex_types
[figure
->vertex_count
- 1] = D2D_VERTEX_TYPE_BEZIER
;
2163 if (!d2d_figure_add_bezier_control(figure
, &p
))
2165 ERR("Failed to add bezier control.\n");
2166 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2170 if (!d2d_figure_add_vertex(figure
, beziers
[i
].point3
))
2172 ERR("Failed to add bezier vertex.\n");
2173 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2178 geometry
->u
.path
.segment_count
+= count
;
2181 static void STDMETHODCALLTYPE
d2d_geometry_sink_EndFigure(ID2D1GeometrySink
*iface
, D2D1_FIGURE_END figure_end
)
2183 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
2184 struct d2d_figure
*figure
;
2186 TRACE("iface %p, figure_end %#x.\n", iface
, figure_end
);
2188 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_FIGURE
)
2190 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2194 figure
= &geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
- 1];
2195 figure
->vertex_types
[figure
->vertex_count
- 1] = D2D_VERTEX_TYPE_LINE
;
2196 if (figure_end
== D2D1_FIGURE_END_CLOSED
)
2198 ++geometry
->u
.path
.segment_count
;
2199 figure
->flags
|= D2D_FIGURE_FLAG_CLOSED
;
2200 if (!memcmp(&figure
->vertices
[0], &figure
->vertices
[figure
->vertex_count
- 1], sizeof(*figure
->vertices
)))
2201 --figure
->vertex_count
;
2204 if (!d2d_geometry_add_figure_outline(geometry
, figure
, figure_end
))
2206 ERR("Failed to add figure outline.\n");
2207 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2211 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_OPEN
;
2214 static void d2d_path_geometry_free_figures(struct d2d_geometry
*geometry
)
2218 if (!geometry
->u
.path
.figures
)
2221 for (i
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
2223 HeapFree(GetProcessHeap(), 0, geometry
->u
.path
.figures
[i
].bezier_controls
);
2224 HeapFree(GetProcessHeap(), 0, geometry
->u
.path
.figures
[i
].vertices
);
2226 HeapFree(GetProcessHeap(), 0, geometry
->u
.path
.figures
);
2227 geometry
->u
.path
.figures
= NULL
;
2228 geometry
->u
.path
.figures_size
= 0;
2231 static HRESULT
d2d_geometry_resolve_beziers(struct d2d_geometry
*geometry
)
2233 size_t bezier_idx
, control_idx
, i
, j
;
2235 for (i
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
2237 geometry
->fill
.bezier_vertex_count
+= 3 * geometry
->u
.path
.figures
[i
].bezier_control_count
;
2240 if (!(geometry
->fill
.bezier_vertices
= HeapAlloc(GetProcessHeap(), 0,
2241 geometry
->fill
.bezier_vertex_count
* sizeof(*geometry
->fill
.bezier_vertices
))))
2243 ERR("Failed to allocate bezier vertices array.\n");
2244 geometry
->fill
.bezier_vertex_count
= 0;
2245 return E_OUTOFMEMORY
;
2248 for (i
= 0, bezier_idx
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
2250 struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[i
];
2251 if (figure
->bezier_control_count
)
2253 for (j
= 0, control_idx
= 0; j
< figure
->vertex_count
; ++j
)
2255 const D2D1_POINT_2F
*p0
, *p1
, *p2
;
2256 struct d2d_bezier_vertex
*b
;
2259 if (figure
->vertex_types
[j
] != D2D_VERTEX_TYPE_BEZIER
)
2262 b
= &geometry
->fill
.bezier_vertices
[bezier_idx
* 3];
2263 p0
= &figure
->vertices
[j
];
2264 p1
= &figure
->bezier_controls
[control_idx
++];
2266 if (d2d_path_geometry_point_inside(geometry
, p1
, FALSE
))
2269 d2d_figure_insert_vertex(figure
, j
+ 1, *p1
);
2270 /* Inserting a vertex potentially invalidates p0. */
2271 p0
= &figure
->vertices
[j
];
2275 if (j
== figure
->vertex_count
- 1)
2276 p2
= &figure
->vertices
[0];
2278 p2
= &figure
->vertices
[j
+ 1];
2280 d2d_bezier_vertex_set(&b
[0], p0
, 0.0f
, 0.0f
, sign
);
2281 d2d_bezier_vertex_set(&b
[1], p1
, 0.5f
, 0.0f
, sign
);
2282 d2d_bezier_vertex_set(&b
[2], p2
, 1.0f
, 1.0f
, sign
);
2291 static HRESULT STDMETHODCALLTYPE
d2d_geometry_sink_Close(ID2D1GeometrySink
*iface
)
2293 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
2294 HRESULT hr
= E_FAIL
;
2296 TRACE("iface %p.\n", iface
);
2298 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_OPEN
)
2300 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_CLOSED
)
2301 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2302 return D2DERR_WRONG_STATE
;
2304 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_CLOSED
;
2306 if (!d2d_geometry_intersect_self(geometry
))
2308 if (FAILED(hr
= d2d_geometry_resolve_beziers(geometry
)))
2310 if (FAILED(hr
= d2d_path_geometry_triangulate(geometry
)))
2316 HeapFree(GetProcessHeap(), 0, geometry
->fill
.bezier_vertices
);
2317 geometry
->fill
.bezier_vertex_count
= 0;
2318 d2d_path_geometry_free_figures(geometry
);
2319 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2324 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddLine(ID2D1GeometrySink
*iface
, D2D1_POINT_2F point
)
2326 TRACE("iface %p, point {%.8e, %.8e}.\n", iface
, point
.x
, point
.y
);
2328 d2d_geometry_sink_AddLines(iface
, &point
, 1);
2331 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddBezier(ID2D1GeometrySink
*iface
, const D2D1_BEZIER_SEGMENT
*bezier
)
2333 TRACE("iface %p, bezier %p.\n", iface
, bezier
);
2335 d2d_geometry_sink_AddBeziers(iface
, bezier
, 1);
2338 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddQuadraticBezier(ID2D1GeometrySink
*iface
,
2339 const D2D1_QUADRATIC_BEZIER_SEGMENT
*bezier
)
2341 TRACE("iface %p, bezier %p.\n", iface
, bezier
);
2343 ID2D1GeometrySink_AddQuadraticBeziers(iface
, bezier
, 1);
2346 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddQuadraticBeziers(ID2D1GeometrySink
*iface
,
2347 const D2D1_QUADRATIC_BEZIER_SEGMENT
*beziers
, UINT32 bezier_count
)
2349 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
2350 struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
- 1];
2353 TRACE("iface %p, beziers %p, bezier_count %u.\n", iface
, beziers
, bezier_count
);
2355 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_FIGURE
)
2357 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2361 for (i
= 0; i
< bezier_count
; ++i
)
2363 figure
->vertex_types
[figure
->vertex_count
- 1] = D2D_VERTEX_TYPE_BEZIER
;
2364 if (!d2d_figure_add_bezier_control(figure
, &beziers
[i
].point1
))
2366 ERR("Failed to add bezier.\n");
2367 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2371 if (!d2d_figure_add_vertex(figure
, beziers
[i
].point2
))
2373 ERR("Failed to add bezier vertex.\n");
2374 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2379 geometry
->u
.path
.segment_count
+= bezier_count
;
2382 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddArc(ID2D1GeometrySink
*iface
, const D2D1_ARC_SEGMENT
*arc
)
2384 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
2386 FIXME("iface %p, arc %p stub!\n", iface
, arc
);
2388 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_FIGURE
)
2390 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2394 if (!d2d_figure_add_vertex(&geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
- 1], arc
->point
))
2396 ERR("Failed to add vertex.\n");
2400 ++geometry
->u
.path
.segment_count
;
2403 static const struct ID2D1GeometrySinkVtbl d2d_geometry_sink_vtbl
=
2405 d2d_geometry_sink_QueryInterface
,
2406 d2d_geometry_sink_AddRef
,
2407 d2d_geometry_sink_Release
,
2408 d2d_geometry_sink_SetFillMode
,
2409 d2d_geometry_sink_SetSegmentFlags
,
2410 d2d_geometry_sink_BeginFigure
,
2411 d2d_geometry_sink_AddLines
,
2412 d2d_geometry_sink_AddBeziers
,
2413 d2d_geometry_sink_EndFigure
,
2414 d2d_geometry_sink_Close
,
2415 d2d_geometry_sink_AddLine
,
2416 d2d_geometry_sink_AddBezier
,
2417 d2d_geometry_sink_AddQuadraticBezier
,
2418 d2d_geometry_sink_AddQuadraticBeziers
,
2419 d2d_geometry_sink_AddArc
,
2422 static inline struct d2d_geometry
*impl_from_ID2D1PathGeometry(ID2D1PathGeometry
*iface
)
2424 return CONTAINING_RECORD(iface
, struct d2d_geometry
, ID2D1Geometry_iface
);
2427 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_QueryInterface(ID2D1PathGeometry
*iface
, REFIID iid
, void **out
)
2429 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
2431 if (IsEqualGUID(iid
, &IID_ID2D1PathGeometry
)
2432 || IsEqualGUID(iid
, &IID_ID2D1Geometry
)
2433 || IsEqualGUID(iid
, &IID_ID2D1Resource
)
2434 || IsEqualGUID(iid
, &IID_IUnknown
))
2436 ID2D1PathGeometry_AddRef(iface
);
2441 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
2444 return E_NOINTERFACE
;
2447 static ULONG STDMETHODCALLTYPE
d2d_path_geometry_AddRef(ID2D1PathGeometry
*iface
)
2449 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
2450 ULONG refcount
= InterlockedIncrement(&geometry
->refcount
);
2452 TRACE("%p increasing refcount to %u.\n", iface
, refcount
);
2457 static ULONG STDMETHODCALLTYPE
d2d_path_geometry_Release(ID2D1PathGeometry
*iface
)
2459 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
2460 ULONG refcount
= InterlockedDecrement(&geometry
->refcount
);
2462 TRACE("%p decreasing refcount to %u.\n", iface
, refcount
);
2466 d2d_path_geometry_free_figures(geometry
);
2467 d2d_geometry_cleanup(geometry
);
2468 HeapFree(GetProcessHeap(), 0, geometry
);
2474 static void STDMETHODCALLTYPE
d2d_path_geometry_GetFactory(ID2D1PathGeometry
*iface
, ID2D1Factory
**factory
)
2476 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
2478 TRACE("iface %p, factory %p.\n", iface
, factory
);
2480 ID2D1Factory_AddRef(*factory
= geometry
->factory
);
2483 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_GetBounds(ID2D1PathGeometry
*iface
,
2484 const D2D1_MATRIX_3X2_F
*transform
, D2D1_RECT_F
*bounds
)
2486 FIXME("iface %p, transform %p, bounds %p stub!\n", iface
, transform
, bounds
);
2491 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_GetWidenedBounds(ID2D1PathGeometry
*iface
, float stroke_width
,
2492 ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_RECT_F
*bounds
)
2494 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
2495 iface
, stroke_width
, stroke_style
, transform
, tolerance
, bounds
);
2500 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_StrokeContainsPoint(ID2D1PathGeometry
*iface
,
2501 D2D1_POINT_2F point
, float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
2502 float tolerance
, BOOL
*contains
)
2504 FIXME("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
2505 "transform %p, tolerance %.8e, contains %p stub!\n",
2506 iface
, point
.x
, point
.y
, stroke_width
, stroke_style
, transform
, tolerance
, contains
);
2511 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_FillContainsPoint(ID2D1PathGeometry
*iface
,
2512 D2D1_POINT_2F point
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, BOOL
*contains
)
2514 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
2515 D2D1_MATRIX_3X2_F g_i
;
2517 TRACE("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p.\n",
2518 iface
, point
.x
, point
.y
, transform
, tolerance
, contains
);
2522 if (!d2d_matrix_invert(&g_i
, transform
))
2523 return D2DERR_UNSUPPORTED_OPERATION
;
2524 d2d_point_transform(&point
, &g_i
, point
.x
, point
.y
);
2527 *contains
= !!d2d_path_geometry_point_inside(geometry
, &point
, FALSE
);
2529 TRACE("-> %#x.\n", *contains
);
2534 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_CompareWithGeometry(ID2D1PathGeometry
*iface
,
2535 ID2D1Geometry
*geometry
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_GEOMETRY_RELATION
*relation
)
2537 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
2538 iface
, geometry
, transform
, tolerance
, relation
);
2543 static void d2d_geometry_flatten_cubic(ID2D1SimplifiedGeometrySink
*sink
, const D2D1_POINT_2F
*p0
,
2544 const D2D1_BEZIER_SEGMENT
*b
, float tolerance
)
2546 D2D1_BEZIER_SEGMENT b0
, b1
;
2550 /* It's certainly possible to calculate the maximum deviation of the
2551 * approximation from the curve, but it's a little involved. Instead, note
2552 * that if the control points were evenly spaced and collinear, p1 would
2553 * be exactly between p0 and p2, and p2 would be exactly between p1 and
2554 * p3. The deviation is a decent enough approximation, and much easier to
2557 * p1' = (p0 + p2) / 2
2558 * p2' = (p1 + p3) / 2
2559 * d = ‖p1 - p1'‖₁ + ‖p2 - p2'‖₁ */
2560 d2d_point_lerp(&q
, p0
, &b
->point2
, 0.5f
);
2561 d2d_point_subtract(&q
, &b
->point1
, &q
);
2562 d
= fabsf(q
.x
) + fabsf(q
.y
);
2563 d2d_point_lerp(&q
, &b
->point1
, &b
->point3
, 0.5f
);
2564 d2d_point_subtract(&q
, &b
->point2
, &q
);
2565 d
+= fabsf(q
.x
) + fabsf(q
.y
);
2568 ID2D1SimplifiedGeometrySink_AddLines(sink
, &b
->point3
, 1);
2572 d2d_point_lerp(&q
, &b
->point1
, &b
->point2
, 0.5f
);
2574 b1
.point3
= b
->point3
;
2575 d2d_point_lerp(&b1
.point2
, &b1
.point3
, &b
->point2
, 0.5f
);
2576 d2d_point_lerp(&b1
.point1
, &b1
.point2
, &q
, 0.5f
);
2578 d2d_point_lerp(&b0
.point1
, p0
, &b
->point1
, 0.5f
);
2579 d2d_point_lerp(&b0
.point2
, &b0
.point1
, &q
, 0.5f
);
2580 d2d_point_lerp(&b0
.point3
, &b0
.point2
, &b1
.point1
, 0.5f
);
2582 d2d_geometry_flatten_cubic(sink
, p0
, &b0
, tolerance
);
2583 ID2D1SimplifiedGeometrySink_SetSegmentFlags(sink
, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN
);
2584 d2d_geometry_flatten_cubic(sink
, &b0
.point3
, &b1
, tolerance
);
2585 ID2D1SimplifiedGeometrySink_SetSegmentFlags(sink
, D2D1_PATH_SEGMENT_NONE
);
2588 static void d2d_geometry_simplify_quadratic(ID2D1SimplifiedGeometrySink
*sink
,
2589 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option
, const D2D1_POINT_2F
*p0
,
2590 const D2D1_POINT_2F
*p1
, const D2D1_POINT_2F
*p2
, float tolerance
)
2592 D2D1_BEZIER_SEGMENT b
;
2594 d2d_point_lerp(&b
.point1
, p0
, p1
, 2.0f
/ 3.0f
);
2595 d2d_point_lerp(&b
.point2
, p2
, p1
, 2.0f
/ 3.0f
);
2598 if (option
== D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES
)
2599 d2d_geometry_flatten_cubic(sink
, p0
, &b
, tolerance
);
2601 ID2D1SimplifiedGeometrySink_AddBeziers(sink
, &b
, 1);
2604 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Simplify(ID2D1PathGeometry
*iface
,
2605 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
2606 ID2D1SimplifiedGeometrySink
*sink
)
2608 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
2609 enum d2d_vertex_type type
= D2D_VERTEX_TYPE_NONE
;
2610 unsigned int i
, j
, bezier_idx
;
2611 D2D1_FIGURE_BEGIN begin
;
2612 D2D1_POINT_2F p
, p1
, p2
;
2613 D2D1_FIGURE_END end
;
2615 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
2616 iface
, option
, transform
, tolerance
, sink
);
2618 ID2D1SimplifiedGeometrySink_SetFillMode(sink
, geometry
->u
.path
.fill_mode
);
2619 for (i
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
2621 const struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[i
];
2623 for (j
= 0; j
< figure
->vertex_count
; ++j
)
2625 if (figure
->vertex_types
[j
] == D2D_VERTEX_TYPE_NONE
)
2628 p
= figure
->vertices
[j
];
2630 d2d_point_transform(&p
, transform
, p
.x
, p
.y
);
2631 begin
= figure
->flags
& D2D_FIGURE_FLAG_HOLLOW
? D2D1_FIGURE_BEGIN_HOLLOW
: D2D1_FIGURE_BEGIN_FILLED
;
2632 ID2D1SimplifiedGeometrySink_BeginFigure(sink
, p
, begin
);
2633 type
= figure
->vertex_types
[j
];
2637 for (bezier_idx
= 0, ++j
; j
< figure
->vertex_count
; ++j
)
2639 if (figure
->vertex_types
[j
] == D2D_VERTEX_TYPE_NONE
)
2644 case D2D_VERTEX_TYPE_LINE
:
2645 p
= figure
->vertices
[j
];
2647 d2d_point_transform(&p
, transform
, p
.x
, p
.y
);
2648 ID2D1SimplifiedGeometrySink_AddLines(sink
, &p
, 1);
2651 case D2D_VERTEX_TYPE_BEZIER
:
2652 p1
= figure
->bezier_controls
[bezier_idx
++];
2654 d2d_point_transform(&p1
, transform
, p1
.x
, p1
.y
);
2655 p2
= figure
->vertices
[j
];
2657 d2d_point_transform(&p2
, transform
, p2
.x
, p2
.y
);
2658 d2d_geometry_simplify_quadratic(sink
, option
, &p
, &p1
, &p2
, tolerance
);
2663 FIXME("Unhandled vertex type %#x.\n", type
);
2664 p
= figure
->vertices
[j
];
2666 d2d_point_transform(&p
, transform
, p
.x
, p
.y
);
2667 ID2D1SimplifiedGeometrySink_AddLines(sink
, &p
, 1);
2671 type
= figure
->vertex_types
[j
];
2674 if (type
== D2D_VERTEX_TYPE_BEZIER
)
2676 p1
= figure
->bezier_controls
[bezier_idx
++];
2678 d2d_point_transform(&p1
, transform
, p1
.x
, p1
.y
);
2679 p2
= figure
->vertices
[0];
2681 d2d_point_transform(&p2
, transform
, p2
.x
, p2
.y
);
2682 d2d_geometry_simplify_quadratic(sink
, option
, &p
, &p1
, &p2
, tolerance
);
2685 end
= figure
->flags
& D2D_FIGURE_FLAG_CLOSED
? D2D1_FIGURE_END_CLOSED
: D2D1_FIGURE_END_OPEN
;
2686 ID2D1SimplifiedGeometrySink_EndFigure(sink
, end
);
2692 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Tessellate(ID2D1PathGeometry
*iface
,
2693 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1TessellationSink
*sink
)
2695 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
2700 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_CombineWithGeometry(ID2D1PathGeometry
*iface
,
2701 ID2D1Geometry
*geometry
, D2D1_COMBINE_MODE combine_mode
, const D2D1_MATRIX_3X2_F
*transform
,
2702 float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
2704 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2705 iface
, geometry
, combine_mode
, transform
, tolerance
, sink
);
2710 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Outline(ID2D1PathGeometry
*iface
,
2711 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
2713 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
2718 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_ComputeArea(ID2D1PathGeometry
*iface
,
2719 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *area
)
2721 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface
, transform
, tolerance
, area
);
2726 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_ComputeLength(ID2D1PathGeometry
*iface
,
2727 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *length
)
2729 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface
, transform
, tolerance
, length
);
2734 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_ComputePointAtLength(ID2D1PathGeometry
*iface
, float length
,
2735 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_POINT_2F
*point
, D2D1_POINT_2F
*tangent
)
2737 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
2738 iface
, length
, transform
, tolerance
, point
, tangent
);
2743 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Widen(ID2D1PathGeometry
*iface
, float stroke_width
,
2744 ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
2745 ID2D1SimplifiedGeometrySink
*sink
)
2747 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
2748 iface
, stroke_width
, stroke_style
, transform
, tolerance
, sink
);
2753 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Open(ID2D1PathGeometry
*iface
, ID2D1GeometrySink
**sink
)
2755 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
2757 TRACE("iface %p, sink %p.\n", iface
, sink
);
2759 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_INITIAL
)
2760 return D2DERR_WRONG_STATE
;
2762 *sink
= &geometry
->u
.path
.ID2D1GeometrySink_iface
;
2763 ID2D1GeometrySink_AddRef(*sink
);
2765 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_OPEN
;
2770 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Stream(ID2D1PathGeometry
*iface
, ID2D1GeometrySink
*sink
)
2772 FIXME("iface %p, sink %p stub!\n", iface
, sink
);
2777 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_GetSegmentCount(ID2D1PathGeometry
*iface
, UINT32
*count
)
2779 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
2781 TRACE("iface %p, count %p.\n", iface
, count
);
2783 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_CLOSED
)
2784 return D2DERR_WRONG_STATE
;
2786 *count
= geometry
->u
.path
.segment_count
;
2791 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_GetFigureCount(ID2D1PathGeometry
*iface
, UINT32
*count
)
2793 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
2795 TRACE("iface %p, count %p.\n", iface
, count
);
2797 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_CLOSED
)
2798 return D2DERR_WRONG_STATE
;
2800 *count
= geometry
->u
.path
.figure_count
;
2805 static const struct ID2D1PathGeometryVtbl d2d_path_geometry_vtbl
=
2807 d2d_path_geometry_QueryInterface
,
2808 d2d_path_geometry_AddRef
,
2809 d2d_path_geometry_Release
,
2810 d2d_path_geometry_GetFactory
,
2811 d2d_path_geometry_GetBounds
,
2812 d2d_path_geometry_GetWidenedBounds
,
2813 d2d_path_geometry_StrokeContainsPoint
,
2814 d2d_path_geometry_FillContainsPoint
,
2815 d2d_path_geometry_CompareWithGeometry
,
2816 d2d_path_geometry_Simplify
,
2817 d2d_path_geometry_Tessellate
,
2818 d2d_path_geometry_CombineWithGeometry
,
2819 d2d_path_geometry_Outline
,
2820 d2d_path_geometry_ComputeArea
,
2821 d2d_path_geometry_ComputeLength
,
2822 d2d_path_geometry_ComputePointAtLength
,
2823 d2d_path_geometry_Widen
,
2824 d2d_path_geometry_Open
,
2825 d2d_path_geometry_Stream
,
2826 d2d_path_geometry_GetSegmentCount
,
2827 d2d_path_geometry_GetFigureCount
,
2830 void d2d_path_geometry_init(struct d2d_geometry
*geometry
, ID2D1Factory
*factory
)
2832 d2d_geometry_init(geometry
, factory
, &identity
, (ID2D1GeometryVtbl
*)&d2d_path_geometry_vtbl
);
2833 geometry
->u
.path
.ID2D1GeometrySink_iface
.lpVtbl
= &d2d_geometry_sink_vtbl
;
2836 static inline struct d2d_geometry
*impl_from_ID2D1RectangleGeometry(ID2D1RectangleGeometry
*iface
)
2838 return CONTAINING_RECORD(iface
, struct d2d_geometry
, ID2D1Geometry_iface
);
2841 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_QueryInterface(ID2D1RectangleGeometry
*iface
,
2842 REFIID iid
, void **out
)
2844 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
2846 if (IsEqualGUID(iid
, &IID_ID2D1RectangleGeometry
)
2847 || IsEqualGUID(iid
, &IID_ID2D1Geometry
)
2848 || IsEqualGUID(iid
, &IID_ID2D1Resource
)
2849 || IsEqualGUID(iid
, &IID_IUnknown
))
2851 ID2D1RectangleGeometry_AddRef(iface
);
2856 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
2859 return E_NOINTERFACE
;
2862 static ULONG STDMETHODCALLTYPE
d2d_rectangle_geometry_AddRef(ID2D1RectangleGeometry
*iface
)
2864 struct d2d_geometry
*geometry
= impl_from_ID2D1RectangleGeometry(iface
);
2865 ULONG refcount
= InterlockedIncrement(&geometry
->refcount
);
2867 TRACE("%p increasing refcount to %u.\n", iface
, refcount
);
2872 static ULONG STDMETHODCALLTYPE
d2d_rectangle_geometry_Release(ID2D1RectangleGeometry
*iface
)
2874 struct d2d_geometry
*geometry
= impl_from_ID2D1RectangleGeometry(iface
);
2875 ULONG refcount
= InterlockedDecrement(&geometry
->refcount
);
2877 TRACE("%p decreasing refcount to %u.\n", iface
, refcount
);
2881 d2d_geometry_cleanup(geometry
);
2882 HeapFree(GetProcessHeap(), 0, geometry
);
2888 static void STDMETHODCALLTYPE
d2d_rectangle_geometry_GetFactory(ID2D1RectangleGeometry
*iface
, ID2D1Factory
**factory
)
2890 struct d2d_geometry
*geometry
= impl_from_ID2D1RectangleGeometry(iface
);
2892 TRACE("iface %p, factory %p.\n", iface
, factory
);
2894 ID2D1Factory_AddRef(*factory
= geometry
->factory
);
2897 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_GetBounds(ID2D1RectangleGeometry
*iface
,
2898 const D2D1_MATRIX_3X2_F
*transform
, D2D1_RECT_F
*bounds
)
2900 struct d2d_geometry
*geometry
= impl_from_ID2D1RectangleGeometry(iface
);
2904 TRACE("iface %p, transform %p, bounds %p.\n", iface
, transform
, bounds
);
2906 rect
= &geometry
->u
.rectangle
.rect
;
2913 bounds
->left
= FLT_MAX
;
2914 bounds
->top
= FLT_MAX
;
2915 bounds
->right
= -FLT_MAX
;
2916 bounds
->bottom
= -FLT_MAX
;
2918 d2d_point_transform(&p
, transform
, rect
->left
, rect
->top
);
2919 d2d_rect_expand(bounds
, &p
);
2920 d2d_point_transform(&p
, transform
, rect
->left
, rect
->bottom
);
2921 d2d_rect_expand(bounds
, &p
);
2922 d2d_point_transform(&p
, transform
, rect
->right
, rect
->bottom
);
2923 d2d_rect_expand(bounds
, &p
);
2924 d2d_point_transform(&p
, transform
, rect
->right
, rect
->top
);
2925 d2d_rect_expand(bounds
, &p
);
2930 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_GetWidenedBounds(ID2D1RectangleGeometry
*iface
,
2931 float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
2932 float tolerance
, D2D1_RECT_F
*bounds
)
2934 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
2935 iface
, stroke_width
, stroke_style
, transform
, tolerance
, bounds
);
2940 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_StrokeContainsPoint(ID2D1RectangleGeometry
*iface
,
2941 D2D1_POINT_2F point
, float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
2942 float tolerance
, BOOL
*contains
)
2944 FIXME("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
2945 "transform %p, tolerance %.8e, contains %p stub!\n",
2946 iface
, point
.x
, point
.y
, stroke_width
, stroke_style
, transform
, tolerance
, contains
);
2951 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_FillContainsPoint(ID2D1RectangleGeometry
*iface
,
2952 D2D1_POINT_2F point
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, BOOL
*contains
)
2954 struct d2d_geometry
*geometry
= impl_from_ID2D1RectangleGeometry(iface
);
2955 D2D1_RECT_F
*rect
= &geometry
->u
.rectangle
.rect
;
2958 TRACE("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p.\n",
2959 iface
, point
.x
, point
.y
, transform
, tolerance
, contains
);
2963 D2D1_MATRIX_3X2_F g_i
;
2965 if (!d2d_matrix_invert(&g_i
, transform
))
2966 return D2DERR_UNSUPPORTED_OPERATION
;
2967 d2d_point_transform(&point
, &g_i
, point
.x
, point
.y
);
2970 if (tolerance
== 0.0f
)
2971 tolerance
= D2D1_DEFAULT_FLATTENING_TOLERANCE
;
2973 dx
= max(fabsf((rect
->right
+ rect
->left
) / 2.0f
- point
.x
) - (rect
->right
- rect
->left
) / 2.0f
, 0.0f
);
2974 dy
= max(fabsf((rect
->bottom
+ rect
->top
) / 2.0f
- point
.y
) - (rect
->bottom
- rect
->top
) / 2.0f
, 0.0f
);
2976 *contains
= tolerance
* tolerance
> (dx
* dx
+ dy
* dy
);
2980 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_CompareWithGeometry(ID2D1RectangleGeometry
*iface
,
2981 ID2D1Geometry
*geometry
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_GEOMETRY_RELATION
*relation
)
2983 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
2984 iface
, geometry
, transform
, tolerance
, relation
);
2989 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_Simplify(ID2D1RectangleGeometry
*iface
,
2990 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
2991 ID2D1SimplifiedGeometrySink
*sink
)
2993 struct d2d_geometry
*geometry
= impl_from_ID2D1RectangleGeometry(iface
);
2994 D2D1_RECT_F
*rect
= &geometry
->u
.rectangle
.rect
;
2998 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
2999 iface
, option
, transform
, tolerance
, sink
);
3001 d2d_point_set(&p
[0], rect
->left
, rect
->top
);
3002 d2d_point_set(&p
[1], rect
->right
, rect
->top
);
3003 d2d_point_set(&p
[2], rect
->right
, rect
->bottom
);
3004 d2d_point_set(&p
[3], rect
->left
, rect
->bottom
);
3008 for (i
= 0; i
< ARRAY_SIZE(p
); ++i
)
3010 d2d_point_transform(&p
[i
], transform
, p
[i
].x
, p
[i
].y
);
3014 ID2D1SimplifiedGeometrySink_SetFillMode(sink
, D2D1_FILL_MODE_ALTERNATE
);
3015 ID2D1SimplifiedGeometrySink_BeginFigure(sink
, p
[0], D2D1_FIGURE_BEGIN_FILLED
);
3016 ID2D1SimplifiedGeometrySink_AddLines(sink
, &p
[1], 3);
3017 ID2D1SimplifiedGeometrySink_EndFigure(sink
, D2D1_FIGURE_END_CLOSED
);
3022 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_Tessellate(ID2D1RectangleGeometry
*iface
,
3023 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1TessellationSink
*sink
)
3025 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
3030 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_CombineWithGeometry(ID2D1RectangleGeometry
*iface
,
3031 ID2D1Geometry
*geometry
, D2D1_COMBINE_MODE combine_mode
, const D2D1_MATRIX_3X2_F
*transform
,
3032 float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
3034 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
3035 iface
, geometry
, combine_mode
, transform
, tolerance
, sink
);
3040 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_Outline(ID2D1RectangleGeometry
*iface
,
3041 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
3043 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
3048 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_ComputeArea(ID2D1RectangleGeometry
*iface
,
3049 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *area
)
3051 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface
, transform
, tolerance
, area
);
3056 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_ComputeLength(ID2D1RectangleGeometry
*iface
,
3057 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *length
)
3059 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface
, transform
, tolerance
, length
);
3064 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_ComputePointAtLength(ID2D1RectangleGeometry
*iface
,
3065 float length
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_POINT_2F
*point
,
3066 D2D1_POINT_2F
*tangent
)
3068 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
3069 iface
, length
, transform
, tolerance
, point
, tangent
);
3074 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_Widen(ID2D1RectangleGeometry
*iface
, float stroke_width
,
3075 ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
3076 ID2D1SimplifiedGeometrySink
*sink
)
3078 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
3079 iface
, stroke_width
, stroke_style
, transform
, tolerance
, sink
);
3084 static void STDMETHODCALLTYPE
d2d_rectangle_geometry_GetRect(ID2D1RectangleGeometry
*iface
, D2D1_RECT_F
*rect
)
3086 struct d2d_geometry
*geometry
= impl_from_ID2D1RectangleGeometry(iface
);
3088 TRACE("iface %p, rect %p.\n", iface
, rect
);
3090 *rect
= geometry
->u
.rectangle
.rect
;
3093 static const struct ID2D1RectangleGeometryVtbl d2d_rectangle_geometry_vtbl
=
3095 d2d_rectangle_geometry_QueryInterface
,
3096 d2d_rectangle_geometry_AddRef
,
3097 d2d_rectangle_geometry_Release
,
3098 d2d_rectangle_geometry_GetFactory
,
3099 d2d_rectangle_geometry_GetBounds
,
3100 d2d_rectangle_geometry_GetWidenedBounds
,
3101 d2d_rectangle_geometry_StrokeContainsPoint
,
3102 d2d_rectangle_geometry_FillContainsPoint
,
3103 d2d_rectangle_geometry_CompareWithGeometry
,
3104 d2d_rectangle_geometry_Simplify
,
3105 d2d_rectangle_geometry_Tessellate
,
3106 d2d_rectangle_geometry_CombineWithGeometry
,
3107 d2d_rectangle_geometry_Outline
,
3108 d2d_rectangle_geometry_ComputeArea
,
3109 d2d_rectangle_geometry_ComputeLength
,
3110 d2d_rectangle_geometry_ComputePointAtLength
,
3111 d2d_rectangle_geometry_Widen
,
3112 d2d_rectangle_geometry_GetRect
,
3115 HRESULT
d2d_rectangle_geometry_init(struct d2d_geometry
*geometry
, ID2D1Factory
*factory
, const D2D1_RECT_F
*rect
)
3121 d2d_geometry_init(geometry
, factory
, &identity
, (ID2D1GeometryVtbl
*)&d2d_rectangle_geometry_vtbl
);
3122 geometry
->u
.rectangle
.rect
= *rect
;
3124 if (!(geometry
->fill
.vertices
= HeapAlloc(GetProcessHeap(), 0, 4 * sizeof(*geometry
->fill
.vertices
))))
3126 if (!d2d_array_reserve((void **)&geometry
->fill
.faces
,
3127 &geometry
->fill
.faces_size
, 2, sizeof(*geometry
->fill
.faces
)))
3130 l
= min(rect
->left
, rect
->right
);
3131 r
= max(rect
->left
, rect
->right
);
3132 t
= min(rect
->top
, rect
->bottom
);
3133 b
= max(rect
->top
, rect
->bottom
);
3135 v
= geometry
->fill
.vertices
;
3136 d2d_point_set(&v
[0], l
, t
);
3137 d2d_point_set(&v
[1], l
, b
);
3138 d2d_point_set(&v
[2], r
, b
);
3139 d2d_point_set(&v
[3], r
, t
);
3140 geometry
->fill
.vertex_count
= 4;
3142 f
= geometry
->fill
.faces
;
3143 d2d_face_set(&f
[0], 1, 2, 0);
3144 d2d_face_set(&f
[1], 0, 2, 3);
3145 geometry
->fill
.face_count
= 2;
3147 if (!d2d_geometry_outline_add_line_segment(geometry
, &v
[0], &v
[1]))
3149 if (!d2d_geometry_outline_add_line_segment(geometry
, &v
[1], &v
[2]))
3151 if (!d2d_geometry_outline_add_line_segment(geometry
, &v
[2], &v
[3]))
3153 if (!d2d_geometry_outline_add_line_segment(geometry
, &v
[3], &v
[0]))
3156 if (!d2d_geometry_outline_add_join(geometry
, &v
[3], &v
[0], &v
[1]))
3158 if (!d2d_geometry_outline_add_join(geometry
, &v
[0], &v
[1], &v
[2]))
3160 if (!d2d_geometry_outline_add_join(geometry
, &v
[1], &v
[2], &v
[3]))
3162 if (!d2d_geometry_outline_add_join(geometry
, &v
[2], &v
[3], &v
[0]))
3168 d2d_geometry_cleanup(geometry
);
3169 return E_OUTOFMEMORY
;
3172 static inline struct d2d_geometry
*impl_from_ID2D1TransformedGeometry(ID2D1TransformedGeometry
*iface
)
3174 return CONTAINING_RECORD(iface
, struct d2d_geometry
, ID2D1Geometry_iface
);
3177 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_QueryInterface(ID2D1TransformedGeometry
*iface
,
3178 REFIID iid
, void **out
)
3180 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
3182 if (IsEqualGUID(iid
, &IID_ID2D1TransformedGeometry
)
3183 || IsEqualGUID(iid
, &IID_ID2D1Geometry
)
3184 || IsEqualGUID(iid
, &IID_ID2D1Resource
)
3185 || IsEqualGUID(iid
, &IID_IUnknown
))
3187 ID2D1TransformedGeometry_AddRef(iface
);
3192 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
3195 return E_NOINTERFACE
;
3198 static ULONG STDMETHODCALLTYPE
d2d_transformed_geometry_AddRef(ID2D1TransformedGeometry
*iface
)
3200 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
3201 ULONG refcount
= InterlockedIncrement(&geometry
->refcount
);
3203 TRACE("%p increasing refcount to %u.\n", iface
, refcount
);
3208 static ULONG STDMETHODCALLTYPE
d2d_transformed_geometry_Release(ID2D1TransformedGeometry
*iface
)
3210 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
3211 ULONG refcount
= InterlockedDecrement(&geometry
->refcount
);
3213 TRACE("%p decreasing refcount to %u.\n", iface
, refcount
);
3217 geometry
->outline
.bezier_faces
= NULL
;
3218 geometry
->outline
.beziers
= NULL
;
3219 geometry
->outline
.faces
= NULL
;
3220 geometry
->outline
.vertices
= NULL
;
3221 geometry
->fill
.bezier_vertices
= NULL
;
3222 geometry
->fill
.faces
= NULL
;
3223 geometry
->fill
.vertices
= NULL
;
3224 ID2D1Geometry_Release(geometry
->u
.transformed
.src_geometry
);
3225 d2d_geometry_cleanup(geometry
);
3226 HeapFree(GetProcessHeap(), 0, geometry
);
3232 static void STDMETHODCALLTYPE
d2d_transformed_geometry_GetFactory(ID2D1TransformedGeometry
*iface
,
3233 ID2D1Factory
**factory
)
3235 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
3237 TRACE("iface %p, factory %p.\n", iface
, factory
);
3239 ID2D1Factory_AddRef(*factory
= geometry
->factory
);
3242 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_GetBounds(ID2D1TransformedGeometry
*iface
,
3243 const D2D1_MATRIX_3X2_F
*transform
, D2D1_RECT_F
*bounds
)
3245 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
3246 D2D1_MATRIX_3X2_F g
;
3248 TRACE("iface %p, transform %p, bounds %p.\n", iface
, transform
, bounds
);
3250 g
= geometry
->transform
;
3252 d2d_matrix_multiply(&g
, transform
);
3254 return ID2D1Geometry_GetBounds(geometry
->u
.transformed
.src_geometry
, &g
, bounds
);
3257 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_GetWidenedBounds(ID2D1TransformedGeometry
*iface
,
3258 float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
3259 float tolerance
, D2D1_RECT_F
*bounds
)
3261 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
3262 iface
, stroke_width
, stroke_style
, transform
, tolerance
, bounds
);
3267 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_StrokeContainsPoint(ID2D1TransformedGeometry
*iface
,
3268 D2D1_POINT_2F point
, float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
3269 float tolerance
, BOOL
*contains
)
3271 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
3272 D2D1_MATRIX_3X2_F g
;
3274 TRACE("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
3275 "transform %p, tolerance %.8e, contains %p.\n",
3276 iface
, point
.x
, point
.y
, stroke_width
, stroke_style
, transform
, tolerance
, contains
);
3278 g
= geometry
->transform
;
3280 d2d_matrix_multiply(&g
, transform
);
3282 return ID2D1Geometry_StrokeContainsPoint(geometry
->u
.transformed
.src_geometry
, point
, stroke_width
, stroke_style
,
3283 &g
, tolerance
, contains
);
3286 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_FillContainsPoint(ID2D1TransformedGeometry
*iface
,
3287 D2D1_POINT_2F point
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, BOOL
*contains
)
3289 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
3290 D2D1_MATRIX_3X2_F g
;
3292 TRACE("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p.\n",
3293 iface
, point
.x
, point
.y
, transform
, tolerance
, contains
);
3295 g
= geometry
->transform
;
3297 d2d_matrix_multiply(&g
, transform
);
3299 return ID2D1Geometry_FillContainsPoint(geometry
->u
.transformed
.src_geometry
, point
, &g
, tolerance
, contains
);
3302 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_CompareWithGeometry(ID2D1TransformedGeometry
*iface
,
3303 ID2D1Geometry
*geometry
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_GEOMETRY_RELATION
*relation
)
3305 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
3306 iface
, geometry
, transform
, tolerance
, relation
);
3311 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_Simplify(ID2D1TransformedGeometry
*iface
,
3312 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
3313 ID2D1SimplifiedGeometrySink
*sink
)
3315 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
3316 D2D1_MATRIX_3X2_F g
;
3318 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
3319 iface
, option
, transform
, tolerance
, sink
);
3321 g
= geometry
->transform
;
3323 d2d_matrix_multiply(&g
, transform
);
3325 return ID2D1Geometry_Simplify(geometry
->u
.transformed
.src_geometry
, option
, &g
, tolerance
, sink
);
3328 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_Tessellate(ID2D1TransformedGeometry
*iface
,
3329 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1TessellationSink
*sink
)
3331 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
3336 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_CombineWithGeometry(ID2D1TransformedGeometry
*iface
,
3337 ID2D1Geometry
*geometry
, D2D1_COMBINE_MODE combine_mode
, const D2D1_MATRIX_3X2_F
*transform
,
3338 float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
3340 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
3341 iface
, geometry
, combine_mode
, transform
, tolerance
, sink
);
3346 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_Outline(ID2D1TransformedGeometry
*iface
,
3347 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
3349 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
3354 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_ComputeArea(ID2D1TransformedGeometry
*iface
,
3355 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *area
)
3357 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface
, transform
, tolerance
, area
);
3362 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_ComputeLength(ID2D1TransformedGeometry
*iface
,
3363 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *length
)
3365 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface
, transform
, tolerance
, length
);
3370 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_ComputePointAtLength(ID2D1TransformedGeometry
*iface
,
3371 float length
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_POINT_2F
*point
,
3372 D2D1_POINT_2F
*tangent
)
3374 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
3375 iface
, length
, transform
, tolerance
, point
, tangent
);
3380 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_Widen(ID2D1TransformedGeometry
*iface
, float stroke_width
,
3381 ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
3382 ID2D1SimplifiedGeometrySink
*sink
)
3384 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
3385 iface
, stroke_width
, stroke_style
, transform
, tolerance
, sink
);
3390 static void STDMETHODCALLTYPE
d2d_transformed_geometry_GetSourceGeometry(ID2D1TransformedGeometry
*iface
,
3391 ID2D1Geometry
**src_geometry
)
3393 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
3395 TRACE("iface %p, src_geometry %p.\n", iface
, src_geometry
);
3397 ID2D1Geometry_AddRef(*src_geometry
= geometry
->u
.transformed
.src_geometry
);
3400 static void STDMETHODCALLTYPE
d2d_transformed_geometry_GetTransform(ID2D1TransformedGeometry
*iface
,
3401 D2D1_MATRIX_3X2_F
*transform
)
3403 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
3405 TRACE("iface %p, transform %p.\n", iface
, transform
);
3407 *transform
= geometry
->u
.transformed
.transform
;
3410 static const struct ID2D1TransformedGeometryVtbl d2d_transformed_geometry_vtbl
=
3412 d2d_transformed_geometry_QueryInterface
,
3413 d2d_transformed_geometry_AddRef
,
3414 d2d_transformed_geometry_Release
,
3415 d2d_transformed_geometry_GetFactory
,
3416 d2d_transformed_geometry_GetBounds
,
3417 d2d_transformed_geometry_GetWidenedBounds
,
3418 d2d_transformed_geometry_StrokeContainsPoint
,
3419 d2d_transformed_geometry_FillContainsPoint
,
3420 d2d_transformed_geometry_CompareWithGeometry
,
3421 d2d_transformed_geometry_Simplify
,
3422 d2d_transformed_geometry_Tessellate
,
3423 d2d_transformed_geometry_CombineWithGeometry
,
3424 d2d_transformed_geometry_Outline
,
3425 d2d_transformed_geometry_ComputeArea
,
3426 d2d_transformed_geometry_ComputeLength
,
3427 d2d_transformed_geometry_ComputePointAtLength
,
3428 d2d_transformed_geometry_Widen
,
3429 d2d_transformed_geometry_GetSourceGeometry
,
3430 d2d_transformed_geometry_GetTransform
,
3433 void d2d_transformed_geometry_init(struct d2d_geometry
*geometry
, ID2D1Factory
*factory
,
3434 ID2D1Geometry
*src_geometry
, const D2D_MATRIX_3X2_F
*transform
)
3436 struct d2d_geometry
*src_impl
;
3439 src_impl
= unsafe_impl_from_ID2D1Geometry(src_geometry
);
3441 g
= src_impl
->transform
;
3442 d2d_matrix_multiply(&g
, transform
);
3443 d2d_geometry_init(geometry
, factory
, &g
, (ID2D1GeometryVtbl
*)&d2d_transformed_geometry_vtbl
);
3444 ID2D1Geometry_AddRef(geometry
->u
.transformed
.src_geometry
= src_geometry
);
3445 geometry
->u
.transformed
.transform
= *transform
;
3446 geometry
->fill
= src_impl
->fill
;
3447 geometry
->outline
= src_impl
->outline
;
3450 struct d2d_geometry
*unsafe_impl_from_ID2D1Geometry(ID2D1Geometry
*iface
)
3454 assert(iface
->lpVtbl
== (const ID2D1GeometryVtbl
*)&d2d_path_geometry_vtbl
3455 || iface
->lpVtbl
== (const ID2D1GeometryVtbl
*)&d2d_rectangle_geometry_vtbl
3456 || iface
->lpVtbl
== (const ID2D1GeometryVtbl
*)&d2d_transformed_geometry_vtbl
);
3457 return CONTAINING_RECORD(iface
, struct d2d_geometry
, ID2D1Geometry_iface
);