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
,
55 struct d2d_segment_idx
64 D2D1_POINT_2F
*vertices
;
66 enum d2d_vertex_type
*vertex_types
;
67 size_t vertex_types_size
;
70 D2D1_POINT_2F
*bezier_controls
;
71 size_t bezier_controls_size
;
72 size_t bezier_control_count
;
74 D2D1_POINT_2F
*original_bezier_controls
;
75 size_t original_bezier_control_count
;
81 struct d2d_cdt_edge_ref
84 enum d2d_cdt_edge_next r
;
89 struct d2d_cdt_edge_ref next
[4];
96 struct d2d_cdt_edge
*edges
;
101 const D2D1_POINT_2F
*vertices
;
104 struct d2d_geometry_intersection
113 struct d2d_geometry_intersections
115 struct d2d_geometry_intersection
*intersections
;
116 size_t intersections_size
;
117 size_t intersection_count
;
120 struct d2d_fp_two_vec2
132 static void d2d_curve_vertex_set(struct d2d_curve_vertex
*b
,
133 const D2D1_POINT_2F
*p
, float u
, float v
, float sign
)
138 b
->texcoord
.sign
= sign
;
141 static void d2d_face_set(struct d2d_face
*f
, UINT16 v0
, UINT16 v1
, UINT16 v2
)
148 static void d2d_outline_vertex_set(struct d2d_outline_vertex
*v
, float x
, float y
,
149 float prev_x
, float prev_y
, float next_x
, float next_y
)
151 d2d_point_set(&v
->position
, x
, y
);
152 d2d_point_set(&v
->prev
, prev_x
, prev_y
);
153 d2d_point_set(&v
->next
, next_x
, next_y
);
156 static void d2d_curve_outline_vertex_set(struct d2d_curve_outline_vertex
*a
, const D2D1_POINT_2F
*position
,
157 const D2D1_POINT_2F
*p0
, const D2D1_POINT_2F
*p1
, const D2D1_POINT_2F
*p2
,
158 float prev_x
, float prev_y
, float next_x
, float next_y
)
160 a
->position
= *position
;
164 d2d_point_set(&a
->prev
, prev_x
, prev_y
);
165 d2d_point_set(&a
->next
, next_x
, next_y
);
168 static void d2d_fp_two_sum(float *out
, float a
, float b
)
170 float a_virt
, a_round
, b_virt
, b_round
;
174 a_virt
= out
[1] - b_virt
;
175 b_round
= b
- b_virt
;
176 a_round
= a
- a_virt
;
177 out
[0] = a_round
+ b_round
;
180 static void d2d_fp_fast_two_sum(float *out
, float a
, float b
)
189 static void d2d_fp_two_two_sum(float *out
, const float *a
, const float *b
)
193 d2d_fp_two_sum(out
, a
[0], b
[0]);
194 d2d_fp_two_sum(sum
, a
[1], out
[1]);
195 d2d_fp_two_sum(&out
[1], sum
[0], b
[1]);
196 d2d_fp_two_sum(&out
[2], sum
[1], out
[2]);
199 static void d2d_fp_two_diff_tail(float *out
, float a
, float b
, float x
)
201 float a_virt
, a_round
, b_virt
, b_round
;
205 b_round
= b_virt
- b
;
206 a_round
= a
- a_virt
;
207 *out
= a_round
+ b_round
;
210 static void d2d_fp_two_two_diff(float *out
, const float *a
, const float *b
)
215 d2d_fp_two_diff_tail(out
, a
[0], b
[0], diff
);
216 d2d_fp_two_sum(sum
, a
[1], diff
);
217 diff
= sum
[0] - b
[1];
218 d2d_fp_two_diff_tail(&out
[1], sum
[0], b
[1], diff
);
219 d2d_fp_two_sum(&out
[2], sum
[1], diff
);
222 static void d2d_fp_split(float *out
, float a
)
226 c
= a
* ((1 << (FLT_MANT_DIG
/ 2)) + 1.0f
);
232 static void d2d_fp_two_product_presplit(float *out
, float a
, float b
, const float *b_split
)
234 float a_split
[2], err1
, err2
, err3
;
237 d2d_fp_split(a_split
, a
);
238 err1
= out
[1] - (a_split
[1] * b_split
[1]);
239 err2
= err1
- (a_split
[0] * b_split
[1]);
240 err3
= err2
- (a_split
[1] * b_split
[0]);
241 out
[0] = (a_split
[0] * b_split
[0]) - err3
;
244 static void d2d_fp_two_product(float *out
, float a
, float b
)
248 d2d_fp_split(b_split
, b
);
249 d2d_fp_two_product_presplit(out
, a
, b
, b_split
);
252 static void d2d_fp_square(float *out
, float a
)
254 float a_split
[2], err1
, err2
;
257 d2d_fp_split(a_split
, a
);
258 err1
= out
[1] - (a_split
[1] * a_split
[1]);
259 err2
= err1
- ((a_split
[1] + a_split
[1]) * a_split
[0]);
260 out
[0] = (a_split
[0] * a_split
[0]) - err2
;
263 static float d2d_fp_estimate(float *a
, size_t len
)
274 static void d2d_fp_fast_expansion_sum_zeroelim(float *out
, size_t *out_len
,
275 const float *a
, size_t a_len
, const float *b
, size_t b_len
)
277 float sum
[2], q
, a_curr
, b_curr
;
278 size_t a_idx
, b_idx
, out_idx
;
283 if ((b_curr
> a_curr
) == (b_curr
> -a_curr
))
294 if (a_idx
< a_len
&& b_idx
< b_len
)
296 if ((b_curr
> a_curr
) == (b_curr
> -a_curr
))
298 d2d_fp_fast_two_sum(sum
, a_curr
, q
);
303 d2d_fp_fast_two_sum(sum
, b_curr
, q
);
307 out
[out_idx
++] = sum
[0];
309 while (a_idx
< a_len
&& b_idx
< b_len
)
311 if ((b_curr
> a_curr
) == (b_curr
> -a_curr
))
313 d2d_fp_two_sum(sum
, q
, a_curr
);
318 d2d_fp_two_sum(sum
, q
, b_curr
);
322 out
[out_idx
++] = sum
[0];
326 while (a_idx
< a_len
)
328 d2d_fp_two_sum(sum
, q
, a_curr
);
331 out
[out_idx
++] = sum
[0];
334 while (b_idx
< b_len
)
336 d2d_fp_two_sum(sum
, q
, b_curr
);
339 out
[out_idx
++] = sum
[0];
342 if (q
!= 0.0f
|| !out_idx
)
348 static void d2d_fp_scale_expansion_zeroelim(float *out
, size_t *out_len
, const float *a
, size_t a_len
, float b
)
350 float product
[2], sum
[2], b_split
[2], q
[2], a_curr
;
351 size_t a_idx
, out_idx
;
353 d2d_fp_split(b_split
, b
);
354 d2d_fp_two_product_presplit(q
, a
[0], b
, b_split
);
357 out
[out_idx
++] = q
[0];
358 for (a_idx
= 1; a_idx
< a_len
; ++a_idx
)
361 d2d_fp_two_product_presplit(product
, a_curr
, b
, b_split
);
362 d2d_fp_two_sum(sum
, q
[1], product
[0]);
364 out
[out_idx
++] = sum
[0];
365 d2d_fp_fast_two_sum(q
, product
[1], sum
[1]);
367 out
[out_idx
++] = q
[0];
369 if (q
[1] != 0.0f
|| !out_idx
)
370 out
[out_idx
++] = q
[1];
375 static void d2d_point_subtract(D2D1_POINT_2F
*out
,
376 const D2D1_POINT_2F
*a
, const D2D1_POINT_2F
*b
)
378 out
->x
= a
->x
- b
->x
;
379 out
->y
= a
->y
- b
->y
;
382 static void d2d_point_scale(D2D1_POINT_2F
*p
, float scale
)
388 static void d2d_point_lerp(D2D1_POINT_2F
*out
,
389 const D2D1_POINT_2F
*a
, const D2D1_POINT_2F
*b
, float t
)
391 out
->x
= a
->x
* (1.0f
- t
) + b
->x
* t
;
392 out
->y
= a
->y
* (1.0f
- t
) + b
->y
* t
;
395 static void d2d_point_calculate_bezier(D2D1_POINT_2F
*out
, const D2D1_POINT_2F
*p0
,
396 const D2D1_POINT_2F
*p1
, const D2D1_POINT_2F
*p2
, float t
)
398 float t_c
= 1.0f
- t
;
400 out
->x
= t_c
* (t_c
* p0
->x
+ t
* p1
->x
) + t
* (t_c
* p1
->x
+ t
* p2
->x
);
401 out
->y
= t_c
* (t_c
* p0
->y
+ t
* p1
->y
) + t
* (t_c
* p1
->y
+ t
* p2
->y
);
404 static void d2d_point_normalise(D2D1_POINT_2F
*p
)
408 if ((l
= sqrtf(d2d_point_dot(p
, p
))) != 0.0f
)
409 d2d_point_scale(p
, 1.0f
/ l
);
412 static BOOL
d2d_vertex_type_is_bezier(enum d2d_vertex_type t
)
414 return (t
== D2D_VERTEX_TYPE_BEZIER
|| t
== D2D_VERTEX_TYPE_SPLIT_BEZIER
);
417 static BOOL
d2d_vertex_type_is_split_bezier(enum d2d_vertex_type t
)
419 return t
== D2D_VERTEX_TYPE_SPLIT_BEZIER
;
422 /* This implementation is based on the paper "Adaptive Precision
423 * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
424 * associated (Public Domain) code by Jonathan Richard Shewchuk. */
425 static float d2d_point_ccw(const D2D1_POINT_2F
*a
, const D2D1_POINT_2F
*b
, const D2D1_POINT_2F
*c
)
427 static const float err_bound_result
= (3.0f
+ 8.0f
* D2D_FP_EPS
) * D2D_FP_EPS
;
428 static const float err_bound_a
= (3.0f
+ 16.0f
* D2D_FP_EPS
) * D2D_FP_EPS
;
429 static const float err_bound_b
= (2.0f
+ 12.0f
* D2D_FP_EPS
) * D2D_FP_EPS
;
430 static const float err_bound_c
= (9.0f
+ 64.0f
* D2D_FP_EPS
) * D2D_FP_EPS
* D2D_FP_EPS
;
431 float det_d
[16], det_c2
[12], det_c1
[8], det_b
[4], temp4
[4], temp2a
[2], temp2b
[2], abxacy
[2], abyacx
[2];
432 size_t det_d_len
, det_c2_len
, det_c1_len
;
433 float det
, det_sum
, err_bound
;
434 struct d2d_fp_two_vec2 ab
, ac
;
436 ab
.x
[1] = b
->x
- a
->x
;
437 ab
.y
[1] = b
->y
- a
->y
;
438 ac
.x
[1] = c
->x
- a
->x
;
439 ac
.y
[1] = c
->y
- a
->y
;
441 abxacy
[1] = ab
.x
[1] * ac
.y
[1];
442 abyacx
[1] = ab
.y
[1] * ac
.x
[1];
443 det
= abxacy
[1] - abyacx
[1];
445 if (abxacy
[1] > 0.0f
)
447 if (abyacx
[1] <= 0.0f
)
449 det_sum
= abxacy
[1] + abyacx
[1];
451 else if (abxacy
[1] < 0.0f
)
453 if (abyacx
[1] >= 0.0f
)
455 det_sum
= -abxacy
[1] - abyacx
[1];
462 err_bound
= err_bound_a
* det_sum
;
463 if (det
>= err_bound
|| -det
>= err_bound
)
466 d2d_fp_two_product(abxacy
, ab
.x
[1], ac
.y
[1]);
467 d2d_fp_two_product(abyacx
, ab
.y
[1], ac
.x
[1]);
468 d2d_fp_two_two_diff(det_b
, abxacy
, abyacx
);
470 det
= d2d_fp_estimate(det_b
, 4);
471 err_bound
= err_bound_b
* det_sum
;
472 if (det
>= err_bound
|| -det
>= err_bound
)
475 d2d_fp_two_diff_tail(&ab
.x
[0], b
->x
, a
->x
, ab
.x
[1]);
476 d2d_fp_two_diff_tail(&ab
.y
[0], b
->y
, a
->y
, ab
.y
[1]);
477 d2d_fp_two_diff_tail(&ac
.x
[0], c
->x
, a
->x
, ac
.x
[1]);
478 d2d_fp_two_diff_tail(&ac
.y
[0], c
->y
, a
->y
, ac
.y
[1]);
480 if (ab
.x
[0] == 0.0f
&& ab
.y
[0] == 0.0f
&& ac
.x
[0] == 0.0f
&& ac
.y
[0] == 0.0f
)
483 err_bound
= err_bound_c
* det_sum
+ err_bound_result
* fabsf(det
);
484 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]);
485 if (det
>= err_bound
|| -det
>= err_bound
)
488 d2d_fp_two_product(temp2a
, ab
.x
[0], ac
.y
[1]);
489 d2d_fp_two_product(temp2b
, ab
.y
[0], ac
.x
[1]);
490 d2d_fp_two_two_diff(temp4
, temp2a
, temp2b
);
491 d2d_fp_fast_expansion_sum_zeroelim(det_c1
, &det_c1_len
, det_b
, 4, temp4
, 4);
493 d2d_fp_two_product(temp2a
, ab
.x
[1], ac
.y
[0]);
494 d2d_fp_two_product(temp2b
, ab
.y
[1], ac
.x
[0]);
495 d2d_fp_two_two_diff(temp4
, temp2a
, temp2b
);
496 d2d_fp_fast_expansion_sum_zeroelim(det_c2
, &det_c2_len
, det_c1
, det_c1_len
, temp4
, 4);
498 d2d_fp_two_product(temp2a
, ab
.x
[0], ac
.y
[0]);
499 d2d_fp_two_product(temp2b
, ab
.y
[0], ac
.x
[0]);
500 d2d_fp_two_two_diff(temp4
, temp2a
, temp2b
);
501 d2d_fp_fast_expansion_sum_zeroelim(det_d
, &det_d_len
, det_c2
, det_c2_len
, temp4
, 4);
503 return det_d
[det_d_len
- 1];
506 static void d2d_rect_union(D2D1_RECT_F
*l
, const D2D1_RECT_F
*r
)
508 l
->left
= min(l
->left
, r
->left
);
509 l
->top
= min(l
->top
, r
->top
);
510 l
->right
= max(l
->right
, r
->right
);
511 l
->bottom
= max(l
->bottom
, r
->bottom
);
514 static BOOL
d2d_rect_check_overlap(const D2D_RECT_F
*p
, const D2D_RECT_F
*q
)
516 return p
->left
< q
->right
&& p
->top
< q
->bottom
&& p
->right
> q
->left
&& p
->bottom
> q
->top
;
519 static void d2d_rect_get_bezier_bounds(D2D_RECT_F
*bounds
, const D2D1_POINT_2F
*p0
,
520 const D2D1_POINT_2F
*p1
, const D2D1_POINT_2F
*p2
)
525 bounds
->left
= p0
->x
;
527 bounds
->right
= p0
->x
;
528 bounds
->bottom
= p0
->y
;
530 d2d_rect_expand(bounds
, p2
);
532 /* f(t) = (1 - t)²P₀ + 2(1 - t)tP₁ + t²P₂
533 * f'(t) = 2(1 - t)(P₁ - P₀) + 2t(P₂ - P₁)
534 * = 2(P₂ - 2P₁ + P₀)t + 2(P₁ - P₀)
537 * t = (P₀ - P₁) / (P₂ - 2P₁ + P₀) */
538 root
= (p0
->x
- p1
->x
) / (p2
->x
- 2.0f
* p1
->x
+ p0
->x
);
539 if (root
> 0.0f
&& root
< 1.0f
)
541 d2d_point_calculate_bezier(&p
, p0
, p1
, p2
, root
);
542 d2d_rect_expand(bounds
, &p
);
545 root
= (p0
->y
- p1
->y
) / (p2
->y
- 2.0f
* p1
->y
+ p0
->y
);
546 if (root
> 0.0f
&& root
< 1.0f
)
548 d2d_point_calculate_bezier(&p
, p0
, p1
, p2
, root
);
549 d2d_rect_expand(bounds
, &p
);
553 static void d2d_rect_get_bezier_segment_bounds(D2D_RECT_F
*bounds
, const D2D1_POINT_2F
*p0
,
554 const D2D1_POINT_2F
*p1
, const D2D1_POINT_2F
*p2
, float start
, float end
)
556 D2D1_POINT_2F q
[3], r
[2];
558 d2d_point_lerp(&r
[0], p0
, p1
, start
);
559 d2d_point_lerp(&r
[1], p1
, p2
, start
);
560 d2d_point_lerp(&q
[0], &r
[0], &r
[1], start
);
562 end
= (end
- start
) / (1.0f
- start
);
563 d2d_point_lerp(&q
[1], &q
[0], &r
[1], end
);
564 d2d_point_lerp(&r
[0], &r
[1], p2
, end
);
565 d2d_point_lerp(&q
[2], &q
[1], &r
[0], end
);
567 d2d_rect_get_bezier_bounds(bounds
, &q
[0], &q
[1], &q
[2]);
570 static BOOL
d2d_figure_insert_vertex(struct d2d_figure
*figure
, size_t idx
, D2D1_POINT_2F vertex
)
572 if (!d2d_array_reserve((void **)&figure
->vertices
, &figure
->vertices_size
,
573 figure
->vertex_count
+ 1, sizeof(*figure
->vertices
)))
575 ERR("Failed to grow vertices array.\n");
579 if (!d2d_array_reserve((void **)&figure
->vertex_types
, &figure
->vertex_types_size
,
580 figure
->vertex_count
+ 1, sizeof(*figure
->vertex_types
)))
582 ERR("Failed to grow vertex types array.\n");
586 memmove(&figure
->vertices
[idx
+ 1], &figure
->vertices
[idx
],
587 (figure
->vertex_count
- idx
) * sizeof(*figure
->vertices
));
588 memmove(&figure
->vertex_types
[idx
+ 1], &figure
->vertex_types
[idx
],
589 (figure
->vertex_count
- idx
) * sizeof(*figure
->vertex_types
));
590 figure
->vertices
[idx
] = vertex
;
591 figure
->vertex_types
[idx
] = D2D_VERTEX_TYPE_NONE
;
592 d2d_rect_expand(&figure
->bounds
, &vertex
);
593 ++figure
->vertex_count
;
597 static BOOL
d2d_figure_add_vertex(struct d2d_figure
*figure
, D2D1_POINT_2F vertex
)
599 size_t last
= figure
->vertex_count
- 1;
601 if (figure
->vertex_count
&& figure
->vertex_types
[last
] == D2D_VERTEX_TYPE_LINE
602 && !memcmp(&figure
->vertices
[last
], &vertex
, sizeof(vertex
)))
605 if (!d2d_array_reserve((void **)&figure
->vertices
, &figure
->vertices_size
,
606 figure
->vertex_count
+ 1, sizeof(*figure
->vertices
)))
608 ERR("Failed to grow vertices array.\n");
612 if (!d2d_array_reserve((void **)&figure
->vertex_types
, &figure
->vertex_types_size
,
613 figure
->vertex_count
+ 1, sizeof(*figure
->vertex_types
)))
615 ERR("Failed to grow vertex types array.\n");
619 figure
->vertices
[figure
->vertex_count
] = vertex
;
620 figure
->vertex_types
[figure
->vertex_count
] = D2D_VERTEX_TYPE_NONE
;
621 d2d_rect_expand(&figure
->bounds
, &vertex
);
622 ++figure
->vertex_count
;
626 static BOOL
d2d_figure_insert_bezier_controls(struct d2d_figure
*figure
,
627 size_t idx
, size_t count
, const D2D1_POINT_2F
*p
)
629 if (!d2d_array_reserve((void **)&figure
->bezier_controls
, &figure
->bezier_controls_size
,
630 figure
->bezier_control_count
+ count
, sizeof(*figure
->bezier_controls
)))
632 ERR("Failed to grow bezier controls array.\n");
636 memmove(&figure
->bezier_controls
[idx
+ count
], &figure
->bezier_controls
[idx
],
637 (figure
->bezier_control_count
- idx
) * sizeof(*figure
->bezier_controls
));
638 memcpy(&figure
->bezier_controls
[idx
], p
, count
* sizeof(*figure
->bezier_controls
));
639 figure
->bezier_control_count
+= count
;
644 static BOOL
d2d_figure_add_bezier_controls(struct d2d_figure
*figure
, size_t count
, const D2D1_POINT_2F
*p
)
646 if (!d2d_array_reserve((void **)&figure
->bezier_controls
, &figure
->bezier_controls_size
,
647 figure
->bezier_control_count
+ count
, sizeof(*figure
->bezier_controls
)))
649 ERR("Failed to grow bezier controls array.\n");
653 memcpy(&figure
->bezier_controls
[figure
->bezier_control_count
], p
, count
* sizeof(*figure
->bezier_controls
));
654 figure
->bezier_control_count
+= count
;
659 static void d2d_cdt_edge_rot(struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
662 dst
->r
= (src
->r
+ D2D_EDGE_NEXT_ROT
) & 3;
665 static void d2d_cdt_edge_sym(struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
668 dst
->r
= (src
->r
+ D2D_EDGE_NEXT_SYM
) & 3;
671 static void d2d_cdt_edge_tor(struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
674 dst
->r
= (src
->r
+ D2D_EDGE_NEXT_TOR
) & 3;
677 static void d2d_cdt_edge_next_left(const struct d2d_cdt
*cdt
,
678 struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
680 d2d_cdt_edge_rot(dst
, &cdt
->edges
[src
->idx
].next
[(src
->r
+ D2D_EDGE_NEXT_TOR
) & 3]);
683 static void d2d_cdt_edge_next_origin(const struct d2d_cdt
*cdt
,
684 struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
686 *dst
= cdt
->edges
[src
->idx
].next
[src
->r
];
689 static void d2d_cdt_edge_prev_origin(const struct d2d_cdt
*cdt
,
690 struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
692 d2d_cdt_edge_rot(dst
, &cdt
->edges
[src
->idx
].next
[(src
->r
+ D2D_EDGE_NEXT_ROT
) & 3]);
695 static size_t d2d_cdt_edge_origin(const struct d2d_cdt
*cdt
, const struct d2d_cdt_edge_ref
*e
)
697 return cdt
->edges
[e
->idx
].vertex
[e
->r
>> 1];
700 static size_t d2d_cdt_edge_destination(const struct d2d_cdt
*cdt
, const struct d2d_cdt_edge_ref
*e
)
702 return cdt
->edges
[e
->idx
].vertex
[!(e
->r
>> 1)];
705 static void d2d_cdt_edge_set_origin(const struct d2d_cdt
*cdt
,
706 const struct d2d_cdt_edge_ref
*e
, size_t vertex
)
708 cdt
->edges
[e
->idx
].vertex
[e
->r
>> 1] = vertex
;
711 static void d2d_cdt_edge_set_destination(const struct d2d_cdt
*cdt
,
712 const struct d2d_cdt_edge_ref
*e
, size_t vertex
)
714 cdt
->edges
[e
->idx
].vertex
[!(e
->r
>> 1)] = vertex
;
717 static float d2d_cdt_ccw(const struct d2d_cdt
*cdt
, size_t a
, size_t b
, size_t c
)
719 return d2d_point_ccw(&cdt
->vertices
[a
], &cdt
->vertices
[b
], &cdt
->vertices
[c
]);
722 static BOOL
d2d_cdt_rightof(const struct d2d_cdt
*cdt
, size_t p
, const struct d2d_cdt_edge_ref
*e
)
724 return d2d_cdt_ccw(cdt
, p
, d2d_cdt_edge_destination(cdt
, e
), d2d_cdt_edge_origin(cdt
, e
)) > 0.0f
;
727 static BOOL
d2d_cdt_leftof(const struct d2d_cdt
*cdt
, size_t p
, const struct d2d_cdt_edge_ref
*e
)
729 return d2d_cdt_ccw(cdt
, p
, d2d_cdt_edge_origin(cdt
, e
), d2d_cdt_edge_destination(cdt
, e
)) > 0.0f
;
734 static void d2d_fp_four_det2x2(float *out
, float ax
, float ay
, float bx
, float by
)
736 float axby
[2], aybx
[2];
738 d2d_fp_two_product(axby
, ax
, by
);
739 d2d_fp_two_product(aybx
, ay
, bx
);
740 d2d_fp_two_two_diff(out
, axby
, aybx
);
743 /* (a->x² + a->y²) * det2x2 */
744 static void d2d_fp_sub_det3x3(float *out
, size_t *out_len
, const struct d2d_fp_two_vec2
*a
, const float *det2x2
)
746 size_t axd_len
, ayd_len
, axxd_len
, ayyd_len
;
747 float axd
[8], ayd
[8], axxd
[16], ayyd
[16];
749 d2d_fp_scale_expansion_zeroelim(axd
, &axd_len
, det2x2
, 4, a
->x
[1]);
750 d2d_fp_scale_expansion_zeroelim(axxd
, &axxd_len
, axd
, axd_len
, a
->x
[1]);
751 d2d_fp_scale_expansion_zeroelim(ayd
, &ayd_len
, det2x2
, 4, a
->y
[1]);
752 d2d_fp_scale_expansion_zeroelim(ayyd
, &ayyd_len
, ayd
, ayd_len
, a
->y
[1]);
753 d2d_fp_fast_expansion_sum_zeroelim(out
, out_len
, axxd
, axxd_len
, ayyd
, ayyd_len
);
756 /* det_abt = det_ab * c[0]
757 * fin += c[0] * (az * b - bz * a + c[1] * det_ab * 2.0f) */
758 static void d2d_cdt_incircle_refine1(struct d2d_fp_fin
*fin
, float *det_abt
, size_t *det_abt_len
,
759 const float *det_ab
, float a
, const float *az
, float b
, const float *bz
, const float *c
)
761 size_t temp48_len
, temp32_len
, temp16a_len
, temp16b_len
, temp16c_len
, temp8_len
;
762 float temp48
[48], temp32
[32], temp16a
[16], temp16b
[16], temp16c
[16], temp8
[8];
765 d2d_fp_scale_expansion_zeroelim(det_abt
, det_abt_len
, det_ab
, 4, c
[0]);
766 d2d_fp_scale_expansion_zeroelim(temp16a
, &temp16a_len
, det_abt
, *det_abt_len
, 2.0f
* c
[1]);
767 d2d_fp_scale_expansion_zeroelim(temp8
, &temp8_len
, az
, 4, c
[0]);
768 d2d_fp_scale_expansion_zeroelim(temp16b
, &temp16b_len
, temp8
, temp8_len
, b
);
769 d2d_fp_scale_expansion_zeroelim(temp8
, &temp8_len
, bz
, 4, c
[0]);
770 d2d_fp_scale_expansion_zeroelim(temp16c
, &temp16c_len
, temp8
, temp8_len
, -a
);
771 d2d_fp_fast_expansion_sum_zeroelim(temp32
, &temp32_len
, temp16a
, temp16a_len
, temp16b
, temp16b_len
);
772 d2d_fp_fast_expansion_sum_zeroelim(temp48
, &temp48_len
, temp16c
, temp16c_len
, temp32
, temp32_len
);
773 d2d_fp_fast_expansion_sum_zeroelim(fin
->other
, &fin
->length
, fin
->now
, fin
->length
, temp48
, temp48_len
);
774 swap
= fin
->now
; fin
->now
= fin
->other
; fin
->other
= swap
;
777 static void d2d_cdt_incircle_refine2(struct d2d_fp_fin
*fin
, const struct d2d_fp_two_vec2
*a
,
778 const struct d2d_fp_two_vec2
*b
, const float *bz
, const struct d2d_fp_two_vec2
*c
, const float *cz
,
779 const float *axt_det_bc
, size_t axt_det_bc_len
, const float *ayt_det_bc
, size_t ayt_det_bc_len
)
781 size_t temp64_len
, temp48_len
, temp32a_len
, temp32b_len
, temp16a_len
, temp16b_len
, temp8_len
;
782 float temp64
[64], temp48
[48], temp32a
[32], temp32b
[32], temp16a
[16], temp16b
[16], temp8
[8];
783 float bct
[8], bctt
[4], temp4a
[4], temp4b
[4], temp2a
[2], temp2b
[2];
784 size_t bct_len
, bctt_len
;
787 /* 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]) */
788 /* bctt = b->x[0] * c->y[0] + c->x[0] * b->y[0] */
789 if (b
->x
[0] != 0.0f
|| b
->y
[0] != 0.0f
|| c
->x
[0] != 0.0f
|| c
->y
[0] != 0.0f
)
791 d2d_fp_two_product(temp2a
, b
->x
[0], c
->y
[1]);
792 d2d_fp_two_product(temp2b
, b
->x
[1], c
->y
[0]);
793 d2d_fp_two_two_sum(temp4a
, temp2a
, temp2b
);
794 d2d_fp_two_product(temp2a
, c
->x
[0], -b
->y
[1]);
795 d2d_fp_two_product(temp2b
, c
->x
[1], -b
->y
[0]);
796 d2d_fp_two_two_sum(temp4b
, temp2a
, temp2b
);
797 d2d_fp_fast_expansion_sum_zeroelim(bct
, &bct_len
, temp4a
, 4, temp4b
, 4);
799 d2d_fp_two_product(temp2a
, b
->x
[0], c
->y
[0]);
800 d2d_fp_two_product(temp2b
, c
->x
[0], b
->y
[0]);
801 d2d_fp_two_two_diff(bctt
, temp2a
, temp2b
);
814 size_t axt_bct_len
, axt_bctt_len
;
815 float axt_bct
[16], axt_bctt
[8];
817 /* fin += a->x[0] * (axt_det_bc + bct * 2.0f * a->x[1]) */
818 d2d_fp_scale_expansion_zeroelim(temp16a
, &temp16a_len
, axt_det_bc
, axt_det_bc_len
, a
->x
[0]);
819 d2d_fp_scale_expansion_zeroelim(axt_bct
, &axt_bct_len
, bct
, bct_len
, a
->x
[0]);
820 d2d_fp_scale_expansion_zeroelim(temp32a
, &temp32a_len
, axt_bct
, axt_bct_len
, 2.0f
* a
->x
[1]);
821 d2d_fp_fast_expansion_sum_zeroelim(temp48
, &temp48_len
, temp16a
, temp16a_len
, temp32a
, temp32a_len
);
822 d2d_fp_fast_expansion_sum_zeroelim(fin
->other
, &fin
->length
, fin
->now
, fin
->length
, temp48
, temp48_len
);
823 swap
= fin
->now
; fin
->now
= fin
->other
; fin
->other
= swap
;
827 /* fin += a->x[0] * cz * b->y[0] */
828 d2d_fp_scale_expansion_zeroelim(temp8
, &temp8_len
, cz
, 4, a
->x
[0]);
829 d2d_fp_scale_expansion_zeroelim(temp16a
, &temp16a_len
, temp8
, temp8_len
, b
->y
[0]);
830 d2d_fp_fast_expansion_sum_zeroelim(fin
->other
, &fin
->length
, fin
->now
, fin
->length
, temp16a
, temp16a_len
);
831 swap
= fin
->now
; fin
->now
= fin
->other
; fin
->other
= swap
;
836 /* fin -= a->x[0] * bz * c->y[0] */
837 d2d_fp_scale_expansion_zeroelim(temp8
, &temp8_len
, bz
, 4, -a
->x
[0]);
838 d2d_fp_scale_expansion_zeroelim(temp16a
, &temp16a_len
, temp8
, temp8_len
, c
->y
[0]);
839 d2d_fp_fast_expansion_sum_zeroelim(fin
->other
, &fin
->length
, fin
->now
, fin
->length
, temp16a
, temp16a_len
);
840 swap
= fin
->now
; fin
->now
= fin
->other
; fin
->other
= swap
;
843 /* fin += a->x[0] * (bct * a->x[0] + bctt * (2.0f * a->x[1] + a->x[0])) */
844 d2d_fp_scale_expansion_zeroelim(temp32a
, &temp32a_len
, axt_bct
, axt_bct_len
, a
->x
[0]);
845 d2d_fp_scale_expansion_zeroelim(axt_bctt
, &axt_bctt_len
, bctt
, bctt_len
, a
->x
[0]);
846 d2d_fp_scale_expansion_zeroelim(temp16a
, &temp16a_len
, axt_bctt
, axt_bctt_len
, 2.0f
* a
->x
[1]);
847 d2d_fp_scale_expansion_zeroelim(temp16b
, &temp16b_len
, axt_bctt
, axt_bctt_len
, a
->x
[0]);
848 d2d_fp_fast_expansion_sum_zeroelim(temp32b
, &temp32b_len
, temp16a
, temp16a_len
, temp16b
, temp16b_len
);
849 d2d_fp_fast_expansion_sum_zeroelim(temp64
, &temp64_len
, temp32a
, temp32a_len
, temp32b
, temp32b_len
);
850 d2d_fp_fast_expansion_sum_zeroelim(fin
->other
, &fin
->length
, fin
->now
, fin
->length
, temp64
, temp64_len
);
851 swap
= fin
->now
; fin
->now
= fin
->other
; fin
->other
= swap
;
856 size_t ayt_bct_len
, ayt_bctt_len
;
857 float ayt_bct
[16], ayt_bctt
[8];
859 /* fin += a->y[0] * (ayt_det_bc + bct * 2.0f * a->y[1]) */
860 d2d_fp_scale_expansion_zeroelim(temp16a
, &temp16a_len
, ayt_det_bc
, ayt_det_bc_len
, a
->y
[0]);
861 d2d_fp_scale_expansion_zeroelim(ayt_bct
, &ayt_bct_len
, bct
, bct_len
, a
->y
[0]);
862 d2d_fp_scale_expansion_zeroelim(temp32a
, &temp32a_len
, ayt_bct
, ayt_bct_len
, 2.0f
* a
->y
[1]);
863 d2d_fp_fast_expansion_sum_zeroelim(temp48
, &temp48_len
, temp16a
, temp16a_len
, temp32a
, temp32a_len
);
864 d2d_fp_fast_expansion_sum_zeroelim(fin
->other
, &fin
->length
, fin
->now
, fin
->length
, temp48
, temp48_len
);
865 swap
= fin
->now
; fin
->now
= fin
->other
; fin
->other
= swap
;
867 /* fin += a->y[0] * (bct * a->y[0] + bctt * (2.0f * a->y[1] + a->y[0])) */
868 d2d_fp_scale_expansion_zeroelim(temp32a
, &temp32a_len
, ayt_bct
, ayt_bct_len
, a
->y
[0]);
869 d2d_fp_scale_expansion_zeroelim(ayt_bctt
, &ayt_bctt_len
, bctt
, bctt_len
, a
->y
[0]);
870 d2d_fp_scale_expansion_zeroelim(temp16a
, &temp16a_len
, ayt_bctt
, ayt_bctt_len
, 2.0f
* a
->y
[1]);
871 d2d_fp_scale_expansion_zeroelim(temp16b
, &temp16b_len
, ayt_bctt
, ayt_bctt_len
, a
->y
[0]);
872 d2d_fp_fast_expansion_sum_zeroelim(temp32b
, &temp32b_len
, temp16a
, temp16a_len
, temp16b
, temp16b_len
);
873 d2d_fp_fast_expansion_sum_zeroelim(temp64
, &temp64_len
, temp32a
, temp32a_len
, temp32b
, temp32b_len
);
874 d2d_fp_fast_expansion_sum_zeroelim(fin
->other
, &fin
->length
, fin
->now
, fin
->length
, temp64
, temp64_len
);
875 swap
= fin
->now
; fin
->now
= fin
->other
; fin
->other
= swap
;
879 /* Determine if point D is inside or outside the circle defined by points A,
880 * B, C. As explained in the paper by Guibas and Stolfi, this is equivalent to
881 * calculating the signed volume of the tetrahedron defined by projecting the
882 * points onto the paraboloid of revolution x = x² + y²,
883 * λ:(x, y) → (x, y, x² + y²). I.e., D is inside the cirlce if
890 * After translating D to the origin, that becomes:
896 * This implementation is based on the paper "Adaptive Precision
897 * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
898 * associated (Public Domain) code by Jonathan Richard Shewchuk. */
899 static BOOL
d2d_cdt_incircle(const struct d2d_cdt
*cdt
, size_t a
, size_t b
, size_t c
, size_t d
)
901 static const float err_bound_result
= (3.0f
+ 8.0f
* D2D_FP_EPS
) * D2D_FP_EPS
;
902 static const float err_bound_a
= (10.0f
+ 96.0f
* D2D_FP_EPS
) * D2D_FP_EPS
;
903 static const float err_bound_b
= (4.0f
+ 48.0f
* D2D_FP_EPS
) * D2D_FP_EPS
;
904 static const float err_bound_c
= (44.0f
+ 576.0f
* D2D_FP_EPS
) * D2D_FP_EPS
* D2D_FP_EPS
;
906 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
;
907 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];
908 float fin1
[1152], fin2
[1152], temp64
[64], sub_det_a
[32], sub_det_b
[32], sub_det_c
[32];
909 float det_bc
[4], det_ca
[4], det_ab
[4], daz
[4], dbz
[4], dcz
[4], temp2a
[2], temp2b
[2];
910 size_t temp64_len
, sub_det_a_len
, sub_det_b_len
, sub_det_c_len
;
911 float dbxdcy
, dbydcx
, dcxday
, dcydax
, daxdby
, daydbx
;
912 const D2D1_POINT_2F
*p
= cdt
->vertices
;
913 struct d2d_fp_two_vec2 da
, db
, dc
;
914 float permanent
, err_bound
, det
;
915 struct d2d_fp_fin fin
;
917 da
.x
[1] = p
[a
].x
- p
[d
].x
;
918 da
.y
[1] = p
[a
].y
- p
[d
].y
;
919 db
.x
[1] = p
[b
].x
- p
[d
].x
;
920 db
.y
[1] = p
[b
].y
- p
[d
].y
;
921 dc
.x
[1] = p
[c
].x
- p
[d
].x
;
922 dc
.y
[1] = p
[c
].y
- p
[d
].y
;
924 daz
[3] = da
.x
[1] * da
.x
[1] + da
.y
[1] * da
.y
[1];
925 dbxdcy
= db
.x
[1] * dc
.y
[1];
926 dbydcx
= db
.y
[1] * dc
.x
[1];
928 dbz
[3] = db
.x
[1] * db
.x
[1] + db
.y
[1] * db
.y
[1];
929 dcxday
= dc
.x
[1] * da
.y
[1];
930 dcydax
= dc
.y
[1] * da
.x
[1];
932 dcz
[3] = dc
.x
[1] * dc
.x
[1] + dc
.y
[1] * dc
.y
[1];
933 daxdby
= da
.x
[1] * db
.y
[1];
934 daydbx
= da
.y
[1] * db
.x
[1];
936 det
= daz
[3] * (dbxdcy
- dbydcx
) + dbz
[3] * (dcxday
- dcydax
) + dcz
[3] * (daxdby
- daydbx
);
937 permanent
= daz
[3] * (fabsf(dbxdcy
) + fabsf(dbydcx
))
938 + dbz
[3] * (fabsf(dcxday
) + fabsf(dcydax
))
939 + dcz
[3] * (fabsf(daxdby
) + fabsf(daydbx
));
940 err_bound
= err_bound_a
* permanent
;
941 if (det
> err_bound
|| -det
> err_bound
)
947 d2d_fp_four_det2x2(det_bc
, db
.x
[1], db
.y
[1], dc
.x
[1], dc
.y
[1]);
948 d2d_fp_sub_det3x3(sub_det_a
, &sub_det_a_len
, &da
, det_bc
);
950 d2d_fp_four_det2x2(det_ca
, dc
.x
[1], dc
.y
[1], da
.x
[1], da
.y
[1]);
951 d2d_fp_sub_det3x3(sub_det_b
, &sub_det_b_len
, &db
, det_ca
);
953 d2d_fp_four_det2x2(det_ab
, da
.x
[1], da
.y
[1], db
.x
[1], db
.y
[1]);
954 d2d_fp_sub_det3x3(sub_det_c
, &sub_det_c_len
, &dc
, det_ab
);
956 d2d_fp_fast_expansion_sum_zeroelim(temp64
, &temp64_len
, sub_det_a
, sub_det_a_len
, sub_det_b
, sub_det_b_len
);
957 d2d_fp_fast_expansion_sum_zeroelim(fin
.now
, &fin
.length
, temp64
, temp64_len
, sub_det_c
, sub_det_c_len
);
958 det
= d2d_fp_estimate(fin
.now
, fin
.length
);
959 err_bound
= err_bound_b
* permanent
;
960 if (det
>= err_bound
|| -det
>= err_bound
)
963 d2d_fp_two_diff_tail(&da
.x
[0], p
[a
].x
, p
[d
].x
, da
.x
[1]);
964 d2d_fp_two_diff_tail(&da
.y
[0], p
[a
].y
, p
[d
].y
, da
.y
[1]);
965 d2d_fp_two_diff_tail(&db
.x
[0], p
[b
].x
, p
[d
].x
, db
.x
[1]);
966 d2d_fp_two_diff_tail(&db
.y
[0], p
[b
].y
, p
[d
].y
, db
.y
[1]);
967 d2d_fp_two_diff_tail(&dc
.x
[0], p
[c
].x
, p
[d
].x
, dc
.x
[1]);
968 d2d_fp_two_diff_tail(&dc
.y
[0], p
[c
].y
, p
[d
].y
, dc
.y
[1]);
969 if (da
.x
[0] == 0.0f
&& db
.x
[0] == 0.0f
&& dc
.x
[0] == 0.0f
970 && da
.y
[0] == 0.0f
&& db
.y
[0] == 0.0f
&& dc
.y
[0] == 0.0f
)
973 err_bound
= err_bound_c
* permanent
+ err_bound_result
* fabsf(det
);
974 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]))
975 + 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]))
976 + (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]))
977 + 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]))
978 + (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]))
979 + 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]));
980 if (det
>= err_bound
|| -det
>= err_bound
)
983 if (db
.x
[0] != 0.0f
|| db
.y
[0] != 0.0f
|| dc
.x
[0] != 0.0f
|| dc
.y
[0] != 0.0f
)
985 d2d_fp_square(temp2a
, da
.x
[1]);
986 d2d_fp_square(temp2b
, da
.y
[1]);
987 d2d_fp_two_two_sum(daz
, temp2a
, temp2b
);
989 if (dc
.x
[0] != 0.0f
|| dc
.y
[0] != 0.0f
|| da
.x
[0] != 0.0f
|| da
.y
[0] != 0.0f
)
991 d2d_fp_square(temp2a
, db
.x
[1]);
992 d2d_fp_square(temp2b
, db
.y
[1]);
993 d2d_fp_two_two_sum(dbz
, temp2a
, temp2b
);
995 if (da
.x
[0] != 0.0f
|| da
.y
[0] != 0.0f
|| db
.x
[0] != 0.0f
|| db
.y
[0] != 0.0f
)
997 d2d_fp_square(temp2a
, dc
.x
[1]);
998 d2d_fp_square(temp2b
, dc
.y
[1]);
999 d2d_fp_two_two_sum(dcz
, temp2a
, temp2b
);
1002 if (da
.x
[0] != 0.0f
)
1003 d2d_cdt_incircle_refine1(&fin
, axt_det_bc
, &axt_det_bc_len
, det_bc
, dc
.y
[1], dcz
, db
.y
[1], dbz
, da
.x
);
1004 if (da
.y
[0] != 0.0f
)
1005 d2d_cdt_incircle_refine1(&fin
, ayt_det_bc
, &ayt_det_bc_len
, det_bc
, db
.x
[1], dbz
, dc
.x
[1], dcz
, da
.y
);
1006 if (db
.x
[0] != 0.0f
)
1007 d2d_cdt_incircle_refine1(&fin
, bxt_det_ca
, &bxt_det_ca_len
, det_ca
, da
.y
[1], daz
, dc
.y
[1], dcz
, db
.x
);
1008 if (db
.y
[0] != 0.0f
)
1009 d2d_cdt_incircle_refine1(&fin
, byt_det_ca
, &byt_det_ca_len
, det_ca
, dc
.x
[1], dcz
, da
.x
[1], daz
, db
.y
);
1010 if (dc
.x
[0] != 0.0f
)
1011 d2d_cdt_incircle_refine1(&fin
, cxt_det_ab
, &cxt_det_ab_len
, det_ab
, db
.y
[1], dbz
, da
.y
[1], daz
, dc
.x
);
1012 if (dc
.y
[0] != 0.0f
)
1013 d2d_cdt_incircle_refine1(&fin
, cyt_det_ab
, &cyt_det_ab_len
, det_ab
, da
.x
[1], daz
, db
.x
[1], dbz
, dc
.y
);
1015 if (da
.x
[0] != 0.0f
|| da
.y
[0] != 0.0f
)
1016 d2d_cdt_incircle_refine2(&fin
, &da
, &db
, dbz
, &dc
, dcz
,
1017 axt_det_bc
, axt_det_bc_len
, ayt_det_bc
, ayt_det_bc_len
);
1018 if (db
.x
[0] != 0.0f
|| db
.y
[0] != 0.0f
)
1019 d2d_cdt_incircle_refine2(&fin
, &db
, &dc
, dcz
, &da
, daz
,
1020 bxt_det_ca
, bxt_det_ca_len
, byt_det_ca
, byt_det_ca_len
);
1021 if (dc
.x
[0] != 0.0f
|| dc
.y
[0] != 0.0f
)
1022 d2d_cdt_incircle_refine2(&fin
, &dc
, &da
, daz
, &db
, dbz
,
1023 cxt_det_ab
, cxt_det_ab_len
, cyt_det_ab
, cyt_det_ab_len
);
1025 return fin
.now
[fin
.length
- 1] > 0.0f
;
1028 static void d2d_cdt_splice(const struct d2d_cdt
*cdt
, const struct d2d_cdt_edge_ref
*a
,
1029 const struct d2d_cdt_edge_ref
*b
)
1031 struct d2d_cdt_edge_ref ta
, tb
, alpha
, beta
;
1033 ta
= cdt
->edges
[a
->idx
].next
[a
->r
];
1034 tb
= cdt
->edges
[b
->idx
].next
[b
->r
];
1035 cdt
->edges
[a
->idx
].next
[a
->r
] = tb
;
1036 cdt
->edges
[b
->idx
].next
[b
->r
] = ta
;
1038 d2d_cdt_edge_rot(&alpha
, &ta
);
1039 d2d_cdt_edge_rot(&beta
, &tb
);
1041 ta
= cdt
->edges
[alpha
.idx
].next
[alpha
.r
];
1042 tb
= cdt
->edges
[beta
.idx
].next
[beta
.r
];
1043 cdt
->edges
[alpha
.idx
].next
[alpha
.r
] = tb
;
1044 cdt
->edges
[beta
.idx
].next
[beta
.r
] = ta
;
1047 static BOOL
d2d_cdt_create_edge(struct d2d_cdt
*cdt
, struct d2d_cdt_edge_ref
*e
)
1049 struct d2d_cdt_edge
*edge
;
1051 if (cdt
->free_edge
!= ~0u)
1053 e
->idx
= cdt
->free_edge
;
1054 cdt
->free_edge
= cdt
->edges
[e
->idx
].next
[D2D_EDGE_NEXT_ORIGIN
].idx
;
1058 if (!d2d_array_reserve((void **)&cdt
->edges
, &cdt
->edges_size
, cdt
->edge_count
+ 1, sizeof(*cdt
->edges
)))
1060 ERR("Failed to grow edges array.\n");
1063 e
->idx
= cdt
->edge_count
++;
1067 edge
= &cdt
->edges
[e
->idx
];
1068 edge
->next
[D2D_EDGE_NEXT_ORIGIN
] = *e
;
1069 d2d_cdt_edge_tor(&edge
->next
[D2D_EDGE_NEXT_ROT
], e
);
1070 d2d_cdt_edge_sym(&edge
->next
[D2D_EDGE_NEXT_SYM
], e
);
1071 d2d_cdt_edge_rot(&edge
->next
[D2D_EDGE_NEXT_TOR
], e
);
1077 static void d2d_cdt_destroy_edge(struct d2d_cdt
*cdt
, const struct d2d_cdt_edge_ref
*e
)
1079 struct d2d_cdt_edge_ref next
, sym
, prev
;
1081 d2d_cdt_edge_next_origin(cdt
, &next
, e
);
1082 if (next
.idx
!= e
->idx
|| next
.r
!= e
->r
)
1084 d2d_cdt_edge_prev_origin(cdt
, &prev
, e
);
1085 d2d_cdt_splice(cdt
, e
, &prev
);
1088 d2d_cdt_edge_sym(&sym
, e
);
1090 d2d_cdt_edge_next_origin(cdt
, &next
, &sym
);
1091 if (next
.idx
!= sym
.idx
|| next
.r
!= sym
.r
)
1093 d2d_cdt_edge_prev_origin(cdt
, &prev
, &sym
);
1094 d2d_cdt_splice(cdt
, &sym
, &prev
);
1097 cdt
->edges
[e
->idx
].flags
|= D2D_CDT_EDGE_FLAG_FREED
;
1098 cdt
->edges
[e
->idx
].next
[D2D_EDGE_NEXT_ORIGIN
].idx
= cdt
->free_edge
;
1099 cdt
->free_edge
= e
->idx
;
1102 static BOOL
d2d_cdt_connect(struct d2d_cdt
*cdt
, struct d2d_cdt_edge_ref
*e
,
1103 const struct d2d_cdt_edge_ref
*a
, const struct d2d_cdt_edge_ref
*b
)
1105 struct d2d_cdt_edge_ref tmp
;
1107 if (!d2d_cdt_create_edge(cdt
, e
))
1109 d2d_cdt_edge_set_origin(cdt
, e
, d2d_cdt_edge_destination(cdt
, a
));
1110 d2d_cdt_edge_set_destination(cdt
, e
, d2d_cdt_edge_origin(cdt
, b
));
1111 d2d_cdt_edge_next_left(cdt
, &tmp
, a
);
1112 d2d_cdt_splice(cdt
, e
, &tmp
);
1113 d2d_cdt_edge_sym(&tmp
, e
);
1114 d2d_cdt_splice(cdt
, &tmp
, b
);
1119 static BOOL
d2d_cdt_merge(struct d2d_cdt
*cdt
, struct d2d_cdt_edge_ref
*left_outer
,
1120 struct d2d_cdt_edge_ref
*left_inner
, struct d2d_cdt_edge_ref
*right_inner
,
1121 struct d2d_cdt_edge_ref
*right_outer
)
1123 struct d2d_cdt_edge_ref base_edge
, tmp
;
1125 /* Create the base edge between both parts. */
1128 if (d2d_cdt_leftof(cdt
, d2d_cdt_edge_origin(cdt
, right_inner
), left_inner
))
1130 d2d_cdt_edge_next_left(cdt
, left_inner
, left_inner
);
1132 else if (d2d_cdt_rightof(cdt
, d2d_cdt_edge_origin(cdt
, left_inner
), right_inner
))
1134 d2d_cdt_edge_sym(&tmp
, right_inner
);
1135 d2d_cdt_edge_next_origin(cdt
, right_inner
, &tmp
);
1143 d2d_cdt_edge_sym(&tmp
, right_inner
);
1144 if (!d2d_cdt_connect(cdt
, &base_edge
, &tmp
, left_inner
))
1146 if (d2d_cdt_edge_origin(cdt
, left_inner
) == d2d_cdt_edge_origin(cdt
, left_outer
))
1147 d2d_cdt_edge_sym(left_outer
, &base_edge
);
1148 if (d2d_cdt_edge_origin(cdt
, right_inner
) == d2d_cdt_edge_origin(cdt
, right_outer
))
1149 *right_outer
= base_edge
;
1153 struct d2d_cdt_edge_ref left_candidate
, right_candidate
, sym_base_edge
;
1154 BOOL left_valid
, right_valid
;
1156 /* Find the left candidate. */
1157 d2d_cdt_edge_sym(&sym_base_edge
, &base_edge
);
1158 d2d_cdt_edge_next_origin(cdt
, &left_candidate
, &sym_base_edge
);
1159 if ((left_valid
= d2d_cdt_leftof(cdt
, d2d_cdt_edge_destination(cdt
, &left_candidate
), &sym_base_edge
)))
1161 d2d_cdt_edge_next_origin(cdt
, &tmp
, &left_candidate
);
1162 while (d2d_cdt_edge_destination(cdt
, &tmp
) != d2d_cdt_edge_destination(cdt
, &sym_base_edge
)
1163 && d2d_cdt_incircle(cdt
,
1164 d2d_cdt_edge_origin(cdt
, &sym_base_edge
), d2d_cdt_edge_destination(cdt
, &sym_base_edge
),
1165 d2d_cdt_edge_destination(cdt
, &left_candidate
), d2d_cdt_edge_destination(cdt
, &tmp
)))
1167 d2d_cdt_destroy_edge(cdt
, &left_candidate
);
1168 left_candidate
= tmp
;
1169 d2d_cdt_edge_next_origin(cdt
, &tmp
, &left_candidate
);
1172 d2d_cdt_edge_sym(&left_candidate
, &left_candidate
);
1174 /* Find the right candidate. */
1175 d2d_cdt_edge_prev_origin(cdt
, &right_candidate
, &base_edge
);
1176 if ((right_valid
= d2d_cdt_rightof(cdt
, d2d_cdt_edge_destination(cdt
, &right_candidate
), &base_edge
)))
1178 d2d_cdt_edge_prev_origin(cdt
, &tmp
, &right_candidate
);
1179 while (d2d_cdt_edge_destination(cdt
, &tmp
) != d2d_cdt_edge_destination(cdt
, &base_edge
)
1180 && d2d_cdt_incircle(cdt
,
1181 d2d_cdt_edge_origin(cdt
, &sym_base_edge
), d2d_cdt_edge_destination(cdt
, &sym_base_edge
),
1182 d2d_cdt_edge_destination(cdt
, &right_candidate
), d2d_cdt_edge_destination(cdt
, &tmp
)))
1184 d2d_cdt_destroy_edge(cdt
, &right_candidate
);
1185 right_candidate
= tmp
;
1186 d2d_cdt_edge_prev_origin(cdt
, &tmp
, &right_candidate
);
1190 if (!left_valid
&& !right_valid
)
1193 /* Connect the appropriate candidate with the base edge. */
1194 if (!left_valid
|| (right_valid
&& d2d_cdt_incircle(cdt
,
1195 d2d_cdt_edge_origin(cdt
, &left_candidate
), d2d_cdt_edge_destination(cdt
, &left_candidate
),
1196 d2d_cdt_edge_origin(cdt
, &right_candidate
), d2d_cdt_edge_destination(cdt
, &right_candidate
))))
1198 if (!d2d_cdt_connect(cdt
, &base_edge
, &right_candidate
, &sym_base_edge
))
1203 if (!d2d_cdt_connect(cdt
, &base_edge
, &sym_base_edge
, &left_candidate
))
1211 /* Create a Delaunay triangulation from a set of vertices. This is an
1212 * implementation of the divide-and-conquer algorithm described by Guibas and
1213 * Stolfi. Should be called with at least two vertices. */
1214 static BOOL
d2d_cdt_triangulate(struct d2d_cdt
*cdt
, size_t start_vertex
, size_t vertex_count
,
1215 struct d2d_cdt_edge_ref
*left_edge
, struct d2d_cdt_edge_ref
*right_edge
)
1217 struct d2d_cdt_edge_ref left_inner
, left_outer
, right_inner
, right_outer
, tmp
;
1220 /* Only two vertices, create a single edge. */
1221 if (vertex_count
== 2)
1223 struct d2d_cdt_edge_ref a
;
1225 if (!d2d_cdt_create_edge(cdt
, &a
))
1227 d2d_cdt_edge_set_origin(cdt
, &a
, start_vertex
);
1228 d2d_cdt_edge_set_destination(cdt
, &a
, start_vertex
+ 1);
1231 d2d_cdt_edge_sym(right_edge
, &a
);
1236 /* Three vertices, create a triangle. */
1237 if (vertex_count
== 3)
1239 struct d2d_cdt_edge_ref a
, b
, c
;
1242 if (!d2d_cdt_create_edge(cdt
, &a
))
1244 if (!d2d_cdt_create_edge(cdt
, &b
))
1246 d2d_cdt_edge_sym(&tmp
, &a
);
1247 d2d_cdt_splice(cdt
, &tmp
, &b
);
1249 d2d_cdt_edge_set_origin(cdt
, &a
, start_vertex
);
1250 d2d_cdt_edge_set_destination(cdt
, &a
, start_vertex
+ 1);
1251 d2d_cdt_edge_set_origin(cdt
, &b
, start_vertex
+ 1);
1252 d2d_cdt_edge_set_destination(cdt
, &b
, start_vertex
+ 2);
1254 det
= d2d_cdt_ccw(cdt
, start_vertex
, start_vertex
+ 1, start_vertex
+ 2);
1255 if (det
!= 0.0f
&& !d2d_cdt_connect(cdt
, &c
, &b
, &a
))
1260 d2d_cdt_edge_sym(left_edge
, &c
);
1266 d2d_cdt_edge_sym(right_edge
, &b
);
1272 /* More than tree vertices, divide. */
1273 cut
= vertex_count
/ 2;
1274 if (!d2d_cdt_triangulate(cdt
, start_vertex
, cut
, &left_outer
, &left_inner
))
1276 if (!d2d_cdt_triangulate(cdt
, start_vertex
+ cut
, vertex_count
- cut
, &right_inner
, &right_outer
))
1278 /* Merge the left and right parts. */
1279 if (!d2d_cdt_merge(cdt
, &left_outer
, &left_inner
, &right_inner
, &right_outer
))
1282 *left_edge
= left_outer
;
1283 *right_edge
= right_outer
;
1287 static int __cdecl
d2d_cdt_compare_vertices(const void *a
, const void *b
)
1289 const D2D1_POINT_2F
*p0
= a
;
1290 const D2D1_POINT_2F
*p1
= b
;
1291 float diff
= p0
->x
- p1
->x
;
1294 diff
= p0
->y
- p1
->y
;
1296 return diff
== 0.0f
? 0 : (diff
> 0.0f
? 1 : -1);
1299 /* Determine whether a given point is inside the geometry, using the current
1300 * fill mode rule. */
1301 static BOOL
d2d_path_geometry_point_inside(const struct d2d_geometry
*geometry
,
1302 const D2D1_POINT_2F
*probe
, BOOL triangles_only
)
1304 const D2D1_POINT_2F
*p0
, *p1
;
1305 D2D1_POINT_2F v_p
, v_probe
;
1309 for (i
= 0, score
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
1311 const struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[i
];
1313 if (probe
->x
< figure
->bounds
.left
|| probe
->x
> figure
->bounds
.right
1314 || probe
->y
< figure
->bounds
.top
|| probe
->y
> figure
->bounds
.bottom
)
1317 last
= figure
->vertex_count
- 1;
1318 if (!triangles_only
)
1320 while (last
&& figure
->vertex_types
[last
] == D2D_VERTEX_TYPE_NONE
)
1323 p0
= &figure
->vertices
[last
];
1324 for (j
= 0; j
<= last
; ++j
)
1326 if (!triangles_only
&& figure
->vertex_types
[j
] == D2D_VERTEX_TYPE_NONE
)
1329 p1
= &figure
->vertices
[j
];
1330 d2d_point_subtract(&v_p
, p1
, p0
);
1331 d2d_point_subtract(&v_probe
, probe
, p0
);
1333 if ((probe
->y
< p0
->y
) != (probe
->y
< p1
->y
) && v_probe
.x
< v_p
.x
* (v_probe
.y
/ v_p
.y
))
1335 if (geometry
->u
.path
.fill_mode
== D2D1_FILL_MODE_ALTERNATE
|| (probe
->y
< p0
->y
))
1345 return geometry
->u
.path
.fill_mode
== D2D1_FILL_MODE_ALTERNATE
? score
& 1 : score
;
1348 static BOOL
d2d_path_geometry_add_fill_face(struct d2d_geometry
*geometry
, const struct d2d_cdt
*cdt
,
1349 const struct d2d_cdt_edge_ref
*base_edge
)
1351 struct d2d_cdt_edge_ref tmp
;
1352 struct d2d_face
*face
;
1353 D2D1_POINT_2F probe
;
1355 if (cdt
->edges
[base_edge
->idx
].flags
& D2D_CDT_EDGE_FLAG_VISITED(base_edge
->r
))
1358 if (!d2d_array_reserve((void **)&geometry
->fill
.faces
, &geometry
->fill
.faces_size
,
1359 geometry
->fill
.face_count
+ 1, sizeof(*geometry
->fill
.faces
)))
1361 ERR("Failed to grow faces array.\n");
1365 face
= &geometry
->fill
.faces
[geometry
->fill
.face_count
];
1367 /* It may seem tempting to use the center of the face as probe origin, but
1368 * multiplying by powers of two works much better for preserving accuracy. */
1371 cdt
->edges
[tmp
.idx
].flags
|= D2D_CDT_EDGE_FLAG_VISITED(tmp
.r
);
1372 face
->v
[0] = d2d_cdt_edge_origin(cdt
, &tmp
);
1373 probe
.x
= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].x
* 0.25f
;
1374 probe
.y
= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].y
* 0.25f
;
1376 d2d_cdt_edge_next_left(cdt
, &tmp
, &tmp
);
1377 cdt
->edges
[tmp
.idx
].flags
|= D2D_CDT_EDGE_FLAG_VISITED(tmp
.r
);
1378 face
->v
[1] = d2d_cdt_edge_origin(cdt
, &tmp
);
1379 probe
.x
+= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].x
* 0.25f
;
1380 probe
.y
+= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].y
* 0.25f
;
1382 d2d_cdt_edge_next_left(cdt
, &tmp
, &tmp
);
1383 cdt
->edges
[tmp
.idx
].flags
|= D2D_CDT_EDGE_FLAG_VISITED(tmp
.r
);
1384 face
->v
[2] = d2d_cdt_edge_origin(cdt
, &tmp
);
1385 probe
.x
+= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].x
* 0.50f
;
1386 probe
.y
+= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].y
* 0.50f
;
1388 if (d2d_cdt_leftof(cdt
, face
->v
[2], base_edge
) && d2d_path_geometry_point_inside(geometry
, &probe
, TRUE
))
1389 ++geometry
->fill
.face_count
;
1394 static BOOL
d2d_cdt_generate_faces(const struct d2d_cdt
*cdt
, struct d2d_geometry
*geometry
)
1396 struct d2d_cdt_edge_ref base_edge
;
1399 for (i
= 0; i
< cdt
->edge_count
; ++i
)
1401 if (cdt
->edges
[i
].flags
& D2D_CDT_EDGE_FLAG_FREED
)
1406 if (!d2d_path_geometry_add_fill_face(geometry
, cdt
, &base_edge
))
1408 d2d_cdt_edge_sym(&base_edge
, &base_edge
);
1409 if (!d2d_path_geometry_add_fill_face(geometry
, cdt
, &base_edge
))
1416 heap_free(geometry
->fill
.faces
);
1417 geometry
->fill
.faces
= NULL
;
1418 geometry
->fill
.faces_size
= 0;
1419 geometry
->fill
.face_count
= 0;
1423 static BOOL
d2d_cdt_fixup(struct d2d_cdt
*cdt
, const struct d2d_cdt_edge_ref
*base_edge
)
1425 struct d2d_cdt_edge_ref candidate
, next
, new_base
;
1426 unsigned int count
= 0;
1428 d2d_cdt_edge_next_left(cdt
, &next
, base_edge
);
1429 if (next
.idx
== base_edge
->idx
)
1431 ERR("Degenerate face.\n");
1436 while (d2d_cdt_edge_destination(cdt
, &next
) != d2d_cdt_edge_origin(cdt
, base_edge
))
1438 if (d2d_cdt_incircle(cdt
, d2d_cdt_edge_origin(cdt
, base_edge
), d2d_cdt_edge_destination(cdt
, base_edge
),
1439 d2d_cdt_edge_destination(cdt
, &candidate
), d2d_cdt_edge_destination(cdt
, &next
)))
1441 d2d_cdt_edge_next_left(cdt
, &next
, &next
);
1447 d2d_cdt_edge_next_left(cdt
, &next
, &candidate
);
1448 if (d2d_cdt_edge_destination(cdt
, &next
) == d2d_cdt_edge_origin(cdt
, base_edge
))
1449 d2d_cdt_edge_next_left(cdt
, &next
, base_edge
);
1452 if (!d2d_cdt_connect(cdt
, &new_base
, &candidate
, &next
))
1454 if (!d2d_cdt_fixup(cdt
, &new_base
))
1456 d2d_cdt_edge_sym(&new_base
, &new_base
);
1457 if (!d2d_cdt_fixup(cdt
, &new_base
))
1464 static void d2d_cdt_cut_edges(struct d2d_cdt
*cdt
, struct d2d_cdt_edge_ref
*end_edge
,
1465 const struct d2d_cdt_edge_ref
*base_edge
, size_t start_vertex
, size_t end_vertex
)
1467 struct d2d_cdt_edge_ref next
;
1470 d2d_cdt_edge_next_left(cdt
, &next
, base_edge
);
1471 if (d2d_cdt_edge_destination(cdt
, &next
) == end_vertex
)
1477 ccw
= d2d_cdt_ccw(cdt
, d2d_cdt_edge_destination(cdt
, &next
), end_vertex
, start_vertex
);
1485 d2d_cdt_edge_next_left(cdt
, &next
, &next
);
1487 d2d_cdt_edge_sym(&next
, &next
);
1488 d2d_cdt_cut_edges(cdt
, end_edge
, &next
, start_vertex
, end_vertex
);
1489 d2d_cdt_destroy_edge(cdt
, &next
);
1492 static BOOL
d2d_cdt_insert_segment(struct d2d_cdt
*cdt
, struct d2d_geometry
*geometry
,
1493 const struct d2d_cdt_edge_ref
*origin
, struct d2d_cdt_edge_ref
*edge
, size_t end_vertex
)
1495 struct d2d_cdt_edge_ref base_edge
, current
, new_origin
, next
, target
;
1496 size_t current_destination
, current_origin
;
1498 for (current
= *origin
;; current
= next
)
1500 d2d_cdt_edge_next_origin(cdt
, &next
, ¤t
);
1502 current_destination
= d2d_cdt_edge_destination(cdt
, ¤t
);
1503 if (current_destination
== end_vertex
)
1505 d2d_cdt_edge_sym(edge
, ¤t
);
1509 current_origin
= d2d_cdt_edge_origin(cdt
, ¤t
);
1510 if (d2d_cdt_ccw(cdt
, end_vertex
, current_origin
, current_destination
) == 0.0f
1511 && (cdt
->vertices
[current_destination
].x
> cdt
->vertices
[current_origin
].x
)
1512 == (cdt
->vertices
[end_vertex
].x
> cdt
->vertices
[current_origin
].x
)
1513 && (cdt
->vertices
[current_destination
].y
> cdt
->vertices
[current_origin
].y
)
1514 == (cdt
->vertices
[end_vertex
].y
> cdt
->vertices
[current_origin
].y
))
1516 d2d_cdt_edge_sym(&new_origin
, ¤t
);
1517 return d2d_cdt_insert_segment(cdt
, geometry
, &new_origin
, edge
, end_vertex
);
1520 if (d2d_cdt_rightof(cdt
, end_vertex
, &next
) && d2d_cdt_leftof(cdt
, end_vertex
, ¤t
))
1522 d2d_cdt_edge_next_left(cdt
, &base_edge
, ¤t
);
1524 d2d_cdt_edge_sym(&base_edge
, &base_edge
);
1525 d2d_cdt_cut_edges(cdt
, &target
, &base_edge
, d2d_cdt_edge_origin(cdt
, origin
), end_vertex
);
1526 d2d_cdt_destroy_edge(cdt
, &base_edge
);
1528 if (!d2d_cdt_connect(cdt
, &base_edge
, &target
, ¤t
))
1531 if (!d2d_cdt_fixup(cdt
, &base_edge
))
1533 d2d_cdt_edge_sym(&base_edge
, &base_edge
);
1534 if (!d2d_cdt_fixup(cdt
, &base_edge
))
1537 if (d2d_cdt_edge_origin(cdt
, edge
) == end_vertex
)
1540 return d2d_cdt_insert_segment(cdt
, geometry
, &new_origin
, edge
, end_vertex
);
1543 if (next
.idx
== origin
->idx
)
1545 ERR("Triangle not found.\n");
1551 static BOOL
d2d_cdt_insert_segments(struct d2d_cdt
*cdt
, struct d2d_geometry
*geometry
)
1553 size_t start_vertex
, end_vertex
, i
, j
, k
;
1554 struct d2d_cdt_edge_ref edge
, new_edge
;
1555 const struct d2d_figure
*figure
;
1556 const D2D1_POINT_2F
*p
;
1559 for (i
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
1561 figure
= &geometry
->u
.path
.figures
[i
];
1563 if (figure
->flags
& D2D_FIGURE_FLAG_HOLLOW
)
1566 /* Degenerate figure. */
1567 if (figure
->vertex_count
< 2)
1570 p
= bsearch(&figure
->vertices
[figure
->vertex_count
- 1], cdt
->vertices
,
1571 geometry
->fill
.vertex_count
, sizeof(*p
), d2d_cdt_compare_vertices
);
1572 start_vertex
= p
- cdt
->vertices
;
1574 for (k
= 0, found
= FALSE
; k
< cdt
->edge_count
; ++k
)
1576 if (cdt
->edges
[k
].flags
& D2D_CDT_EDGE_FLAG_FREED
)
1582 if (d2d_cdt_edge_origin(cdt
, &edge
) == start_vertex
)
1587 d2d_cdt_edge_sym(&edge
, &edge
);
1588 if (d2d_cdt_edge_origin(cdt
, &edge
) == start_vertex
)
1597 ERR("Edge not found.\n");
1601 for (j
= 0; j
< figure
->vertex_count
; start_vertex
= end_vertex
, ++j
)
1603 p
= bsearch(&figure
->vertices
[j
], cdt
->vertices
,
1604 geometry
->fill
.vertex_count
, sizeof(*p
), d2d_cdt_compare_vertices
);
1605 end_vertex
= p
- cdt
->vertices
;
1607 if (start_vertex
== end_vertex
)
1610 if (!d2d_cdt_insert_segment(cdt
, geometry
, &edge
, &new_edge
, end_vertex
))
1619 static BOOL
d2d_geometry_intersections_add(struct d2d_geometry_intersections
*i
,
1620 const struct d2d_segment_idx
*segment_idx
, float t
, D2D1_POINT_2F p
)
1622 struct d2d_geometry_intersection
*intersection
;
1624 if (!d2d_array_reserve((void **)&i
->intersections
, &i
->intersections_size
,
1625 i
->intersection_count
+ 1, sizeof(*i
->intersections
)))
1627 ERR("Failed to grow intersections array.\n");
1631 intersection
= &i
->intersections
[i
->intersection_count
++];
1632 intersection
->figure_idx
= segment_idx
->figure_idx
;
1633 intersection
->vertex_idx
= segment_idx
->vertex_idx
;
1634 intersection
->control_idx
= segment_idx
->control_idx
;
1635 intersection
->t
= t
;
1636 intersection
->p
= p
;
1641 static int __cdecl
d2d_geometry_intersections_compare(const void *a
, const void *b
)
1643 const struct d2d_geometry_intersection
*i0
= a
;
1644 const struct d2d_geometry_intersection
*i1
= b
;
1646 if (i0
->figure_idx
!= i1
->figure_idx
)
1647 return i0
->figure_idx
- i1
->figure_idx
;
1648 if (i0
->vertex_idx
!= i1
->vertex_idx
)
1649 return i0
->vertex_idx
- i1
->vertex_idx
;
1651 return i0
->t
> i1
->t
? 1 : -1;
1655 static BOOL
d2d_geometry_intersect_line_line(struct d2d_geometry
*geometry
,
1656 struct d2d_geometry_intersections
*intersections
, const struct d2d_segment_idx
*idx_p
,
1657 const struct d2d_segment_idx
*idx_q
)
1659 D2D1_POINT_2F v_p
, v_q
, v_qp
, intersection
;
1660 const D2D1_POINT_2F
*p
[2], *q
[2];
1661 const struct d2d_figure
*figure
;
1665 figure
= &geometry
->u
.path
.figures
[idx_p
->figure_idx
];
1666 p
[0] = &figure
->vertices
[idx_p
->vertex_idx
];
1667 next
= idx_p
->vertex_idx
+ 1;
1668 if (next
== figure
->vertex_count
)
1670 p
[1] = &figure
->vertices
[next
];
1672 figure
= &geometry
->u
.path
.figures
[idx_q
->figure_idx
];
1673 q
[0] = &figure
->vertices
[idx_q
->vertex_idx
];
1674 next
= idx_q
->vertex_idx
+ 1;
1675 if (next
== figure
->vertex_count
)
1677 q
[1] = &figure
->vertices
[next
];
1679 d2d_point_subtract(&v_p
, p
[1], p
[0]);
1680 d2d_point_subtract(&v_q
, q
[1], q
[0]);
1681 d2d_point_subtract(&v_qp
, p
[0], q
[0]);
1683 det
= v_p
.x
* v_q
.y
- v_p
.y
* v_q
.x
;
1687 s
= (v_q
.x
* v_qp
.y
- v_q
.y
* v_qp
.x
) / det
;
1688 t
= (v_p
.x
* v_qp
.y
- v_p
.y
* v_qp
.x
) / det
;
1690 if (s
< 0.0f
|| s
> 1.0f
|| t
< 0.0f
|| t
> 1.0f
)
1693 intersection
.x
= p
[0]->x
+ v_p
.x
* s
;
1694 intersection
.y
= p
[0]->y
+ v_p
.y
* s
;
1696 if (s
> 0.0f
&& s
< 1.0f
&& !d2d_geometry_intersections_add(intersections
, idx_p
, s
, intersection
))
1699 if (t
> 0.0f
&& t
< 1.0f
&& !d2d_geometry_intersections_add(intersections
, idx_q
, t
, intersection
))
1705 static BOOL
d2d_geometry_add_bezier_line_intersections(struct d2d_geometry
*geometry
,
1706 struct d2d_geometry_intersections
*intersections
, const struct d2d_segment_idx
*idx_p
,
1707 const D2D1_POINT_2F
**p
, const struct d2d_segment_idx
*idx_q
, const D2D1_POINT_2F
**q
, float s
)
1709 D2D1_POINT_2F intersection
;
1712 d2d_point_calculate_bezier(&intersection
, p
[0], p
[1], p
[2], s
);
1713 if (fabsf(q
[1]->x
- q
[0]->x
) > fabsf(q
[1]->y
- q
[0]->y
))
1714 t
= (intersection
.x
- q
[0]->x
) / (q
[1]->x
- q
[0]->x
);
1716 t
= (intersection
.y
- q
[0]->y
) / (q
[1]->y
- q
[0]->y
);
1717 if (t
< 0.0f
|| t
> 1.0f
)
1720 d2d_point_lerp(&intersection
, q
[0], q
[1], t
);
1722 if (s
> 0.0f
&& s
< 1.0f
&& !d2d_geometry_intersections_add(intersections
, idx_p
, s
, intersection
))
1725 if (t
> 0.0f
&& t
< 1.0f
&& !d2d_geometry_intersections_add(intersections
, idx_q
, t
, intersection
))
1731 static BOOL
d2d_geometry_intersect_bezier_line(struct d2d_geometry
*geometry
,
1732 struct d2d_geometry_intersections
*intersections
,
1733 const struct d2d_segment_idx
*idx_p
, const struct d2d_segment_idx
*idx_q
)
1735 const D2D1_POINT_2F
*p
[3], *q
[2];
1736 const struct d2d_figure
*figure
;
1737 float y
[3], root
, theta
, d
, e
;
1740 figure
= &geometry
->u
.path
.figures
[idx_p
->figure_idx
];
1741 p
[0] = &figure
->vertices
[idx_p
->vertex_idx
];
1742 p
[1] = &figure
->bezier_controls
[idx_p
->control_idx
];
1743 next
= idx_p
->vertex_idx
+ 1;
1744 if (next
== figure
->vertex_count
)
1746 p
[2] = &figure
->vertices
[next
];
1748 figure
= &geometry
->u
.path
.figures
[idx_q
->figure_idx
];
1749 q
[0] = &figure
->vertices
[idx_q
->vertex_idx
];
1750 next
= idx_q
->vertex_idx
+ 1;
1751 if (next
== figure
->vertex_count
)
1753 q
[1] = &figure
->vertices
[next
];
1755 /* Align the line with x-axis. */
1756 theta
= -atan2f(q
[1]->y
- q
[0]->y
, q
[1]->x
- q
[0]->x
);
1757 y
[0] = (p
[0]->x
- q
[0]->x
) * sinf(theta
) + (p
[0]->y
- q
[0]->y
) * cosf(theta
);
1758 y
[1] = (p
[1]->x
- q
[0]->x
) * sinf(theta
) + (p
[1]->y
- q
[0]->y
) * cosf(theta
);
1759 y
[2] = (p
[2]->x
- q
[0]->x
) * sinf(theta
) + (p
[2]->y
- q
[0]->y
) * cosf(theta
);
1761 /* Intersect the transformed curve with the x-axis.
1763 * f(t) = (1 - t)²P₀ + 2(1 - t)tP₁ + t²P₂
1764 * = (P₀ - 2P₁ + P₂)t² + 2(P₁ - P₀)t + P₀
1771 * t = (-b ± √(b² - 4ac)) / 2a
1772 * = (-2(P₁ - P₀) ± √((2(P₁ - P₀))² - 4((P₀ - 2P₁ + P₂)P₀))) / 2(P₀ - 2P₁ + P₂)
1773 * = (2P₀ - 2P₁ ± √(4P₀² + 4P₁² - 8P₀P₁ - 4P₀² + 8P₀P₁ - 4P₀P₂)) / (2P₀ - 4P₁ + 2P₂)
1774 * = (P₀ - P₁ ± √(P₁² - P₀P₂)) / (P₀ - 2P₁ + P₂) */
1776 d
= y
[0] - 2 * y
[1] + y
[2];
1779 /* P₀ - 2P₁ + P₂ = 0
1780 * f(t) = (P₀ - 2P₁ + P₂)t² + 2(P₁ - P₀)t + P₀ = 0
1781 * t = -P₀ / 2(P₁ - P₀) */
1782 root
= -y
[0] / (2.0f
* (y
[1] - y
[0]));
1783 if (root
< 0.0f
|| root
> 1.0f
)
1786 return d2d_geometry_add_bezier_line_intersections(geometry
, intersections
, idx_p
, p
, idx_q
, q
, root
);
1789 e
= y
[1] * y
[1] - y
[0] * y
[2];
1793 root
= (y
[0] - y
[1] + sqrtf(e
)) / d
;
1794 if (root
>= 0.0f
&& root
<= 1.0f
&& !d2d_geometry_add_bezier_line_intersections(geometry
,
1795 intersections
, idx_p
, p
, idx_q
, q
, root
))
1798 root
= (y
[0] - y
[1] - sqrtf(e
)) / d
;
1799 if (root
>= 0.0f
&& root
<= 1.0f
&& !d2d_geometry_add_bezier_line_intersections(geometry
,
1800 intersections
, idx_p
, p
, idx_q
, q
, root
))
1806 static BOOL
d2d_geometry_intersect_bezier_bezier(struct d2d_geometry
*geometry
,
1807 struct d2d_geometry_intersections
*intersections
,
1808 const struct d2d_segment_idx
*idx_p
, float start_p
, float end_p
,
1809 const struct d2d_segment_idx
*idx_q
, float start_q
, float end_q
)
1811 const D2D1_POINT_2F
*p
[3], *q
[3];
1812 const struct d2d_figure
*figure
;
1813 D2D_RECT_F p_bounds
, q_bounds
;
1814 D2D1_POINT_2F intersection
;
1815 float centre_p
, centre_q
;
1818 figure
= &geometry
->u
.path
.figures
[idx_p
->figure_idx
];
1819 p
[0] = &figure
->vertices
[idx_p
->vertex_idx
];
1820 p
[1] = &figure
->bezier_controls
[idx_p
->control_idx
];
1821 next
= idx_p
->vertex_idx
+ 1;
1822 if (next
== figure
->vertex_count
)
1824 p
[2] = &figure
->vertices
[next
];
1826 figure
= &geometry
->u
.path
.figures
[idx_q
->figure_idx
];
1827 q
[0] = &figure
->vertices
[idx_q
->vertex_idx
];
1828 q
[1] = &figure
->bezier_controls
[idx_q
->control_idx
];
1829 next
= idx_q
->vertex_idx
+ 1;
1830 if (next
== figure
->vertex_count
)
1832 q
[2] = &figure
->vertices
[next
];
1834 d2d_rect_get_bezier_segment_bounds(&p_bounds
, p
[0], p
[1], p
[2], start_p
, end_p
);
1835 d2d_rect_get_bezier_segment_bounds(&q_bounds
, q
[0], q
[1], q
[2], start_q
, end_q
);
1837 if (!d2d_rect_check_overlap(&p_bounds
, &q_bounds
))
1840 centre_p
= (start_p
+ end_p
) / 2.0f
;
1841 centre_q
= (start_q
+ end_q
) / 2.0f
;
1843 if (end_p
- start_p
< 1e-3f
)
1845 d2d_point_calculate_bezier(&intersection
, p
[0], p
[1], p
[2], centre_p
);
1846 if (start_p
> 0.0f
&& end_p
< 1.0f
&& !d2d_geometry_intersections_add(intersections
,
1847 idx_p
, centre_p
, intersection
))
1849 if (start_q
> 0.0f
&& end_q
< 1.0f
&& !d2d_geometry_intersections_add(intersections
,
1850 idx_q
, centre_q
, intersection
))
1855 if (!d2d_geometry_intersect_bezier_bezier(geometry
, intersections
,
1856 idx_p
, start_p
, centre_p
, idx_q
, start_q
, centre_q
))
1858 if (!d2d_geometry_intersect_bezier_bezier(geometry
, intersections
,
1859 idx_p
, start_p
, centre_p
, idx_q
, centre_q
, end_q
))
1861 if (!d2d_geometry_intersect_bezier_bezier(geometry
, intersections
,
1862 idx_p
, centre_p
, end_p
, idx_q
, start_q
, centre_q
))
1864 if (!d2d_geometry_intersect_bezier_bezier(geometry
, intersections
,
1865 idx_p
, centre_p
, end_p
, idx_q
, centre_q
, end_q
))
1871 static BOOL
d2d_geometry_apply_intersections(struct d2d_geometry
*geometry
,
1872 struct d2d_geometry_intersections
*intersections
)
1874 size_t vertex_offset
, control_offset
, next
, i
;
1875 struct d2d_geometry_intersection
*inter
;
1876 enum d2d_vertex_type vertex_type
;
1877 const D2D1_POINT_2F
*p
[3];
1878 struct d2d_figure
*figure
;
1882 for (i
= 0; i
< intersections
->intersection_count
; ++i
)
1884 inter
= &intersections
->intersections
[i
];
1885 if (!i
|| inter
->figure_idx
!= intersections
->intersections
[i
- 1].figure_idx
)
1886 vertex_offset
= control_offset
= 0;
1888 figure
= &geometry
->u
.path
.figures
[inter
->figure_idx
];
1889 vertex_type
= figure
->vertex_types
[inter
->vertex_idx
+ vertex_offset
];
1890 if (!d2d_vertex_type_is_bezier(vertex_type
))
1892 if (!d2d_figure_insert_vertex(&geometry
->u
.path
.figures
[inter
->figure_idx
],
1893 inter
->vertex_idx
+ vertex_offset
+ 1, inter
->p
))
1900 if (i
&& inter
->figure_idx
== intersections
->intersections
[i
- 1].figure_idx
1901 && inter
->vertex_idx
== intersections
->intersections
[i
- 1].vertex_idx
)
1903 t_prev
= intersections
->intersections
[i
- 1].t
;
1904 if (t
- t_prev
< 1e-3f
)
1906 inter
->t
= intersections
->intersections
[i
- 1].t
;
1909 t
= (t
- t_prev
) / (1.0f
- t_prev
);
1912 p
[0] = &figure
->vertices
[inter
->vertex_idx
+ vertex_offset
];
1913 p
[1] = &figure
->bezier_controls
[inter
->control_idx
+ control_offset
];
1914 next
= inter
->vertex_idx
+ vertex_offset
+ 1;
1915 if (next
== figure
->vertex_count
)
1917 p
[2] = &figure
->vertices
[next
];
1919 d2d_point_lerp(&q
[0], p
[0], p
[1], t
);
1920 d2d_point_lerp(&q
[1], p
[1], p
[2], t
);
1922 figure
->bezier_controls
[inter
->control_idx
+ control_offset
] = q
[0];
1923 if (!(d2d_figure_insert_bezier_controls(figure
, inter
->control_idx
+ control_offset
+ 1, 1, &q
[1])))
1927 if (!(d2d_figure_insert_vertex(figure
, inter
->vertex_idx
+ vertex_offset
+ 1, inter
->p
)))
1929 figure
->vertex_types
[inter
->vertex_idx
+ vertex_offset
+ 1] = D2D_VERTEX_TYPE_SPLIT_BEZIER
;
1936 /* Intersect the geometry's segments with themselves. This uses the
1937 * straightforward approach of testing everything against everything, but
1938 * there certainly exist more scalable algorithms for this. */
1939 static BOOL
d2d_geometry_intersect_self(struct d2d_geometry
*geometry
)
1941 struct d2d_geometry_intersections intersections
= {0};
1942 const struct d2d_figure
*figure_p
, *figure_q
;
1943 struct d2d_segment_idx idx_p
, idx_q
;
1944 enum d2d_vertex_type type_p
, type_q
;
1948 if (!geometry
->u
.path
.figure_count
)
1951 for (idx_p
.figure_idx
= 0; idx_p
.figure_idx
< geometry
->u
.path
.figure_count
; ++idx_p
.figure_idx
)
1953 figure_p
= &geometry
->u
.path
.figures
[idx_p
.figure_idx
];
1954 idx_p
.control_idx
= 0;
1955 for (idx_p
.vertex_idx
= 0; idx_p
.vertex_idx
< figure_p
->vertex_count
; ++idx_p
.vertex_idx
)
1957 type_p
= figure_p
->vertex_types
[idx_p
.vertex_idx
];
1958 for (idx_q
.figure_idx
= 0; idx_q
.figure_idx
<= idx_p
.figure_idx
; ++idx_q
.figure_idx
)
1960 figure_q
= &geometry
->u
.path
.figures
[idx_q
.figure_idx
];
1961 if (idx_q
.figure_idx
!= idx_p
.figure_idx
)
1963 if (!d2d_rect_check_overlap(&figure_p
->bounds
, &figure_q
->bounds
))
1965 max_q
= figure_q
->vertex_count
;
1969 max_q
= idx_p
.vertex_idx
;
1972 idx_q
.control_idx
= 0;
1973 for (idx_q
.vertex_idx
= 0; idx_q
.vertex_idx
< max_q
; ++idx_q
.vertex_idx
)
1975 type_q
= figure_q
->vertex_types
[idx_q
.vertex_idx
];
1976 if (d2d_vertex_type_is_bezier(type_q
))
1978 if (d2d_vertex_type_is_bezier(type_p
))
1980 if (!d2d_geometry_intersect_bezier_bezier(geometry
, &intersections
,
1981 &idx_p
, 0.0f
, 1.0f
, &idx_q
, 0.0f
, 1.0f
))
1986 if (!d2d_geometry_intersect_bezier_line(geometry
, &intersections
, &idx_q
, &idx_p
))
1989 ++idx_q
.control_idx
;
1993 if (d2d_vertex_type_is_bezier(type_p
))
1995 if (!d2d_geometry_intersect_bezier_line(geometry
, &intersections
, &idx_p
, &idx_q
))
2000 if (!d2d_geometry_intersect_line_line(geometry
, &intersections
, &idx_p
, &idx_q
))
2006 if (d2d_vertex_type_is_bezier(type_p
))
2007 ++idx_p
.control_idx
;
2011 qsort(intersections
.intersections
, intersections
.intersection_count
,
2012 sizeof(*intersections
.intersections
), d2d_geometry_intersections_compare
);
2013 ret
= d2d_geometry_apply_intersections(geometry
, &intersections
);
2016 heap_free(intersections
.intersections
);
2020 static HRESULT
d2d_path_geometry_triangulate(struct d2d_geometry
*geometry
)
2022 struct d2d_cdt_edge_ref left_edge
, right_edge
;
2023 size_t vertex_count
, i
, j
;
2024 struct d2d_cdt cdt
= {0};
2025 D2D1_POINT_2F
*vertices
;
2027 for (i
= 0, vertex_count
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
2029 if (geometry
->u
.path
.figures
[i
].flags
& D2D_FIGURE_FLAG_HOLLOW
)
2031 vertex_count
+= geometry
->u
.path
.figures
[i
].vertex_count
;
2034 if (vertex_count
< 3)
2036 WARN("Geometry has %lu vertices.\n", (long)vertex_count
);
2040 if (!(vertices
= heap_calloc(vertex_count
, sizeof(*vertices
))))
2041 return E_OUTOFMEMORY
;
2043 for (i
= 0, j
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
2045 if (geometry
->u
.path
.figures
[i
].flags
& D2D_FIGURE_FLAG_HOLLOW
)
2047 memcpy(&vertices
[j
], geometry
->u
.path
.figures
[i
].vertices
,
2048 geometry
->u
.path
.figures
[i
].vertex_count
* sizeof(*vertices
));
2049 j
+= geometry
->u
.path
.figures
[i
].vertex_count
;
2052 /* Sort vertices, eliminate duplicates. */
2053 qsort(vertices
, vertex_count
, sizeof(*vertices
), d2d_cdt_compare_vertices
);
2054 for (i
= 1; i
< vertex_count
; ++i
)
2056 if (!memcmp(&vertices
[i
- 1], &vertices
[i
], sizeof(*vertices
)))
2059 memmove(&vertices
[i
], &vertices
[i
+ 1], (vertex_count
- i
) * sizeof(*vertices
));
2064 if (vertex_count
< 3)
2066 WARN("Geometry has %lu vertices after eliminating duplicates.\n", (long)vertex_count
);
2067 heap_free(vertices
);
2071 geometry
->fill
.vertices
= vertices
;
2072 geometry
->fill
.vertex_count
= vertex_count
;
2074 cdt
.free_edge
= ~0u;
2075 cdt
.vertices
= vertices
;
2076 if (!d2d_cdt_triangulate(&cdt
, 0, vertex_count
, &left_edge
, &right_edge
))
2078 if (!d2d_cdt_insert_segments(&cdt
, geometry
))
2080 if (!d2d_cdt_generate_faces(&cdt
, geometry
))
2083 heap_free(cdt
.edges
);
2087 geometry
->fill
.vertices
= NULL
;
2088 geometry
->fill
.vertex_count
= 0;
2089 heap_free(vertices
);
2090 heap_free(cdt
.edges
);
2094 static BOOL
d2d_path_geometry_add_figure(struct d2d_geometry
*geometry
)
2096 struct d2d_figure
*figure
;
2098 if (!d2d_array_reserve((void **)&geometry
->u
.path
.figures
, &geometry
->u
.path
.figures_size
,
2099 geometry
->u
.path
.figure_count
+ 1, sizeof(*geometry
->u
.path
.figures
)))
2101 ERR("Failed to grow figures array.\n");
2105 figure
= &geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
];
2106 memset(figure
, 0, sizeof(*figure
));
2107 figure
->bounds
.left
= FLT_MAX
;
2108 figure
->bounds
.top
= FLT_MAX
;
2109 figure
->bounds
.right
= -FLT_MAX
;
2110 figure
->bounds
.bottom
= -FLT_MAX
;
2112 ++geometry
->u
.path
.figure_count
;
2116 static BOOL
d2d_geometry_outline_add_join(struct d2d_geometry
*geometry
,
2117 const D2D1_POINT_2F
*prev
, const D2D1_POINT_2F
*p0
, const D2D1_POINT_2F
*next
)
2119 static const D2D1_POINT_2F origin
= {0.0f
, 0.0f
};
2120 struct d2d_outline_vertex
*v
;
2125 if (!d2d_array_reserve((void **)&geometry
->outline
.vertices
, &geometry
->outline
.vertices_size
,
2126 geometry
->outline
.vertex_count
+ 4, sizeof(*geometry
->outline
.vertices
)))
2128 ERR("Failed to grow outline vertices array.\n");
2131 base_idx
= geometry
->outline
.vertex_count
;
2132 v
= &geometry
->outline
.vertices
[base_idx
];
2134 if (!d2d_array_reserve((void **)&geometry
->outline
.faces
, &geometry
->outline
.faces_size
,
2135 geometry
->outline
.face_count
+ 2, sizeof(*geometry
->outline
.faces
)))
2137 ERR("Failed to grow outline faces array.\n");
2140 f
= &geometry
->outline
.faces
[geometry
->outline
.face_count
];
2142 ccw
= d2d_point_ccw(&origin
, prev
, next
);
2145 d2d_outline_vertex_set(&v
[0], p0
->x
, p0
->y
, -prev
->x
, -prev
->y
, -prev
->x
, -prev
->y
);
2146 d2d_outline_vertex_set(&v
[1], p0
->x
, p0
->y
, prev
->x
, prev
->y
, prev
->x
, prev
->y
);
2147 d2d_outline_vertex_set(&v
[2], p0
->x
+ 25.0f
* -prev
->x
, p0
->y
+ 25.0f
* -prev
->y
,
2148 prev
->x
, prev
->y
, prev
->x
, prev
->y
);
2149 d2d_outline_vertex_set(&v
[3], p0
->x
+ 25.0f
* -prev
->x
, p0
->y
+ 25.0f
* -prev
->y
,
2150 -prev
->x
, -prev
->y
, -prev
->x
, -prev
->y
);
2152 else if (ccw
< 0.0f
)
2154 d2d_outline_vertex_set(&v
[0], p0
->x
, p0
->y
, next
->x
, next
->y
, -prev
->x
, -prev
->y
);
2155 d2d_outline_vertex_set(&v
[1], p0
->x
, p0
->y
, -next
->x
, -next
->y
, -next
->x
, -next
->y
);
2156 d2d_outline_vertex_set(&v
[2], p0
->x
, p0
->y
, -next
->x
, -next
->y
, prev
->x
, prev
->y
);
2157 d2d_outline_vertex_set(&v
[3], p0
->x
, p0
->y
, prev
->x
, prev
->y
, prev
->x
, prev
->y
);
2161 d2d_outline_vertex_set(&v
[0], p0
->x
, p0
->y
, prev
->x
, prev
->y
, -next
->x
, -next
->y
);
2162 d2d_outline_vertex_set(&v
[1], p0
->x
, p0
->y
, -prev
->x
, -prev
->y
, -prev
->x
, -prev
->y
);
2163 d2d_outline_vertex_set(&v
[2], p0
->x
, p0
->y
, -prev
->x
, -prev
->y
, next
->x
, next
->y
);
2164 d2d_outline_vertex_set(&v
[3], p0
->x
, p0
->y
, next
->x
, next
->y
, next
->x
, next
->y
);
2166 geometry
->outline
.vertex_count
+= 4;
2168 d2d_face_set(&f
[0], base_idx
+ 1, base_idx
+ 0, base_idx
+ 2);
2169 d2d_face_set(&f
[1], base_idx
+ 2, base_idx
+ 0, base_idx
+ 3);
2170 geometry
->outline
.face_count
+= 2;
2175 static BOOL
d2d_geometry_outline_add_line_segment(struct d2d_geometry
*geometry
,
2176 const D2D1_POINT_2F
*p0
, const D2D1_POINT_2F
*next
)
2178 struct d2d_outline_vertex
*v
;
2179 D2D1_POINT_2F q_next
;
2183 if (!d2d_array_reserve((void **)&geometry
->outline
.vertices
, &geometry
->outline
.vertices_size
,
2184 geometry
->outline
.vertex_count
+ 4, sizeof(*geometry
->outline
.vertices
)))
2186 ERR("Failed to grow outline vertices array.\n");
2189 base_idx
= geometry
->outline
.vertex_count
;
2190 v
= &geometry
->outline
.vertices
[base_idx
];
2192 if (!d2d_array_reserve((void **)&geometry
->outline
.faces
, &geometry
->outline
.faces_size
,
2193 geometry
->outline
.face_count
+ 2, sizeof(*geometry
->outline
.faces
)))
2195 ERR("Failed to grow outline faces array.\n");
2198 f
= &geometry
->outline
.faces
[geometry
->outline
.face_count
];
2200 d2d_point_subtract(&q_next
, next
, p0
);
2201 d2d_point_normalise(&q_next
);
2203 d2d_outline_vertex_set(&v
[0], p0
->x
, p0
->y
, q_next
.x
, q_next
.y
, q_next
.x
, q_next
.y
);
2204 d2d_outline_vertex_set(&v
[1], p0
->x
, p0
->y
, -q_next
.x
, -q_next
.y
, -q_next
.x
, -q_next
.y
);
2205 d2d_outline_vertex_set(&v
[2], next
->x
, next
->y
, q_next
.x
, q_next
.y
, q_next
.x
, q_next
.y
);
2206 d2d_outline_vertex_set(&v
[3], next
->x
, next
->y
, -q_next
.x
, -q_next
.y
, -q_next
.x
, -q_next
.y
);
2207 geometry
->outline
.vertex_count
+= 4;
2209 d2d_face_set(&f
[0], base_idx
+ 0, base_idx
+ 1, base_idx
+ 2);
2210 d2d_face_set(&f
[1], base_idx
+ 2, base_idx
+ 1, base_idx
+ 3);
2211 geometry
->outline
.face_count
+= 2;
2216 static BOOL
d2d_geometry_outline_add_bezier_segment(struct d2d_geometry
*geometry
,
2217 const D2D1_POINT_2F
*p0
, const D2D1_POINT_2F
*p1
, const D2D1_POINT_2F
*p2
)
2219 struct d2d_curve_outline_vertex
*b
;
2220 D2D1_POINT_2F r0
, r1
, r2
;
2221 D2D1_POINT_2F q0
, q1
, q2
;
2225 if (!d2d_array_reserve((void **)&geometry
->outline
.beziers
, &geometry
->outline
.beziers_size
,
2226 geometry
->outline
.bezier_count
+ 7, sizeof(*geometry
->outline
.beziers
)))
2228 ERR("Failed to grow outline beziers array.\n");
2231 base_idx
= geometry
->outline
.bezier_count
;
2232 b
= &geometry
->outline
.beziers
[base_idx
];
2234 if (!d2d_array_reserve((void **)&geometry
->outline
.bezier_faces
, &geometry
->outline
.bezier_faces_size
,
2235 geometry
->outline
.bezier_face_count
+ 5, sizeof(*geometry
->outline
.bezier_faces
)))
2237 ERR("Failed to grow outline faces array.\n");
2240 f
= &geometry
->outline
.bezier_faces
[geometry
->outline
.bezier_face_count
];
2242 d2d_point_lerp(&q0
, p0
, p1
, 0.5f
);
2243 d2d_point_lerp(&q1
, p1
, p2
, 0.5f
);
2244 d2d_point_lerp(&q2
, &q0
, &q1
, 0.5f
);
2246 d2d_point_subtract(&r0
, &q0
, p0
);
2247 d2d_point_subtract(&r1
, &q1
, &q0
);
2248 d2d_point_subtract(&r2
, p2
, &q1
);
2250 d2d_point_normalise(&r0
);
2251 d2d_point_normalise(&r1
);
2252 d2d_point_normalise(&r2
);
2254 if (d2d_point_ccw(p0
, p1
, p2
) > 0.0f
)
2256 d2d_point_scale(&r0
, -1.0f
);
2257 d2d_point_scale(&r1
, -1.0f
);
2258 d2d_point_scale(&r2
, -1.0f
);
2261 d2d_curve_outline_vertex_set(&b
[0], p0
, p0
, p1
, p2
, r0
.x
, r0
.y
, r0
.x
, r0
.y
);
2262 d2d_curve_outline_vertex_set(&b
[1], p0
, p0
, p1
, p2
, -r0
.x
, -r0
.y
, -r0
.x
, -r0
.y
);
2263 d2d_curve_outline_vertex_set(&b
[2], &q0
, p0
, p1
, p2
, r0
.x
, r0
.y
, r1
.x
, r1
.y
);
2264 d2d_curve_outline_vertex_set(&b
[3], &q2
, p0
, p1
, p2
, -r1
.x
, -r1
.y
, -r1
.x
, -r1
.y
);
2265 d2d_curve_outline_vertex_set(&b
[4], &q1
, p0
, p1
, p2
, r1
.x
, r1
.y
, r2
.x
, r2
.y
);
2266 d2d_curve_outline_vertex_set(&b
[5], p2
, p0
, p1
, p2
, -r2
.x
, -r2
.y
, -r2
.x
, -r2
.y
);
2267 d2d_curve_outline_vertex_set(&b
[6], p2
, p0
, p1
, p2
, r2
.x
, r2
.y
, r2
.x
, r2
.y
);
2268 geometry
->outline
.bezier_count
+= 7;
2270 d2d_face_set(&f
[0], base_idx
+ 0, base_idx
+ 1, base_idx
+ 2);
2271 d2d_face_set(&f
[1], base_idx
+ 2, base_idx
+ 1, base_idx
+ 3);
2272 d2d_face_set(&f
[2], base_idx
+ 3, base_idx
+ 4, base_idx
+ 2);
2273 d2d_face_set(&f
[3], base_idx
+ 5, base_idx
+ 4, base_idx
+ 3);
2274 d2d_face_set(&f
[4], base_idx
+ 5, base_idx
+ 6, base_idx
+ 4);
2275 geometry
->outline
.bezier_face_count
+= 5;
2280 static BOOL
d2d_geometry_outline_add_arc_quadrant(struct d2d_geometry
*geometry
,
2281 const D2D1_POINT_2F
*p0
, const D2D1_POINT_2F
*p1
, const D2D1_POINT_2F
*p2
)
2283 struct d2d_curve_outline_vertex
*a
;
2284 D2D1_POINT_2F r0
, r1
;
2288 if (!d2d_array_reserve((void **)&geometry
->outline
.arcs
, &geometry
->outline
.arcs_size
,
2289 geometry
->outline
.arc_count
+ 5, sizeof(*geometry
->outline
.arcs
)))
2291 ERR("Failed to grow outline arcs array.\n");
2294 base_idx
= geometry
->outline
.arc_count
;
2295 a
= &geometry
->outline
.arcs
[base_idx
];
2297 if (!d2d_array_reserve((void **)&geometry
->outline
.arc_faces
, &geometry
->outline
.arc_faces_size
,
2298 geometry
->outline
.arc_face_count
+ 3, sizeof(*geometry
->outline
.arc_faces
)))
2300 ERR("Failed to grow outline faces array.\n");
2303 f
= &geometry
->outline
.arc_faces
[geometry
->outline
.arc_face_count
];
2305 d2d_point_subtract(&r0
, p1
, p0
);
2306 d2d_point_subtract(&r1
, p2
, p1
);
2308 d2d_point_normalise(&r0
);
2309 d2d_point_normalise(&r1
);
2311 if (d2d_point_ccw(p0
, p1
, p2
) > 0.0f
)
2313 d2d_point_scale(&r0
, -1.0f
);
2314 d2d_point_scale(&r1
, -1.0f
);
2317 d2d_curve_outline_vertex_set(&a
[0], p0
, p0
, p1
, p2
, r0
.x
, r0
.y
, r0
.x
, r0
.y
);
2318 d2d_curve_outline_vertex_set(&a
[1], p0
, p0
, p1
, p2
, -r0
.x
, -r0
.y
, -r0
.x
, -r0
.y
);
2319 d2d_curve_outline_vertex_set(&a
[2], p1
, p0
, p1
, p2
, r0
.x
, r0
.y
, r1
.x
, r1
.y
);
2320 d2d_curve_outline_vertex_set(&a
[3], p2
, p0
, p1
, p2
, -r1
.x
, -r1
.y
, -r1
.x
, -r1
.y
);
2321 d2d_curve_outline_vertex_set(&a
[4], p2
, p0
, p1
, p2
, r1
.x
, r1
.y
, r1
.x
, r1
.y
);
2322 geometry
->outline
.arc_count
+= 5;
2324 d2d_face_set(&f
[0], base_idx
+ 0, base_idx
+ 1, base_idx
+ 2);
2325 d2d_face_set(&f
[1], base_idx
+ 2, base_idx
+ 1, base_idx
+ 3);
2326 d2d_face_set(&f
[2], base_idx
+ 2, base_idx
+ 4, base_idx
+ 3);
2327 geometry
->outline
.arc_face_count
+= 3;
2332 static BOOL
d2d_geometry_add_figure_outline(struct d2d_geometry
*geometry
,
2333 struct d2d_figure
*figure
, D2D1_FIGURE_END figure_end
)
2335 const D2D1_POINT_2F
*prev
, *p0
, *next
;
2336 enum d2d_vertex_type prev_type
, type
;
2337 size_t bezier_idx
, i
;
2339 for (i
= 0, bezier_idx
= 0; i
< figure
->vertex_count
; ++i
)
2341 type
= figure
->vertex_types
[i
];
2342 if (type
== D2D_VERTEX_TYPE_NONE
)
2345 p0
= &figure
->vertices
[i
];
2349 prev_type
= figure
->vertex_types
[figure
->vertex_count
- 1];
2350 if (d2d_vertex_type_is_bezier(prev_type
))
2351 prev
= &figure
->bezier_controls
[figure
->bezier_control_count
- 1];
2353 prev
= &figure
->vertices
[figure
->vertex_count
- 1];
2357 prev_type
= figure
->vertex_types
[i
- 1];
2358 if (d2d_vertex_type_is_bezier(prev_type
))
2359 prev
= &figure
->bezier_controls
[bezier_idx
- 1];
2361 prev
= &figure
->vertices
[i
- 1];
2364 if (d2d_vertex_type_is_bezier(type
))
2365 next
= &figure
->bezier_controls
[bezier_idx
++];
2366 else if (i
== figure
->vertex_count
- 1)
2367 next
= &figure
->vertices
[0];
2369 next
= &figure
->vertices
[i
+ 1];
2371 if (figure_end
== D2D1_FIGURE_END_CLOSED
|| (i
&& i
< figure
->vertex_count
- 1))
2373 D2D1_POINT_2F q_next
, q_prev
;
2375 d2d_point_subtract(&q_prev
, prev
, p0
);
2376 d2d_point_subtract(&q_next
, next
, p0
);
2378 d2d_point_normalise(&q_prev
);
2379 d2d_point_normalise(&q_next
);
2381 if (!d2d_geometry_outline_add_join(geometry
, &q_prev
, p0
, &q_next
))
2383 ERR("Failed to add join.\n");
2388 if (type
== D2D_VERTEX_TYPE_LINE
&& (figure_end
== D2D1_FIGURE_END_CLOSED
|| i
< figure
->vertex_count
- 1)
2389 && !d2d_geometry_outline_add_line_segment(geometry
, p0
, next
))
2391 ERR("Failed to add line segment.\n");
2394 else if (d2d_vertex_type_is_bezier(type
))
2396 const D2D1_POINT_2F
*p2
;
2398 if (i
== figure
->vertex_count
- 1)
2399 p2
= &figure
->vertices
[0];
2401 p2
= &figure
->vertices
[i
+ 1];
2403 if (!d2d_geometry_outline_add_bezier_segment(geometry
, p0
, next
, p2
))
2405 ERR("Failed to add bezier segment.\n");
2414 static BOOL
d2d_geometry_fill_add_arc_triangle(struct d2d_geometry
*geometry
,
2415 const D2D1_POINT_2F
*p0
, const D2D1_POINT_2F
*p1
, const D2D1_POINT_2F
*p2
)
2417 struct d2d_curve_vertex
*a
;
2419 if (!d2d_array_reserve((void **)&geometry
->fill
.arc_vertices
, &geometry
->fill
.arc_vertices_size
,
2420 geometry
->fill
.arc_vertex_count
+ 3, sizeof(*geometry
->fill
.arc_vertices
)))
2423 a
= &geometry
->fill
.arc_vertices
[geometry
->fill
.arc_vertex_count
];
2424 d2d_curve_vertex_set(&a
[0], p0
, 0.0f
, 1.0f
, -1.0f
);
2425 d2d_curve_vertex_set(&a
[1], p1
, 1.0f
, 1.0f
, -1.0f
);
2426 d2d_curve_vertex_set(&a
[2], p2
, 1.0f
, 0.0f
, -1.0f
);
2427 geometry
->fill
.arc_vertex_count
+= 3;
2432 static void d2d_geometry_cleanup(struct d2d_geometry
*geometry
)
2434 heap_free(geometry
->outline
.arc_faces
);
2435 heap_free(geometry
->outline
.arcs
);
2436 heap_free(geometry
->outline
.bezier_faces
);
2437 heap_free(geometry
->outline
.beziers
);
2438 heap_free(geometry
->outline
.faces
);
2439 heap_free(geometry
->outline
.vertices
);
2440 heap_free(geometry
->fill
.arc_vertices
);
2441 heap_free(geometry
->fill
.bezier_vertices
);
2442 heap_free(geometry
->fill
.faces
);
2443 heap_free(geometry
->fill
.vertices
);
2444 ID2D1Factory_Release(geometry
->factory
);
2447 static void d2d_geometry_init(struct d2d_geometry
*geometry
, ID2D1Factory
*factory
,
2448 const D2D1_MATRIX_3X2_F
*transform
, const struct ID2D1GeometryVtbl
*vtbl
)
2450 geometry
->ID2D1Geometry_iface
.lpVtbl
= vtbl
;
2451 geometry
->refcount
= 1;
2452 ID2D1Factory_AddRef(geometry
->factory
= factory
);
2453 geometry
->transform
= *transform
;
2456 static inline struct d2d_geometry
*impl_from_ID2D1GeometrySink(ID2D1GeometrySink
*iface
)
2458 return CONTAINING_RECORD(iface
, struct d2d_geometry
, u
.path
.ID2D1GeometrySink_iface
);
2461 static HRESULT STDMETHODCALLTYPE
d2d_geometry_sink_QueryInterface(ID2D1GeometrySink
*iface
, REFIID iid
, void **out
)
2463 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
2465 if (IsEqualGUID(iid
, &IID_ID2D1GeometrySink
)
2466 || IsEqualGUID(iid
, &IID_ID2D1SimplifiedGeometrySink
)
2467 || IsEqualGUID(iid
, &IID_IUnknown
))
2469 ID2D1GeometrySink_AddRef(iface
);
2474 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
2477 return E_NOINTERFACE
;
2480 static ULONG STDMETHODCALLTYPE
d2d_geometry_sink_AddRef(ID2D1GeometrySink
*iface
)
2482 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
2484 TRACE("iface %p.\n", iface
);
2486 return ID2D1Geometry_AddRef(&geometry
->ID2D1Geometry_iface
);
2489 static ULONG STDMETHODCALLTYPE
d2d_geometry_sink_Release(ID2D1GeometrySink
*iface
)
2491 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
2493 TRACE("iface %p.\n", iface
);
2495 return ID2D1Geometry_Release(&geometry
->ID2D1Geometry_iface
);
2498 static void STDMETHODCALLTYPE
d2d_geometry_sink_SetFillMode(ID2D1GeometrySink
*iface
, D2D1_FILL_MODE mode
)
2500 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
2502 TRACE("iface %p, mode %#x.\n", iface
, mode
);
2504 if (geometry
->u
.path
.state
== D2D_GEOMETRY_STATE_CLOSED
)
2506 geometry
->u
.path
.fill_mode
= mode
;
2509 static void STDMETHODCALLTYPE
d2d_geometry_sink_SetSegmentFlags(ID2D1GeometrySink
*iface
, D2D1_PATH_SEGMENT flags
)
2511 FIXME("iface %p, flags %#x stub!\n", iface
, flags
);
2514 static void STDMETHODCALLTYPE
d2d_geometry_sink_BeginFigure(ID2D1GeometrySink
*iface
,
2515 D2D1_POINT_2F start_point
, D2D1_FIGURE_BEGIN figure_begin
)
2517 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
2518 struct d2d_figure
*figure
;
2520 TRACE("iface %p, start_point %s, figure_begin %#x.\n",
2521 iface
, debug_d2d_point_2f(&start_point
), figure_begin
);
2523 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_OPEN
)
2525 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2529 if (!d2d_path_geometry_add_figure(geometry
))
2531 ERR("Failed to add figure.\n");
2532 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2536 figure
= &geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
- 1];
2537 if (figure_begin
== D2D1_FIGURE_BEGIN_HOLLOW
)
2538 figure
->flags
|= D2D_FIGURE_FLAG_HOLLOW
;
2540 if (!d2d_figure_add_vertex(figure
, start_point
))
2542 ERR("Failed to add vertex.\n");
2543 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2547 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_FIGURE
;
2550 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddLines(ID2D1GeometrySink
*iface
,
2551 const D2D1_POINT_2F
*points
, UINT32 count
)
2553 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
2554 struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
- 1];
2557 TRACE("iface %p, points %p, count %u.\n", iface
, points
, count
);
2559 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_FIGURE
)
2561 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2565 for (i
= 0; i
< count
; ++i
)
2567 figure
->vertex_types
[figure
->vertex_count
- 1] = D2D_VERTEX_TYPE_LINE
;
2568 if (!d2d_figure_add_vertex(figure
, points
[i
]))
2570 ERR("Failed to add vertex.\n");
2575 geometry
->u
.path
.segment_count
+= count
;
2578 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddBeziers(ID2D1GeometrySink
*iface
,
2579 const D2D1_BEZIER_SEGMENT
*beziers
, UINT32 count
)
2581 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
2582 struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
- 1];
2586 TRACE("iface %p, beziers %p, count %u.\n", iface
, beziers
, count
);
2588 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_FIGURE
)
2590 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2594 for (i
= 0; i
< count
; ++i
)
2596 D2D1_RECT_F bezier_bounds
;
2598 /* FIXME: This tries to approximate a cubic bezier with a quadratic one. */
2599 p
.x
= (beziers
[i
].point1
.x
+ beziers
[i
].point2
.x
) * 0.75f
;
2600 p
.y
= (beziers
[i
].point1
.y
+ beziers
[i
].point2
.y
) * 0.75f
;
2601 p
.x
-= (figure
->vertices
[figure
->vertex_count
- 1].x
+ beziers
[i
].point3
.x
) * 0.25f
;
2602 p
.y
-= (figure
->vertices
[figure
->vertex_count
- 1].y
+ beziers
[i
].point3
.y
) * 0.25f
;
2603 figure
->vertex_types
[figure
->vertex_count
- 1] = D2D_VERTEX_TYPE_BEZIER
;
2605 d2d_rect_get_bezier_bounds(&bezier_bounds
, &figure
->vertices
[figure
->vertex_count
- 1],
2606 &p
, &beziers
[i
].point3
);
2608 if (!d2d_figure_add_bezier_controls(figure
, 1, &p
))
2610 ERR("Failed to add bezier control.\n");
2611 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2615 if (!d2d_figure_add_vertex(figure
, beziers
[i
].point3
))
2617 ERR("Failed to add bezier vertex.\n");
2618 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2622 d2d_rect_union(&figure
->bounds
, &bezier_bounds
);
2625 geometry
->u
.path
.segment_count
+= count
;
2628 static void STDMETHODCALLTYPE
d2d_geometry_sink_EndFigure(ID2D1GeometrySink
*iface
, D2D1_FIGURE_END figure_end
)
2630 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
2631 struct d2d_figure
*figure
;
2633 TRACE("iface %p, figure_end %#x.\n", iface
, figure_end
);
2635 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_FIGURE
)
2637 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2641 figure
= &geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
- 1];
2642 figure
->vertex_types
[figure
->vertex_count
- 1] = D2D_VERTEX_TYPE_LINE
;
2643 if (figure_end
== D2D1_FIGURE_END_CLOSED
)
2645 ++geometry
->u
.path
.segment_count
;
2646 figure
->flags
|= D2D_FIGURE_FLAG_CLOSED
;
2647 if (!memcmp(&figure
->vertices
[0], &figure
->vertices
[figure
->vertex_count
- 1], sizeof(*figure
->vertices
)))
2648 --figure
->vertex_count
;
2651 if (!d2d_geometry_add_figure_outline(geometry
, figure
, figure_end
))
2653 ERR("Failed to add figure outline.\n");
2654 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2658 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_OPEN
;
2661 static void d2d_path_geometry_free_figures(struct d2d_geometry
*geometry
)
2665 if (!geometry
->u
.path
.figures
)
2668 for (i
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
2670 heap_free(geometry
->u
.path
.figures
[i
].bezier_controls
);
2671 heap_free(geometry
->u
.path
.figures
[i
].original_bezier_controls
);
2672 heap_free(geometry
->u
.path
.figures
[i
].vertices
);
2674 heap_free(geometry
->u
.path
.figures
);
2675 geometry
->u
.path
.figures
= NULL
;
2676 geometry
->u
.path
.figures_size
= 0;
2679 static BOOL
d2d_geometry_get_bezier_segment_idx(struct d2d_geometry
*geometry
, struct d2d_segment_idx
*idx
, BOOL next
)
2687 for (; idx
->figure_idx
< geometry
->u
.path
.figure_count
; ++idx
->figure_idx
, idx
->vertex_idx
= idx
->control_idx
= 0)
2689 struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[idx
->figure_idx
];
2691 if (!figure
->bezier_control_count
|| figure
->flags
& D2D_FIGURE_FLAG_HOLLOW
)
2694 for (; idx
->vertex_idx
< figure
->vertex_count
; ++idx
->vertex_idx
)
2696 if (d2d_vertex_type_is_bezier(figure
->vertex_types
[idx
->vertex_idx
]))
2704 static BOOL
d2d_geometry_get_first_bezier_segment_idx(struct d2d_geometry
*geometry
, struct d2d_segment_idx
*idx
)
2706 memset(idx
, 0, sizeof(*idx
));
2708 return d2d_geometry_get_bezier_segment_idx(geometry
, idx
, FALSE
);
2711 static BOOL
d2d_geometry_get_next_bezier_segment_idx(struct d2d_geometry
*geometry
, struct d2d_segment_idx
*idx
)
2713 return d2d_geometry_get_bezier_segment_idx(geometry
, idx
, TRUE
);
2716 static BOOL
d2d_geometry_check_bezier_overlap(struct d2d_geometry
*geometry
,
2717 const struct d2d_segment_idx
*idx_p
, const struct d2d_segment_idx
*idx_q
)
2719 const D2D1_POINT_2F
*a
[3], *b
[3], *p
[2], *q
;
2720 const struct d2d_figure
*figure
;
2721 D2D1_POINT_2F v_q
[3], v_p
, v_qp
;
2722 unsigned int i
, j
, score
;
2725 figure
= &geometry
->u
.path
.figures
[idx_p
->figure_idx
];
2726 a
[0] = &figure
->vertices
[idx_p
->vertex_idx
];
2727 a
[1] = &figure
->bezier_controls
[idx_p
->control_idx
];
2728 if (idx_p
->vertex_idx
== figure
->vertex_count
- 1)
2729 a
[2] = &figure
->vertices
[0];
2731 a
[2] = &figure
->vertices
[idx_p
->vertex_idx
+ 1];
2733 figure
= &geometry
->u
.path
.figures
[idx_q
->figure_idx
];
2734 b
[0] = &figure
->vertices
[idx_q
->vertex_idx
];
2735 b
[1] = &figure
->bezier_controls
[idx_q
->control_idx
];
2736 if (idx_q
->vertex_idx
== figure
->vertex_count
- 1)
2737 b
[2] = &figure
->vertices
[0];
2739 b
[2] = &figure
->vertices
[idx_q
->vertex_idx
+ 1];
2741 if (d2d_point_ccw(a
[0], a
[1], a
[2]) == 0.0f
|| d2d_point_ccw(b
[0], b
[1], b
[2]) == 0.0f
)
2744 d2d_point_subtract(&v_q
[0], b
[1], b
[0]);
2745 d2d_point_subtract(&v_q
[1], b
[2], b
[0]);
2746 d2d_point_subtract(&v_q
[2], b
[1], b
[2]);
2748 /* Check for intersections between the edges. Strictly speaking we'd only
2749 * need to check 8 of the 9 possible intersections, since if there's any
2750 * intersection there has to be a second intersection as well. */
2751 for (i
= 0; i
< 3; ++i
)
2753 d2d_point_subtract(&v_p
, a
[(i
& 1) + 1], a
[i
& 2]);
2754 for (j
= 0; j
< 3; ++j
)
2756 det
= v_p
.x
* v_q
[j
].y
- v_p
.y
* v_q
[j
].x
;
2760 d2d_point_subtract(&v_qp
, a
[i
& 2], b
[j
& 2]);
2761 t
= (v_q
[j
].x
* v_qp
.y
- v_q
[j
].y
* v_qp
.x
) / det
;
2762 if (t
<= 0.0f
|| t
>= 1.0f
)
2765 t
= (v_p
.x
* v_qp
.y
- v_p
.y
* v_qp
.x
) / det
;
2766 if (t
<= 0.0f
|| t
>= 1.0f
)
2773 /* Check if one triangle is contained within the other. */
2774 for (j
= 0, score
= 0, q
= a
[1], p
[0] = b
[2]; j
< 3; ++j
)
2777 d2d_point_subtract(&v_p
, p
[1], p
[0]);
2778 d2d_point_subtract(&v_qp
, q
, p
[0]);
2780 if ((q
->y
< p
[0]->y
) != (q
->y
< p
[1]->y
) && v_qp
.x
< v_p
.x
* (v_qp
.y
/ v_p
.y
))
2789 for (j
= 0, score
= 0, q
= b
[1], p
[0] = a
[2]; j
< 3; ++j
)
2792 d2d_point_subtract(&v_p
, p
[1], p
[0]);
2793 d2d_point_subtract(&v_qp
, q
, p
[0]);
2795 if ((q
->y
< p
[0]->y
) != (q
->y
< p
[1]->y
) && v_qp
.x
< v_p
.x
* (v_qp
.y
/ v_p
.y
))
2804 static float d2d_geometry_bezier_ccw(struct d2d_geometry
*geometry
, const struct d2d_segment_idx
*idx
)
2806 const struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[idx
->figure_idx
];
2807 size_t next
= idx
->vertex_idx
+ 1;
2809 if (next
== figure
->vertex_count
)
2812 return d2d_point_ccw(&figure
->vertices
[idx
->vertex_idx
],
2813 &figure
->bezier_controls
[idx
->control_idx
], &figure
->vertices
[next
]);
2816 static BOOL
d2d_geometry_split_bezier(struct d2d_geometry
*geometry
, const struct d2d_segment_idx
*idx
)
2818 const D2D1_POINT_2F
*p
[3];
2819 struct d2d_figure
*figure
;
2823 figure
= &geometry
->u
.path
.figures
[idx
->figure_idx
];
2824 p
[0] = &figure
->vertices
[idx
->vertex_idx
];
2825 p
[1] = &figure
->bezier_controls
[idx
->control_idx
];
2826 next
= idx
->vertex_idx
+ 1;
2827 if (next
== figure
->vertex_count
)
2829 p
[2] = &figure
->vertices
[next
];
2831 d2d_point_lerp(&q
[0], p
[0], p
[1], 0.5f
);
2832 d2d_point_lerp(&q
[1], p
[1], p
[2], 0.5f
);
2833 d2d_point_lerp(&q
[2], &q
[0], &q
[1], 0.5f
);
2835 figure
->bezier_controls
[idx
->control_idx
] = q
[0];
2836 if (!(d2d_figure_insert_bezier_controls(figure
, idx
->control_idx
+ 1, 1, &q
[1])))
2838 if (!(d2d_figure_insert_vertex(figure
, idx
->vertex_idx
+ 1, q
[2])))
2840 figure
->vertex_types
[idx
->vertex_idx
+ 1] = D2D_VERTEX_TYPE_SPLIT_BEZIER
;
2845 static HRESULT
d2d_geometry_resolve_beziers(struct d2d_geometry
*geometry
)
2847 struct d2d_segment_idx idx_p
, idx_q
;
2848 struct d2d_curve_vertex
*b
;
2849 const D2D1_POINT_2F
*p
[3];
2850 struct d2d_figure
*figure
;
2851 size_t bezier_idx
, i
;
2853 if (!d2d_geometry_get_first_bezier_segment_idx(geometry
, &idx_p
))
2856 /* Split overlapping bezier control triangles. */
2857 while (d2d_geometry_get_next_bezier_segment_idx(geometry
, &idx_p
))
2859 d2d_geometry_get_first_bezier_segment_idx(geometry
, &idx_q
);
2860 while (idx_q
.figure_idx
< idx_p
.figure_idx
|| idx_q
.vertex_idx
< idx_p
.vertex_idx
)
2862 while (d2d_geometry_check_bezier_overlap(geometry
, &idx_p
, &idx_q
))
2864 if (fabsf(d2d_geometry_bezier_ccw(geometry
, &idx_q
)) > fabsf(d2d_geometry_bezier_ccw(geometry
, &idx_p
)))
2866 if (!d2d_geometry_split_bezier(geometry
, &idx_q
))
2867 return E_OUTOFMEMORY
;
2868 if (idx_p
.figure_idx
== idx_q
.figure_idx
)
2871 ++idx_p
.control_idx
;
2876 if (!d2d_geometry_split_bezier(geometry
, &idx_p
))
2877 return E_OUTOFMEMORY
;
2880 d2d_geometry_get_next_bezier_segment_idx(geometry
, &idx_q
);
2884 for (i
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
2886 if (geometry
->u
.path
.figures
[i
].flags
& D2D_FIGURE_FLAG_HOLLOW
)
2888 geometry
->fill
.bezier_vertex_count
+= 3 * geometry
->u
.path
.figures
[i
].bezier_control_count
;
2891 if (!(geometry
->fill
.bezier_vertices
= heap_calloc(geometry
->fill
.bezier_vertex_count
,
2892 sizeof(*geometry
->fill
.bezier_vertices
))))
2894 ERR("Failed to allocate bezier vertices array.\n");
2895 geometry
->fill
.bezier_vertex_count
= 0;
2896 return E_OUTOFMEMORY
;
2900 d2d_geometry_get_first_bezier_segment_idx(geometry
, &idx_p
);
2905 figure
= &geometry
->u
.path
.figures
[idx_p
.figure_idx
];
2906 p
[0] = &figure
->vertices
[idx_p
.vertex_idx
];
2907 p
[1] = &figure
->bezier_controls
[idx_p
.control_idx
];
2909 i
= idx_p
.vertex_idx
+ 1;
2910 if (d2d_path_geometry_point_inside(geometry
, p
[1], FALSE
))
2913 d2d_figure_insert_vertex(figure
, i
, *p
[1]);
2914 /* Inserting a vertex potentially invalidates p[0]. */
2915 p
[0] = &figure
->vertices
[idx_p
.vertex_idx
];
2919 if (i
== figure
->vertex_count
)
2921 p
[2] = &figure
->vertices
[i
];
2923 b
= &geometry
->fill
.bezier_vertices
[bezier_idx
* 3];
2924 d2d_curve_vertex_set(&b
[0], p
[0], 0.0f
, 0.0f
, sign
);
2925 d2d_curve_vertex_set(&b
[1], p
[1], 0.5f
, 0.0f
, sign
);
2926 d2d_curve_vertex_set(&b
[2], p
[2], 1.0f
, 1.0f
, sign
);
2928 if (!d2d_geometry_get_next_bezier_segment_idx(geometry
, &idx_p
))
2936 static HRESULT STDMETHODCALLTYPE
d2d_geometry_sink_Close(ID2D1GeometrySink
*iface
)
2938 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
2939 HRESULT hr
= E_FAIL
;
2942 TRACE("iface %p.\n", iface
);
2944 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_OPEN
)
2946 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_CLOSED
)
2947 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2948 return D2DERR_WRONG_STATE
;
2950 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_CLOSED
;
2952 for (i
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
2954 struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[i
];
2955 size_t size
= figure
->bezier_control_count
* sizeof(*figure
->original_bezier_controls
);
2956 if (!(figure
->original_bezier_controls
= heap_alloc(size
)))
2958 memcpy(figure
->original_bezier_controls
, figure
->bezier_controls
, size
);
2961 if (!d2d_geometry_intersect_self(geometry
))
2963 if (FAILED(hr
= d2d_geometry_resolve_beziers(geometry
)))
2965 if (FAILED(hr
= d2d_path_geometry_triangulate(geometry
)))
2971 heap_free(geometry
->fill
.bezier_vertices
);
2972 geometry
->fill
.bezier_vertex_count
= 0;
2973 d2d_path_geometry_free_figures(geometry
);
2974 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
2979 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddLine(ID2D1GeometrySink
*iface
, D2D1_POINT_2F point
)
2981 TRACE("iface %p, point %s.\n", iface
, debug_d2d_point_2f(&point
));
2983 d2d_geometry_sink_AddLines(iface
, &point
, 1);
2986 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddBezier(ID2D1GeometrySink
*iface
, const D2D1_BEZIER_SEGMENT
*bezier
)
2988 TRACE("iface %p, bezier %p.\n", iface
, bezier
);
2990 d2d_geometry_sink_AddBeziers(iface
, bezier
, 1);
2993 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddQuadraticBezier(ID2D1GeometrySink
*iface
,
2994 const D2D1_QUADRATIC_BEZIER_SEGMENT
*bezier
)
2996 TRACE("iface %p, bezier %p.\n", iface
, bezier
);
2998 ID2D1GeometrySink_AddQuadraticBeziers(iface
, bezier
, 1);
3001 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddQuadraticBeziers(ID2D1GeometrySink
*iface
,
3002 const D2D1_QUADRATIC_BEZIER_SEGMENT
*beziers
, UINT32 bezier_count
)
3004 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
3005 struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
- 1];
3008 TRACE("iface %p, beziers %p, bezier_count %u.\n", iface
, beziers
, bezier_count
);
3010 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_FIGURE
)
3012 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
3016 for (i
= 0; i
< bezier_count
; ++i
)
3018 D2D1_RECT_F bezier_bounds
;
3020 d2d_rect_get_bezier_bounds(&bezier_bounds
, &figure
->vertices
[figure
->vertex_count
- 1],
3021 &beziers
[i
].point1
, &beziers
[i
].point2
);
3023 figure
->vertex_types
[figure
->vertex_count
- 1] = D2D_VERTEX_TYPE_BEZIER
;
3024 if (!d2d_figure_add_bezier_controls(figure
, 1, &beziers
[i
].point1
))
3026 ERR("Failed to add bezier.\n");
3027 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
3031 if (!d2d_figure_add_vertex(figure
, beziers
[i
].point2
))
3033 ERR("Failed to add bezier vertex.\n");
3034 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
3038 d2d_rect_union(&figure
->bounds
, &bezier_bounds
);
3041 geometry
->u
.path
.segment_count
+= bezier_count
;
3044 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddArc(ID2D1GeometrySink
*iface
, const D2D1_ARC_SEGMENT
*arc
)
3046 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
3048 FIXME("iface %p, arc %p stub!\n", iface
, arc
);
3050 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_FIGURE
)
3052 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
3056 if (!d2d_figure_add_vertex(&geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
- 1], arc
->point
))
3058 ERR("Failed to add vertex.\n");
3062 ++geometry
->u
.path
.segment_count
;
3065 static const struct ID2D1GeometrySinkVtbl d2d_geometry_sink_vtbl
=
3067 d2d_geometry_sink_QueryInterface
,
3068 d2d_geometry_sink_AddRef
,
3069 d2d_geometry_sink_Release
,
3070 d2d_geometry_sink_SetFillMode
,
3071 d2d_geometry_sink_SetSegmentFlags
,
3072 d2d_geometry_sink_BeginFigure
,
3073 d2d_geometry_sink_AddLines
,
3074 d2d_geometry_sink_AddBeziers
,
3075 d2d_geometry_sink_EndFigure
,
3076 d2d_geometry_sink_Close
,
3077 d2d_geometry_sink_AddLine
,
3078 d2d_geometry_sink_AddBezier
,
3079 d2d_geometry_sink_AddQuadraticBezier
,
3080 d2d_geometry_sink_AddQuadraticBeziers
,
3081 d2d_geometry_sink_AddArc
,
3084 static inline struct d2d_geometry
*impl_from_ID2D1PathGeometry(ID2D1PathGeometry
*iface
)
3086 return CONTAINING_RECORD(iface
, struct d2d_geometry
, ID2D1Geometry_iface
);
3089 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_QueryInterface(ID2D1PathGeometry
*iface
, REFIID iid
, void **out
)
3091 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
3093 if (IsEqualGUID(iid
, &IID_ID2D1PathGeometry
)
3094 || IsEqualGUID(iid
, &IID_ID2D1Geometry
)
3095 || IsEqualGUID(iid
, &IID_ID2D1Resource
)
3096 || IsEqualGUID(iid
, &IID_IUnknown
))
3098 ID2D1PathGeometry_AddRef(iface
);
3103 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
3106 return E_NOINTERFACE
;
3109 static ULONG STDMETHODCALLTYPE
d2d_path_geometry_AddRef(ID2D1PathGeometry
*iface
)
3111 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
3112 ULONG refcount
= InterlockedIncrement(&geometry
->refcount
);
3114 TRACE("%p increasing refcount to %u.\n", iface
, refcount
);
3119 static ULONG STDMETHODCALLTYPE
d2d_path_geometry_Release(ID2D1PathGeometry
*iface
)
3121 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
3122 ULONG refcount
= InterlockedDecrement(&geometry
->refcount
);
3124 TRACE("%p decreasing refcount to %u.\n", iface
, refcount
);
3128 d2d_path_geometry_free_figures(geometry
);
3129 d2d_geometry_cleanup(geometry
);
3130 heap_free(geometry
);
3136 static void STDMETHODCALLTYPE
d2d_path_geometry_GetFactory(ID2D1PathGeometry
*iface
, ID2D1Factory
**factory
)
3138 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
3140 TRACE("iface %p, factory %p.\n", iface
, factory
);
3142 ID2D1Factory_AddRef(*factory
= geometry
->factory
);
3145 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_GetBounds(ID2D1PathGeometry
*iface
,
3146 const D2D1_MATRIX_3X2_F
*transform
, D2D1_RECT_F
*bounds
)
3148 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
3151 TRACE("iface %p, transform %p, bounds %p.\n", iface
, transform
, bounds
);
3153 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_CLOSED
)
3154 return D2DERR_WRONG_STATE
;
3156 bounds
->left
= FLT_MAX
;
3157 bounds
->top
= FLT_MAX
;
3158 bounds
->right
= -FLT_MAX
;
3159 bounds
->bottom
= -FLT_MAX
;
3163 if (geometry
->u
.path
.bounds
.left
> geometry
->u
.path
.bounds
.right
3164 && !isinf(geometry
->u
.path
.bounds
.left
))
3166 for (i
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
3168 if (geometry
->u
.path
.figures
[i
].flags
& D2D_FIGURE_FLAG_HOLLOW
)
3170 d2d_rect_union(&geometry
->u
.path
.bounds
, &geometry
->u
.path
.figures
[i
].bounds
);
3172 if (geometry
->u
.path
.bounds
.left
> geometry
->u
.path
.bounds
.right
)
3174 geometry
->u
.path
.bounds
.left
= INFINITY
;
3175 geometry
->u
.path
.bounds
.right
= FLT_MAX
;
3176 geometry
->u
.path
.bounds
.top
= INFINITY
;
3177 geometry
->u
.path
.bounds
.bottom
= FLT_MAX
;
3181 *bounds
= geometry
->u
.path
.bounds
;
3185 for (i
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
3187 const struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[i
];
3188 enum d2d_vertex_type type
= D2D_VERTEX_TYPE_NONE
;
3189 D2D1_RECT_F bezier_bounds
;
3190 D2D1_POINT_2F p
, p1
, p2
;
3191 size_t j
, bezier_idx
;
3193 if (figure
->flags
& D2D_FIGURE_FLAG_HOLLOW
)
3196 /* Single vertex figures are reduced by CloseFigure(). */
3197 if (figure
->vertex_count
== 0)
3199 d2d_point_transform(&p
, transform
, figure
->bounds
.left
, figure
->bounds
.top
);
3200 d2d_rect_expand(bounds
, &p
);
3204 for (j
= 0; j
< figure
->vertex_count
; ++j
)
3206 if (figure
->vertex_types
[j
] == D2D_VERTEX_TYPE_NONE
)
3209 p
= figure
->vertices
[j
];
3210 type
= figure
->vertex_types
[j
];
3211 d2d_point_transform(&p
, transform
, p
.x
, p
.y
);
3212 d2d_rect_expand(bounds
, &p
);
3216 for (bezier_idx
= 0, ++j
; j
< figure
->vertex_count
; ++j
)
3218 if (figure
->vertex_types
[j
] == D2D_VERTEX_TYPE_NONE
3219 || d2d_vertex_type_is_split_bezier(figure
->vertex_types
[j
]))
3224 case D2D_VERTEX_TYPE_LINE
:
3225 p
= figure
->vertices
[j
];
3226 d2d_point_transform(&p
, transform
, p
.x
, p
.y
);
3227 d2d_rect_expand(bounds
, &p
);
3230 case D2D_VERTEX_TYPE_BEZIER
:
3231 p1
= figure
->original_bezier_controls
[bezier_idx
++];
3232 d2d_point_transform(&p1
, transform
, p1
.x
, p1
.y
);
3233 p2
= figure
->vertices
[j
];
3234 d2d_point_transform(&p2
, transform
, p2
.x
, p2
.y
);
3235 d2d_rect_get_bezier_bounds(&bezier_bounds
, &p
, &p1
, &p2
);
3236 d2d_rect_union(bounds
, &bezier_bounds
);
3241 FIXME("Unhandled vertex type %#x.\n", type
);
3242 p
= figure
->vertices
[j
];
3243 d2d_point_transform(&p
, transform
, p
.x
, p
.y
);
3244 d2d_rect_expand(bounds
, &p
);
3248 type
= figure
->vertex_types
[j
];
3251 if (d2d_vertex_type_is_bezier(type
))
3253 p1
= figure
->original_bezier_controls
[bezier_idx
++];
3254 d2d_point_transform(&p1
, transform
, p1
.x
, p1
.y
);
3255 p2
= figure
->vertices
[0];
3256 d2d_point_transform(&p2
, transform
, p2
.x
, p2
.y
);
3257 d2d_rect_get_bezier_bounds(&bezier_bounds
, &p
, &p1
, &p2
);
3258 d2d_rect_union(bounds
, &bezier_bounds
);
3262 if (bounds
->left
> bounds
->right
)
3264 bounds
->left
= INFINITY
;
3265 bounds
->right
= FLT_MAX
;
3266 bounds
->top
= INFINITY
;
3267 bounds
->bottom
= FLT_MAX
;
3273 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_GetWidenedBounds(ID2D1PathGeometry
*iface
, float stroke_width
,
3274 ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_RECT_F
*bounds
)
3276 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
3277 iface
, stroke_width
, stroke_style
, transform
, tolerance
, bounds
);
3282 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_StrokeContainsPoint(ID2D1PathGeometry
*iface
,
3283 D2D1_POINT_2F point
, float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
3284 float tolerance
, BOOL
*contains
)
3286 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, "
3287 "transform %p, tolerance %.8e, contains %p stub!\n",
3288 iface
, debug_d2d_point_2f(&point
), stroke_width
, stroke_style
, transform
, tolerance
, contains
);
3293 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_FillContainsPoint(ID2D1PathGeometry
*iface
,
3294 D2D1_POINT_2F point
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, BOOL
*contains
)
3296 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
3297 D2D1_MATRIX_3X2_F g_i
;
3299 TRACE("iface %p, point %s, transform %p, tolerance %.8e, contains %p.\n",
3300 iface
, debug_d2d_point_2f(&point
), transform
, tolerance
, contains
);
3304 if (!d2d_matrix_invert(&g_i
, transform
))
3305 return D2DERR_UNSUPPORTED_OPERATION
;
3306 d2d_point_transform(&point
, &g_i
, point
.x
, point
.y
);
3309 *contains
= !!d2d_path_geometry_point_inside(geometry
, &point
, FALSE
);
3311 TRACE("-> %#x.\n", *contains
);
3316 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_CompareWithGeometry(ID2D1PathGeometry
*iface
,
3317 ID2D1Geometry
*geometry
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_GEOMETRY_RELATION
*relation
)
3319 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
3320 iface
, geometry
, transform
, tolerance
, relation
);
3325 static void d2d_geometry_flatten_cubic(ID2D1SimplifiedGeometrySink
*sink
, const D2D1_POINT_2F
*p0
,
3326 const D2D1_BEZIER_SEGMENT
*b
, float tolerance
)
3328 D2D1_BEZIER_SEGMENT b0
, b1
;
3332 /* It's certainly possible to calculate the maximum deviation of the
3333 * approximation from the curve, but it's a little involved. Instead, note
3334 * that if the control points were evenly spaced and collinear, p1 would
3335 * be exactly between p0 and p2, and p2 would be exactly between p1 and
3336 * p3. The deviation is a decent enough approximation, and much easier to
3339 * p1' = (p0 + p2) / 2
3340 * p2' = (p1 + p3) / 2
3341 * d = ‖p1 - p1'‖₁ + ‖p2 - p2'‖₁ */
3342 d2d_point_lerp(&q
, p0
, &b
->point2
, 0.5f
);
3343 d2d_point_subtract(&q
, &b
->point1
, &q
);
3344 d
= fabsf(q
.x
) + fabsf(q
.y
);
3345 d2d_point_lerp(&q
, &b
->point1
, &b
->point3
, 0.5f
);
3346 d2d_point_subtract(&q
, &b
->point2
, &q
);
3347 d
+= fabsf(q
.x
) + fabsf(q
.y
);
3350 ID2D1SimplifiedGeometrySink_AddLines(sink
, &b
->point3
, 1);
3354 d2d_point_lerp(&q
, &b
->point1
, &b
->point2
, 0.5f
);
3356 b1
.point3
= b
->point3
;
3357 d2d_point_lerp(&b1
.point2
, &b1
.point3
, &b
->point2
, 0.5f
);
3358 d2d_point_lerp(&b1
.point1
, &b1
.point2
, &q
, 0.5f
);
3360 d2d_point_lerp(&b0
.point1
, p0
, &b
->point1
, 0.5f
);
3361 d2d_point_lerp(&b0
.point2
, &b0
.point1
, &q
, 0.5f
);
3362 d2d_point_lerp(&b0
.point3
, &b0
.point2
, &b1
.point1
, 0.5f
);
3364 d2d_geometry_flatten_cubic(sink
, p0
, &b0
, tolerance
);
3365 ID2D1SimplifiedGeometrySink_SetSegmentFlags(sink
, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN
);
3366 d2d_geometry_flatten_cubic(sink
, &b0
.point3
, &b1
, tolerance
);
3367 ID2D1SimplifiedGeometrySink_SetSegmentFlags(sink
, D2D1_PATH_SEGMENT_NONE
);
3370 static void d2d_geometry_simplify_quadratic(ID2D1SimplifiedGeometrySink
*sink
,
3371 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option
, const D2D1_POINT_2F
*p0
,
3372 const D2D1_POINT_2F
*p1
, const D2D1_POINT_2F
*p2
, float tolerance
)
3374 D2D1_BEZIER_SEGMENT b
;
3376 d2d_point_lerp(&b
.point1
, p0
, p1
, 2.0f
/ 3.0f
);
3377 d2d_point_lerp(&b
.point2
, p2
, p1
, 2.0f
/ 3.0f
);
3380 if (option
== D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES
)
3381 d2d_geometry_flatten_cubic(sink
, p0
, &b
, tolerance
);
3383 ID2D1SimplifiedGeometrySink_AddBeziers(sink
, &b
, 1);
3386 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Simplify(ID2D1PathGeometry
*iface
,
3387 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
3388 ID2D1SimplifiedGeometrySink
*sink
)
3390 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
3391 enum d2d_vertex_type type
= D2D_VERTEX_TYPE_NONE
;
3392 unsigned int i
, j
, bezier_idx
;
3393 D2D1_FIGURE_BEGIN begin
;
3394 D2D1_POINT_2F p
, p1
, p2
;
3395 D2D1_FIGURE_END end
;
3397 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
3398 iface
, option
, transform
, tolerance
, sink
);
3400 ID2D1SimplifiedGeometrySink_SetFillMode(sink
, geometry
->u
.path
.fill_mode
);
3401 for (i
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
3403 const struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[i
];
3405 for (j
= 0; j
< figure
->vertex_count
; ++j
)
3407 if (figure
->vertex_types
[j
] == D2D_VERTEX_TYPE_NONE
)
3410 p
= figure
->vertices
[j
];
3412 d2d_point_transform(&p
, transform
, p
.x
, p
.y
);
3413 begin
= figure
->flags
& D2D_FIGURE_FLAG_HOLLOW
? D2D1_FIGURE_BEGIN_HOLLOW
: D2D1_FIGURE_BEGIN_FILLED
;
3414 ID2D1SimplifiedGeometrySink_BeginFigure(sink
, p
, begin
);
3415 type
= figure
->vertex_types
[j
];
3419 for (bezier_idx
= 0, ++j
; j
< figure
->vertex_count
; ++j
)
3421 if (figure
->vertex_types
[j
] == D2D_VERTEX_TYPE_NONE
3422 || d2d_vertex_type_is_split_bezier(figure
->vertex_types
[j
]))
3427 case D2D_VERTEX_TYPE_LINE
:
3428 p
= figure
->vertices
[j
];
3430 d2d_point_transform(&p
, transform
, p
.x
, p
.y
);
3431 ID2D1SimplifiedGeometrySink_AddLines(sink
, &p
, 1);
3434 case D2D_VERTEX_TYPE_BEZIER
:
3435 p1
= figure
->original_bezier_controls
[bezier_idx
++];
3437 d2d_point_transform(&p1
, transform
, p1
.x
, p1
.y
);
3438 p2
= figure
->vertices
[j
];
3440 d2d_point_transform(&p2
, transform
, p2
.x
, p2
.y
);
3441 d2d_geometry_simplify_quadratic(sink
, option
, &p
, &p1
, &p2
, tolerance
);
3446 FIXME("Unhandled vertex type %#x.\n", type
);
3447 p
= figure
->vertices
[j
];
3449 d2d_point_transform(&p
, transform
, p
.x
, p
.y
);
3450 ID2D1SimplifiedGeometrySink_AddLines(sink
, &p
, 1);
3454 type
= figure
->vertex_types
[j
];
3457 if (d2d_vertex_type_is_bezier(type
))
3459 p1
= figure
->original_bezier_controls
[bezier_idx
++];
3461 d2d_point_transform(&p1
, transform
, p1
.x
, p1
.y
);
3462 p2
= figure
->vertices
[0];
3464 d2d_point_transform(&p2
, transform
, p2
.x
, p2
.y
);
3465 d2d_geometry_simplify_quadratic(sink
, option
, &p
, &p1
, &p2
, tolerance
);
3468 end
= figure
->flags
& D2D_FIGURE_FLAG_CLOSED
? D2D1_FIGURE_END_CLOSED
: D2D1_FIGURE_END_OPEN
;
3469 ID2D1SimplifiedGeometrySink_EndFigure(sink
, end
);
3475 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Tessellate(ID2D1PathGeometry
*iface
,
3476 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1TessellationSink
*sink
)
3478 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
3483 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_CombineWithGeometry(ID2D1PathGeometry
*iface
,
3484 ID2D1Geometry
*geometry
, D2D1_COMBINE_MODE combine_mode
, const D2D1_MATRIX_3X2_F
*transform
,
3485 float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
3487 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
3488 iface
, geometry
, combine_mode
, transform
, tolerance
, sink
);
3493 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Outline(ID2D1PathGeometry
*iface
,
3494 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
3496 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
3501 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_ComputeArea(ID2D1PathGeometry
*iface
,
3502 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *area
)
3504 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface
, transform
, tolerance
, area
);
3509 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_ComputeLength(ID2D1PathGeometry
*iface
,
3510 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *length
)
3512 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface
, transform
, tolerance
, length
);
3517 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_ComputePointAtLength(ID2D1PathGeometry
*iface
, float length
,
3518 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_POINT_2F
*point
, D2D1_POINT_2F
*tangent
)
3520 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
3521 iface
, length
, transform
, tolerance
, point
, tangent
);
3526 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Widen(ID2D1PathGeometry
*iface
, float stroke_width
,
3527 ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
3528 ID2D1SimplifiedGeometrySink
*sink
)
3530 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
3531 iface
, stroke_width
, stroke_style
, transform
, tolerance
, sink
);
3536 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Open(ID2D1PathGeometry
*iface
, ID2D1GeometrySink
**sink
)
3538 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
3540 TRACE("iface %p, sink %p.\n", iface
, sink
);
3542 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_INITIAL
)
3543 return D2DERR_WRONG_STATE
;
3545 *sink
= &geometry
->u
.path
.ID2D1GeometrySink_iface
;
3546 ID2D1GeometrySink_AddRef(*sink
);
3548 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_OPEN
;
3553 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Stream(ID2D1PathGeometry
*iface
, ID2D1GeometrySink
*sink
)
3555 FIXME("iface %p, sink %p stub!\n", iface
, sink
);
3560 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_GetSegmentCount(ID2D1PathGeometry
*iface
, UINT32
*count
)
3562 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
3564 TRACE("iface %p, count %p.\n", iface
, count
);
3566 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_CLOSED
)
3567 return D2DERR_WRONG_STATE
;
3569 *count
= geometry
->u
.path
.segment_count
;
3574 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_GetFigureCount(ID2D1PathGeometry
*iface
, UINT32
*count
)
3576 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
3578 TRACE("iface %p, count %p.\n", iface
, count
);
3580 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_CLOSED
)
3581 return D2DERR_WRONG_STATE
;
3583 *count
= geometry
->u
.path
.figure_count
;
3588 static const struct ID2D1PathGeometryVtbl d2d_path_geometry_vtbl
=
3590 d2d_path_geometry_QueryInterface
,
3591 d2d_path_geometry_AddRef
,
3592 d2d_path_geometry_Release
,
3593 d2d_path_geometry_GetFactory
,
3594 d2d_path_geometry_GetBounds
,
3595 d2d_path_geometry_GetWidenedBounds
,
3596 d2d_path_geometry_StrokeContainsPoint
,
3597 d2d_path_geometry_FillContainsPoint
,
3598 d2d_path_geometry_CompareWithGeometry
,
3599 d2d_path_geometry_Simplify
,
3600 d2d_path_geometry_Tessellate
,
3601 d2d_path_geometry_CombineWithGeometry
,
3602 d2d_path_geometry_Outline
,
3603 d2d_path_geometry_ComputeArea
,
3604 d2d_path_geometry_ComputeLength
,
3605 d2d_path_geometry_ComputePointAtLength
,
3606 d2d_path_geometry_Widen
,
3607 d2d_path_geometry_Open
,
3608 d2d_path_geometry_Stream
,
3609 d2d_path_geometry_GetSegmentCount
,
3610 d2d_path_geometry_GetFigureCount
,
3613 void d2d_path_geometry_init(struct d2d_geometry
*geometry
, ID2D1Factory
*factory
)
3615 d2d_geometry_init(geometry
, factory
, &identity
, (ID2D1GeometryVtbl
*)&d2d_path_geometry_vtbl
);
3616 geometry
->u
.path
.ID2D1GeometrySink_iface
.lpVtbl
= &d2d_geometry_sink_vtbl
;
3617 geometry
->u
.path
.bounds
.left
= FLT_MAX
;
3618 geometry
->u
.path
.bounds
.right
= -FLT_MAX
;
3619 geometry
->u
.path
.bounds
.top
= FLT_MAX
;
3620 geometry
->u
.path
.bounds
.bottom
= -FLT_MAX
;
3623 static inline struct d2d_geometry
*impl_from_ID2D1EllipseGeometry(ID2D1EllipseGeometry
*iface
)
3625 return CONTAINING_RECORD(iface
, struct d2d_geometry
, ID2D1Geometry_iface
);
3628 static HRESULT STDMETHODCALLTYPE
d2d_ellipse_geometry_QueryInterface(ID2D1EllipseGeometry
*iface
,
3629 REFIID iid
, void **out
)
3631 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
3633 if (IsEqualGUID(iid
, &IID_ID2D1EllipseGeometry
)
3634 || IsEqualGUID(iid
, &IID_ID2D1Geometry
)
3635 || IsEqualGUID(iid
, &IID_ID2D1Resource
)
3636 || IsEqualGUID(iid
, &IID_IUnknown
))
3638 ID2D1EllipseGeometry_AddRef(iface
);
3643 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
3646 return E_NOINTERFACE
;
3649 static ULONG STDMETHODCALLTYPE
d2d_ellipse_geometry_AddRef(ID2D1EllipseGeometry
*iface
)
3651 struct d2d_geometry
*geometry
= impl_from_ID2D1EllipseGeometry(iface
);
3652 ULONG refcount
= InterlockedIncrement(&geometry
->refcount
);
3654 TRACE("%p increasing refcount to %u.\n", iface
, refcount
);
3659 static ULONG STDMETHODCALLTYPE
d2d_ellipse_geometry_Release(ID2D1EllipseGeometry
*iface
)
3661 struct d2d_geometry
*geometry
= impl_from_ID2D1EllipseGeometry(iface
);
3662 ULONG refcount
= InterlockedDecrement(&geometry
->refcount
);
3664 TRACE("%p decreasing refcount to %u.\n", iface
, refcount
);
3668 d2d_geometry_cleanup(geometry
);
3669 heap_free(geometry
);
3675 static void STDMETHODCALLTYPE
d2d_ellipse_geometry_GetFactory(ID2D1EllipseGeometry
*iface
, ID2D1Factory
**factory
)
3677 struct d2d_geometry
*geometry
= impl_from_ID2D1EllipseGeometry(iface
);
3679 TRACE("iface %p, factory %p.\n", iface
, factory
);
3681 ID2D1Factory_AddRef(*factory
= geometry
->factory
);
3684 static HRESULT STDMETHODCALLTYPE
d2d_ellipse_geometry_GetBounds(ID2D1EllipseGeometry
*iface
,
3685 const D2D1_MATRIX_3X2_F
*transform
, D2D1_RECT_F
*bounds
)
3687 FIXME("iface %p, transform %p, bounds %p stub!\n", iface
, transform
, bounds
);
3692 static HRESULT STDMETHODCALLTYPE
d2d_ellipse_geometry_GetWidenedBounds(ID2D1EllipseGeometry
*iface
,
3693 float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
3694 float tolerance
, D2D1_RECT_F
*bounds
)
3696 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
3697 iface
, stroke_width
, stroke_style
, transform
, tolerance
, bounds
);
3702 static HRESULT STDMETHODCALLTYPE
d2d_ellipse_geometry_StrokeContainsPoint(ID2D1EllipseGeometry
*iface
,
3703 D2D1_POINT_2F point
, float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
3704 float tolerance
, BOOL
*contains
)
3706 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p stub!\n",
3707 iface
, debug_d2d_point_2f(&point
), stroke_width
, stroke_style
, transform
, tolerance
, contains
);
3712 static HRESULT STDMETHODCALLTYPE
d2d_ellipse_geometry_FillContainsPoint(ID2D1EllipseGeometry
*iface
,
3713 D2D1_POINT_2F point
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, BOOL
*contains
)
3715 FIXME("iface %p, point %s, transform %p, tolerance %.8e, contains %p stub!\n",
3716 iface
, debug_d2d_point_2f(&point
), transform
, tolerance
, contains
);
3721 static HRESULT STDMETHODCALLTYPE
d2d_ellipse_geometry_CompareWithGeometry(ID2D1EllipseGeometry
*iface
,
3722 ID2D1Geometry
*geometry
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_GEOMETRY_RELATION
*relation
)
3724 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
3725 iface
, geometry
, transform
, tolerance
, relation
);
3730 static HRESULT STDMETHODCALLTYPE
d2d_ellipse_geometry_Simplify(ID2D1EllipseGeometry
*iface
,
3731 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
3732 ID2D1SimplifiedGeometrySink
*sink
)
3734 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
3735 iface
, option
, transform
, tolerance
, sink
);
3740 static HRESULT STDMETHODCALLTYPE
d2d_ellipse_geometry_Tessellate(ID2D1EllipseGeometry
*iface
,
3741 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1TessellationSink
*sink
)
3743 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
3748 static HRESULT STDMETHODCALLTYPE
d2d_ellipse_geometry_CombineWithGeometry(ID2D1EllipseGeometry
*iface
,
3749 ID2D1Geometry
*geometry
, D2D1_COMBINE_MODE combine_mode
, const D2D1_MATRIX_3X2_F
*transform
,
3750 float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
3752 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
3753 iface
, geometry
, combine_mode
, transform
, tolerance
, sink
);
3758 static HRESULT STDMETHODCALLTYPE
d2d_ellipse_geometry_Outline(ID2D1EllipseGeometry
*iface
,
3759 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
3761 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
3766 static HRESULT STDMETHODCALLTYPE
d2d_ellipse_geometry_ComputeArea(ID2D1EllipseGeometry
*iface
,
3767 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *area
)
3769 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface
, transform
, tolerance
, area
);
3774 static HRESULT STDMETHODCALLTYPE
d2d_ellipse_geometry_ComputeLength(ID2D1EllipseGeometry
*iface
,
3775 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *length
)
3777 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface
, transform
, tolerance
, length
);
3782 static HRESULT STDMETHODCALLTYPE
d2d_ellipse_geometry_ComputePointAtLength(ID2D1EllipseGeometry
*iface
,
3783 float length
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_POINT_2F
*point
,
3784 D2D1_POINT_2F
*tangent
)
3786 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
3787 iface
, length
, transform
, tolerance
, point
, tangent
);
3792 static HRESULT STDMETHODCALLTYPE
d2d_ellipse_geometry_Widen(ID2D1EllipseGeometry
*iface
, float stroke_width
,
3793 ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
3794 ID2D1SimplifiedGeometrySink
*sink
)
3796 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
3797 iface
, stroke_width
, stroke_style
, transform
, tolerance
, sink
);
3802 static void STDMETHODCALLTYPE
d2d_ellipse_geometry_GetEllipse(ID2D1EllipseGeometry
*iface
, D2D1_ELLIPSE
*ellipse
)
3804 struct d2d_geometry
*geometry
= impl_from_ID2D1EllipseGeometry(iface
);
3806 TRACE("iface %p, ellipse %p.\n", iface
, ellipse
);
3808 *ellipse
= geometry
->u
.ellipse
.ellipse
;
3811 static const struct ID2D1EllipseGeometryVtbl d2d_ellipse_geometry_vtbl
=
3813 d2d_ellipse_geometry_QueryInterface
,
3814 d2d_ellipse_geometry_AddRef
,
3815 d2d_ellipse_geometry_Release
,
3816 d2d_ellipse_geometry_GetFactory
,
3817 d2d_ellipse_geometry_GetBounds
,
3818 d2d_ellipse_geometry_GetWidenedBounds
,
3819 d2d_ellipse_geometry_StrokeContainsPoint
,
3820 d2d_ellipse_geometry_FillContainsPoint
,
3821 d2d_ellipse_geometry_CompareWithGeometry
,
3822 d2d_ellipse_geometry_Simplify
,
3823 d2d_ellipse_geometry_Tessellate
,
3824 d2d_ellipse_geometry_CombineWithGeometry
,
3825 d2d_ellipse_geometry_Outline
,
3826 d2d_ellipse_geometry_ComputeArea
,
3827 d2d_ellipse_geometry_ComputeLength
,
3828 d2d_ellipse_geometry_ComputePointAtLength
,
3829 d2d_ellipse_geometry_Widen
,
3830 d2d_ellipse_geometry_GetEllipse
,
3833 HRESULT
d2d_ellipse_geometry_init(struct d2d_geometry
*geometry
, ID2D1Factory
*factory
, const D2D1_ELLIPSE
*ellipse
)
3835 D2D1_POINT_2F
*v
, v1
, v2
, v3
, v4
;
3839 d2d_geometry_init(geometry
, factory
, &identity
, (ID2D1GeometryVtbl
*)&d2d_ellipse_geometry_vtbl
);
3840 geometry
->u
.ellipse
.ellipse
= *ellipse
;
3842 if (!(geometry
->fill
.vertices
= heap_alloc(4 * sizeof(*geometry
->fill
.vertices
))))
3844 if (!d2d_array_reserve((void **)&geometry
->fill
.faces
,
3845 &geometry
->fill
.faces_size
, 2, sizeof(*geometry
->fill
.faces
)))
3848 l
= ellipse
->point
.x
- ellipse
->radiusX
;
3849 r
= ellipse
->point
.x
+ ellipse
->radiusX
;
3850 t
= ellipse
->point
.y
- ellipse
->radiusY
;
3851 b
= ellipse
->point
.y
+ ellipse
->radiusY
;
3853 d2d_point_set(&v1
, r
, t
);
3854 d2d_point_set(&v2
, r
, b
);
3855 d2d_point_set(&v3
, l
, b
);
3856 d2d_point_set(&v4
, l
, t
);
3858 v
= geometry
->fill
.vertices
;
3859 d2d_point_set(&v
[0], ellipse
->point
.x
, t
);
3860 d2d_point_set(&v
[1], r
, ellipse
->point
.y
);
3861 d2d_point_set(&v
[2], ellipse
->point
.x
, b
);
3862 d2d_point_set(&v
[3], l
, ellipse
->point
.y
);
3863 geometry
->fill
.vertex_count
= 4;
3865 f
= geometry
->fill
.faces
;
3866 d2d_face_set(&f
[0], 0, 3, 2);
3867 d2d_face_set(&f
[1], 0, 2, 1);
3868 geometry
->fill
.face_count
= 2;
3870 if (!d2d_geometry_fill_add_arc_triangle(geometry
, &v
[0], &v1
, &v
[1]))
3872 if (!d2d_geometry_fill_add_arc_triangle(geometry
, &v
[1], &v2
, &v
[2]))
3874 if (!d2d_geometry_fill_add_arc_triangle(geometry
, &v
[2], &v3
, &v
[3]))
3876 if (!d2d_geometry_fill_add_arc_triangle(geometry
, &v
[3], &v4
, &v
[0]))
3879 if (!d2d_geometry_outline_add_arc_quadrant(geometry
, &v
[0], &v1
, &v
[1]))
3881 if (!d2d_geometry_outline_add_arc_quadrant(geometry
, &v
[1], &v2
, &v
[2]))
3883 if (!d2d_geometry_outline_add_arc_quadrant(geometry
, &v
[2], &v3
, &v
[3]))
3885 if (!d2d_geometry_outline_add_arc_quadrant(geometry
, &v
[3], &v4
, &v
[0]))
3891 d2d_geometry_cleanup(geometry
);
3892 return E_OUTOFMEMORY
;
3895 static inline struct d2d_geometry
*impl_from_ID2D1RectangleGeometry(ID2D1RectangleGeometry
*iface
)
3897 return CONTAINING_RECORD(iface
, struct d2d_geometry
, ID2D1Geometry_iface
);
3900 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_QueryInterface(ID2D1RectangleGeometry
*iface
,
3901 REFIID iid
, void **out
)
3903 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
3905 if (IsEqualGUID(iid
, &IID_ID2D1RectangleGeometry
)
3906 || IsEqualGUID(iid
, &IID_ID2D1Geometry
)
3907 || IsEqualGUID(iid
, &IID_ID2D1Resource
)
3908 || IsEqualGUID(iid
, &IID_IUnknown
))
3910 ID2D1RectangleGeometry_AddRef(iface
);
3915 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
3918 return E_NOINTERFACE
;
3921 static ULONG STDMETHODCALLTYPE
d2d_rectangle_geometry_AddRef(ID2D1RectangleGeometry
*iface
)
3923 struct d2d_geometry
*geometry
= impl_from_ID2D1RectangleGeometry(iface
);
3924 ULONG refcount
= InterlockedIncrement(&geometry
->refcount
);
3926 TRACE("%p increasing refcount to %u.\n", iface
, refcount
);
3931 static ULONG STDMETHODCALLTYPE
d2d_rectangle_geometry_Release(ID2D1RectangleGeometry
*iface
)
3933 struct d2d_geometry
*geometry
= impl_from_ID2D1RectangleGeometry(iface
);
3934 ULONG refcount
= InterlockedDecrement(&geometry
->refcount
);
3936 TRACE("%p decreasing refcount to %u.\n", iface
, refcount
);
3940 d2d_geometry_cleanup(geometry
);
3941 heap_free(geometry
);
3947 static void STDMETHODCALLTYPE
d2d_rectangle_geometry_GetFactory(ID2D1RectangleGeometry
*iface
, ID2D1Factory
**factory
)
3949 struct d2d_geometry
*geometry
= impl_from_ID2D1RectangleGeometry(iface
);
3951 TRACE("iface %p, factory %p.\n", iface
, factory
);
3953 ID2D1Factory_AddRef(*factory
= geometry
->factory
);
3956 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_GetBounds(ID2D1RectangleGeometry
*iface
,
3957 const D2D1_MATRIX_3X2_F
*transform
, D2D1_RECT_F
*bounds
)
3959 struct d2d_geometry
*geometry
= impl_from_ID2D1RectangleGeometry(iface
);
3963 TRACE("iface %p, transform %p, bounds %p.\n", iface
, transform
, bounds
);
3965 rect
= &geometry
->u
.rectangle
.rect
;
3972 bounds
->left
= FLT_MAX
;
3973 bounds
->top
= FLT_MAX
;
3974 bounds
->right
= -FLT_MAX
;
3975 bounds
->bottom
= -FLT_MAX
;
3977 d2d_point_transform(&p
, transform
, rect
->left
, rect
->top
);
3978 d2d_rect_expand(bounds
, &p
);
3979 d2d_point_transform(&p
, transform
, rect
->left
, rect
->bottom
);
3980 d2d_rect_expand(bounds
, &p
);
3981 d2d_point_transform(&p
, transform
, rect
->right
, rect
->bottom
);
3982 d2d_rect_expand(bounds
, &p
);
3983 d2d_point_transform(&p
, transform
, rect
->right
, rect
->top
);
3984 d2d_rect_expand(bounds
, &p
);
3989 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_GetWidenedBounds(ID2D1RectangleGeometry
*iface
,
3990 float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
3991 float tolerance
, D2D1_RECT_F
*bounds
)
3993 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
3994 iface
, stroke_width
, stroke_style
, transform
, tolerance
, bounds
);
3999 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_StrokeContainsPoint(ID2D1RectangleGeometry
*iface
,
4000 D2D1_POINT_2F point
, float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
4001 float tolerance
, BOOL
*contains
)
4003 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p stub!\n",
4004 iface
, debug_d2d_point_2f(&point
), stroke_width
, stroke_style
, transform
, tolerance
, contains
);
4009 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_FillContainsPoint(ID2D1RectangleGeometry
*iface
,
4010 D2D1_POINT_2F point
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, BOOL
*contains
)
4012 struct d2d_geometry
*geometry
= impl_from_ID2D1RectangleGeometry(iface
);
4013 D2D1_RECT_F
*rect
= &geometry
->u
.rectangle
.rect
;
4016 TRACE("iface %p, point %s, transform %p, tolerance %.8e, contains %p.\n",
4017 iface
, debug_d2d_point_2f(&point
), transform
, tolerance
, contains
);
4021 D2D1_MATRIX_3X2_F g_i
;
4023 if (!d2d_matrix_invert(&g_i
, transform
))
4024 return D2DERR_UNSUPPORTED_OPERATION
;
4025 d2d_point_transform(&point
, &g_i
, point
.x
, point
.y
);
4028 if (tolerance
== 0.0f
)
4029 tolerance
= D2D1_DEFAULT_FLATTENING_TOLERANCE
;
4031 dx
= max(fabsf((rect
->right
+ rect
->left
) / 2.0f
- point
.x
) - (rect
->right
- rect
->left
) / 2.0f
, 0.0f
);
4032 dy
= max(fabsf((rect
->bottom
+ rect
->top
) / 2.0f
- point
.y
) - (rect
->bottom
- rect
->top
) / 2.0f
, 0.0f
);
4034 *contains
= tolerance
* tolerance
> (dx
* dx
+ dy
* dy
);
4038 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_CompareWithGeometry(ID2D1RectangleGeometry
*iface
,
4039 ID2D1Geometry
*geometry
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_GEOMETRY_RELATION
*relation
)
4041 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
4042 iface
, geometry
, transform
, tolerance
, relation
);
4047 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_Simplify(ID2D1RectangleGeometry
*iface
,
4048 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
4049 ID2D1SimplifiedGeometrySink
*sink
)
4051 struct d2d_geometry
*geometry
= impl_from_ID2D1RectangleGeometry(iface
);
4052 D2D1_RECT_F
*rect
= &geometry
->u
.rectangle
.rect
;
4056 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
4057 iface
, option
, transform
, tolerance
, sink
);
4059 d2d_point_set(&p
[0], rect
->left
, rect
->top
);
4060 d2d_point_set(&p
[1], rect
->right
, rect
->top
);
4061 d2d_point_set(&p
[2], rect
->right
, rect
->bottom
);
4062 d2d_point_set(&p
[3], rect
->left
, rect
->bottom
);
4066 for (i
= 0; i
< ARRAY_SIZE(p
); ++i
)
4068 d2d_point_transform(&p
[i
], transform
, p
[i
].x
, p
[i
].y
);
4072 ID2D1SimplifiedGeometrySink_SetFillMode(sink
, D2D1_FILL_MODE_ALTERNATE
);
4073 ID2D1SimplifiedGeometrySink_BeginFigure(sink
, p
[0], D2D1_FIGURE_BEGIN_FILLED
);
4074 ID2D1SimplifiedGeometrySink_AddLines(sink
, &p
[1], 3);
4075 ID2D1SimplifiedGeometrySink_EndFigure(sink
, D2D1_FIGURE_END_CLOSED
);
4080 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_Tessellate(ID2D1RectangleGeometry
*iface
,
4081 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1TessellationSink
*sink
)
4083 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
4088 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_CombineWithGeometry(ID2D1RectangleGeometry
*iface
,
4089 ID2D1Geometry
*geometry
, D2D1_COMBINE_MODE combine_mode
, const D2D1_MATRIX_3X2_F
*transform
,
4090 float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
4092 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4093 iface
, geometry
, combine_mode
, transform
, tolerance
, sink
);
4098 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_Outline(ID2D1RectangleGeometry
*iface
,
4099 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
4101 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
4106 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_ComputeArea(ID2D1RectangleGeometry
*iface
,
4107 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *area
)
4109 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface
, transform
, tolerance
, area
);
4114 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_ComputeLength(ID2D1RectangleGeometry
*iface
,
4115 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *length
)
4117 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface
, transform
, tolerance
, length
);
4122 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_ComputePointAtLength(ID2D1RectangleGeometry
*iface
,
4123 float length
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_POINT_2F
*point
,
4124 D2D1_POINT_2F
*tangent
)
4126 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
4127 iface
, length
, transform
, tolerance
, point
, tangent
);
4132 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_Widen(ID2D1RectangleGeometry
*iface
, float stroke_width
,
4133 ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
4134 ID2D1SimplifiedGeometrySink
*sink
)
4136 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
4137 iface
, stroke_width
, stroke_style
, transform
, tolerance
, sink
);
4142 static void STDMETHODCALLTYPE
d2d_rectangle_geometry_GetRect(ID2D1RectangleGeometry
*iface
, D2D1_RECT_F
*rect
)
4144 struct d2d_geometry
*geometry
= impl_from_ID2D1RectangleGeometry(iface
);
4146 TRACE("iface %p, rect %p.\n", iface
, rect
);
4148 *rect
= geometry
->u
.rectangle
.rect
;
4151 static const struct ID2D1RectangleGeometryVtbl d2d_rectangle_geometry_vtbl
=
4153 d2d_rectangle_geometry_QueryInterface
,
4154 d2d_rectangle_geometry_AddRef
,
4155 d2d_rectangle_geometry_Release
,
4156 d2d_rectangle_geometry_GetFactory
,
4157 d2d_rectangle_geometry_GetBounds
,
4158 d2d_rectangle_geometry_GetWidenedBounds
,
4159 d2d_rectangle_geometry_StrokeContainsPoint
,
4160 d2d_rectangle_geometry_FillContainsPoint
,
4161 d2d_rectangle_geometry_CompareWithGeometry
,
4162 d2d_rectangle_geometry_Simplify
,
4163 d2d_rectangle_geometry_Tessellate
,
4164 d2d_rectangle_geometry_CombineWithGeometry
,
4165 d2d_rectangle_geometry_Outline
,
4166 d2d_rectangle_geometry_ComputeArea
,
4167 d2d_rectangle_geometry_ComputeLength
,
4168 d2d_rectangle_geometry_ComputePointAtLength
,
4169 d2d_rectangle_geometry_Widen
,
4170 d2d_rectangle_geometry_GetRect
,
4173 HRESULT
d2d_rectangle_geometry_init(struct d2d_geometry
*geometry
, ID2D1Factory
*factory
, const D2D1_RECT_F
*rect
)
4179 static const D2D1_POINT_2F prev
[] =
4186 static const D2D1_POINT_2F next
[] =
4194 d2d_geometry_init(geometry
, factory
, &identity
, (ID2D1GeometryVtbl
*)&d2d_rectangle_geometry_vtbl
);
4195 geometry
->u
.rectangle
.rect
= *rect
;
4197 if (!(geometry
->fill
.vertices
= heap_alloc(4 * sizeof(*geometry
->fill
.vertices
))))
4199 if (!d2d_array_reserve((void **)&geometry
->fill
.faces
,
4200 &geometry
->fill
.faces_size
, 2, sizeof(*geometry
->fill
.faces
)))
4203 l
= min(rect
->left
, rect
->right
);
4204 r
= max(rect
->left
, rect
->right
);
4205 t
= min(rect
->top
, rect
->bottom
);
4206 b
= max(rect
->top
, rect
->bottom
);
4208 v
= geometry
->fill
.vertices
;
4209 d2d_point_set(&v
[0], l
, t
);
4210 d2d_point_set(&v
[1], l
, b
);
4211 d2d_point_set(&v
[2], r
, b
);
4212 d2d_point_set(&v
[3], r
, t
);
4213 geometry
->fill
.vertex_count
= 4;
4215 f
= geometry
->fill
.faces
;
4216 d2d_face_set(&f
[0], 1, 2, 0);
4217 d2d_face_set(&f
[1], 0, 2, 3);
4218 geometry
->fill
.face_count
= 2;
4220 if (!d2d_geometry_outline_add_line_segment(geometry
, &v
[0], &v
[1]))
4222 if (!d2d_geometry_outline_add_line_segment(geometry
, &v
[1], &v
[2]))
4224 if (!d2d_geometry_outline_add_line_segment(geometry
, &v
[2], &v
[3]))
4226 if (!d2d_geometry_outline_add_line_segment(geometry
, &v
[3], &v
[0]))
4229 if (!d2d_geometry_outline_add_join(geometry
, &prev
[0], &v
[0], &next
[0]))
4231 if (!d2d_geometry_outline_add_join(geometry
, &prev
[1], &v
[1], &next
[1]))
4233 if (!d2d_geometry_outline_add_join(geometry
, &prev
[2], &v
[2], &next
[2]))
4235 if (!d2d_geometry_outline_add_join(geometry
, &prev
[3], &v
[3], &next
[3]))
4241 d2d_geometry_cleanup(geometry
);
4242 return E_OUTOFMEMORY
;
4245 static inline struct d2d_geometry
*impl_from_ID2D1RoundedRectangleGeometry(ID2D1RoundedRectangleGeometry
*iface
)
4247 return CONTAINING_RECORD(iface
, struct d2d_geometry
, ID2D1Geometry_iface
);
4250 static HRESULT STDMETHODCALLTYPE
d2d_rounded_rectangle_geometry_QueryInterface(ID2D1RoundedRectangleGeometry
*iface
,
4251 REFIID iid
, void **out
)
4253 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
4255 if (IsEqualGUID(iid
, &IID_ID2D1RoundedRectangleGeometry
)
4256 || IsEqualGUID(iid
, &IID_ID2D1Geometry
)
4257 || IsEqualGUID(iid
, &IID_ID2D1Resource
)
4258 || IsEqualGUID(iid
, &IID_IUnknown
))
4260 ID2D1RoundedRectangleGeometry_AddRef(iface
);
4265 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
4268 return E_NOINTERFACE
;
4271 static ULONG STDMETHODCALLTYPE
d2d_rounded_rectangle_geometry_AddRef(ID2D1RoundedRectangleGeometry
*iface
)
4273 struct d2d_geometry
*geometry
= impl_from_ID2D1RoundedRectangleGeometry(iface
);
4274 ULONG refcount
= InterlockedIncrement(&geometry
->refcount
);
4276 TRACE("%p increasing refcount to %u.\n", iface
, refcount
);
4281 static ULONG STDMETHODCALLTYPE
d2d_rounded_rectangle_geometry_Release(ID2D1RoundedRectangleGeometry
*iface
)
4283 struct d2d_geometry
*geometry
= impl_from_ID2D1RoundedRectangleGeometry(iface
);
4284 ULONG refcount
= InterlockedDecrement(&geometry
->refcount
);
4286 TRACE("%p decreasing refcount to %u.\n", iface
, refcount
);
4290 d2d_geometry_cleanup(geometry
);
4291 heap_free(geometry
);
4297 static void STDMETHODCALLTYPE
d2d_rounded_rectangle_geometry_GetFactory(ID2D1RoundedRectangleGeometry
*iface
,
4298 ID2D1Factory
**factory
)
4300 struct d2d_geometry
*geometry
= impl_from_ID2D1RoundedRectangleGeometry(iface
);
4302 TRACE("iface %p, factory %p.\n", iface
, factory
);
4304 ID2D1Factory_AddRef(*factory
= geometry
->factory
);
4307 static HRESULT STDMETHODCALLTYPE
d2d_rounded_rectangle_geometry_GetBounds(ID2D1RoundedRectangleGeometry
*iface
,
4308 const D2D1_MATRIX_3X2_F
*transform
, D2D1_RECT_F
*bounds
)
4310 FIXME("iface %p, transform %p, bounds %p stub!\n", iface
, transform
, bounds
);
4315 static HRESULT STDMETHODCALLTYPE
d2d_rounded_rectangle_geometry_GetWidenedBounds(ID2D1RoundedRectangleGeometry
*iface
,
4316 float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
4317 float tolerance
, D2D1_RECT_F
*bounds
)
4319 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
4320 iface
, stroke_width
, stroke_style
, transform
, tolerance
, bounds
);
4325 static HRESULT STDMETHODCALLTYPE
d2d_rounded_rectangle_geometry_StrokeContainsPoint(
4326 ID2D1RoundedRectangleGeometry
*iface
, D2D1_POINT_2F point
, float stroke_width
,
4327 ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, BOOL
*contains
)
4329 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p stub!\n",
4330 iface
, debug_d2d_point_2f(&point
), stroke_width
, stroke_style
, transform
, tolerance
, contains
);
4335 static HRESULT STDMETHODCALLTYPE
d2d_rounded_rectangle_geometry_FillContainsPoint(ID2D1RoundedRectangleGeometry
*iface
,
4336 D2D1_POINT_2F point
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, BOOL
*contains
)
4338 FIXME("iface %p, point %s, transform %p, tolerance %.8e, contains %p stub!\n",
4339 iface
, debug_d2d_point_2f(&point
), transform
, tolerance
, contains
);
4344 static HRESULT STDMETHODCALLTYPE
d2d_rounded_rectangle_geometry_CompareWithGeometry(
4345 ID2D1RoundedRectangleGeometry
*iface
, ID2D1Geometry
*geometry
,
4346 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_GEOMETRY_RELATION
*relation
)
4348 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
4349 iface
, geometry
, transform
, tolerance
, relation
);
4354 static HRESULT STDMETHODCALLTYPE
d2d_rounded_rectangle_geometry_Simplify(ID2D1RoundedRectangleGeometry
*iface
,
4355 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
4356 ID2D1SimplifiedGeometrySink
*sink
)
4358 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4359 iface
, option
, transform
, tolerance
, sink
);
4364 static HRESULT STDMETHODCALLTYPE
d2d_rounded_rectangle_geometry_Tessellate(ID2D1RoundedRectangleGeometry
*iface
,
4365 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1TessellationSink
*sink
)
4367 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
4372 static HRESULT STDMETHODCALLTYPE
d2d_rounded_rectangle_geometry_CombineWithGeometry(
4373 ID2D1RoundedRectangleGeometry
*iface
, ID2D1Geometry
*geometry
, D2D1_COMBINE_MODE combine_mode
,
4374 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
4376 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4377 iface
, geometry
, combine_mode
, transform
, tolerance
, sink
);
4382 static HRESULT STDMETHODCALLTYPE
d2d_rounded_rectangle_geometry_Outline(ID2D1RoundedRectangleGeometry
*iface
,
4383 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
4385 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
4390 static HRESULT STDMETHODCALLTYPE
d2d_rounded_rectangle_geometry_ComputeArea(ID2D1RoundedRectangleGeometry
*iface
,
4391 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *area
)
4393 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface
, transform
, tolerance
, area
);
4398 static HRESULT STDMETHODCALLTYPE
d2d_rounded_rectangle_geometry_ComputeLength(ID2D1RoundedRectangleGeometry
*iface
,
4399 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *length
)
4401 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface
, transform
, tolerance
, length
);
4406 static HRESULT STDMETHODCALLTYPE
d2d_rounded_rectangle_geometry_ComputePointAtLength(
4407 ID2D1RoundedRectangleGeometry
*iface
, float length
, const D2D1_MATRIX_3X2_F
*transform
,
4408 float tolerance
, D2D1_POINT_2F
*point
, D2D1_POINT_2F
*tangent
)
4410 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
4411 iface
, length
, transform
, tolerance
, point
, tangent
);
4416 static HRESULT STDMETHODCALLTYPE
d2d_rounded_rectangle_geometry_Widen(ID2D1RoundedRectangleGeometry
*iface
,
4417 float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
4418 float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
4420 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
4421 iface
, stroke_width
, stroke_style
, transform
, tolerance
, sink
);
4426 static void STDMETHODCALLTYPE
d2d_rounded_rectangle_geometry_GetRoundedRect(ID2D1RoundedRectangleGeometry
*iface
,
4427 D2D1_ROUNDED_RECT
*rounded_rect
)
4429 struct d2d_geometry
*geometry
= impl_from_ID2D1RoundedRectangleGeometry(iface
);
4431 TRACE("iface %p, rounded_rect %p.\n", iface
, rounded_rect
);
4433 *rounded_rect
= geometry
->u
.rounded_rectangle
.rounded_rect
;
4436 static const struct ID2D1RoundedRectangleGeometryVtbl d2d_rounded_rectangle_geometry_vtbl
=
4438 d2d_rounded_rectangle_geometry_QueryInterface
,
4439 d2d_rounded_rectangle_geometry_AddRef
,
4440 d2d_rounded_rectangle_geometry_Release
,
4441 d2d_rounded_rectangle_geometry_GetFactory
,
4442 d2d_rounded_rectangle_geometry_GetBounds
,
4443 d2d_rounded_rectangle_geometry_GetWidenedBounds
,
4444 d2d_rounded_rectangle_geometry_StrokeContainsPoint
,
4445 d2d_rounded_rectangle_geometry_FillContainsPoint
,
4446 d2d_rounded_rectangle_geometry_CompareWithGeometry
,
4447 d2d_rounded_rectangle_geometry_Simplify
,
4448 d2d_rounded_rectangle_geometry_Tessellate
,
4449 d2d_rounded_rectangle_geometry_CombineWithGeometry
,
4450 d2d_rounded_rectangle_geometry_Outline
,
4451 d2d_rounded_rectangle_geometry_ComputeArea
,
4452 d2d_rounded_rectangle_geometry_ComputeLength
,
4453 d2d_rounded_rectangle_geometry_ComputePointAtLength
,
4454 d2d_rounded_rectangle_geometry_Widen
,
4455 d2d_rounded_rectangle_geometry_GetRoundedRect
,
4458 HRESULT
d2d_rounded_rectangle_geometry_init(struct d2d_geometry
*geometry
,
4459 ID2D1Factory
*factory
, const D2D1_ROUNDED_RECT
*rounded_rect
)
4461 D2D1_POINT_2F
*v
, v1
, v2
, v3
, v4
;
4466 d2d_geometry_init(geometry
, factory
, &identity
, (ID2D1GeometryVtbl
*)&d2d_rounded_rectangle_geometry_vtbl
);
4467 geometry
->u
.rounded_rectangle
.rounded_rect
= *rounded_rect
;
4469 if (!(geometry
->fill
.vertices
= heap_alloc(8 * sizeof(*geometry
->fill
.vertices
))))
4471 if (!d2d_array_reserve((void **)&geometry
->fill
.faces
,
4472 &geometry
->fill
.faces_size
, 6, sizeof(*geometry
->fill
.faces
)))
4475 l
= min(rounded_rect
->rect
.left
, rounded_rect
->rect
.right
);
4476 r
= max(rounded_rect
->rect
.left
, rounded_rect
->rect
.right
);
4477 t
= min(rounded_rect
->rect
.top
, rounded_rect
->rect
.bottom
);
4478 b
= max(rounded_rect
->rect
.top
, rounded_rect
->rect
.bottom
);
4480 rx
= min(rounded_rect
->radiusX
, 0.5f
* (r
- l
));
4481 ry
= min(rounded_rect
->radiusY
, 0.5f
* (b
- t
));
4483 d2d_point_set(&v1
, r
, t
);
4484 d2d_point_set(&v2
, r
, b
);
4485 d2d_point_set(&v3
, l
, b
);
4486 d2d_point_set(&v4
, l
, t
);
4488 v
= geometry
->fill
.vertices
;
4489 d2d_point_set(&v
[0], l
+ rx
, t
);
4490 d2d_point_set(&v
[1], r
- rx
, t
);
4491 d2d_point_set(&v
[2], r
, t
+ ry
);
4492 d2d_point_set(&v
[3], r
, b
- ry
);
4493 d2d_point_set(&v
[4], r
- rx
, b
);
4494 d2d_point_set(&v
[5], l
+ rx
, b
);
4495 d2d_point_set(&v
[6], l
, b
- ry
);
4496 d2d_point_set(&v
[7], l
, t
+ ry
);
4497 geometry
->fill
.vertex_count
= 8;
4499 f
= geometry
->fill
.faces
;
4500 d2d_face_set(&f
[0], 0, 7, 6);
4501 d2d_face_set(&f
[1], 0, 6, 5);
4502 d2d_face_set(&f
[2], 0, 5, 4);
4503 d2d_face_set(&f
[3], 0, 4, 1);
4504 d2d_face_set(&f
[4], 1, 4, 3);
4505 d2d_face_set(&f
[5], 1, 3, 2);
4506 geometry
->fill
.face_count
= 6;
4508 if (!d2d_geometry_fill_add_arc_triangle(geometry
, &v
[1], &v1
, &v
[2]))
4510 if (!d2d_geometry_fill_add_arc_triangle(geometry
, &v
[3], &v2
, &v
[4]))
4512 if (!d2d_geometry_fill_add_arc_triangle(geometry
, &v
[5], &v3
, &v
[6]))
4514 if (!d2d_geometry_fill_add_arc_triangle(geometry
, &v
[7], &v4
, &v
[0]))
4517 if (!d2d_geometry_outline_add_line_segment(geometry
, &v
[0], &v
[1]))
4519 if (!d2d_geometry_outline_add_arc_quadrant(geometry
, &v
[1], &v1
, &v
[2]))
4521 if (!d2d_geometry_outline_add_line_segment(geometry
, &v
[2], &v
[3]))
4523 if (!d2d_geometry_outline_add_arc_quadrant(geometry
, &v
[3], &v2
, &v
[4]))
4525 if (!d2d_geometry_outline_add_line_segment(geometry
, &v
[4], &v
[5]))
4527 if (!d2d_geometry_outline_add_arc_quadrant(geometry
, &v
[5], &v3
, &v
[6]))
4529 if (!d2d_geometry_outline_add_line_segment(geometry
, &v
[6], &v
[7]))
4531 if (!d2d_geometry_outline_add_arc_quadrant(geometry
, &v
[7], &v4
, &v
[0]))
4537 d2d_geometry_cleanup(geometry
);
4538 return E_OUTOFMEMORY
;
4541 static inline struct d2d_geometry
*impl_from_ID2D1TransformedGeometry(ID2D1TransformedGeometry
*iface
)
4543 return CONTAINING_RECORD(iface
, struct d2d_geometry
, ID2D1Geometry_iface
);
4546 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_QueryInterface(ID2D1TransformedGeometry
*iface
,
4547 REFIID iid
, void **out
)
4549 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
4551 if (IsEqualGUID(iid
, &IID_ID2D1TransformedGeometry
)
4552 || IsEqualGUID(iid
, &IID_ID2D1Geometry
)
4553 || IsEqualGUID(iid
, &IID_ID2D1Resource
)
4554 || IsEqualGUID(iid
, &IID_IUnknown
))
4556 ID2D1TransformedGeometry_AddRef(iface
);
4561 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
4564 return E_NOINTERFACE
;
4567 static ULONG STDMETHODCALLTYPE
d2d_transformed_geometry_AddRef(ID2D1TransformedGeometry
*iface
)
4569 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
4570 ULONG refcount
= InterlockedIncrement(&geometry
->refcount
);
4572 TRACE("%p increasing refcount to %u.\n", iface
, refcount
);
4577 static ULONG STDMETHODCALLTYPE
d2d_transformed_geometry_Release(ID2D1TransformedGeometry
*iface
)
4579 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
4580 ULONG refcount
= InterlockedDecrement(&geometry
->refcount
);
4582 TRACE("%p decreasing refcount to %u.\n", iface
, refcount
);
4586 geometry
->outline
.arc_faces
= NULL
;
4587 geometry
->outline
.arcs
= NULL
;
4588 geometry
->outline
.bezier_faces
= NULL
;
4589 geometry
->outline
.beziers
= NULL
;
4590 geometry
->outline
.faces
= NULL
;
4591 geometry
->outline
.vertices
= NULL
;
4592 geometry
->fill
.arc_vertices
= NULL
;
4593 geometry
->fill
.bezier_vertices
= NULL
;
4594 geometry
->fill
.faces
= NULL
;
4595 geometry
->fill
.vertices
= NULL
;
4596 ID2D1Geometry_Release(geometry
->u
.transformed
.src_geometry
);
4597 d2d_geometry_cleanup(geometry
);
4598 heap_free(geometry
);
4604 static void STDMETHODCALLTYPE
d2d_transformed_geometry_GetFactory(ID2D1TransformedGeometry
*iface
,
4605 ID2D1Factory
**factory
)
4607 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
4609 TRACE("iface %p, factory %p.\n", iface
, factory
);
4611 ID2D1Factory_AddRef(*factory
= geometry
->factory
);
4614 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_GetBounds(ID2D1TransformedGeometry
*iface
,
4615 const D2D1_MATRIX_3X2_F
*transform
, D2D1_RECT_F
*bounds
)
4617 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
4618 D2D1_MATRIX_3X2_F g
;
4620 TRACE("iface %p, transform %p, bounds %p.\n", iface
, transform
, bounds
);
4622 g
= geometry
->transform
;
4624 d2d_matrix_multiply(&g
, transform
);
4626 return ID2D1Geometry_GetBounds(geometry
->u
.transformed
.src_geometry
, &g
, bounds
);
4629 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_GetWidenedBounds(ID2D1TransformedGeometry
*iface
,
4630 float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
4631 float tolerance
, D2D1_RECT_F
*bounds
)
4633 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
4634 iface
, stroke_width
, stroke_style
, transform
, tolerance
, bounds
);
4639 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_StrokeContainsPoint(ID2D1TransformedGeometry
*iface
,
4640 D2D1_POINT_2F point
, float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
4641 float tolerance
, BOOL
*contains
)
4643 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
4644 D2D1_MATRIX_3X2_F g
;
4646 TRACE("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p.\n",
4647 iface
, debug_d2d_point_2f(&point
), stroke_width
, stroke_style
, transform
, tolerance
, contains
);
4649 g
= geometry
->transform
;
4651 d2d_matrix_multiply(&g
, transform
);
4653 return ID2D1Geometry_StrokeContainsPoint(geometry
->u
.transformed
.src_geometry
, point
, stroke_width
, stroke_style
,
4654 &g
, tolerance
, contains
);
4657 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_FillContainsPoint(ID2D1TransformedGeometry
*iface
,
4658 D2D1_POINT_2F point
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, BOOL
*contains
)
4660 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
4661 D2D1_MATRIX_3X2_F g
;
4663 TRACE("iface %p, point %s, transform %p, tolerance %.8e, contains %p.\n",
4664 iface
, debug_d2d_point_2f(&point
), transform
, tolerance
, contains
);
4666 g
= geometry
->transform
;
4668 d2d_matrix_multiply(&g
, transform
);
4670 return ID2D1Geometry_FillContainsPoint(geometry
->u
.transformed
.src_geometry
, point
, &g
, tolerance
, contains
);
4673 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_CompareWithGeometry(ID2D1TransformedGeometry
*iface
,
4674 ID2D1Geometry
*geometry
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_GEOMETRY_RELATION
*relation
)
4676 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
4677 iface
, geometry
, transform
, tolerance
, relation
);
4682 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_Simplify(ID2D1TransformedGeometry
*iface
,
4683 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
4684 ID2D1SimplifiedGeometrySink
*sink
)
4686 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
4687 D2D1_MATRIX_3X2_F g
;
4689 TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
4690 iface
, option
, transform
, tolerance
, sink
);
4692 g
= geometry
->transform
;
4694 d2d_matrix_multiply(&g
, transform
);
4696 return ID2D1Geometry_Simplify(geometry
->u
.transformed
.src_geometry
, option
, &g
, tolerance
, sink
);
4699 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_Tessellate(ID2D1TransformedGeometry
*iface
,
4700 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1TessellationSink
*sink
)
4702 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
4707 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_CombineWithGeometry(ID2D1TransformedGeometry
*iface
,
4708 ID2D1Geometry
*geometry
, D2D1_COMBINE_MODE combine_mode
, const D2D1_MATRIX_3X2_F
*transform
,
4709 float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
4711 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4712 iface
, geometry
, combine_mode
, transform
, tolerance
, sink
);
4717 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_Outline(ID2D1TransformedGeometry
*iface
,
4718 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
4720 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
4725 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_ComputeArea(ID2D1TransformedGeometry
*iface
,
4726 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *area
)
4728 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface
, transform
, tolerance
, area
);
4733 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_ComputeLength(ID2D1TransformedGeometry
*iface
,
4734 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *length
)
4736 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface
, transform
, tolerance
, length
);
4741 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_ComputePointAtLength(ID2D1TransformedGeometry
*iface
,
4742 float length
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_POINT_2F
*point
,
4743 D2D1_POINT_2F
*tangent
)
4745 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
4746 iface
, length
, transform
, tolerance
, point
, tangent
);
4751 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_Widen(ID2D1TransformedGeometry
*iface
, float stroke_width
,
4752 ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
4753 ID2D1SimplifiedGeometrySink
*sink
)
4755 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
4756 iface
, stroke_width
, stroke_style
, transform
, tolerance
, sink
);
4761 static void STDMETHODCALLTYPE
d2d_transformed_geometry_GetSourceGeometry(ID2D1TransformedGeometry
*iface
,
4762 ID2D1Geometry
**src_geometry
)
4764 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
4766 TRACE("iface %p, src_geometry %p.\n", iface
, src_geometry
);
4768 ID2D1Geometry_AddRef(*src_geometry
= geometry
->u
.transformed
.src_geometry
);
4771 static void STDMETHODCALLTYPE
d2d_transformed_geometry_GetTransform(ID2D1TransformedGeometry
*iface
,
4772 D2D1_MATRIX_3X2_F
*transform
)
4774 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
4776 TRACE("iface %p, transform %p.\n", iface
, transform
);
4778 *transform
= geometry
->u
.transformed
.transform
;
4781 static const struct ID2D1TransformedGeometryVtbl d2d_transformed_geometry_vtbl
=
4783 d2d_transformed_geometry_QueryInterface
,
4784 d2d_transformed_geometry_AddRef
,
4785 d2d_transformed_geometry_Release
,
4786 d2d_transformed_geometry_GetFactory
,
4787 d2d_transformed_geometry_GetBounds
,
4788 d2d_transformed_geometry_GetWidenedBounds
,
4789 d2d_transformed_geometry_StrokeContainsPoint
,
4790 d2d_transformed_geometry_FillContainsPoint
,
4791 d2d_transformed_geometry_CompareWithGeometry
,
4792 d2d_transformed_geometry_Simplify
,
4793 d2d_transformed_geometry_Tessellate
,
4794 d2d_transformed_geometry_CombineWithGeometry
,
4795 d2d_transformed_geometry_Outline
,
4796 d2d_transformed_geometry_ComputeArea
,
4797 d2d_transformed_geometry_ComputeLength
,
4798 d2d_transformed_geometry_ComputePointAtLength
,
4799 d2d_transformed_geometry_Widen
,
4800 d2d_transformed_geometry_GetSourceGeometry
,
4801 d2d_transformed_geometry_GetTransform
,
4804 void d2d_transformed_geometry_init(struct d2d_geometry
*geometry
, ID2D1Factory
*factory
,
4805 ID2D1Geometry
*src_geometry
, const D2D_MATRIX_3X2_F
*transform
)
4807 struct d2d_geometry
*src_impl
;
4810 src_impl
= unsafe_impl_from_ID2D1Geometry(src_geometry
);
4812 g
= src_impl
->transform
;
4813 d2d_matrix_multiply(&g
, transform
);
4814 d2d_geometry_init(geometry
, factory
, &g
, (ID2D1GeometryVtbl
*)&d2d_transformed_geometry_vtbl
);
4815 ID2D1Geometry_AddRef(geometry
->u
.transformed
.src_geometry
= src_geometry
);
4816 geometry
->u
.transformed
.transform
= *transform
;
4817 geometry
->fill
= src_impl
->fill
;
4818 geometry
->outline
= src_impl
->outline
;
4821 static inline struct d2d_geometry
*impl_from_ID2D1GeometryGroup(ID2D1GeometryGroup
*iface
)
4823 return CONTAINING_RECORD(iface
, struct d2d_geometry
, ID2D1Geometry_iface
);
4826 static HRESULT STDMETHODCALLTYPE
d2d_geometry_group_QueryInterface(ID2D1GeometryGroup
*iface
,
4827 REFIID iid
, void **out
)
4829 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
4831 if (IsEqualGUID(iid
, &IID_ID2D1GeometryGroup
)
4832 || IsEqualGUID(iid
, &IID_ID2D1Geometry
)
4833 || IsEqualGUID(iid
, &IID_ID2D1Resource
)
4834 || IsEqualGUID(iid
, &IID_IUnknown
))
4836 ID2D1GeometryGroup_AddRef(iface
);
4841 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
4844 return E_NOINTERFACE
;
4847 static ULONG STDMETHODCALLTYPE
d2d_geometry_group_AddRef(ID2D1GeometryGroup
*iface
)
4849 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometryGroup(iface
);
4850 ULONG refcount
= InterlockedIncrement(&geometry
->refcount
);
4852 TRACE("%p increasing refcount to %u.\n", iface
, refcount
);
4857 static ULONG STDMETHODCALLTYPE
d2d_geometry_group_Release(ID2D1GeometryGroup
*iface
)
4859 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometryGroup(iface
);
4860 ULONG refcount
= InterlockedDecrement(&geometry
->refcount
);
4863 TRACE("%p decreasing refcount to %u.\n", iface
, refcount
);
4867 for (i
= 0; i
< geometry
->u
.group
.geometry_count
; ++i
)
4868 ID2D1Geometry_Release(geometry
->u
.group
.src_geometries
[i
]);
4869 heap_free(geometry
->u
.group
.src_geometries
);
4870 d2d_geometry_cleanup(geometry
);
4871 heap_free(geometry
);
4877 static void STDMETHODCALLTYPE
d2d_geometry_group_GetFactory(ID2D1GeometryGroup
*iface
,
4878 ID2D1Factory
**factory
)
4880 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometryGroup(iface
);
4882 TRACE("iface %p, factory %p.\n", iface
, factory
);
4884 ID2D1Factory_AddRef(*factory
= geometry
->factory
);
4887 static HRESULT STDMETHODCALLTYPE
d2d_geometry_group_GetBounds(ID2D1GeometryGroup
*iface
,
4888 const D2D1_MATRIX_3X2_F
*transform
, D2D1_RECT_F
*bounds
)
4890 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometryGroup(iface
);
4894 TRACE("iface %p, transform %p, bounds %p.\n", iface
, transform
, bounds
);
4896 bounds
->left
= FLT_MAX
;
4897 bounds
->top
= FLT_MAX
;
4898 bounds
->right
= -FLT_MAX
;
4899 bounds
->bottom
= -FLT_MAX
;
4901 for (i
= 0; i
< geometry
->u
.group
.geometry_count
; ++i
)
4903 if (SUCCEEDED(ID2D1Geometry_GetBounds(geometry
->u
.group
.src_geometries
[i
], transform
, &rect
)))
4904 d2d_rect_union(bounds
, &rect
);
4910 static HRESULT STDMETHODCALLTYPE
d2d_geometry_group_GetWidenedBounds(ID2D1GeometryGroup
*iface
,
4911 float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
4912 float tolerance
, D2D1_RECT_F
*bounds
)
4914 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
4915 iface
, stroke_width
, stroke_style
, transform
, tolerance
, bounds
);
4920 static HRESULT STDMETHODCALLTYPE
d2d_geometry_group_StrokeContainsPoint(ID2D1GeometryGroup
*iface
,
4921 D2D1_POINT_2F point
, float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
4922 float tolerance
, BOOL
*contains
)
4924 FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p.\n",
4925 iface
, debug_d2d_point_2f(&point
), stroke_width
, stroke_style
, transform
, tolerance
, contains
);
4930 static HRESULT STDMETHODCALLTYPE
d2d_geometry_group_FillContainsPoint(ID2D1GeometryGroup
*iface
,
4931 D2D1_POINT_2F point
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, BOOL
*contains
)
4933 FIXME("iface %p, point %s, transform %p, tolerance %.8e, contains %p stub!.\n",
4934 iface
, debug_d2d_point_2f(&point
), transform
, tolerance
, contains
);
4939 static HRESULT STDMETHODCALLTYPE
d2d_geometry_group_CompareWithGeometry(ID2D1GeometryGroup
*iface
,
4940 ID2D1Geometry
*geometry
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_GEOMETRY_RELATION
*relation
)
4942 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
4943 iface
, geometry
, transform
, tolerance
, relation
);
4948 static HRESULT STDMETHODCALLTYPE
d2d_geometry_group_Simplify(ID2D1GeometryGroup
*iface
,
4949 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
4950 ID2D1SimplifiedGeometrySink
*sink
)
4952 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!.\n",
4953 iface
, option
, transform
, tolerance
, sink
);
4958 static HRESULT STDMETHODCALLTYPE
d2d_geometry_group_Tessellate(ID2D1GeometryGroup
*iface
,
4959 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1TessellationSink
*sink
)
4961 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
4966 static HRESULT STDMETHODCALLTYPE
d2d_geometry_group_CombineWithGeometry(ID2D1GeometryGroup
*iface
,
4967 ID2D1Geometry
*geometry
, D2D1_COMBINE_MODE combine_mode
, const D2D1_MATRIX_3X2_F
*transform
,
4968 float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
4970 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
4971 iface
, geometry
, combine_mode
, transform
, tolerance
, sink
);
4976 static HRESULT STDMETHODCALLTYPE
d2d_geometry_group_Outline(ID2D1GeometryGroup
*iface
,
4977 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
4979 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
4984 static HRESULT STDMETHODCALLTYPE
d2d_geometry_group_ComputeArea(ID2D1GeometryGroup
*iface
,
4985 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *area
)
4987 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface
, transform
, tolerance
, area
);
4992 static HRESULT STDMETHODCALLTYPE
d2d_geometry_group_ComputeLength(ID2D1GeometryGroup
*iface
,
4993 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *length
)
4995 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface
, transform
, tolerance
, length
);
5000 static HRESULT STDMETHODCALLTYPE
d2d_geometry_group_ComputePointAtLength(ID2D1GeometryGroup
*iface
,
5001 float length
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_POINT_2F
*point
,
5002 D2D1_POINT_2F
*tangent
)
5004 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
5005 iface
, length
, transform
, tolerance
, point
, tangent
);
5010 static HRESULT STDMETHODCALLTYPE
d2d_geometry_group_Widen(ID2D1GeometryGroup
*iface
, float stroke_width
,
5011 ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
5012 ID2D1SimplifiedGeometrySink
*sink
)
5014 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
5015 iface
, stroke_width
, stroke_style
, transform
, tolerance
, sink
);
5020 static D2D1_FILL_MODE STDMETHODCALLTYPE
d2d_geometry_group_GetFillMode(ID2D1GeometryGroup
*iface
)
5022 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometryGroup(iface
);
5024 TRACE("iface %p.\n", iface
);
5026 return geometry
->u
.group
.fill_mode
;
5029 static UINT32 STDMETHODCALLTYPE
d2d_geometry_group_GetSourceGeometryCount(ID2D1GeometryGroup
*iface
)
5031 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometryGroup(iface
);
5033 TRACE("iface %p.\n", iface
);
5035 return geometry
->u
.group
.geometry_count
;
5038 static void STDMETHODCALLTYPE
d2d_geometry_group_GetSourceGeometries(ID2D1GeometryGroup
*iface
,
5039 ID2D1Geometry
**geometries
, UINT32 geometry_count
)
5041 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometryGroup(iface
);
5044 TRACE("iface %p, geometries %p, geometry_count %u.\n", iface
, geometries
, geometry_count
);
5046 geometry_count
= min(geometry_count
, geometry
->u
.group
.geometry_count
);
5047 for (i
= 0; i
< geometry_count
; ++i
)
5048 ID2D1Geometry_AddRef(geometries
[i
] = geometry
->u
.group
.src_geometries
[i
]);
5051 static const struct ID2D1GeometryGroupVtbl d2d_geometry_group_vtbl
=
5053 d2d_geometry_group_QueryInterface
,
5054 d2d_geometry_group_AddRef
,
5055 d2d_geometry_group_Release
,
5056 d2d_geometry_group_GetFactory
,
5057 d2d_geometry_group_GetBounds
,
5058 d2d_geometry_group_GetWidenedBounds
,
5059 d2d_geometry_group_StrokeContainsPoint
,
5060 d2d_geometry_group_FillContainsPoint
,
5061 d2d_geometry_group_CompareWithGeometry
,
5062 d2d_geometry_group_Simplify
,
5063 d2d_geometry_group_Tessellate
,
5064 d2d_geometry_group_CombineWithGeometry
,
5065 d2d_geometry_group_Outline
,
5066 d2d_geometry_group_ComputeArea
,
5067 d2d_geometry_group_ComputeLength
,
5068 d2d_geometry_group_ComputePointAtLength
,
5069 d2d_geometry_group_Widen
,
5070 d2d_geometry_group_GetFillMode
,
5071 d2d_geometry_group_GetSourceGeometryCount
,
5072 d2d_geometry_group_GetSourceGeometries
,
5075 HRESULT
d2d_geometry_group_init(struct d2d_geometry
*geometry
, ID2D1Factory
*factory
,
5076 D2D1_FILL_MODE fill_mode
, ID2D1Geometry
**geometries
, unsigned int geometry_count
)
5080 d2d_geometry_init(geometry
, factory
, &identity
, (ID2D1GeometryVtbl
*)&d2d_geometry_group_vtbl
);
5082 if (!(geometry
->u
.group
.src_geometries
= heap_calloc(geometry_count
, sizeof(*geometries
))))
5084 d2d_geometry_cleanup(geometry
);
5085 return E_OUTOFMEMORY
;
5088 for (i
= 0; i
< geometry_count
; ++i
)
5090 ID2D1Geometry_AddRef(geometry
->u
.group
.src_geometries
[i
] = geometries
[i
]);
5092 geometry
->u
.group
.geometry_count
= geometry_count
;
5093 geometry
->u
.group
.fill_mode
= fill_mode
;
5098 struct d2d_geometry
*unsafe_impl_from_ID2D1Geometry(ID2D1Geometry
*iface
)
5102 assert(iface
->lpVtbl
== (const ID2D1GeometryVtbl
*)&d2d_ellipse_geometry_vtbl
5103 || iface
->lpVtbl
== (const ID2D1GeometryVtbl
*)&d2d_path_geometry_vtbl
5104 || iface
->lpVtbl
== (const ID2D1GeometryVtbl
*)&d2d_rectangle_geometry_vtbl
5105 || iface
->lpVtbl
== (const ID2D1GeometryVtbl
*)&d2d_rounded_rectangle_geometry_vtbl
5106 || iface
->lpVtbl
== (const ID2D1GeometryVtbl
*)&d2d_transformed_geometry_vtbl
5107 || iface
->lpVtbl
== (const ID2D1GeometryVtbl
*)&d2d_geometry_group_vtbl
);
5108 return CONTAINING_RECORD(iface
, struct d2d_geometry
, ID2D1Geometry_iface
);