2 * Copyright 2015 Henri Verbeet for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "wine/port.h"
22 #include "d2d1_private.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(d2d
);
29 #define D2D_CDT_EDGE_FLAG_FREED 0x80000000u
30 #define D2D_CDT_EDGE_FLAG_VISITED(r) (1u << (r))
32 #define D2D_FP_EPS (1.0f / (1 << FLT_MANT_DIG))
34 static const D2D1_MATRIX_3X2_F identity
=
41 enum d2d_cdt_edge_next
43 D2D_EDGE_NEXT_ORIGIN
= 0,
44 D2D_EDGE_NEXT_ROT
= 1,
45 D2D_EDGE_NEXT_SYM
= 2,
46 D2D_EDGE_NEXT_TOR
= 3,
51 D2D1_POINT_2F
*vertices
;
55 struct d2d_bezier
*beziers
;
62 struct d2d_cdt_edge_ref
65 enum d2d_cdt_edge_next r
;
70 struct d2d_cdt_edge_ref next
[4];
77 struct d2d_cdt_edge
*edges
;
82 const D2D1_POINT_2F
*vertices
;
85 struct d2d_fp_two_vec2
97 static void d2d_fp_two_sum(float *out
, float a
, float b
)
99 float a_virt
, a_round
, b_virt
, b_round
;
103 a_virt
= out
[1] - b_virt
;
104 b_round
= b
- b_virt
;
105 a_round
= a
- a_virt
;
106 out
[0] = a_round
+ b_round
;
109 static void d2d_fp_fast_two_sum(float *out
, float a
, float b
)
118 static void d2d_fp_two_two_sum(float *out
, const float *a
, const float *b
)
122 d2d_fp_two_sum(out
, a
[0], b
[0]);
123 d2d_fp_two_sum(sum
, a
[1], out
[1]);
124 d2d_fp_two_sum(&out
[1], sum
[0], b
[1]);
125 d2d_fp_two_sum(&out
[2], sum
[1], out
[2]);
128 static void d2d_fp_two_diff_tail(float *out
, float a
, float b
, float x
)
130 float a_virt
, a_round
, b_virt
, b_round
;
134 b_round
= b_virt
- b
;
135 a_round
= a
- a_virt
;
136 *out
= a_round
+ b_round
;
139 static void d2d_fp_two_two_diff(float *out
, const float *a
, const float *b
)
144 d2d_fp_two_diff_tail(out
, a
[0], b
[0], diff
);
145 d2d_fp_two_sum(sum
, a
[1], diff
);
146 diff
= sum
[0] - b
[1];
147 d2d_fp_two_diff_tail(&out
[1], sum
[0], b
[1], diff
);
148 d2d_fp_two_sum(&out
[2], sum
[1], diff
);
151 static void d2d_fp_split(float *out
, float a
)
155 c
= a
* ((1 << (FLT_MANT_DIG
/ 2)) + 1.0f
);
161 static void d2d_fp_two_product_presplit(float *out
, float a
, float b
, const float *b_split
)
163 float a_split
[2], err1
, err2
, err3
;
166 d2d_fp_split(a_split
, a
);
167 err1
= out
[1] - (a_split
[1] * b_split
[1]);
168 err2
= err1
- (a_split
[0] * b_split
[1]);
169 err3
= err2
- (a_split
[1] * b_split
[0]);
170 out
[0] = (a_split
[0] * b_split
[0]) - err3
;
173 static void d2d_fp_two_product(float *out
, float a
, float b
)
177 d2d_fp_split(b_split
, b
);
178 d2d_fp_two_product_presplit(out
, a
, b
, b_split
);
181 static void d2d_fp_square(float *out
, float a
)
183 float a_split
[2], err1
, err2
;
186 d2d_fp_split(a_split
, a
);
187 err1
= out
[1] - (a_split
[1] * a_split
[1]);
188 err2
= err1
- ((a_split
[1] + a_split
[1]) * a_split
[0]);
189 out
[0] = (a_split
[0] * a_split
[0]) - err2
;
192 static float d2d_fp_estimate(float *a
, size_t len
)
203 static void d2d_fp_fast_expansion_sum_zeroelim(float *out
, size_t *out_len
,
204 const float *a
, size_t a_len
, const float *b
, size_t b_len
)
206 float sum
[2], q
, a_curr
, b_curr
;
207 size_t a_idx
, b_idx
, out_idx
;
212 if ((b_curr
> a_curr
) == (b_curr
> -a_curr
))
223 if (a_idx
< a_len
&& b_idx
< b_len
)
225 if ((b_curr
> a_curr
) == (b_curr
> -a_curr
))
227 d2d_fp_fast_two_sum(sum
, a_curr
, q
);
232 d2d_fp_fast_two_sum(sum
, b_curr
, q
);
236 out
[out_idx
++] = sum
[0];
238 while (a_idx
< a_len
&& b_idx
< b_len
)
240 if ((b_curr
> a_curr
) == (b_curr
> -a_curr
))
242 d2d_fp_two_sum(sum
, q
, a_curr
);
247 d2d_fp_two_sum(sum
, q
, b_curr
);
251 out
[out_idx
++] = sum
[0];
255 while (a_idx
< a_len
)
257 d2d_fp_two_sum(sum
, q
, a_curr
);
260 out
[out_idx
++] = sum
[0];
263 while (b_idx
< b_len
)
265 d2d_fp_two_sum(sum
, q
, b_curr
);
268 out
[out_idx
++] = sum
[0];
271 if (q
!= 0.0f
|| !out_idx
)
277 static void d2d_fp_scale_expansion_zeroelim(float *out
, size_t *out_len
, const float *a
, size_t a_len
, float b
)
279 float product
[2], sum
[2], b_split
[2], q
[2], a_curr
;
280 size_t a_idx
, out_idx
;
282 d2d_fp_split(b_split
, b
);
283 d2d_fp_two_product_presplit(q
, a
[0], b
, b_split
);
286 out
[out_idx
++] = q
[0];
287 for (a_idx
= 1; a_idx
< a_len
; ++a_idx
)
290 d2d_fp_two_product_presplit(product
, a_curr
, b
, b_split
);
291 d2d_fp_two_sum(sum
, q
[1], product
[0]);
293 out
[out_idx
++] = sum
[0];
294 d2d_fp_fast_two_sum(q
, product
[1], sum
[1]);
296 out
[out_idx
++] = q
[0];
298 if (q
[1] != 0.0f
|| !out_idx
)
299 out
[out_idx
++] = q
[1];
304 static void d2d_point_subtract(D2D1_POINT_2F
*out
,
305 const D2D1_POINT_2F
*a
, const D2D1_POINT_2F
*b
)
307 out
->x
= a
->x
- b
->x
;
308 out
->y
= a
->y
- b
->y
;
311 /* This implementation is based on the paper "Adaptive Precision
312 * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
313 * associated (Public Domain) code by Jonathan Richard Shewchuk. */
314 static float d2d_point_ccw(const D2D1_POINT_2F
*a
, const D2D1_POINT_2F
*b
, const D2D1_POINT_2F
*c
)
316 static const float err_bound_result
= (3.0f
+ 8.0f
* D2D_FP_EPS
) * D2D_FP_EPS
;
317 static const float err_bound_a
= (3.0f
+ 16.0f
* D2D_FP_EPS
) * D2D_FP_EPS
;
318 static const float err_bound_b
= (2.0f
+ 12.0f
* D2D_FP_EPS
) * D2D_FP_EPS
;
319 static const float err_bound_c
= (9.0f
+ 64.0f
* D2D_FP_EPS
) * D2D_FP_EPS
* D2D_FP_EPS
;
320 float det_d
[16], det_c2
[12], det_c1
[8], det_b
[4], temp4
[4], temp2a
[2], temp2b
[2], abxacy
[2], abyacx
[2];
321 size_t det_d_len
, det_c2_len
, det_c1_len
;
322 float det
, det_sum
, err_bound
;
323 struct d2d_fp_two_vec2 ab
, ac
;
325 ab
.x
[1] = b
->x
- a
->x
;
326 ab
.y
[1] = b
->y
- a
->y
;
327 ac
.x
[1] = c
->x
- a
->x
;
328 ac
.y
[1] = c
->y
- a
->y
;
330 abxacy
[1] = ab
.x
[1] * ac
.y
[1];
331 abyacx
[1] = ab
.y
[1] * ac
.x
[1];
332 det
= abxacy
[1] - abyacx
[1];
334 if (abxacy
[1] > 0.0f
)
336 if (abyacx
[1] <= 0.0f
)
338 det_sum
= abxacy
[1] + abyacx
[1];
340 else if (abxacy
[1] < 0.0f
)
342 if (abyacx
[1] >= 0.0f
)
344 det_sum
= -abxacy
[1] - abyacx
[1];
351 err_bound
= err_bound_a
* det_sum
;
352 if (det
>= err_bound
|| -det
>= err_bound
)
355 d2d_fp_two_product(abxacy
, ab
.x
[1], ac
.y
[1]);
356 d2d_fp_two_product(abyacx
, ab
.y
[1], ac
.x
[1]);
357 d2d_fp_two_two_diff(det_b
, abxacy
, abyacx
);
359 det
= d2d_fp_estimate(det_b
, 4);
360 err_bound
= err_bound_b
* det_sum
;
361 if (det
>= err_bound
|| -det
>= err_bound
)
364 d2d_fp_two_diff_tail(&ab
.x
[0], b
->x
, a
->x
, ab
.x
[1]);
365 d2d_fp_two_diff_tail(&ab
.y
[0], b
->y
, a
->y
, ab
.y
[1]);
366 d2d_fp_two_diff_tail(&ac
.x
[0], c
->x
, a
->x
, ac
.x
[1]);
367 d2d_fp_two_diff_tail(&ac
.y
[0], c
->y
, a
->y
, ac
.y
[1]);
369 if (ab
.x
[0] == 0.0f
&& ab
.y
[0] == 0.0f
&& ac
.x
[0] == 0.0f
&& ac
.y
[0] == 0.0f
)
372 err_bound
= err_bound_c
* det_sum
+ err_bound_result
* fabsf(det
);
373 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]);
374 if (det
>= err_bound
|| -det
>= err_bound
)
377 d2d_fp_two_product(temp2a
, ab
.x
[0], ac
.y
[1]);
378 d2d_fp_two_product(temp2b
, ab
.y
[0], ac
.x
[1]);
379 d2d_fp_two_two_diff(temp4
, temp2a
, temp2b
);
380 d2d_fp_fast_expansion_sum_zeroelim(det_c1
, &det_c1_len
, det_b
, 4, temp4
, 4);
382 d2d_fp_two_product(temp2a
, ab
.x
[1], ac
.y
[0]);
383 d2d_fp_two_product(temp2b
, ab
.y
[1], ac
.x
[0]);
384 d2d_fp_two_two_diff(temp4
, temp2a
, temp2b
);
385 d2d_fp_fast_expansion_sum_zeroelim(det_c2
, &det_c2_len
, det_c1
, det_c1_len
, temp4
, 4);
387 d2d_fp_two_product(temp2a
, ab
.x
[0], ac
.y
[0]);
388 d2d_fp_two_product(temp2b
, ab
.y
[0], ac
.x
[0]);
389 d2d_fp_two_two_diff(temp4
, temp2a
, temp2b
);
390 d2d_fp_fast_expansion_sum_zeroelim(det_d
, &det_d_len
, det_c2
, det_c2_len
, temp4
, 4);
392 return det_d
[det_d_len
- 1];
395 static BOOL
d2d_array_reserve(void **elements
, size_t *capacity
, size_t element_count
, size_t element_size
)
397 size_t new_capacity
, max_capacity
;
400 if (element_count
<= *capacity
)
403 max_capacity
= ~(size_t)0 / element_size
;
404 if (max_capacity
< element_count
)
407 new_capacity
= max(*capacity
, 4);
408 while (new_capacity
< element_count
&& new_capacity
<= max_capacity
/ 2)
411 if (new_capacity
< element_count
)
412 new_capacity
= max_capacity
;
415 new_elements
= HeapReAlloc(GetProcessHeap(), 0, *elements
, new_capacity
* element_size
);
417 new_elements
= HeapAlloc(GetProcessHeap(), 0, new_capacity
* element_size
);
422 *elements
= new_elements
;
423 *capacity
= new_capacity
;
427 static void d2d_figure_update_bounds(struct d2d_figure
*figure
, D2D1_POINT_2F vertex
)
429 if (vertex
.x
< figure
->bounds
.left
)
430 figure
->bounds
.left
= vertex
.x
;
431 if (vertex
.x
> figure
->bounds
.right
)
432 figure
->bounds
.right
= vertex
.x
;
433 if (vertex
.y
< figure
->bounds
.top
)
434 figure
->bounds
.top
= vertex
.y
;
435 if (vertex
.y
> figure
->bounds
.bottom
)
436 figure
->bounds
.bottom
= vertex
.y
;
439 static BOOL
d2d_figure_insert_vertex(struct d2d_figure
*figure
, size_t idx
, D2D1_POINT_2F vertex
)
441 if (!d2d_array_reserve((void **)&figure
->vertices
, &figure
->vertices_size
,
442 figure
->vertex_count
+ 1, sizeof(*figure
->vertices
)))
444 ERR("Failed to grow vertices array.\n");
448 memmove(&figure
->vertices
[idx
+ 1], &figure
->vertices
[idx
],
449 (figure
->vertex_count
- idx
) * sizeof(*figure
->vertices
));
450 figure
->vertices
[idx
] = vertex
;
451 d2d_figure_update_bounds(figure
, vertex
);
452 ++figure
->vertex_count
;
456 static BOOL
d2d_figure_add_vertex(struct d2d_figure
*figure
, D2D1_POINT_2F vertex
)
458 if (!d2d_array_reserve((void **)&figure
->vertices
, &figure
->vertices_size
,
459 figure
->vertex_count
+ 1, sizeof(*figure
->vertices
)))
461 ERR("Failed to grow vertices array.\n");
465 figure
->vertices
[figure
->vertex_count
] = vertex
;
466 d2d_figure_update_bounds(figure
, vertex
);
467 ++figure
->vertex_count
;
471 /* FIXME: No inside/outside testing is done for beziers. */
472 static BOOL
d2d_figure_add_bezier(struct d2d_figure
*figure
, D2D1_POINT_2F p0
, D2D1_POINT_2F p1
, D2D1_POINT_2F p2
)
474 struct d2d_bezier
*b
;
475 unsigned int idx1
, idx2
;
478 if (!d2d_array_reserve((void **)&figure
->beziers
, &figure
->beziers_size
,
479 figure
->bezier_count
+ 1, sizeof(*figure
->beziers
)))
481 ERR("Failed to grow beziers array.\n");
485 if (d2d_point_ccw(&p0
, &p1
, &p2
) > 0.0f
)
498 b
= &figure
->beziers
[figure
->bezier_count
];
499 b
->v
[0].position
= p0
;
500 b
->v
[0].texcoord
.u
= 0.0f
;
501 b
->v
[0].texcoord
.v
= 0.0f
;
502 b
->v
[0].texcoord
.sign
= sign
;
503 b
->v
[idx1
].position
= p1
;
504 b
->v
[idx1
].texcoord
.u
= 0.5f
;
505 b
->v
[idx1
].texcoord
.v
= 0.0f
;
506 b
->v
[idx1
].texcoord
.sign
= sign
;
507 b
->v
[idx2
].position
= p2
;
508 b
->v
[idx2
].texcoord
.u
= 1.0f
;
509 b
->v
[idx2
].texcoord
.v
= 1.0f
;
510 b
->v
[idx2
].texcoord
.sign
= sign
;
511 ++figure
->bezier_count
;
513 if (sign
> 0.0f
&& !d2d_figure_add_vertex(figure
, p1
))
515 if (!d2d_figure_add_vertex(figure
, p2
))
520 static void d2d_cdt_edge_rot(struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
523 dst
->r
= (src
->r
+ D2D_EDGE_NEXT_ROT
) & 3;
526 static void d2d_cdt_edge_sym(struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
529 dst
->r
= (src
->r
+ D2D_EDGE_NEXT_SYM
) & 3;
532 static void d2d_cdt_edge_tor(struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
535 dst
->r
= (src
->r
+ D2D_EDGE_NEXT_TOR
) & 3;
538 static void d2d_cdt_edge_next_left(const struct d2d_cdt
*cdt
,
539 struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
541 d2d_cdt_edge_rot(dst
, &cdt
->edges
[src
->idx
].next
[(src
->r
+ D2D_EDGE_NEXT_TOR
) & 3]);
544 static void d2d_cdt_edge_next_origin(const struct d2d_cdt
*cdt
,
545 struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
547 *dst
= cdt
->edges
[src
->idx
].next
[src
->r
];
550 static void d2d_cdt_edge_prev_origin(const struct d2d_cdt
*cdt
,
551 struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
553 d2d_cdt_edge_rot(dst
, &cdt
->edges
[src
->idx
].next
[(src
->r
+ D2D_EDGE_NEXT_ROT
) & 3]);
556 static size_t d2d_cdt_edge_origin(const struct d2d_cdt
*cdt
, const struct d2d_cdt_edge_ref
*e
)
558 return cdt
->edges
[e
->idx
].vertex
[e
->r
>> 1];
561 static size_t d2d_cdt_edge_destination(const struct d2d_cdt
*cdt
, const struct d2d_cdt_edge_ref
*e
)
563 return cdt
->edges
[e
->idx
].vertex
[!(e
->r
>> 1)];
566 static void d2d_cdt_edge_set_origin(const struct d2d_cdt
*cdt
,
567 const struct d2d_cdt_edge_ref
*e
, size_t vertex
)
569 cdt
->edges
[e
->idx
].vertex
[e
->r
>> 1] = vertex
;
572 static void d2d_cdt_edge_set_destination(const struct d2d_cdt
*cdt
,
573 const struct d2d_cdt_edge_ref
*e
, size_t vertex
)
575 cdt
->edges
[e
->idx
].vertex
[!(e
->r
>> 1)] = vertex
;
578 static float d2d_cdt_ccw(const struct d2d_cdt
*cdt
, size_t a
, size_t b
, size_t c
)
580 return d2d_point_ccw(&cdt
->vertices
[a
], &cdt
->vertices
[b
], &cdt
->vertices
[c
]);
583 static BOOL
d2d_cdt_rightof(const struct d2d_cdt
*cdt
, size_t p
, const struct d2d_cdt_edge_ref
*e
)
585 return d2d_cdt_ccw(cdt
, p
, d2d_cdt_edge_destination(cdt
, e
), d2d_cdt_edge_origin(cdt
, e
)) > 0.0f
;
588 static BOOL
d2d_cdt_leftof(const struct d2d_cdt
*cdt
, size_t p
, const struct d2d_cdt_edge_ref
*e
)
590 return d2d_cdt_ccw(cdt
, p
, d2d_cdt_edge_origin(cdt
, e
), d2d_cdt_edge_destination(cdt
, e
)) > 0.0f
;
595 static void d2d_fp_four_det2x2(float *out
, float ax
, float ay
, float bx
, float by
)
597 float axby
[2], aybx
[2];
599 d2d_fp_two_product(axby
, ax
, by
);
600 d2d_fp_two_product(aybx
, ay
, bx
);
601 d2d_fp_two_two_diff(out
, axby
, aybx
);
604 /* (a->x² + a->y²) * det2x2 */
605 static void d2d_fp_sub_det3x3(float *out
, size_t *out_len
, const struct d2d_fp_two_vec2
*a
, const float *det2x2
)
607 size_t axd_len
, ayd_len
, axxd_len
, ayyd_len
;
608 float axd
[8], ayd
[8], axxd
[16], ayyd
[16];
610 d2d_fp_scale_expansion_zeroelim(axd
, &axd_len
, det2x2
, 4, a
->x
[1]);
611 d2d_fp_scale_expansion_zeroelim(axxd
, &axxd_len
, axd
, axd_len
, a
->x
[1]);
612 d2d_fp_scale_expansion_zeroelim(ayd
, &ayd_len
, det2x2
, 4, a
->y
[1]);
613 d2d_fp_scale_expansion_zeroelim(ayyd
, &ayyd_len
, ayd
, ayd_len
, a
->y
[1]);
614 d2d_fp_fast_expansion_sum_zeroelim(out
, out_len
, axxd
, axxd_len
, ayyd
, ayyd_len
);
617 /* det_abt = det_ab * c[0]
618 * fin += c[0] * (az * b - bz * a + c[1] * det_ab * 2.0f) */
619 static void d2d_cdt_incircle_refine1(struct d2d_fp_fin
*fin
, float *det_abt
, size_t *det_abt_len
,
620 const float *det_ab
, float a
, const float *az
, float b
, const float *bz
, const float *c
)
622 size_t temp48_len
, temp32_len
, temp16a_len
, temp16b_len
, temp16c_len
, temp8_len
;
623 float temp48
[48], temp32
[32], temp16a
[16], temp16b
[16], temp16c
[16], temp8
[8];
626 d2d_fp_scale_expansion_zeroelim(det_abt
, det_abt_len
, det_ab
, 4, c
[0]);
627 d2d_fp_scale_expansion_zeroelim(temp16a
, &temp16a_len
, det_abt
, *det_abt_len
, 2.0f
* c
[1]);
628 d2d_fp_scale_expansion_zeroelim(temp8
, &temp8_len
, az
, 4, c
[0]);
629 d2d_fp_scale_expansion_zeroelim(temp16b
, &temp16b_len
, temp8
, temp8_len
, b
);
630 d2d_fp_scale_expansion_zeroelim(temp8
, &temp8_len
, bz
, 4, c
[0]);
631 d2d_fp_scale_expansion_zeroelim(temp16c
, &temp16c_len
, temp8
, temp8_len
, -a
);
632 d2d_fp_fast_expansion_sum_zeroelim(temp32
, &temp32_len
, temp16a
, temp16a_len
, temp16b
, temp16b_len
);
633 d2d_fp_fast_expansion_sum_zeroelim(temp48
, &temp48_len
, temp16c
, temp16c_len
, temp32
, temp32_len
);
634 d2d_fp_fast_expansion_sum_zeroelim(fin
->other
, &fin
->length
, fin
->now
, fin
->length
, temp48
, temp48_len
);
635 swap
= fin
->now
; fin
->now
= fin
->other
; fin
->other
= swap
;
638 static void d2d_cdt_incircle_refine2(struct d2d_fp_fin
*fin
, const struct d2d_fp_two_vec2
*a
,
639 const struct d2d_fp_two_vec2
*b
, const float *bz
, const struct d2d_fp_two_vec2
*c
, const float *cz
,
640 const float *axt_det_bc
, size_t axt_det_bc_len
, const float *ayt_det_bc
, size_t ayt_det_bc_len
)
642 size_t temp64_len
, temp48_len
, temp32a_len
, temp32b_len
, temp16a_len
, temp16b_len
, temp8_len
;
643 float temp64
[64], temp48
[48], temp32a
[32], temp32b
[32], temp16a
[16], temp16b
[16], temp8
[8];
644 float bct
[8], bctt
[4], temp4a
[4], temp4b
[4], temp2a
[2], temp2b
[2];
645 size_t bct_len
, bctt_len
;
648 /* 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]) */
649 /* bctt = b->x[0] * c->y[0] + c->x[0] * b->y[0] */
650 if (b
->x
[0] != 0.0f
|| b
->y
[0] != 0.0f
|| c
->x
[0] != 0.0f
|| c
->y
[0] != 0.0f
)
652 d2d_fp_two_product(temp2a
, b
->x
[0], c
->y
[1]);
653 d2d_fp_two_product(temp2b
, b
->x
[1], c
->y
[0]);
654 d2d_fp_two_two_sum(temp4a
, temp2a
, temp2b
);
655 d2d_fp_two_product(temp2a
, c
->x
[0], -b
->y
[1]);
656 d2d_fp_two_product(temp2b
, c
->x
[1], -b
->y
[0]);
657 d2d_fp_two_two_sum(temp4b
, temp2a
, temp2b
);
658 d2d_fp_fast_expansion_sum_zeroelim(bct
, &bct_len
, temp4a
, 4, temp4b
, 4);
660 d2d_fp_two_product(temp2a
, b
->x
[0], c
->y
[0]);
661 d2d_fp_two_product(temp2b
, c
->x
[0], b
->y
[0]);
662 d2d_fp_two_two_diff(bctt
, temp2a
, temp2b
);
675 size_t axt_bct_len
, axt_bctt_len
;
676 float axt_bct
[16], axt_bctt
[8];
678 /* fin += a->x[0] * (axt_det_bc + bct * 2.0f * a->x[1]) */
679 d2d_fp_scale_expansion_zeroelim(temp16a
, &temp16a_len
, axt_det_bc
, axt_det_bc_len
, a
->x
[0]);
680 d2d_fp_scale_expansion_zeroelim(axt_bct
, &axt_bct_len
, bct
, bct_len
, a
->x
[0]);
681 d2d_fp_scale_expansion_zeroelim(temp32a
, &temp32a_len
, axt_bct
, axt_bct_len
, 2.0f
* a
->x
[1]);
682 d2d_fp_fast_expansion_sum_zeroelim(temp48
, &temp48_len
, temp16a
, temp16a_len
, temp32a
, temp32a_len
);
683 d2d_fp_fast_expansion_sum_zeroelim(fin
->other
, &fin
->length
, fin
->now
, fin
->length
, temp48
, temp48_len
);
684 swap
= fin
->now
; fin
->now
= fin
->other
; fin
->other
= swap
;
688 /* fin += a->x[0] * cz * b->y[0] */
689 d2d_fp_scale_expansion_zeroelim(temp8
, &temp8_len
, cz
, 4, a
->x
[0]);
690 d2d_fp_scale_expansion_zeroelim(temp16a
, &temp16a_len
, temp8
, temp8_len
, b
->y
[0]);
691 d2d_fp_fast_expansion_sum_zeroelim(fin
->other
, &fin
->length
, fin
->now
, fin
->length
, temp16a
, temp16a_len
);
692 swap
= fin
->now
; fin
->now
= fin
->other
; fin
->other
= swap
;
697 /* fin -= a->x[0] * bz * c->y[0] */
698 d2d_fp_scale_expansion_zeroelim(temp8
, &temp8_len
, bz
, 4, -a
->x
[0]);
699 d2d_fp_scale_expansion_zeroelim(temp16a
, &temp16a_len
, temp8
, temp8_len
, c
->y
[0]);
700 d2d_fp_fast_expansion_sum_zeroelim(fin
->other
, &fin
->length
, fin
->now
, fin
->length
, temp16a
, temp16a_len
);
701 swap
= fin
->now
; fin
->now
= fin
->other
; fin
->other
= swap
;
704 /* fin += a->x[0] * (bct * a->x[0] + bctt * (2.0f * a->x[1] + a->x[0])) */
705 d2d_fp_scale_expansion_zeroelim(temp32a
, &temp32a_len
, axt_bct
, axt_bct_len
, a
->x
[0]);
706 d2d_fp_scale_expansion_zeroelim(axt_bctt
, &axt_bctt_len
, bctt
, bctt_len
, a
->x
[0]);
707 d2d_fp_scale_expansion_zeroelim(temp16a
, &temp16a_len
, axt_bctt
, axt_bctt_len
, 2.0f
* a
->x
[1]);
708 d2d_fp_scale_expansion_zeroelim(temp16b
, &temp16b_len
, axt_bctt
, axt_bctt_len
, a
->x
[0]);
709 d2d_fp_fast_expansion_sum_zeroelim(temp32b
, &temp32b_len
, temp16a
, temp16a_len
, temp16b
, temp16b_len
);
710 d2d_fp_fast_expansion_sum_zeroelim(temp64
, &temp64_len
, temp32a
, temp32a_len
, temp32b
, temp32b_len
);
711 d2d_fp_fast_expansion_sum_zeroelim(fin
->other
, &fin
->length
, fin
->now
, fin
->length
, temp64
, temp64_len
);
712 swap
= fin
->now
; fin
->now
= fin
->other
; fin
->other
= swap
;
717 size_t ayt_bct_len
, ayt_bctt_len
;
718 float ayt_bct
[16], ayt_bctt
[8];
720 /* fin += a->y[0] * (ayt_det_bc + bct * 2.0f * a->y[1]) */
721 d2d_fp_scale_expansion_zeroelim(temp16a
, &temp16a_len
, ayt_det_bc
, ayt_det_bc_len
, a
->y
[0]);
722 d2d_fp_scale_expansion_zeroelim(ayt_bct
, &ayt_bct_len
, bct
, bct_len
, a
->y
[0]);
723 d2d_fp_scale_expansion_zeroelim(temp32a
, &temp32a_len
, ayt_bct
, ayt_bct_len
, 2.0f
* a
->y
[1]);
724 d2d_fp_fast_expansion_sum_zeroelim(temp48
, &temp48_len
, temp16a
, temp16a_len
, temp32a
, temp32a_len
);
725 d2d_fp_fast_expansion_sum_zeroelim(fin
->other
, &fin
->length
, fin
->now
, fin
->length
, temp48
, temp48_len
);
726 swap
= fin
->now
; fin
->now
= fin
->other
; fin
->other
= swap
;
728 /* fin += a->y[0] * (bct * a->y[0] + bctt * (2.0f * a->y[1] + a->y[0])) */
729 d2d_fp_scale_expansion_zeroelim(temp32a
, &temp32a_len
, ayt_bct
, ayt_bct_len
, a
->y
[0]);
730 d2d_fp_scale_expansion_zeroelim(ayt_bctt
, &ayt_bctt_len
, bctt
, bctt_len
, a
->y
[0]);
731 d2d_fp_scale_expansion_zeroelim(temp16a
, &temp16a_len
, ayt_bctt
, ayt_bctt_len
, 2.0f
* a
->y
[1]);
732 d2d_fp_scale_expansion_zeroelim(temp16b
, &temp16b_len
, ayt_bctt
, ayt_bctt_len
, a
->y
[0]);
733 d2d_fp_fast_expansion_sum_zeroelim(temp32b
, &temp32b_len
, temp16a
, temp16a_len
, temp16b
, temp16b_len
);
734 d2d_fp_fast_expansion_sum_zeroelim(temp64
, &temp64_len
, temp32a
, temp32a_len
, temp32b
, temp32b_len
);
735 d2d_fp_fast_expansion_sum_zeroelim(fin
->other
, &fin
->length
, fin
->now
, fin
->length
, temp64
, temp64_len
);
736 swap
= fin
->now
; fin
->now
= fin
->other
; fin
->other
= swap
;
740 /* Determine if point D is inside or outside the circle defined by points A,
741 * B, C. As explained in the paper by Guibas and Stolfi, this is equivalent to
742 * calculating the signed volume of the tetrahedron defined by projecting the
743 * points onto the paraboloid of revolution x = x² + y²,
744 * λ:(x, y) → (x, y, x² + y²). I.e., D is inside the cirlce if
751 * After translating D to the origin, that becomes:
757 * This implementation is based on the paper "Adaptive Precision
758 * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
759 * associated (Public Domain) code by Jonathan Richard Shewchuk. */
760 static BOOL
d2d_cdt_incircle(const struct d2d_cdt
*cdt
, size_t a
, size_t b
, size_t c
, size_t d
)
762 static const float err_bound_result
= (3.0f
+ 8.0f
* D2D_FP_EPS
) * D2D_FP_EPS
;
763 static const float err_bound_a
= (10.0f
+ 96.0f
* D2D_FP_EPS
) * D2D_FP_EPS
;
764 static const float err_bound_b
= (4.0f
+ 48.0f
* D2D_FP_EPS
) * D2D_FP_EPS
;
765 static const float err_bound_c
= (44.0f
+ 576.0f
* D2D_FP_EPS
) * D2D_FP_EPS
* D2D_FP_EPS
;
767 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
;
768 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];
769 float fin1
[1152], fin2
[1152], temp64
[64], sub_det_a
[32], sub_det_b
[32], sub_det_c
[32];
770 float det_bc
[4], det_ca
[4], det_ab
[4], daz
[4], dbz
[4], dcz
[4], temp2a
[2], temp2b
[2];
771 size_t temp64_len
, sub_det_a_len
, sub_det_b_len
, sub_det_c_len
;
772 float dbxdcy
, dbydcx
, dcxday
, dcydax
, daxdby
, daydbx
;
773 const D2D1_POINT_2F
*p
= cdt
->vertices
;
774 struct d2d_fp_two_vec2 da
, db
, dc
;
775 float permanent
, err_bound
, det
;
776 struct d2d_fp_fin fin
;
778 da
.x
[1] = p
[a
].x
- p
[d
].x
;
779 da
.y
[1] = p
[a
].y
- p
[d
].y
;
780 db
.x
[1] = p
[b
].x
- p
[d
].x
;
781 db
.y
[1] = p
[b
].y
- p
[d
].y
;
782 dc
.x
[1] = p
[c
].x
- p
[d
].x
;
783 dc
.y
[1] = p
[c
].y
- p
[d
].y
;
785 daz
[3] = da
.x
[1] * da
.x
[1] + da
.y
[1] * da
.y
[1];
786 dbxdcy
= db
.x
[1] * dc
.y
[1];
787 dbydcx
= db
.y
[1] * dc
.x
[1];
789 dbz
[3] = db
.x
[1] * db
.x
[1] + db
.y
[1] * db
.y
[1];
790 dcxday
= dc
.x
[1] * da
.y
[1];
791 dcydax
= dc
.y
[1] * da
.x
[1];
793 dcz
[3] = dc
.x
[1] * dc
.x
[1] + dc
.y
[1] * dc
.y
[1];
794 daxdby
= da
.x
[1] * db
.y
[1];
795 daydbx
= da
.y
[1] * db
.x
[1];
797 det
= daz
[3] * (dbxdcy
- dbydcx
) + dbz
[3] * (dcxday
- dcydax
) + dcz
[3] * (daxdby
- daydbx
);
798 permanent
= daz
[3] * (fabsf(dbxdcy
) + fabsf(dbydcx
))
799 + dbz
[3] * (fabsf(dcxday
) + fabsf(dcydax
))
800 + dcz
[3] * (fabsf(daxdby
) + fabsf(daydbx
));
801 err_bound
= err_bound_a
* permanent
;
802 if (det
> err_bound
|| -det
> err_bound
)
808 d2d_fp_four_det2x2(det_bc
, db
.x
[1], db
.y
[1], dc
.x
[1], dc
.y
[1]);
809 d2d_fp_sub_det3x3(sub_det_a
, &sub_det_a_len
, &da
, det_bc
);
811 d2d_fp_four_det2x2(det_ca
, dc
.x
[1], dc
.y
[1], da
.x
[1], da
.y
[1]);
812 d2d_fp_sub_det3x3(sub_det_b
, &sub_det_b_len
, &db
, det_ca
);
814 d2d_fp_four_det2x2(det_ab
, da
.x
[1], da
.y
[1], db
.x
[1], db
.y
[1]);
815 d2d_fp_sub_det3x3(sub_det_c
, &sub_det_c_len
, &dc
, det_ab
);
817 d2d_fp_fast_expansion_sum_zeroelim(temp64
, &temp64_len
, sub_det_a
, sub_det_a_len
, sub_det_b
, sub_det_b_len
);
818 d2d_fp_fast_expansion_sum_zeroelim(fin
.now
, &fin
.length
, temp64
, temp64_len
, sub_det_c
, sub_det_c_len
);
819 det
= d2d_fp_estimate(fin
.now
, fin
.length
);
820 err_bound
= err_bound_b
* permanent
;
821 if (det
>= err_bound
|| -det
>= err_bound
)
824 d2d_fp_two_diff_tail(&da
.x
[0], p
[a
].x
, p
[d
].x
, da
.x
[1]);
825 d2d_fp_two_diff_tail(&da
.y
[0], p
[a
].y
, p
[d
].y
, da
.y
[1]);
826 d2d_fp_two_diff_tail(&db
.x
[0], p
[b
].x
, p
[d
].x
, db
.x
[1]);
827 d2d_fp_two_diff_tail(&db
.y
[0], p
[b
].y
, p
[d
].y
, db
.y
[1]);
828 d2d_fp_two_diff_tail(&dc
.x
[0], p
[c
].x
, p
[d
].x
, dc
.x
[1]);
829 d2d_fp_two_diff_tail(&dc
.y
[0], p
[c
].y
, p
[d
].y
, dc
.y
[1]);
830 if (da
.x
[0] == 0.0f
&& db
.x
[0] == 0.0f
&& dc
.x
[0] == 0.0f
831 && da
.y
[0] == 0.0f
&& db
.y
[0] == 0.0f
&& dc
.y
[0] == 0.0f
)
834 err_bound
= err_bound_c
* permanent
+ err_bound_result
* fabsf(det
);
835 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]))
836 + 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]))
837 + (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]))
838 + 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]))
839 + (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]))
840 + 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]));
841 if (det
>= err_bound
|| -det
>= err_bound
)
844 if (db
.x
[0] != 0.0f
|| db
.y
[0] != 0.0f
|| dc
.x
[0] != 0.0f
|| dc
.y
[0] != 0.0f
)
846 d2d_fp_square(temp2a
, da
.x
[1]);
847 d2d_fp_square(temp2b
, da
.y
[1]);
848 d2d_fp_two_two_sum(daz
, temp2a
, temp2b
);
850 if (dc
.x
[0] != 0.0f
|| dc
.y
[0] != 0.0f
|| da
.x
[0] != 0.0f
|| da
.y
[0] != 0.0f
)
852 d2d_fp_square(temp2a
, db
.x
[1]);
853 d2d_fp_square(temp2b
, db
.y
[1]);
854 d2d_fp_two_two_sum(dbz
, temp2a
, temp2b
);
856 if (da
.x
[0] != 0.0f
|| da
.y
[0] != 0.0f
|| db
.x
[0] != 0.0f
|| db
.y
[0] != 0.0f
)
858 d2d_fp_square(temp2a
, dc
.x
[1]);
859 d2d_fp_square(temp2b
, dc
.y
[1]);
860 d2d_fp_two_two_sum(dcz
, temp2a
, temp2b
);
864 d2d_cdt_incircle_refine1(&fin
, axt_det_bc
, &axt_det_bc_len
, det_bc
, dc
.y
[1], dcz
, db
.y
[1], dbz
, da
.x
);
866 d2d_cdt_incircle_refine1(&fin
, ayt_det_bc
, &ayt_det_bc_len
, det_bc
, db
.x
[1], dbz
, dc
.x
[1], dcz
, da
.y
);
868 d2d_cdt_incircle_refine1(&fin
, bxt_det_ca
, &bxt_det_ca_len
, det_ca
, da
.y
[1], daz
, dc
.y
[1], dcz
, db
.x
);
870 d2d_cdt_incircle_refine1(&fin
, byt_det_ca
, &byt_det_ca_len
, det_ca
, dc
.x
[1], dcz
, da
.x
[1], daz
, db
.y
);
872 d2d_cdt_incircle_refine1(&fin
, cxt_det_ab
, &cxt_det_ab_len
, det_ab
, db
.y
[1], dbz
, da
.y
[1], daz
, dc
.x
);
874 d2d_cdt_incircle_refine1(&fin
, cyt_det_ab
, &cyt_det_ab_len
, det_ab
, da
.x
[1], daz
, db
.x
[1], dbz
, dc
.y
);
876 if (da
.x
[0] != 0.0f
|| da
.y
[0] != 0.0f
)
877 d2d_cdt_incircle_refine2(&fin
, &da
, &db
, dbz
, &dc
, dcz
,
878 axt_det_bc
, axt_det_bc_len
, ayt_det_bc
, ayt_det_bc_len
);
879 if (db
.x
[0] != 0.0f
|| db
.y
[0] != 0.0f
)
880 d2d_cdt_incircle_refine2(&fin
, &db
, &dc
, dcz
, &da
, daz
,
881 bxt_det_ca
, bxt_det_ca_len
, byt_det_ca
, byt_det_ca_len
);
882 if (dc
.x
[0] != 0.0f
|| dc
.y
[0] != 0.0f
)
883 d2d_cdt_incircle_refine2(&fin
, &dc
, &da
, daz
, &db
, dbz
,
884 cxt_det_ab
, cxt_det_ab_len
, cyt_det_ab
, cyt_det_ab_len
);
886 return fin
.now
[fin
.length
- 1] > 0.0f
;
889 static void d2d_cdt_splice(const struct d2d_cdt
*cdt
, const struct d2d_cdt_edge_ref
*a
,
890 const struct d2d_cdt_edge_ref
*b
)
892 struct d2d_cdt_edge_ref ta
, tb
, alpha
, beta
;
894 ta
= cdt
->edges
[a
->idx
].next
[a
->r
];
895 tb
= cdt
->edges
[b
->idx
].next
[b
->r
];
896 cdt
->edges
[a
->idx
].next
[a
->r
] = tb
;
897 cdt
->edges
[b
->idx
].next
[b
->r
] = ta
;
899 d2d_cdt_edge_rot(&alpha
, &ta
);
900 d2d_cdt_edge_rot(&beta
, &tb
);
902 ta
= cdt
->edges
[alpha
.idx
].next
[alpha
.r
];
903 tb
= cdt
->edges
[beta
.idx
].next
[beta
.r
];
904 cdt
->edges
[alpha
.idx
].next
[alpha
.r
] = tb
;
905 cdt
->edges
[beta
.idx
].next
[beta
.r
] = ta
;
908 static BOOL
d2d_cdt_create_edge(struct d2d_cdt
*cdt
, struct d2d_cdt_edge_ref
*e
)
910 struct d2d_cdt_edge
*edge
;
912 if (cdt
->free_edge
!= ~0u)
914 e
->idx
= cdt
->free_edge
;
915 cdt
->free_edge
= cdt
->edges
[e
->idx
].next
[D2D_EDGE_NEXT_ORIGIN
].idx
;
919 if (!d2d_array_reserve((void **)&cdt
->edges
, &cdt
->edges_size
, cdt
->edge_count
+ 1, sizeof(*cdt
->edges
)))
921 ERR("Failed to grow edges array.\n");
924 e
->idx
= cdt
->edge_count
++;
928 edge
= &cdt
->edges
[e
->idx
];
929 edge
->next
[D2D_EDGE_NEXT_ORIGIN
] = *e
;
930 d2d_cdt_edge_tor(&edge
->next
[D2D_EDGE_NEXT_ROT
], e
);
931 d2d_cdt_edge_sym(&edge
->next
[D2D_EDGE_NEXT_SYM
], e
);
932 d2d_cdt_edge_rot(&edge
->next
[D2D_EDGE_NEXT_TOR
], e
);
938 static void d2d_cdt_destroy_edge(struct d2d_cdt
*cdt
, const struct d2d_cdt_edge_ref
*e
)
940 struct d2d_cdt_edge_ref next
, sym
, prev
;
942 d2d_cdt_edge_next_origin(cdt
, &next
, e
);
943 if (next
.idx
!= e
->idx
|| next
.r
!= e
->r
)
945 d2d_cdt_edge_prev_origin(cdt
, &prev
, e
);
946 d2d_cdt_splice(cdt
, e
, &prev
);
949 d2d_cdt_edge_sym(&sym
, e
);
951 d2d_cdt_edge_next_origin(cdt
, &next
, &sym
);
952 if (next
.idx
!= sym
.idx
|| next
.r
!= sym
.r
)
954 d2d_cdt_edge_prev_origin(cdt
, &prev
, &sym
);
955 d2d_cdt_splice(cdt
, &sym
, &prev
);
958 cdt
->edges
[e
->idx
].flags
|= D2D_CDT_EDGE_FLAG_FREED
;
959 cdt
->edges
[e
->idx
].next
[D2D_EDGE_NEXT_ORIGIN
].idx
= cdt
->free_edge
;
960 cdt
->free_edge
= e
->idx
;
963 static BOOL
d2d_cdt_connect(struct d2d_cdt
*cdt
, struct d2d_cdt_edge_ref
*e
,
964 const struct d2d_cdt_edge_ref
*a
, const struct d2d_cdt_edge_ref
*b
)
966 struct d2d_cdt_edge_ref tmp
;
968 if (!d2d_cdt_create_edge(cdt
, e
))
970 d2d_cdt_edge_set_origin(cdt
, e
, d2d_cdt_edge_destination(cdt
, a
));
971 d2d_cdt_edge_set_destination(cdt
, e
, d2d_cdt_edge_origin(cdt
, b
));
972 d2d_cdt_edge_next_left(cdt
, &tmp
, a
);
973 d2d_cdt_splice(cdt
, e
, &tmp
);
974 d2d_cdt_edge_sym(&tmp
, e
);
975 d2d_cdt_splice(cdt
, &tmp
, b
);
980 static BOOL
d2d_cdt_merge(struct d2d_cdt
*cdt
, struct d2d_cdt_edge_ref
*left_outer
,
981 struct d2d_cdt_edge_ref
*left_inner
, struct d2d_cdt_edge_ref
*right_inner
,
982 struct d2d_cdt_edge_ref
*right_outer
)
984 struct d2d_cdt_edge_ref base_edge
, tmp
;
986 /* Create the base edge between both parts. */
989 if (d2d_cdt_leftof(cdt
, d2d_cdt_edge_origin(cdt
, right_inner
), left_inner
))
991 d2d_cdt_edge_next_left(cdt
, left_inner
, left_inner
);
993 else if (d2d_cdt_rightof(cdt
, d2d_cdt_edge_origin(cdt
, left_inner
), right_inner
))
995 d2d_cdt_edge_sym(&tmp
, right_inner
);
996 d2d_cdt_edge_next_origin(cdt
, right_inner
, &tmp
);
1004 d2d_cdt_edge_sym(&tmp
, right_inner
);
1005 if (!d2d_cdt_connect(cdt
, &base_edge
, &tmp
, left_inner
))
1007 if (d2d_cdt_edge_origin(cdt
, left_inner
) == d2d_cdt_edge_origin(cdt
, left_outer
))
1008 d2d_cdt_edge_sym(left_outer
, &base_edge
);
1009 if (d2d_cdt_edge_origin(cdt
, right_inner
) == d2d_cdt_edge_origin(cdt
, right_outer
))
1010 *right_outer
= base_edge
;
1014 struct d2d_cdt_edge_ref left_candidate
, right_candidate
, sym_base_edge
;
1015 BOOL left_valid
, right_valid
;
1017 /* Find the left candidate. */
1018 d2d_cdt_edge_sym(&sym_base_edge
, &base_edge
);
1019 d2d_cdt_edge_next_origin(cdt
, &left_candidate
, &sym_base_edge
);
1020 if ((left_valid
= d2d_cdt_leftof(cdt
, d2d_cdt_edge_destination(cdt
, &left_candidate
), &sym_base_edge
)))
1022 d2d_cdt_edge_next_origin(cdt
, &tmp
, &left_candidate
);
1023 while (d2d_cdt_edge_destination(cdt
, &tmp
) != d2d_cdt_edge_destination(cdt
, &sym_base_edge
)
1024 && d2d_cdt_incircle(cdt
,
1025 d2d_cdt_edge_origin(cdt
, &sym_base_edge
), d2d_cdt_edge_destination(cdt
, &sym_base_edge
),
1026 d2d_cdt_edge_destination(cdt
, &left_candidate
), d2d_cdt_edge_destination(cdt
, &tmp
)))
1028 d2d_cdt_destroy_edge(cdt
, &left_candidate
);
1029 left_candidate
= tmp
;
1030 d2d_cdt_edge_next_origin(cdt
, &tmp
, &left_candidate
);
1033 d2d_cdt_edge_sym(&left_candidate
, &left_candidate
);
1035 /* Find the right candidate. */
1036 d2d_cdt_edge_prev_origin(cdt
, &right_candidate
, &base_edge
);
1037 if ((right_valid
= d2d_cdt_rightof(cdt
, d2d_cdt_edge_destination(cdt
, &right_candidate
), &base_edge
)))
1039 d2d_cdt_edge_prev_origin(cdt
, &tmp
, &right_candidate
);
1040 while (d2d_cdt_edge_destination(cdt
, &tmp
) != d2d_cdt_edge_destination(cdt
, &base_edge
)
1041 && d2d_cdt_incircle(cdt
,
1042 d2d_cdt_edge_origin(cdt
, &sym_base_edge
), d2d_cdt_edge_destination(cdt
, &sym_base_edge
),
1043 d2d_cdt_edge_destination(cdt
, &right_candidate
), d2d_cdt_edge_destination(cdt
, &tmp
)))
1045 d2d_cdt_destroy_edge(cdt
, &right_candidate
);
1046 right_candidate
= tmp
;
1047 d2d_cdt_edge_prev_origin(cdt
, &tmp
, &right_candidate
);
1051 if (!left_valid
&& !right_valid
)
1054 /* Connect the appropriate candidate with the base edge. */
1055 if (!left_valid
|| (right_valid
&& d2d_cdt_incircle(cdt
,
1056 d2d_cdt_edge_origin(cdt
, &left_candidate
), d2d_cdt_edge_destination(cdt
, &left_candidate
),
1057 d2d_cdt_edge_origin(cdt
, &right_candidate
), d2d_cdt_edge_destination(cdt
, &right_candidate
))))
1059 if (!d2d_cdt_connect(cdt
, &base_edge
, &right_candidate
, &sym_base_edge
))
1064 if (!d2d_cdt_connect(cdt
, &base_edge
, &sym_base_edge
, &left_candidate
))
1072 /* Create a Delaunay triangulation from a set of vertices. This is an
1073 * implementation of the divide-and-conquer algorithm described by Guibas and
1074 * Stolfi. Should be called with at least two vertices. */
1075 static BOOL
d2d_cdt_triangulate(struct d2d_cdt
*cdt
, size_t start_vertex
, size_t vertex_count
,
1076 struct d2d_cdt_edge_ref
*left_edge
, struct d2d_cdt_edge_ref
*right_edge
)
1078 struct d2d_cdt_edge_ref left_inner
, left_outer
, right_inner
, right_outer
, tmp
;
1081 /* Only two vertices, create a single edge. */
1082 if (vertex_count
== 2)
1084 struct d2d_cdt_edge_ref a
;
1086 if (!d2d_cdt_create_edge(cdt
, &a
))
1088 d2d_cdt_edge_set_origin(cdt
, &a
, start_vertex
);
1089 d2d_cdt_edge_set_destination(cdt
, &a
, start_vertex
+ 1);
1092 d2d_cdt_edge_sym(right_edge
, &a
);
1097 /* Three vertices, create a triangle. */
1098 if (vertex_count
== 3)
1100 struct d2d_cdt_edge_ref a
, b
, c
;
1103 if (!d2d_cdt_create_edge(cdt
, &a
))
1105 if (!d2d_cdt_create_edge(cdt
, &b
))
1107 d2d_cdt_edge_sym(&tmp
, &a
);
1108 d2d_cdt_splice(cdt
, &tmp
, &b
);
1110 d2d_cdt_edge_set_origin(cdt
, &a
, start_vertex
);
1111 d2d_cdt_edge_set_destination(cdt
, &a
, start_vertex
+ 1);
1112 d2d_cdt_edge_set_origin(cdt
, &b
, start_vertex
+ 1);
1113 d2d_cdt_edge_set_destination(cdt
, &b
, start_vertex
+ 2);
1115 det
= d2d_cdt_ccw(cdt
, start_vertex
, start_vertex
+ 1, start_vertex
+ 2);
1116 if (det
!= 0.0f
&& !d2d_cdt_connect(cdt
, &c
, &b
, &a
))
1121 d2d_cdt_edge_sym(left_edge
, &c
);
1127 d2d_cdt_edge_sym(right_edge
, &b
);
1133 /* More than tree vertices, divide. */
1134 cut
= vertex_count
/ 2;
1135 if (!d2d_cdt_triangulate(cdt
, start_vertex
, cut
, &left_outer
, &left_inner
))
1137 if (!d2d_cdt_triangulate(cdt
, start_vertex
+ cut
, vertex_count
- cut
, &right_inner
, &right_outer
))
1139 /* Merge the left and right parts. */
1140 if (!d2d_cdt_merge(cdt
, &left_outer
, &left_inner
, &right_inner
, &right_outer
))
1143 *left_edge
= left_outer
;
1144 *right_edge
= right_outer
;
1148 static int d2d_cdt_compare_vertices(const void *a
, const void *b
)
1150 const D2D1_POINT_2F
*p0
= a
;
1151 const D2D1_POINT_2F
*p1
= b
;
1152 float diff
= p0
->x
- p1
->x
;
1155 diff
= p0
->y
- p1
->y
;
1157 return diff
== 0.0f
? 0 : (diff
> 0.0f
? 1 : -1);
1160 /* Determine whether a given point is inside the geometry, using the current
1161 * fill mode rule. */
1162 static BOOL
d2d_path_geometry_point_inside(const struct d2d_geometry
*geometry
, const D2D1_POINT_2F
*probe
)
1164 const D2D1_POINT_2F
*p0
, *p1
;
1165 D2D1_POINT_2F v_p
, v_probe
;
1169 for (i
= 0, score
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
1171 const struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[i
];
1173 p0
= &figure
->vertices
[figure
->vertex_count
- 1];
1174 for (j
= 0; j
< figure
->vertex_count
; p0
= p1
, ++j
)
1176 p1
= &figure
->vertices
[j
];
1177 d2d_point_subtract(&v_p
, p1
, p0
);
1178 d2d_point_subtract(&v_probe
, probe
, p0
);
1180 if ((probe
->y
< p0
->y
) != (probe
->y
< p1
->y
) && v_probe
.x
< v_p
.x
* (v_probe
.y
/ v_p
.y
))
1182 if (geometry
->u
.path
.fill_mode
== D2D1_FILL_MODE_ALTERNATE
|| (probe
->y
< p0
->y
))
1190 return geometry
->u
.path
.fill_mode
== D2D1_FILL_MODE_ALTERNATE
? score
& 1 : score
;
1193 static BOOL
d2d_path_geometry_add_face(struct d2d_geometry
*geometry
, const struct d2d_cdt
*cdt
,
1194 const struct d2d_cdt_edge_ref
*base_edge
)
1196 struct d2d_cdt_edge_ref tmp
;
1197 struct d2d_face
*face
;
1198 D2D1_POINT_2F probe
;
1200 if (cdt
->edges
[base_edge
->idx
].flags
& D2D_CDT_EDGE_FLAG_VISITED(base_edge
->r
))
1203 if (!d2d_array_reserve((void **)&geometry
->faces
, &geometry
->faces_size
,
1204 geometry
->face_count
+ 1, sizeof(*geometry
->faces
)))
1206 ERR("Failed to grow faces array.\n");
1210 face
= &geometry
->faces
[geometry
->face_count
];
1212 /* It may seem tempting to use the center of the face as probe origin, but
1213 * multiplying by powers of two works much better for preserving accuracy. */
1216 cdt
->edges
[tmp
.idx
].flags
|= D2D_CDT_EDGE_FLAG_VISITED(tmp
.r
);
1217 face
->v
[0] = d2d_cdt_edge_origin(cdt
, &tmp
);
1218 probe
.x
= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].x
* 0.25f
;
1219 probe
.y
= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].y
* 0.25f
;
1221 d2d_cdt_edge_next_left(cdt
, &tmp
, &tmp
);
1222 cdt
->edges
[tmp
.idx
].flags
|= D2D_CDT_EDGE_FLAG_VISITED(tmp
.r
);
1223 face
->v
[1] = d2d_cdt_edge_origin(cdt
, &tmp
);
1224 probe
.x
+= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].x
* 0.25f
;
1225 probe
.y
+= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].y
* 0.25f
;
1227 d2d_cdt_edge_next_left(cdt
, &tmp
, &tmp
);
1228 cdt
->edges
[tmp
.idx
].flags
|= D2D_CDT_EDGE_FLAG_VISITED(tmp
.r
);
1229 face
->v
[2] = d2d_cdt_edge_origin(cdt
, &tmp
);
1230 probe
.x
+= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].x
* 0.50f
;
1231 probe
.y
+= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].y
* 0.50f
;
1233 d2d_cdt_edge_next_left(cdt
, &tmp
, &tmp
);
1234 if (tmp
.idx
== base_edge
->idx
&& d2d_path_geometry_point_inside(geometry
, &probe
))
1235 ++geometry
->face_count
;
1240 static BOOL
d2d_cdt_generate_faces(const struct d2d_cdt
*cdt
, struct d2d_geometry
*geometry
)
1242 struct d2d_cdt_edge_ref base_edge
;
1245 for (i
= 0; i
< cdt
->edge_count
; ++i
)
1247 if (cdt
->edges
[i
].flags
& D2D_CDT_EDGE_FLAG_FREED
)
1252 if (!d2d_path_geometry_add_face(geometry
, cdt
, &base_edge
))
1254 d2d_cdt_edge_sym(&base_edge
, &base_edge
);
1255 if (!d2d_path_geometry_add_face(geometry
, cdt
, &base_edge
))
1262 HeapFree(GetProcessHeap(), 0, geometry
->faces
);
1263 geometry
->faces
= NULL
;
1264 geometry
->faces_size
= 0;
1265 geometry
->face_count
= 0;
1269 static BOOL
d2d_cdt_fixup(struct d2d_cdt
*cdt
, const struct d2d_cdt_edge_ref
*base_edge
)
1271 struct d2d_cdt_edge_ref candidate
, next
, new_base
;
1272 unsigned int count
= 0;
1274 d2d_cdt_edge_next_left(cdt
, &next
, base_edge
);
1275 if (next
.idx
== base_edge
->idx
)
1277 ERR("Degenerate face.\n");
1282 while (d2d_cdt_edge_destination(cdt
, &next
) != d2d_cdt_edge_origin(cdt
, base_edge
))
1284 if (d2d_cdt_incircle(cdt
, d2d_cdt_edge_origin(cdt
, base_edge
), d2d_cdt_edge_destination(cdt
, base_edge
),
1285 d2d_cdt_edge_destination(cdt
, &candidate
), d2d_cdt_edge_destination(cdt
, &next
)))
1287 d2d_cdt_edge_next_left(cdt
, &next
, &next
);
1293 d2d_cdt_edge_next_left(cdt
, &next
, &candidate
);
1294 if (d2d_cdt_edge_destination(cdt
, &next
) == d2d_cdt_edge_origin(cdt
, base_edge
))
1295 d2d_cdt_edge_next_left(cdt
, &next
, base_edge
);
1298 if (!d2d_cdt_connect(cdt
, &new_base
, &candidate
, &next
))
1300 if (!d2d_cdt_fixup(cdt
, &new_base
))
1302 d2d_cdt_edge_sym(&new_base
, &new_base
);
1303 if (!d2d_cdt_fixup(cdt
, &new_base
))
1310 static void d2d_cdt_cut_edges(struct d2d_cdt
*cdt
, struct d2d_cdt_edge_ref
*end_edge
,
1311 const struct d2d_cdt_edge_ref
*base_edge
, size_t start_vertex
, size_t end_vertex
)
1313 struct d2d_cdt_edge_ref next
;
1315 d2d_cdt_edge_next_left(cdt
, &next
, base_edge
);
1316 if (d2d_cdt_edge_destination(cdt
, &next
) == end_vertex
)
1322 if (d2d_cdt_ccw(cdt
, d2d_cdt_edge_destination(cdt
, &next
), end_vertex
, start_vertex
) > 0.0f
)
1323 d2d_cdt_edge_next_left(cdt
, &next
, &next
);
1325 d2d_cdt_edge_sym(&next
, &next
);
1326 d2d_cdt_cut_edges(cdt
, end_edge
, &next
, start_vertex
, end_vertex
);
1327 d2d_cdt_destroy_edge(cdt
, &next
);
1330 static BOOL
d2d_cdt_insert_segment(struct d2d_cdt
*cdt
, struct d2d_geometry
*geometry
,
1331 const struct d2d_cdt_edge_ref
*origin
, size_t end_vertex
)
1333 struct d2d_cdt_edge_ref base_edge
, current
, next
, target
;
1335 for (current
= *origin
;; current
= next
)
1337 d2d_cdt_edge_next_origin(cdt
, &next
, ¤t
);
1339 if (d2d_cdt_edge_destination(cdt
, ¤t
) == end_vertex
)
1342 if (d2d_cdt_rightof(cdt
, end_vertex
, &next
) && d2d_cdt_leftof(cdt
, end_vertex
, ¤t
))
1344 d2d_cdt_edge_next_left(cdt
, &base_edge
, ¤t
);
1346 d2d_cdt_edge_sym(&base_edge
, &base_edge
);
1347 d2d_cdt_cut_edges(cdt
, &target
, &base_edge
, d2d_cdt_edge_origin(cdt
, origin
), end_vertex
);
1348 d2d_cdt_destroy_edge(cdt
, &base_edge
);
1350 if (!d2d_cdt_connect(cdt
, &base_edge
, &target
, ¤t
))
1352 if (!d2d_cdt_fixup(cdt
, &base_edge
))
1354 d2d_cdt_edge_sym(&base_edge
, &base_edge
);
1355 if (!d2d_cdt_fixup(cdt
, &base_edge
))
1361 if (next
.idx
== origin
->idx
)
1363 ERR("Triangle not found.\n");
1369 static BOOL
d2d_cdt_insert_segments(struct d2d_cdt
*cdt
, struct d2d_geometry
*geometry
)
1371 size_t start_vertex
, end_vertex
, i
, j
, k
;
1372 const struct d2d_figure
*figure
;
1373 struct d2d_cdt_edge_ref edge
;
1374 const D2D1_POINT_2F
*p
;
1376 for (i
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
1378 figure
= &geometry
->u
.path
.figures
[i
];
1380 p
= bsearch(&figure
->vertices
[figure
->vertex_count
- 1], cdt
->vertices
,
1381 geometry
->vertex_count
, sizeof(*p
), d2d_cdt_compare_vertices
);
1382 start_vertex
= p
- cdt
->vertices
;
1384 for (j
= 0; j
< figure
->vertex_count
; start_vertex
= end_vertex
, ++j
)
1386 p
= bsearch(&figure
->vertices
[j
], cdt
->vertices
,
1387 geometry
->vertex_count
, sizeof(*p
), d2d_cdt_compare_vertices
);
1388 end_vertex
= p
- cdt
->vertices
;
1390 if (start_vertex
== end_vertex
)
1393 for (k
= 0; k
< cdt
->edge_count
; ++k
)
1395 if (cdt
->edges
[k
].flags
& D2D_CDT_EDGE_FLAG_FREED
)
1401 if (d2d_cdt_edge_origin(cdt
, &edge
) == start_vertex
)
1403 if (!d2d_cdt_insert_segment(cdt
, geometry
, &edge
, end_vertex
))
1407 d2d_cdt_edge_sym(&edge
, &edge
);
1408 if (d2d_cdt_edge_origin(cdt
, &edge
) == start_vertex
)
1410 if (!d2d_cdt_insert_segment(cdt
, geometry
, &edge
, end_vertex
))
1421 /* Intersect the geometry's segments with themselves. This uses the
1422 * straightforward approach of testing everything against everything, but
1423 * there certainly exist more scalable algorithms for this. */
1424 /* FIXME: Beziers can't currently self-intersect. */
1425 static BOOL
d2d_geometry_intersect_self(struct d2d_geometry
*geometry
)
1427 D2D1_POINT_2F p0
, p1
, q0
, q1
, v_p
, v_q
, v_qp
, intersection
;
1428 struct d2d_figure
*figure_p
, *figure_q
;
1429 size_t i
, j
, k
, l
, min_j
, min_l
, max_l
;
1432 for (i
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
1434 figure_p
= &geometry
->u
.path
.figures
[i
];
1435 p0
= figure_p
->vertices
[figure_p
->vertex_count
- 1];
1438 for (k
= 0; k
< figure_p
->vertex_count
; p0
= p1
, ++k
)
1440 p1
= figure_p
->vertices
[k
];
1441 d2d_point_subtract(&v_p
, &p1
, &p0
);
1442 for (j
= min_j
, min_j
= 0, l
= min_l
, min_l
= 0; j
< i
|| (j
== i
&& k
); ++j
, l
= 0)
1444 figure_q
= &geometry
->u
.path
.figures
[j
];
1446 if (figure_p
->bounds
.left
> figure_q
->bounds
.right
1447 || figure_q
->bounds
.left
> figure_p
->bounds
.right
1448 || figure_p
->bounds
.top
> figure_q
->bounds
.bottom
1449 || figure_q
->bounds
.top
> figure_p
->bounds
.bottom
)
1452 max_l
= j
== i
? k
- 1 : figure_q
->vertex_count
;
1453 q0
= figure_q
->vertices
[l
== 0 ? figure_q
->vertex_count
- 1 : l
- 1];
1454 for (; l
< max_l
; q0
= q1
, ++l
)
1456 q1
= figure_q
->vertices
[l
];
1457 d2d_point_subtract(&v_q
, &q1
, &q0
);
1458 d2d_point_subtract(&v_qp
, &p0
, &q0
);
1460 det
= v_p
.x
* v_q
.y
- v_p
.y
* v_q
.x
;
1464 s
= (v_q
.x
* v_qp
.y
- v_q
.y
* v_qp
.x
) / det
;
1465 t
= (v_p
.x
* v_qp
.y
- v_p
.y
* v_qp
.x
) / det
;
1467 if (s
< 0.0f
|| s
> 1.0f
|| t
< 0.0f
|| t
> 1.0f
)
1470 intersection
.x
= p0
.x
+ v_p
.x
* s
;
1471 intersection
.y
= p0
.y
+ v_p
.y
* s
;
1473 if (t
> 0.0f
&& t
< 1.0f
)
1475 if (!d2d_figure_insert_vertex(figure_q
, l
, intersection
))
1483 if (s
> 0.0f
&& s
< 1.0f
)
1485 if (!d2d_figure_insert_vertex(figure_p
, k
, intersection
))
1490 d2d_point_subtract(&v_p
, &p1
, &p0
);
1500 static HRESULT
d2d_path_geometry_triangulate(struct d2d_geometry
*geometry
)
1502 struct d2d_cdt_edge_ref left_edge
, right_edge
;
1503 size_t vertex_count
, i
, j
;
1504 struct d2d_cdt cdt
= {0};
1505 D2D1_POINT_2F
*vertices
;
1507 for (i
= 0, vertex_count
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
1509 vertex_count
+= geometry
->u
.path
.figures
[i
].vertex_count
;
1512 if (vertex_count
< 3)
1514 WARN("Geometry has %lu vertices.\n", (long)vertex_count
);
1518 if (!(vertices
= HeapAlloc(GetProcessHeap(), 0, vertex_count
* sizeof(*vertices
))))
1519 return E_OUTOFMEMORY
;
1521 for (i
= 0, j
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
1523 memcpy(&vertices
[j
], geometry
->u
.path
.figures
[i
].vertices
,
1524 geometry
->u
.path
.figures
[i
].vertex_count
* sizeof(*vertices
));
1525 j
+= geometry
->u
.path
.figures
[i
].vertex_count
;
1528 /* Sort vertices, eliminate duplicates. */
1529 qsort(vertices
, vertex_count
, sizeof(*vertices
), d2d_cdt_compare_vertices
);
1530 for (i
= 1; i
< vertex_count
; ++i
)
1532 if (!memcmp(&vertices
[i
- 1], &vertices
[i
], sizeof(*vertices
)))
1535 memmove(&vertices
[i
], &vertices
[i
+ 1], (vertex_count
- i
) * sizeof(*vertices
));
1540 geometry
->vertices
= vertices
;
1541 geometry
->vertex_count
= vertex_count
;
1543 cdt
.free_edge
= ~0u;
1544 cdt
.vertices
= vertices
;
1545 if (!d2d_cdt_triangulate(&cdt
, 0, vertex_count
, &left_edge
, &right_edge
))
1547 if (!d2d_cdt_insert_segments(&cdt
, geometry
))
1549 if (!d2d_cdt_generate_faces(&cdt
, geometry
))
1552 HeapFree(GetProcessHeap(), 0, cdt
.edges
);
1556 geometry
->vertices
= NULL
;
1557 geometry
->vertex_count
= 0;
1558 HeapFree(GetProcessHeap(), 0, vertices
);
1559 HeapFree(GetProcessHeap(), 0, cdt
.edges
);
1563 static BOOL
d2d_path_geometry_add_figure(struct d2d_geometry
*geometry
)
1565 struct d2d_figure
*figure
;
1567 if (!d2d_array_reserve((void **)&geometry
->u
.path
.figures
, &geometry
->u
.path
.figures_size
,
1568 geometry
->u
.path
.figure_count
+ 1, sizeof(*geometry
->u
.path
.figures
)))
1570 ERR("Failed to grow figures array.\n");
1574 figure
= &geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
];
1575 memset(figure
, 0, sizeof(*figure
));
1576 figure
->bounds
.left
= FLT_MAX
;
1577 figure
->bounds
.top
= FLT_MAX
;
1578 figure
->bounds
.right
= -FLT_MAX
;
1579 figure
->bounds
.bottom
= -FLT_MAX
;
1581 ++geometry
->u
.path
.figure_count
;
1585 static void d2d_geometry_cleanup(struct d2d_geometry
*geometry
)
1587 HeapFree(GetProcessHeap(), 0, geometry
->beziers
);
1588 HeapFree(GetProcessHeap(), 0, geometry
->faces
);
1589 HeapFree(GetProcessHeap(), 0, geometry
->vertices
);
1590 ID2D1Factory_Release(geometry
->factory
);
1593 static void d2d_geometry_init(struct d2d_geometry
*geometry
, ID2D1Factory
*factory
,
1594 const D2D1_MATRIX_3X2_F
*transform
, const struct ID2D1GeometryVtbl
*vtbl
)
1596 geometry
->ID2D1Geometry_iface
.lpVtbl
= vtbl
;
1597 geometry
->refcount
= 1;
1598 ID2D1Factory_AddRef(geometry
->factory
= factory
);
1599 geometry
->transform
= *transform
;
1602 static inline struct d2d_geometry
*impl_from_ID2D1GeometrySink(ID2D1GeometrySink
*iface
)
1604 return CONTAINING_RECORD(iface
, struct d2d_geometry
, u
.path
.ID2D1GeometrySink_iface
);
1607 static HRESULT STDMETHODCALLTYPE
d2d_geometry_sink_QueryInterface(ID2D1GeometrySink
*iface
, REFIID iid
, void **out
)
1609 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
1611 if (IsEqualGUID(iid
, &IID_ID2D1GeometrySink
)
1612 || IsEqualGUID(iid
, &IID_ID2D1SimplifiedGeometrySink
)
1613 || IsEqualGUID(iid
, &IID_IUnknown
))
1615 ID2D1GeometrySink_AddRef(iface
);
1620 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
1623 return E_NOINTERFACE
;
1626 static ULONG STDMETHODCALLTYPE
d2d_geometry_sink_AddRef(ID2D1GeometrySink
*iface
)
1628 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
1630 TRACE("iface %p.\n", iface
);
1632 return ID2D1Geometry_AddRef(&geometry
->ID2D1Geometry_iface
);
1635 static ULONG STDMETHODCALLTYPE
d2d_geometry_sink_Release(ID2D1GeometrySink
*iface
)
1637 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
1639 TRACE("iface %p.\n", iface
);
1641 return ID2D1Geometry_Release(&geometry
->ID2D1Geometry_iface
);
1644 static void STDMETHODCALLTYPE
d2d_geometry_sink_SetFillMode(ID2D1GeometrySink
*iface
, D2D1_FILL_MODE mode
)
1646 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
1648 TRACE("iface %p, mode %#x.\n", iface
, mode
);
1650 geometry
->u
.path
.fill_mode
= mode
;
1653 static void STDMETHODCALLTYPE
d2d_geometry_sink_SetSegmentFlags(ID2D1GeometrySink
*iface
, D2D1_PATH_SEGMENT flags
)
1655 FIXME("iface %p, flags %#x stub!\n", iface
, flags
);
1658 static void STDMETHODCALLTYPE
d2d_geometry_sink_BeginFigure(ID2D1GeometrySink
*iface
,
1659 D2D1_POINT_2F start_point
, D2D1_FIGURE_BEGIN figure_begin
)
1661 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
1663 TRACE("iface %p, start_point {%.8e, %.8e}, figure_begin %#x.\n",
1664 iface
, start_point
.x
, start_point
.y
, figure_begin
);
1666 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_OPEN
)
1668 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
1672 if (figure_begin
!= D2D1_FIGURE_BEGIN_FILLED
)
1673 FIXME("Ignoring figure_begin %#x.\n", figure_begin
);
1675 if (!d2d_path_geometry_add_figure(geometry
))
1677 ERR("Failed to add figure.\n");
1678 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
1682 if (!d2d_figure_add_vertex(&geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
- 1], start_point
))
1683 ERR("Failed to add vertex.\n");
1685 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_FIGURE
;
1686 ++geometry
->u
.path
.segment_count
;
1689 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddLines(ID2D1GeometrySink
*iface
,
1690 const D2D1_POINT_2F
*points
, UINT32 count
)
1692 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
1695 TRACE("iface %p, points %p, count %u.\n", iface
, points
, count
);
1697 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_FIGURE
)
1699 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
1703 for (i
= 0; i
< count
; ++i
)
1705 if (!d2d_figure_add_vertex(&geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
- 1], points
[i
]))
1707 ERR("Failed to add vertex.\n");
1712 geometry
->u
.path
.segment_count
+= count
;
1715 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddBeziers(ID2D1GeometrySink
*iface
,
1716 const D2D1_BEZIER_SEGMENT
*beziers
, UINT32 count
)
1718 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
1719 struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
- 1];
1723 TRACE("iface %p, beziers %p, count %u.\n", iface
, beziers
, count
);
1725 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_FIGURE
)
1727 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
1731 for (i
= 0; i
< count
; ++i
)
1733 /* FIXME: This tries to approximate a cubic bezier with a quadratic one. */
1734 p
.x
= (beziers
[i
].point1
.x
+ beziers
[i
].point2
.x
) * 0.75f
;
1735 p
.y
= (beziers
[i
].point1
.y
+ beziers
[i
].point2
.y
) * 0.75f
;
1736 p
.x
-= (figure
->vertices
[figure
->vertex_count
- 1].x
+ beziers
[i
].point3
.x
) * 0.25f
;
1737 p
.y
-= (figure
->vertices
[figure
->vertex_count
- 1].y
+ beziers
[i
].point3
.y
) * 0.25f
;
1738 if (!d2d_figure_add_bezier(figure
, figure
->vertices
[figure
->vertex_count
- 1], p
, beziers
[i
].point3
))
1740 ERR("Failed to add bezier.\n");
1745 geometry
->u
.path
.segment_count
+= count
;
1748 static void STDMETHODCALLTYPE
d2d_geometry_sink_EndFigure(ID2D1GeometrySink
*iface
, D2D1_FIGURE_END figure_end
)
1750 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
1752 TRACE("iface %p, figure_end %#x.\n", iface
, figure_end
);
1754 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_FIGURE
)
1756 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
1760 if (figure_end
!= D2D1_FIGURE_END_CLOSED
)
1761 FIXME("Ignoring figure_end %#x.\n", figure_end
);
1763 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_OPEN
;
1766 static void d2d_path_geometry_free_figures(struct d2d_geometry
*geometry
)
1770 if (!geometry
->u
.path
.figures
)
1773 for (i
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
1775 HeapFree(GetProcessHeap(), 0, geometry
->u
.path
.figures
[i
].beziers
);
1776 HeapFree(GetProcessHeap(), 0, geometry
->u
.path
.figures
[i
].vertices
);
1778 HeapFree(GetProcessHeap(), 0, geometry
->u
.path
.figures
);
1779 geometry
->u
.path
.figures
= NULL
;
1780 geometry
->u
.path
.figures_size
= 0;
1783 static HRESULT STDMETHODCALLTYPE
d2d_geometry_sink_Close(ID2D1GeometrySink
*iface
)
1785 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
1786 HRESULT hr
= E_FAIL
;
1789 TRACE("iface %p.\n", iface
);
1791 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_OPEN
)
1793 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_CLOSED
)
1794 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
1795 return D2DERR_WRONG_STATE
;
1797 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_CLOSED
;
1799 if (!d2d_geometry_intersect_self(geometry
))
1801 if (FAILED(hr
= d2d_path_geometry_triangulate(geometry
)))
1804 for (i
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
1806 geometry
->bezier_count
+= geometry
->u
.path
.figures
[i
].bezier_count
;
1809 if (!(geometry
->beziers
= HeapAlloc(GetProcessHeap(), 0,
1810 geometry
->bezier_count
* sizeof(*geometry
->beziers
))))
1812 ERR("Failed to allocate beziers array.\n");
1813 geometry
->bezier_count
= 0;
1818 for (i
= 0, start
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
1820 struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[i
];
1821 if (figure
->bezier_count
)
1823 memcpy(&geometry
->beziers
[start
], figure
->beziers
,
1824 figure
->bezier_count
* sizeof(*figure
->beziers
));
1825 start
+= figure
->bezier_count
;
1830 d2d_path_geometry_free_figures(geometry
);
1832 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
1836 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddLine(ID2D1GeometrySink
*iface
, D2D1_POINT_2F point
)
1838 TRACE("iface %p, point {%.8e, %.8e}.\n", iface
, point
.x
, point
.y
);
1840 d2d_geometry_sink_AddLines(iface
, &point
, 1);
1843 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddBezier(ID2D1GeometrySink
*iface
, const D2D1_BEZIER_SEGMENT
*bezier
)
1845 TRACE("iface %p, bezier %p.\n", iface
, bezier
);
1847 d2d_geometry_sink_AddBeziers(iface
, bezier
, 1);
1850 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddQuadraticBezier(ID2D1GeometrySink
*iface
,
1851 const D2D1_QUADRATIC_BEZIER_SEGMENT
*bezier
)
1853 TRACE("iface %p, bezier %p.\n", iface
, bezier
);
1855 ID2D1GeometrySink_AddQuadraticBeziers(iface
, bezier
, 1);
1858 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddQuadraticBeziers(ID2D1GeometrySink
*iface
,
1859 const D2D1_QUADRATIC_BEZIER_SEGMENT
*beziers
, UINT32 bezier_count
)
1861 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
1862 struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
- 1];
1865 TRACE("iface %p, beziers %p, bezier_count %u.\n", iface
, beziers
, bezier_count
);
1867 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_FIGURE
)
1869 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
1873 for (i
= 0; i
< bezier_count
; ++i
)
1875 if (!d2d_figure_add_bezier(figure
, figure
->vertices
[figure
->vertex_count
- 1],
1876 beziers
[i
].point1
, beziers
[i
].point2
))
1878 ERR("Failed to add bezier.\n");
1883 geometry
->u
.path
.segment_count
+= bezier_count
;
1886 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddArc(ID2D1GeometrySink
*iface
, const D2D1_ARC_SEGMENT
*arc
)
1888 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
1890 FIXME("iface %p, arc %p stub!\n", iface
, arc
);
1892 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_FIGURE
)
1894 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
1898 if (!d2d_figure_add_vertex(&geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
- 1], arc
->point
))
1900 ERR("Failed to add vertex.\n");
1904 ++geometry
->u
.path
.segment_count
;
1907 static const struct ID2D1GeometrySinkVtbl d2d_geometry_sink_vtbl
=
1909 d2d_geometry_sink_QueryInterface
,
1910 d2d_geometry_sink_AddRef
,
1911 d2d_geometry_sink_Release
,
1912 d2d_geometry_sink_SetFillMode
,
1913 d2d_geometry_sink_SetSegmentFlags
,
1914 d2d_geometry_sink_BeginFigure
,
1915 d2d_geometry_sink_AddLines
,
1916 d2d_geometry_sink_AddBeziers
,
1917 d2d_geometry_sink_EndFigure
,
1918 d2d_geometry_sink_Close
,
1919 d2d_geometry_sink_AddLine
,
1920 d2d_geometry_sink_AddBezier
,
1921 d2d_geometry_sink_AddQuadraticBezier
,
1922 d2d_geometry_sink_AddQuadraticBeziers
,
1923 d2d_geometry_sink_AddArc
,
1926 static inline struct d2d_geometry
*impl_from_ID2D1PathGeometry(ID2D1PathGeometry
*iface
)
1928 return CONTAINING_RECORD(iface
, struct d2d_geometry
, ID2D1Geometry_iface
);
1931 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_QueryInterface(ID2D1PathGeometry
*iface
, REFIID iid
, void **out
)
1933 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
1935 if (IsEqualGUID(iid
, &IID_ID2D1PathGeometry
)
1936 || IsEqualGUID(iid
, &IID_ID2D1Geometry
)
1937 || IsEqualGUID(iid
, &IID_ID2D1Resource
)
1938 || IsEqualGUID(iid
, &IID_IUnknown
))
1940 ID2D1PathGeometry_AddRef(iface
);
1945 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
1948 return E_NOINTERFACE
;
1951 static ULONG STDMETHODCALLTYPE
d2d_path_geometry_AddRef(ID2D1PathGeometry
*iface
)
1953 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
1954 ULONG refcount
= InterlockedIncrement(&geometry
->refcount
);
1956 TRACE("%p increasing refcount to %u.\n", iface
, refcount
);
1961 static ULONG STDMETHODCALLTYPE
d2d_path_geometry_Release(ID2D1PathGeometry
*iface
)
1963 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
1964 ULONG refcount
= InterlockedDecrement(&geometry
->refcount
);
1966 TRACE("%p decreasing refcount to %u.\n", iface
, refcount
);
1970 d2d_path_geometry_free_figures(geometry
);
1971 d2d_geometry_cleanup(geometry
);
1972 HeapFree(GetProcessHeap(), 0, geometry
);
1978 static void STDMETHODCALLTYPE
d2d_path_geometry_GetFactory(ID2D1PathGeometry
*iface
, ID2D1Factory
**factory
)
1980 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
1982 TRACE("iface %p, factory %p.\n", iface
, factory
);
1984 ID2D1Factory_AddRef(*factory
= geometry
->factory
);
1987 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_GetBounds(ID2D1PathGeometry
*iface
,
1988 const D2D1_MATRIX_3X2_F
*transform
, D2D1_RECT_F
*bounds
)
1990 FIXME("iface %p, transform %p, bounds %p stub!\n", iface
, transform
, bounds
);
1995 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_GetWidenedBounds(ID2D1PathGeometry
*iface
, float stroke_width
,
1996 ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_RECT_F
*bounds
)
1998 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
1999 iface
, stroke_width
, stroke_style
, transform
, tolerance
, bounds
);
2004 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_StrokeContainsPoint(ID2D1PathGeometry
*iface
,
2005 D2D1_POINT_2F point
, float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
2006 float tolerance
, BOOL
*contains
)
2008 FIXME("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
2009 "transform %p, tolerance %.8e, contains %p stub!\n",
2010 iface
, point
.x
, point
.y
, stroke_width
, stroke_style
, transform
, tolerance
, contains
);
2015 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_FillContainsPoint(ID2D1PathGeometry
*iface
,
2016 D2D1_POINT_2F point
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, BOOL
*contains
)
2018 FIXME("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p stub!\n",
2019 iface
, point
.x
, point
.y
, transform
, tolerance
, contains
);
2024 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_CompareWithGeometry(ID2D1PathGeometry
*iface
,
2025 ID2D1Geometry
*geometry
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_GEOMETRY_RELATION
*relation
)
2027 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
2028 iface
, geometry
, transform
, tolerance
, relation
);
2033 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Simplify(ID2D1PathGeometry
*iface
,
2034 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
2035 ID2D1SimplifiedGeometrySink
*sink
)
2037 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2038 iface
, option
, transform
, tolerance
, sink
);
2043 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Tessellate(ID2D1PathGeometry
*iface
,
2044 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1TessellationSink
*sink
)
2046 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
2051 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_CombineWithGeometry(ID2D1PathGeometry
*iface
,
2052 ID2D1Geometry
*geometry
, D2D1_COMBINE_MODE combine_mode
, const D2D1_MATRIX_3X2_F
*transform
,
2053 float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
2055 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2056 iface
, geometry
, combine_mode
, transform
, tolerance
, sink
);
2061 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Outline(ID2D1PathGeometry
*iface
,
2062 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
2064 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
2069 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_ComputeArea(ID2D1PathGeometry
*iface
,
2070 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *area
)
2072 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface
, transform
, tolerance
, area
);
2077 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_ComputeLength(ID2D1PathGeometry
*iface
,
2078 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *length
)
2080 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface
, transform
, tolerance
, length
);
2085 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_ComputePointAtLength(ID2D1PathGeometry
*iface
, float length
,
2086 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_POINT_2F
*point
, D2D1_POINT_2F
*tangent
)
2088 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
2089 iface
, length
, transform
, tolerance
, point
, tangent
);
2094 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Widen(ID2D1PathGeometry
*iface
, float stroke_width
,
2095 ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
2096 ID2D1SimplifiedGeometrySink
*sink
)
2098 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
2099 iface
, stroke_width
, stroke_style
, transform
, tolerance
, sink
);
2104 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Open(ID2D1PathGeometry
*iface
, ID2D1GeometrySink
**sink
)
2106 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
2108 TRACE("iface %p, sink %p.\n", iface
, sink
);
2110 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_INITIAL
)
2111 return D2DERR_WRONG_STATE
;
2113 *sink
= &geometry
->u
.path
.ID2D1GeometrySink_iface
;
2114 ID2D1GeometrySink_AddRef(*sink
);
2116 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_OPEN
;
2121 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Stream(ID2D1PathGeometry
*iface
, ID2D1GeometrySink
*sink
)
2123 FIXME("iface %p, sink %p stub!\n", iface
, sink
);
2128 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_GetSegmentCount(ID2D1PathGeometry
*iface
, UINT32
*count
)
2130 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
2132 TRACE("iface %p, count %p.\n", iface
, count
);
2134 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_CLOSED
)
2135 return D2DERR_WRONG_STATE
;
2137 *count
= geometry
->u
.path
.segment_count
;
2142 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_GetFigureCount(ID2D1PathGeometry
*iface
, UINT32
*count
)
2144 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
2146 TRACE("iface %p, count %p.\n", iface
, count
);
2148 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_CLOSED
)
2149 return D2DERR_WRONG_STATE
;
2151 *count
= geometry
->u
.path
.figure_count
;
2156 static const struct ID2D1PathGeometryVtbl d2d_path_geometry_vtbl
=
2158 d2d_path_geometry_QueryInterface
,
2159 d2d_path_geometry_AddRef
,
2160 d2d_path_geometry_Release
,
2161 d2d_path_geometry_GetFactory
,
2162 d2d_path_geometry_GetBounds
,
2163 d2d_path_geometry_GetWidenedBounds
,
2164 d2d_path_geometry_StrokeContainsPoint
,
2165 d2d_path_geometry_FillContainsPoint
,
2166 d2d_path_geometry_CompareWithGeometry
,
2167 d2d_path_geometry_Simplify
,
2168 d2d_path_geometry_Tessellate
,
2169 d2d_path_geometry_CombineWithGeometry
,
2170 d2d_path_geometry_Outline
,
2171 d2d_path_geometry_ComputeArea
,
2172 d2d_path_geometry_ComputeLength
,
2173 d2d_path_geometry_ComputePointAtLength
,
2174 d2d_path_geometry_Widen
,
2175 d2d_path_geometry_Open
,
2176 d2d_path_geometry_Stream
,
2177 d2d_path_geometry_GetSegmentCount
,
2178 d2d_path_geometry_GetFigureCount
,
2181 void d2d_path_geometry_init(struct d2d_geometry
*geometry
, ID2D1Factory
*factory
)
2183 d2d_geometry_init(geometry
, factory
, &identity
, (ID2D1GeometryVtbl
*)&d2d_path_geometry_vtbl
);
2184 geometry
->u
.path
.ID2D1GeometrySink_iface
.lpVtbl
= &d2d_geometry_sink_vtbl
;
2187 static inline struct d2d_geometry
*impl_from_ID2D1RectangleGeometry(ID2D1RectangleGeometry
*iface
)
2189 return CONTAINING_RECORD(iface
, struct d2d_geometry
, ID2D1Geometry_iface
);
2192 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_QueryInterface(ID2D1RectangleGeometry
*iface
,
2193 REFIID iid
, void **out
)
2195 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
2197 if (IsEqualGUID(iid
, &IID_ID2D1RectangleGeometry
)
2198 || IsEqualGUID(iid
, &IID_ID2D1Geometry
)
2199 || IsEqualGUID(iid
, &IID_ID2D1Resource
)
2200 || IsEqualGUID(iid
, &IID_IUnknown
))
2202 ID2D1RectangleGeometry_AddRef(iface
);
2207 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
2210 return E_NOINTERFACE
;
2213 static ULONG STDMETHODCALLTYPE
d2d_rectangle_geometry_AddRef(ID2D1RectangleGeometry
*iface
)
2215 struct d2d_geometry
*geometry
= impl_from_ID2D1RectangleGeometry(iface
);
2216 ULONG refcount
= InterlockedIncrement(&geometry
->refcount
);
2218 TRACE("%p increasing refcount to %u.\n", iface
, refcount
);
2223 static ULONG STDMETHODCALLTYPE
d2d_rectangle_geometry_Release(ID2D1RectangleGeometry
*iface
)
2225 struct d2d_geometry
*geometry
= impl_from_ID2D1RectangleGeometry(iface
);
2226 ULONG refcount
= InterlockedDecrement(&geometry
->refcount
);
2228 TRACE("%p decreasing refcount to %u.\n", iface
, refcount
);
2232 d2d_geometry_cleanup(geometry
);
2233 HeapFree(GetProcessHeap(), 0, geometry
);
2239 static void STDMETHODCALLTYPE
d2d_rectangle_geometry_GetFactory(ID2D1RectangleGeometry
*iface
, ID2D1Factory
**factory
)
2241 struct d2d_geometry
*geometry
= impl_from_ID2D1RectangleGeometry(iface
);
2243 TRACE("iface %p, factory %p.\n", iface
, factory
);
2245 ID2D1Factory_AddRef(*factory
= geometry
->factory
);
2248 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_GetBounds(ID2D1RectangleGeometry
*iface
,
2249 const D2D1_MATRIX_3X2_F
*transform
, D2D1_RECT_F
*bounds
)
2251 FIXME("iface %p, transform %p, bounds %p stub!\n", iface
, transform
, bounds
);
2256 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_GetWidenedBounds(ID2D1RectangleGeometry
*iface
,
2257 float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
2258 float tolerance
, D2D1_RECT_F
*bounds
)
2260 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
2261 iface
, stroke_width
, stroke_style
, transform
, tolerance
, bounds
);
2266 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_StrokeContainsPoint(ID2D1RectangleGeometry
*iface
,
2267 D2D1_POINT_2F point
, float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
2268 float tolerance
, BOOL
*contains
)
2270 FIXME("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
2271 "transform %p, tolerance %.8e, contains %p stub!\n",
2272 iface
, point
.x
, point
.y
, stroke_width
, stroke_style
, transform
, tolerance
, contains
);
2277 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_FillContainsPoint(ID2D1RectangleGeometry
*iface
,
2278 D2D1_POINT_2F point
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, BOOL
*contains
)
2280 FIXME("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p stub!\n",
2281 iface
, point
.x
, point
.y
, transform
, tolerance
, contains
);
2286 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_CompareWithGeometry(ID2D1RectangleGeometry
*iface
,
2287 ID2D1Geometry
*geometry
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_GEOMETRY_RELATION
*relation
)
2289 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
2290 iface
, geometry
, transform
, tolerance
, relation
);
2295 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_Simplify(ID2D1RectangleGeometry
*iface
,
2296 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
2297 ID2D1SimplifiedGeometrySink
*sink
)
2299 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2300 iface
, option
, transform
, tolerance
, sink
);
2305 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_Tessellate(ID2D1RectangleGeometry
*iface
,
2306 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1TessellationSink
*sink
)
2308 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
2313 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_CombineWithGeometry(ID2D1RectangleGeometry
*iface
,
2314 ID2D1Geometry
*geometry
, D2D1_COMBINE_MODE combine_mode
, const D2D1_MATRIX_3X2_F
*transform
,
2315 float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
2317 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2318 iface
, geometry
, combine_mode
, transform
, tolerance
, sink
);
2323 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_Outline(ID2D1RectangleGeometry
*iface
,
2324 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
2326 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
2331 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_ComputeArea(ID2D1RectangleGeometry
*iface
,
2332 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *area
)
2334 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface
, transform
, tolerance
, area
);
2339 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_ComputeLength(ID2D1RectangleGeometry
*iface
,
2340 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *length
)
2342 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface
, transform
, tolerance
, length
);
2347 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_ComputePointAtLength(ID2D1RectangleGeometry
*iface
,
2348 float length
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_POINT_2F
*point
,
2349 D2D1_POINT_2F
*tangent
)
2351 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
2352 iface
, length
, transform
, tolerance
, point
, tangent
);
2357 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_Widen(ID2D1RectangleGeometry
*iface
, float stroke_width
,
2358 ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
2359 ID2D1SimplifiedGeometrySink
*sink
)
2361 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
2362 iface
, stroke_width
, stroke_style
, transform
, tolerance
, sink
);
2367 static void STDMETHODCALLTYPE
d2d_rectangle_geometry_GetRect(ID2D1RectangleGeometry
*iface
, D2D1_RECT_F
*rect
)
2369 struct d2d_geometry
*geometry
= impl_from_ID2D1RectangleGeometry(iface
);
2371 TRACE("iface %p, rect %p.\n", iface
, rect
);
2373 *rect
= geometry
->u
.rectangle
.rect
;
2376 static const struct ID2D1RectangleGeometryVtbl d2d_rectangle_geometry_vtbl
=
2378 d2d_rectangle_geometry_QueryInterface
,
2379 d2d_rectangle_geometry_AddRef
,
2380 d2d_rectangle_geometry_Release
,
2381 d2d_rectangle_geometry_GetFactory
,
2382 d2d_rectangle_geometry_GetBounds
,
2383 d2d_rectangle_geometry_GetWidenedBounds
,
2384 d2d_rectangle_geometry_StrokeContainsPoint
,
2385 d2d_rectangle_geometry_FillContainsPoint
,
2386 d2d_rectangle_geometry_CompareWithGeometry
,
2387 d2d_rectangle_geometry_Simplify
,
2388 d2d_rectangle_geometry_Tessellate
,
2389 d2d_rectangle_geometry_CombineWithGeometry
,
2390 d2d_rectangle_geometry_Outline
,
2391 d2d_rectangle_geometry_ComputeArea
,
2392 d2d_rectangle_geometry_ComputeLength
,
2393 d2d_rectangle_geometry_ComputePointAtLength
,
2394 d2d_rectangle_geometry_Widen
,
2395 d2d_rectangle_geometry_GetRect
,
2398 HRESULT
d2d_rectangle_geometry_init(struct d2d_geometry
*geometry
, ID2D1Factory
*factory
, const D2D1_RECT_F
*rect
)
2400 d2d_geometry_init(geometry
, factory
, &identity
, (ID2D1GeometryVtbl
*)&d2d_rectangle_geometry_vtbl
);
2401 geometry
->u
.rectangle
.rect
= *rect
;
2403 if (!(geometry
->vertices
= HeapAlloc(GetProcessHeap(), 0, 4 * sizeof(*geometry
->vertices
))))
2405 d2d_geometry_cleanup(geometry
);
2406 return E_OUTOFMEMORY
;
2408 geometry
->vertex_count
= 4;
2409 if (!d2d_array_reserve((void **)&geometry
->faces
, &geometry
->faces_size
, 2, sizeof(*geometry
->faces
)))
2411 d2d_geometry_cleanup(geometry
);
2412 return E_OUTOFMEMORY
;
2414 geometry
->face_count
= 2;
2416 geometry
->vertices
[0].x
= min(rect
->left
, rect
->right
);
2417 geometry
->vertices
[0].y
= min(rect
->top
, rect
->bottom
);
2418 geometry
->vertices
[1].x
= min(rect
->left
, rect
->right
);
2419 geometry
->vertices
[1].y
= max(rect
->top
, rect
->bottom
);
2420 geometry
->vertices
[2].x
= max(rect
->left
, rect
->right
);
2421 geometry
->vertices
[2].y
= min(rect
->top
, rect
->bottom
);
2422 geometry
->vertices
[3].x
= max(rect
->left
, rect
->right
);
2423 geometry
->vertices
[3].y
= max(rect
->top
, rect
->bottom
);
2425 geometry
->faces
[0].v
[0] = 0;
2426 geometry
->faces
[0].v
[1] = 2;
2427 geometry
->faces
[0].v
[2] = 1;
2428 geometry
->faces
[1].v
[0] = 1;
2429 geometry
->faces
[1].v
[1] = 2;
2430 geometry
->faces
[1].v
[2] = 3;
2435 static inline struct d2d_geometry
*impl_from_ID2D1TransformedGeometry(ID2D1TransformedGeometry
*iface
)
2437 return CONTAINING_RECORD(iface
, struct d2d_geometry
, ID2D1Geometry_iface
);
2440 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_QueryInterface(ID2D1TransformedGeometry
*iface
,
2441 REFIID iid
, void **out
)
2443 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
2445 if (IsEqualGUID(iid
, &IID_ID2D1TransformedGeometry
)
2446 || IsEqualGUID(iid
, &IID_ID2D1Geometry
)
2447 || IsEqualGUID(iid
, &IID_ID2D1Resource
)
2448 || IsEqualGUID(iid
, &IID_IUnknown
))
2450 ID2D1TransformedGeometry_AddRef(iface
);
2455 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
2458 return E_NOINTERFACE
;
2461 static ULONG STDMETHODCALLTYPE
d2d_transformed_geometry_AddRef(ID2D1TransformedGeometry
*iface
)
2463 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
2464 ULONG refcount
= InterlockedIncrement(&geometry
->refcount
);
2466 TRACE("%p increasing refcount to %u.\n", iface
, refcount
);
2471 static ULONG STDMETHODCALLTYPE
d2d_transformed_geometry_Release(ID2D1TransformedGeometry
*iface
)
2473 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
2474 ULONG refcount
= InterlockedDecrement(&geometry
->refcount
);
2476 TRACE("%p decreasing refcount to %u.\n", iface
, refcount
);
2480 geometry
->beziers
= NULL
;
2481 geometry
->faces
= NULL
;
2482 geometry
->vertices
= NULL
;
2483 ID2D1Geometry_Release(geometry
->u
.transformed
.src_geometry
);
2484 d2d_geometry_cleanup(geometry
);
2485 HeapFree(GetProcessHeap(), 0, geometry
);
2491 static void STDMETHODCALLTYPE
d2d_transformed_geometry_GetFactory(ID2D1TransformedGeometry
*iface
,
2492 ID2D1Factory
**factory
)
2494 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
2496 TRACE("iface %p, factory %p.\n", iface
, factory
);
2498 ID2D1Factory_AddRef(*factory
= geometry
->factory
);
2501 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_GetBounds(ID2D1TransformedGeometry
*iface
,
2502 const D2D1_MATRIX_3X2_F
*transform
, D2D1_RECT_F
*bounds
)
2504 FIXME("iface %p, transform %p, bounds %p stub!\n", iface
, transform
, bounds
);
2509 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_GetWidenedBounds(ID2D1TransformedGeometry
*iface
,
2510 float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
2511 float tolerance
, D2D1_RECT_F
*bounds
)
2513 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
2514 iface
, stroke_width
, stroke_style
, transform
, tolerance
, bounds
);
2519 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_StrokeContainsPoint(ID2D1TransformedGeometry
*iface
,
2520 D2D1_POINT_2F point
, float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
2521 float tolerance
, BOOL
*contains
)
2523 FIXME("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
2524 "transform %p, tolerance %.8e, contains %p stub!\n",
2525 iface
, point
.x
, point
.y
, stroke_width
, stroke_style
, transform
, tolerance
, contains
);
2530 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_FillContainsPoint(ID2D1TransformedGeometry
*iface
,
2531 D2D1_POINT_2F point
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, BOOL
*contains
)
2533 FIXME("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p stub!\n",
2534 iface
, point
.x
, point
.y
, transform
, tolerance
, contains
);
2539 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_CompareWithGeometry(ID2D1TransformedGeometry
*iface
,
2540 ID2D1Geometry
*geometry
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_GEOMETRY_RELATION
*relation
)
2542 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
2543 iface
, geometry
, transform
, tolerance
, relation
);
2548 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_Simplify(ID2D1TransformedGeometry
*iface
,
2549 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
2550 ID2D1SimplifiedGeometrySink
*sink
)
2552 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2553 iface
, option
, transform
, tolerance
, sink
);
2558 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_Tessellate(ID2D1TransformedGeometry
*iface
,
2559 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1TessellationSink
*sink
)
2561 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
2566 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_CombineWithGeometry(ID2D1TransformedGeometry
*iface
,
2567 ID2D1Geometry
*geometry
, D2D1_COMBINE_MODE combine_mode
, const D2D1_MATRIX_3X2_F
*transform
,
2568 float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
2570 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
2571 iface
, geometry
, combine_mode
, transform
, tolerance
, sink
);
2576 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_Outline(ID2D1TransformedGeometry
*iface
,
2577 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
2579 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
2584 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_ComputeArea(ID2D1TransformedGeometry
*iface
,
2585 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *area
)
2587 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface
, transform
, tolerance
, area
);
2592 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_ComputeLength(ID2D1TransformedGeometry
*iface
,
2593 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *length
)
2595 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface
, transform
, tolerance
, length
);
2600 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_ComputePointAtLength(ID2D1TransformedGeometry
*iface
,
2601 float length
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_POINT_2F
*point
,
2602 D2D1_POINT_2F
*tangent
)
2604 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
2605 iface
, length
, transform
, tolerance
, point
, tangent
);
2610 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_Widen(ID2D1TransformedGeometry
*iface
, float stroke_width
,
2611 ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
2612 ID2D1SimplifiedGeometrySink
*sink
)
2614 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
2615 iface
, stroke_width
, stroke_style
, transform
, tolerance
, sink
);
2620 static void STDMETHODCALLTYPE
d2d_transformed_geometry_GetSourceGeometry(ID2D1TransformedGeometry
*iface
,
2621 ID2D1Geometry
**src_geometry
)
2623 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
2625 TRACE("iface %p, src_geometry %p.\n", iface
, src_geometry
);
2627 ID2D1Geometry_AddRef(*src_geometry
= geometry
->u
.transformed
.src_geometry
);
2630 static void STDMETHODCALLTYPE
d2d_transformed_geometry_GetTransform(ID2D1TransformedGeometry
*iface
,
2631 D2D1_MATRIX_3X2_F
*transform
)
2633 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
2635 TRACE("iface %p, transform %p.\n", iface
, transform
);
2637 *transform
= geometry
->transform
;
2640 static const struct ID2D1TransformedGeometryVtbl d2d_transformed_geometry_vtbl
=
2642 d2d_transformed_geometry_QueryInterface
,
2643 d2d_transformed_geometry_AddRef
,
2644 d2d_transformed_geometry_Release
,
2645 d2d_transformed_geometry_GetFactory
,
2646 d2d_transformed_geometry_GetBounds
,
2647 d2d_transformed_geometry_GetWidenedBounds
,
2648 d2d_transformed_geometry_StrokeContainsPoint
,
2649 d2d_transformed_geometry_FillContainsPoint
,
2650 d2d_transformed_geometry_CompareWithGeometry
,
2651 d2d_transformed_geometry_Simplify
,
2652 d2d_transformed_geometry_Tessellate
,
2653 d2d_transformed_geometry_CombineWithGeometry
,
2654 d2d_transformed_geometry_Outline
,
2655 d2d_transformed_geometry_ComputeArea
,
2656 d2d_transformed_geometry_ComputeLength
,
2657 d2d_transformed_geometry_ComputePointAtLength
,
2658 d2d_transformed_geometry_Widen
,
2659 d2d_transformed_geometry_GetSourceGeometry
,
2660 d2d_transformed_geometry_GetTransform
,
2663 void d2d_transformed_geometry_init(struct d2d_geometry
*geometry
, ID2D1Factory
*factory
,
2664 ID2D1Geometry
*src_geometry
, const D2D_MATRIX_3X2_F
*transform
)
2666 struct d2d_geometry
*src_impl
;
2668 d2d_geometry_init(geometry
, factory
, transform
, (ID2D1GeometryVtbl
*)&d2d_transformed_geometry_vtbl
);
2669 ID2D1Geometry_AddRef(geometry
->u
.transformed
.src_geometry
= src_geometry
);
2670 src_impl
= unsafe_impl_from_ID2D1Geometry(src_geometry
);
2671 geometry
->vertices
= src_impl
->vertices
;
2672 geometry
->vertex_count
= src_impl
->vertex_count
;
2673 geometry
->faces
= src_impl
->faces
;
2674 geometry
->face_count
= src_impl
->face_count
;
2675 geometry
->beziers
= src_impl
->beziers
;
2676 geometry
->bezier_count
= src_impl
->bezier_count
;
2679 struct d2d_geometry
*unsafe_impl_from_ID2D1Geometry(ID2D1Geometry
*iface
)
2683 assert(iface
->lpVtbl
== (const ID2D1GeometryVtbl
*)&d2d_path_geometry_vtbl
2684 || iface
->lpVtbl
== (const ID2D1GeometryVtbl
*)&d2d_rectangle_geometry_vtbl
2685 || iface
->lpVtbl
== (const ID2D1GeometryVtbl
*)&d2d_transformed_geometry_vtbl
);
2686 return CONTAINING_RECORD(iface
, struct d2d_geometry
, ID2D1Geometry_iface
);