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