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"
24 WINE_DEFAULT_DEBUG_CHANNEL(d2d
);
26 #define D2D_CDT_EDGE_FLAG_FREED 0x80000000u
27 #define D2D_CDT_EDGE_FLAG_VISITED(r) (1u << (r))
29 static const D2D1_MATRIX_3X2_F identity
=
36 enum d2d_cdt_edge_next
38 D2D_EDGE_NEXT_ORIGIN
= 0,
39 D2D_EDGE_NEXT_ROT
= 1,
40 D2D_EDGE_NEXT_SYM
= 2,
41 D2D_EDGE_NEXT_TOR
= 3,
46 D2D1_POINT_2F
*vertices
;
50 struct d2d_bezier
*beziers
;
55 struct d2d_cdt_edge_ref
58 enum d2d_cdt_edge_next r
;
63 struct d2d_cdt_edge_ref next
[4];
70 struct d2d_cdt_edge
*edges
;
75 const D2D1_POINT_2F
*vertices
;
78 static void d2d_point_subtract(D2D1_POINT_2F
*out
,
79 const D2D1_POINT_2F
*a
, const D2D1_POINT_2F
*b
)
85 static float d2d_point_ccw(const D2D1_POINT_2F
*a
, const D2D1_POINT_2F
*b
, const D2D1_POINT_2F
*c
)
89 d2d_point_subtract(&ab
, b
, a
);
90 d2d_point_subtract(&ac
, c
, a
);
92 return ab
.x
* ac
.y
- ab
.y
* ac
.x
;
95 static BOOL
d2d_array_reserve(void **elements
, size_t *capacity
, size_t element_count
, size_t element_size
)
97 size_t new_capacity
, max_capacity
;
100 if (element_count
<= *capacity
)
103 max_capacity
= ~(size_t)0 / element_size
;
104 if (max_capacity
< element_count
)
107 new_capacity
= max(*capacity
, 4);
108 while (new_capacity
< element_count
&& new_capacity
<= max_capacity
/ 2)
111 if (new_capacity
< element_count
)
112 new_capacity
= max_capacity
;
115 new_elements
= HeapReAlloc(GetProcessHeap(), 0, *elements
, new_capacity
* element_size
);
117 new_elements
= HeapAlloc(GetProcessHeap(), 0, new_capacity
* element_size
);
122 *elements
= new_elements
;
123 *capacity
= new_capacity
;
127 static BOOL
d2d_figure_insert_vertex(struct d2d_figure
*figure
, size_t idx
, D2D1_POINT_2F vertex
)
129 if (!d2d_array_reserve((void **)&figure
->vertices
, &figure
->vertices_size
,
130 figure
->vertex_count
+ 1, sizeof(*figure
->vertices
)))
132 ERR("Failed to grow vertices array.\n");
136 memmove(&figure
->vertices
[idx
+ 1], &figure
->vertices
[idx
],
137 (figure
->vertex_count
- idx
) * sizeof(*figure
->vertices
));
138 figure
->vertices
[idx
] = vertex
;
139 ++figure
->vertex_count
;
143 static BOOL
d2d_figure_add_vertex(struct d2d_figure
*figure
, D2D1_POINT_2F vertex
)
145 if (!d2d_array_reserve((void **)&figure
->vertices
, &figure
->vertices_size
,
146 figure
->vertex_count
+ 1, sizeof(*figure
->vertices
)))
148 ERR("Failed to grow vertices array.\n");
152 figure
->vertices
[figure
->vertex_count
] = vertex
;
153 ++figure
->vertex_count
;
157 /* FIXME: No inside/outside testing is done for beziers. */
158 static BOOL
d2d_figure_add_bezier(struct d2d_figure
*figure
, D2D1_POINT_2F p0
, D2D1_POINT_2F p1
, D2D1_POINT_2F p2
)
160 struct d2d_bezier
*b
;
161 unsigned int idx1
, idx2
;
164 if (!d2d_array_reserve((void **)&figure
->beziers
, &figure
->beziers_size
,
165 figure
->bezier_count
+ 1, sizeof(*figure
->beziers
)))
167 ERR("Failed to grow beziers array.\n");
171 if (d2d_point_ccw(&p0
, &p1
, &p2
) > 0.0f
)
184 b
= &figure
->beziers
[figure
->bezier_count
];
185 b
->v
[0].position
= p0
;
186 b
->v
[0].texcoord
.u
= 0.0f
;
187 b
->v
[0].texcoord
.v
= 0.0f
;
188 b
->v
[0].texcoord
.sign
= sign
;
189 b
->v
[idx1
].position
= p1
;
190 b
->v
[idx1
].texcoord
.u
= 0.5f
;
191 b
->v
[idx1
].texcoord
.v
= 0.0f
;
192 b
->v
[idx1
].texcoord
.sign
= sign
;
193 b
->v
[idx2
].position
= p2
;
194 b
->v
[idx2
].texcoord
.u
= 1.0f
;
195 b
->v
[idx2
].texcoord
.v
= 1.0f
;
196 b
->v
[idx2
].texcoord
.sign
= sign
;
197 ++figure
->bezier_count
;
199 if (sign
> 0.0f
&& !d2d_figure_add_vertex(figure
, p1
))
201 if (!d2d_figure_add_vertex(figure
, p2
))
206 static void d2d_cdt_edge_rot(struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
209 dst
->r
= (src
->r
+ D2D_EDGE_NEXT_ROT
) & 3;
212 static void d2d_cdt_edge_sym(struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
215 dst
->r
= (src
->r
+ D2D_EDGE_NEXT_SYM
) & 3;
218 static void d2d_cdt_edge_tor(struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
221 dst
->r
= (src
->r
+ D2D_EDGE_NEXT_TOR
) & 3;
224 static void d2d_cdt_edge_next_left(const struct d2d_cdt
*cdt
,
225 struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
227 d2d_cdt_edge_rot(dst
, &cdt
->edges
[src
->idx
].next
[(src
->r
+ D2D_EDGE_NEXT_TOR
) & 3]);
230 static void d2d_cdt_edge_next_origin(const struct d2d_cdt
*cdt
,
231 struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
233 *dst
= cdt
->edges
[src
->idx
].next
[src
->r
];
236 static void d2d_cdt_edge_prev_origin(const struct d2d_cdt
*cdt
,
237 struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
239 d2d_cdt_edge_rot(dst
, &cdt
->edges
[src
->idx
].next
[(src
->r
+ D2D_EDGE_NEXT_ROT
) & 3]);
242 static size_t d2d_cdt_edge_origin(const struct d2d_cdt
*cdt
, const struct d2d_cdt_edge_ref
*e
)
244 return cdt
->edges
[e
->idx
].vertex
[e
->r
>> 1];
247 static size_t d2d_cdt_edge_destination(const struct d2d_cdt
*cdt
, const struct d2d_cdt_edge_ref
*e
)
249 return cdt
->edges
[e
->idx
].vertex
[!(e
->r
>> 1)];
252 static void d2d_cdt_edge_set_origin(const struct d2d_cdt
*cdt
,
253 const struct d2d_cdt_edge_ref
*e
, size_t vertex
)
255 cdt
->edges
[e
->idx
].vertex
[e
->r
>> 1] = vertex
;
258 static void d2d_cdt_edge_set_destination(const struct d2d_cdt
*cdt
,
259 const struct d2d_cdt_edge_ref
*e
, size_t vertex
)
261 cdt
->edges
[e
->idx
].vertex
[!(e
->r
>> 1)] = vertex
;
264 static float d2d_cdt_ccw(const struct d2d_cdt
*cdt
, size_t a
, size_t b
, size_t c
)
266 return d2d_point_ccw(&cdt
->vertices
[a
], &cdt
->vertices
[b
], &cdt
->vertices
[c
]);
269 static BOOL
d2d_cdt_rightof(const struct d2d_cdt
*cdt
, size_t p
, const struct d2d_cdt_edge_ref
*e
)
271 return d2d_cdt_ccw(cdt
, p
, d2d_cdt_edge_destination(cdt
, e
), d2d_cdt_edge_origin(cdt
, e
)) > 0.0f
;
274 static BOOL
d2d_cdt_leftof(const struct d2d_cdt
*cdt
, size_t p
, const struct d2d_cdt_edge_ref
*e
)
276 return d2d_cdt_ccw(cdt
, p
, d2d_cdt_edge_origin(cdt
, e
), d2d_cdt_edge_destination(cdt
, e
)) > 0.0f
;
279 /* Determine if point D is inside or outside the circle defined by points A,
280 * B, C. As explained in the paper by Guibas and Stolfi, this is equivalent to
281 * calculating the signed volume of the tetrahedron defined by projecting the
282 * points onto the paraboloid of revolution x = x² + y²,
283 * λ:(x, y) → (x, y, x² + y²). I.e., D is inside the cirlce if
290 * After translating D to the origin, that becomes:
295 static BOOL
d2d_cdt_incircle(const struct d2d_cdt
*cdt
, size_t a
, size_t b
, size_t c
, size_t d
)
297 const D2D1_POINT_2F
*p
= cdt
->vertices
;
302 da
= {p
[a
].x
- p
[d
].x
, p
[a
].y
- p
[d
].y
},
303 db
= {p
[b
].x
- p
[d
].x
, p
[b
].y
- p
[d
].y
},
304 dc
= {p
[c
].x
- p
[d
].x
, p
[c
].y
- p
[d
].y
};
306 return (da
.x
* da
.x
+ da
.y
* da
.y
) * (db
.x
* dc
.y
- db
.y
* dc
.x
)
307 + (db
.x
* db
.x
+ db
.y
* db
.y
) * (dc
.x
* da
.y
- dc
.y
* da
.x
)
308 + (dc
.x
* dc
.x
+ dc
.y
* dc
.y
) * (da
.x
* db
.y
- da
.y
* db
.x
) > 0.0;
311 static void d2d_cdt_splice(const struct d2d_cdt
*cdt
, const struct d2d_cdt_edge_ref
*a
,
312 const struct d2d_cdt_edge_ref
*b
)
314 struct d2d_cdt_edge_ref ta
, tb
, alpha
, beta
;
316 ta
= cdt
->edges
[a
->idx
].next
[a
->r
];
317 tb
= cdt
->edges
[b
->idx
].next
[b
->r
];
318 cdt
->edges
[a
->idx
].next
[a
->r
] = tb
;
319 cdt
->edges
[b
->idx
].next
[b
->r
] = ta
;
321 d2d_cdt_edge_rot(&alpha
, &ta
);
322 d2d_cdt_edge_rot(&beta
, &tb
);
324 ta
= cdt
->edges
[alpha
.idx
].next
[alpha
.r
];
325 tb
= cdt
->edges
[beta
.idx
].next
[beta
.r
];
326 cdt
->edges
[alpha
.idx
].next
[alpha
.r
] = tb
;
327 cdt
->edges
[beta
.idx
].next
[beta
.r
] = ta
;
330 static BOOL
d2d_cdt_create_edge(struct d2d_cdt
*cdt
, struct d2d_cdt_edge_ref
*e
)
332 struct d2d_cdt_edge
*edge
;
334 if (cdt
->free_edge
!= ~0u)
336 e
->idx
= cdt
->free_edge
;
337 cdt
->free_edge
= cdt
->edges
[e
->idx
].next
[D2D_EDGE_NEXT_ORIGIN
].idx
;
341 if (!d2d_array_reserve((void **)&cdt
->edges
, &cdt
->edges_size
, cdt
->edge_count
+ 1, sizeof(*cdt
->edges
)))
343 ERR("Failed to grow edges array.\n");
346 e
->idx
= cdt
->edge_count
++;
350 edge
= &cdt
->edges
[e
->idx
];
351 edge
->next
[D2D_EDGE_NEXT_ORIGIN
] = *e
;
352 d2d_cdt_edge_tor(&edge
->next
[D2D_EDGE_NEXT_ROT
], e
);
353 d2d_cdt_edge_sym(&edge
->next
[D2D_EDGE_NEXT_SYM
], e
);
354 d2d_cdt_edge_rot(&edge
->next
[D2D_EDGE_NEXT_TOR
], e
);
360 static void d2d_cdt_destroy_edge(struct d2d_cdt
*cdt
, const struct d2d_cdt_edge_ref
*e
)
362 struct d2d_cdt_edge_ref next
, sym
, prev
;
364 d2d_cdt_edge_next_origin(cdt
, &next
, e
);
365 if (next
.idx
!= e
->idx
|| next
.r
!= e
->r
)
367 d2d_cdt_edge_prev_origin(cdt
, &prev
, e
);
368 d2d_cdt_splice(cdt
, e
, &prev
);
371 d2d_cdt_edge_sym(&sym
, e
);
373 d2d_cdt_edge_next_origin(cdt
, &next
, &sym
);
374 if (next
.idx
!= sym
.idx
|| next
.r
!= sym
.r
)
376 d2d_cdt_edge_prev_origin(cdt
, &prev
, &sym
);
377 d2d_cdt_splice(cdt
, &sym
, &prev
);
380 cdt
->edges
[e
->idx
].flags
|= D2D_CDT_EDGE_FLAG_FREED
;
381 cdt
->edges
[e
->idx
].next
[D2D_EDGE_NEXT_ORIGIN
].idx
= cdt
->free_edge
;
382 cdt
->free_edge
= e
->idx
;
385 static BOOL
d2d_cdt_connect(struct d2d_cdt
*cdt
, struct d2d_cdt_edge_ref
*e
,
386 const struct d2d_cdt_edge_ref
*a
, const struct d2d_cdt_edge_ref
*b
)
388 struct d2d_cdt_edge_ref tmp
;
390 if (!d2d_cdt_create_edge(cdt
, e
))
392 d2d_cdt_edge_set_origin(cdt
, e
, d2d_cdt_edge_destination(cdt
, a
));
393 d2d_cdt_edge_set_destination(cdt
, e
, d2d_cdt_edge_origin(cdt
, b
));
394 d2d_cdt_edge_next_left(cdt
, &tmp
, a
);
395 d2d_cdt_splice(cdt
, e
, &tmp
);
396 d2d_cdt_edge_sym(&tmp
, e
);
397 d2d_cdt_splice(cdt
, &tmp
, b
);
402 static BOOL
d2d_cdt_merge(struct d2d_cdt
*cdt
, struct d2d_cdt_edge_ref
*left_outer
,
403 struct d2d_cdt_edge_ref
*left_inner
, struct d2d_cdt_edge_ref
*right_inner
,
404 struct d2d_cdt_edge_ref
*right_outer
)
406 struct d2d_cdt_edge_ref base_edge
, tmp
;
408 /* Create the base edge between both parts. */
411 if (d2d_cdt_leftof(cdt
, d2d_cdt_edge_origin(cdt
, right_inner
), left_inner
))
413 d2d_cdt_edge_next_left(cdt
, left_inner
, left_inner
);
415 else if (d2d_cdt_rightof(cdt
, d2d_cdt_edge_origin(cdt
, left_inner
), right_inner
))
417 d2d_cdt_edge_sym(&tmp
, right_inner
);
418 d2d_cdt_edge_next_origin(cdt
, right_inner
, &tmp
);
426 d2d_cdt_edge_sym(&tmp
, right_inner
);
427 if (!d2d_cdt_connect(cdt
, &base_edge
, &tmp
, left_inner
))
429 if (d2d_cdt_edge_origin(cdt
, left_inner
) == d2d_cdt_edge_origin(cdt
, left_outer
))
430 d2d_cdt_edge_sym(left_outer
, &base_edge
);
431 if (d2d_cdt_edge_origin(cdt
, right_inner
) == d2d_cdt_edge_origin(cdt
, right_outer
))
432 *right_outer
= base_edge
;
436 struct d2d_cdt_edge_ref left_candidate
, right_candidate
, sym_base_edge
;
437 BOOL left_valid
, right_valid
;
439 /* Find the left candidate. */
440 d2d_cdt_edge_sym(&sym_base_edge
, &base_edge
);
441 d2d_cdt_edge_next_origin(cdt
, &left_candidate
, &sym_base_edge
);
442 if ((left_valid
= d2d_cdt_leftof(cdt
, d2d_cdt_edge_destination(cdt
, &left_candidate
), &sym_base_edge
)))
444 d2d_cdt_edge_next_origin(cdt
, &tmp
, &left_candidate
);
445 while (d2d_cdt_edge_destination(cdt
, &tmp
) != d2d_cdt_edge_destination(cdt
, &sym_base_edge
)
446 && d2d_cdt_incircle(cdt
,
447 d2d_cdt_edge_origin(cdt
, &sym_base_edge
), d2d_cdt_edge_destination(cdt
, &sym_base_edge
),
448 d2d_cdt_edge_destination(cdt
, &left_candidate
), d2d_cdt_edge_destination(cdt
, &tmp
)))
450 d2d_cdt_destroy_edge(cdt
, &left_candidate
);
451 left_candidate
= tmp
;
452 d2d_cdt_edge_next_origin(cdt
, &tmp
, &left_candidate
);
455 d2d_cdt_edge_sym(&left_candidate
, &left_candidate
);
457 /* Find the right candidate. */
458 d2d_cdt_edge_prev_origin(cdt
, &right_candidate
, &base_edge
);
459 if ((right_valid
= d2d_cdt_rightof(cdt
, d2d_cdt_edge_destination(cdt
, &right_candidate
), &base_edge
)))
461 d2d_cdt_edge_prev_origin(cdt
, &tmp
, &right_candidate
);
462 while (d2d_cdt_edge_destination(cdt
, &tmp
) != d2d_cdt_edge_destination(cdt
, &base_edge
)
463 && d2d_cdt_incircle(cdt
,
464 d2d_cdt_edge_origin(cdt
, &sym_base_edge
), d2d_cdt_edge_destination(cdt
, &sym_base_edge
),
465 d2d_cdt_edge_destination(cdt
, &right_candidate
), d2d_cdt_edge_destination(cdt
, &tmp
)))
467 d2d_cdt_destroy_edge(cdt
, &right_candidate
);
468 right_candidate
= tmp
;
469 d2d_cdt_edge_prev_origin(cdt
, &tmp
, &right_candidate
);
473 if (!left_valid
&& !right_valid
)
476 /* Connect the appropriate candidate with the base edge. */
477 if (!left_valid
|| (right_valid
&& d2d_cdt_incircle(cdt
,
478 d2d_cdt_edge_origin(cdt
, &left_candidate
), d2d_cdt_edge_destination(cdt
, &left_candidate
),
479 d2d_cdt_edge_origin(cdt
, &right_candidate
), d2d_cdt_edge_destination(cdt
, &right_candidate
))))
481 if (!d2d_cdt_connect(cdt
, &base_edge
, &right_candidate
, &sym_base_edge
))
486 if (!d2d_cdt_connect(cdt
, &base_edge
, &sym_base_edge
, &left_candidate
))
494 /* Create a Delaunay triangulation from a set of vertices. This is an
495 * implementation of the divide-and-conquer algorithm described by Guibas and
496 * Stolfi. Should be called with at least two vertices. */
497 static BOOL
d2d_cdt_triangulate(struct d2d_cdt
*cdt
, size_t start_vertex
, size_t vertex_count
,
498 struct d2d_cdt_edge_ref
*left_edge
, struct d2d_cdt_edge_ref
*right_edge
)
500 struct d2d_cdt_edge_ref left_inner
, left_outer
, right_inner
, right_outer
, tmp
;
503 /* Only two vertices, create a single edge. */
504 if (vertex_count
== 2)
506 struct d2d_cdt_edge_ref a
;
508 if (!d2d_cdt_create_edge(cdt
, &a
))
510 d2d_cdt_edge_set_origin(cdt
, &a
, start_vertex
);
511 d2d_cdt_edge_set_destination(cdt
, &a
, start_vertex
+ 1);
514 d2d_cdt_edge_sym(right_edge
, &a
);
519 /* Three vertices, create a triangle. */
520 if (vertex_count
== 3)
522 struct d2d_cdt_edge_ref a
, b
, c
;
525 if (!d2d_cdt_create_edge(cdt
, &a
))
527 if (!d2d_cdt_create_edge(cdt
, &b
))
529 d2d_cdt_edge_sym(&tmp
, &a
);
530 d2d_cdt_splice(cdt
, &tmp
, &b
);
532 d2d_cdt_edge_set_origin(cdt
, &a
, start_vertex
);
533 d2d_cdt_edge_set_destination(cdt
, &a
, start_vertex
+ 1);
534 d2d_cdt_edge_set_origin(cdt
, &b
, start_vertex
+ 1);
535 d2d_cdt_edge_set_destination(cdt
, &b
, start_vertex
+ 2);
537 det
= d2d_cdt_ccw(cdt
, start_vertex
, start_vertex
+ 1, start_vertex
+ 2);
538 if (det
!= 0.0f
&& !d2d_cdt_connect(cdt
, &c
, &b
, &a
))
543 d2d_cdt_edge_sym(left_edge
, &c
);
549 d2d_cdt_edge_sym(right_edge
, &b
);
555 /* More than tree vertices, divide. */
556 cut
= vertex_count
/ 2;
557 if (!d2d_cdt_triangulate(cdt
, start_vertex
, cut
, &left_outer
, &left_inner
))
559 if (!d2d_cdt_triangulate(cdt
, start_vertex
+ cut
, vertex_count
- cut
, &right_inner
, &right_outer
))
561 /* Merge the left and right parts. */
562 if (!d2d_cdt_merge(cdt
, &left_outer
, &left_inner
, &right_inner
, &right_outer
))
565 *left_edge
= left_outer
;
566 *right_edge
= right_outer
;
570 static int d2d_cdt_compare_vertices(const void *a
, const void *b
)
572 const D2D1_POINT_2F
*p0
= a
;
573 const D2D1_POINT_2F
*p1
= b
;
574 float diff
= p0
->x
- p1
->x
;
577 diff
= p0
->y
- p1
->y
;
579 return diff
== 0.0f
? 0 : (diff
> 0.0f
? 1 : -1);
582 /* Determine whether a given point is inside the geometry, using the current
584 static BOOL
d2d_path_geometry_point_inside(const struct d2d_geometry
*geometry
, const D2D1_POINT_2F
*probe
)
586 const D2D1_POINT_2F
*p0
, *p1
;
587 D2D1_POINT_2F v_p
, v_probe
;
591 for (i
= 0, score
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
593 const struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[i
];
595 p0
= &figure
->vertices
[figure
->vertex_count
- 1];
596 for (j
= 0; j
< figure
->vertex_count
; p0
= p1
, ++j
)
598 p1
= &figure
->vertices
[j
];
599 d2d_point_subtract(&v_p
, p1
, p0
);
600 d2d_point_subtract(&v_probe
, probe
, p0
);
602 if ((probe
->y
< p0
->y
) != (probe
->y
< p1
->y
) && v_probe
.x
< v_p
.x
* (v_probe
.y
/ v_p
.y
))
604 if (geometry
->u
.path
.fill_mode
== D2D1_FILL_MODE_ALTERNATE
|| (probe
->y
< p0
->y
))
612 return geometry
->u
.path
.fill_mode
== D2D1_FILL_MODE_ALTERNATE
? score
& 1 : score
;
615 static BOOL
d2d_path_geometry_add_face(struct d2d_geometry
*geometry
, const struct d2d_cdt
*cdt
,
616 const struct d2d_cdt_edge_ref
*base_edge
)
618 struct d2d_cdt_edge_ref tmp
;
619 struct d2d_face
*face
;
622 if (cdt
->edges
[base_edge
->idx
].flags
& D2D_CDT_EDGE_FLAG_VISITED(base_edge
->r
))
625 if (!d2d_array_reserve((void **)&geometry
->faces
, &geometry
->faces_size
,
626 geometry
->face_count
+ 1, sizeof(*geometry
->faces
)))
628 ERR("Failed to grow faces array.\n");
632 face
= &geometry
->faces
[geometry
->face_count
];
634 /* It may seem tempting to use the center of the face as probe origin, but
635 * multiplying by powers of two works much better for preserving accuracy. */
638 cdt
->edges
[tmp
.idx
].flags
|= D2D_CDT_EDGE_FLAG_VISITED(tmp
.r
);
639 face
->v
[0] = d2d_cdt_edge_origin(cdt
, &tmp
);
640 probe
.x
= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].x
* 0.25f
;
641 probe
.y
= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].y
* 0.25f
;
643 d2d_cdt_edge_next_left(cdt
, &tmp
, &tmp
);
644 cdt
->edges
[tmp
.idx
].flags
|= D2D_CDT_EDGE_FLAG_VISITED(tmp
.r
);
645 face
->v
[1] = d2d_cdt_edge_origin(cdt
, &tmp
);
646 probe
.x
+= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].x
* 0.25f
;
647 probe
.y
+= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].y
* 0.25f
;
649 d2d_cdt_edge_next_left(cdt
, &tmp
, &tmp
);
650 cdt
->edges
[tmp
.idx
].flags
|= D2D_CDT_EDGE_FLAG_VISITED(tmp
.r
);
651 face
->v
[2] = d2d_cdt_edge_origin(cdt
, &tmp
);
652 probe
.x
+= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].x
* 0.50f
;
653 probe
.y
+= cdt
->vertices
[d2d_cdt_edge_origin(cdt
, &tmp
)].y
* 0.50f
;
655 d2d_cdt_edge_next_left(cdt
, &tmp
, &tmp
);
656 if (tmp
.idx
== base_edge
->idx
&& d2d_path_geometry_point_inside(geometry
, &probe
))
657 ++geometry
->face_count
;
662 static BOOL
d2d_cdt_generate_faces(const struct d2d_cdt
*cdt
, struct d2d_geometry
*geometry
)
664 struct d2d_cdt_edge_ref base_edge
;
667 for (i
= 0; i
< cdt
->edge_count
; ++i
)
669 if (cdt
->edges
[i
].flags
& D2D_CDT_EDGE_FLAG_FREED
)
674 if (!d2d_path_geometry_add_face(geometry
, cdt
, &base_edge
))
676 d2d_cdt_edge_sym(&base_edge
, &base_edge
);
677 if (!d2d_path_geometry_add_face(geometry
, cdt
, &base_edge
))
684 HeapFree(GetProcessHeap(), 0, geometry
->faces
);
685 geometry
->faces
= NULL
;
686 geometry
->faces_size
= 0;
687 geometry
->face_count
= 0;
691 static BOOL
d2d_cdt_fixup(struct d2d_cdt
*cdt
, const struct d2d_cdt_edge_ref
*base_edge
)
693 struct d2d_cdt_edge_ref candidate
, next
, new_base
;
694 unsigned int count
= 0;
696 d2d_cdt_edge_next_left(cdt
, &next
, base_edge
);
697 if (next
.idx
== base_edge
->idx
)
699 ERR("Degenerate face.\n");
704 while (d2d_cdt_edge_destination(cdt
, &next
) != d2d_cdt_edge_origin(cdt
, base_edge
))
706 if (d2d_cdt_incircle(cdt
, d2d_cdt_edge_origin(cdt
, base_edge
), d2d_cdt_edge_destination(cdt
, base_edge
),
707 d2d_cdt_edge_destination(cdt
, &candidate
), d2d_cdt_edge_destination(cdt
, &next
)))
709 d2d_cdt_edge_next_left(cdt
, &next
, &next
);
715 if (!d2d_cdt_connect(cdt
, &new_base
, &candidate
, base_edge
))
717 if (!d2d_cdt_fixup(cdt
, &new_base
))
719 d2d_cdt_edge_sym(&new_base
, &new_base
);
720 if (!d2d_cdt_fixup(cdt
, &new_base
))
727 static void d2d_cdt_cut_edges(struct d2d_cdt
*cdt
, struct d2d_cdt_edge_ref
*end_edge
,
728 const struct d2d_cdt_edge_ref
*base_edge
, size_t start_vertex
, size_t end_vertex
)
730 struct d2d_cdt_edge_ref next
;
732 d2d_cdt_edge_next_left(cdt
, &next
, base_edge
);
733 if (d2d_cdt_edge_destination(cdt
, &next
) == end_vertex
)
739 if (d2d_cdt_ccw(cdt
, d2d_cdt_edge_destination(cdt
, &next
), end_vertex
, start_vertex
) > 0.0f
)
740 d2d_cdt_edge_next_left(cdt
, &next
, &next
);
742 d2d_cdt_edge_sym(&next
, &next
);
743 d2d_cdt_cut_edges(cdt
, end_edge
, &next
, start_vertex
, end_vertex
);
744 d2d_cdt_destroy_edge(cdt
, &next
);
747 static BOOL
d2d_cdt_insert_segment(struct d2d_cdt
*cdt
, struct d2d_geometry
*geometry
,
748 const struct d2d_cdt_edge_ref
*origin
, size_t end_vertex
)
750 struct d2d_cdt_edge_ref base_edge
, current
, next
, target
;
752 for (current
= *origin
;; current
= next
)
754 d2d_cdt_edge_next_origin(cdt
, &next
, ¤t
);
756 if (d2d_cdt_edge_destination(cdt
, ¤t
) == end_vertex
)
759 if (d2d_cdt_rightof(cdt
, end_vertex
, &next
) && d2d_cdt_leftof(cdt
, end_vertex
, ¤t
))
761 d2d_cdt_edge_next_left(cdt
, &base_edge
, ¤t
);
763 d2d_cdt_edge_sym(&base_edge
, &base_edge
);
764 d2d_cdt_cut_edges(cdt
, &target
, &base_edge
, d2d_cdt_edge_origin(cdt
, origin
), end_vertex
);
765 d2d_cdt_destroy_edge(cdt
, &base_edge
);
767 if (!d2d_cdt_connect(cdt
, &base_edge
, &target
, ¤t
))
769 if (!d2d_cdt_fixup(cdt
, &base_edge
))
771 d2d_cdt_edge_sym(&base_edge
, &base_edge
);
772 if (!d2d_cdt_fixup(cdt
, &base_edge
))
778 if (next
.idx
== origin
->idx
)
780 ERR("Triangle not found.\n");
786 static BOOL
d2d_cdt_insert_segments(struct d2d_cdt
*cdt
, struct d2d_geometry
*geometry
)
788 size_t start_vertex
, end_vertex
, i
, j
, k
;
789 const struct d2d_figure
*figure
;
790 struct d2d_cdt_edge_ref edge
;
791 const D2D1_POINT_2F
*p
;
793 for (i
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
795 figure
= &geometry
->u
.path
.figures
[i
];
797 p
= bsearch(&figure
->vertices
[figure
->vertex_count
- 1], cdt
->vertices
,
798 geometry
->vertex_count
, sizeof(*p
), d2d_cdt_compare_vertices
);
799 start_vertex
= p
- cdt
->vertices
;
801 for (j
= 0; j
< figure
->vertex_count
; start_vertex
= end_vertex
, ++j
)
803 p
= bsearch(&figure
->vertices
[j
], cdt
->vertices
,
804 geometry
->vertex_count
, sizeof(*p
), d2d_cdt_compare_vertices
);
805 end_vertex
= p
- cdt
->vertices
;
807 if (start_vertex
== end_vertex
)
810 for (k
= 0; k
< cdt
->edge_count
; ++k
)
812 if (cdt
->edges
[k
].flags
& D2D_CDT_EDGE_FLAG_FREED
)
818 if (d2d_cdt_edge_origin(cdt
, &edge
) == start_vertex
)
820 if (!d2d_cdt_insert_segment(cdt
, geometry
, &edge
, end_vertex
))
824 d2d_cdt_edge_sym(&edge
, &edge
);
825 if (d2d_cdt_edge_origin(cdt
, &edge
) == start_vertex
)
827 if (!d2d_cdt_insert_segment(cdt
, geometry
, &edge
, end_vertex
))
838 /* Intersect the geometry's segments with themselves. This uses the
839 * straightforward approach of testing everything against everything, but
840 * there certainly exist more scalable algorithms for this. */
841 /* FIXME: Beziers can't currently self-intersect. */
842 static BOOL
d2d_geometry_intersect_self(struct d2d_geometry
*geometry
)
844 D2D1_POINT_2F p0
, p1
, q0
, q1
, v_p
, v_q
, v_qp
, intersection
;
845 struct d2d_figure
*figure_p
, *figure_q
;
846 size_t i
, j
, k
, l
, limit
;
849 for (i
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
851 figure_p
= &geometry
->u
.path
.figures
[i
];
852 p0
= figure_p
->vertices
[figure_p
->vertex_count
- 1];
853 for (k
= 0; k
< figure_p
->vertex_count
; p0
= p1
, ++k
)
855 p1
= figure_p
->vertices
[k
];
856 d2d_point_subtract(&v_p
, &p1
, &p0
);
857 for (j
= 0; j
< i
|| (j
== i
&& k
); ++j
)
859 figure_q
= &geometry
->u
.path
.figures
[j
];
860 limit
= j
== i
? k
- 1 : figure_q
->vertex_count
;
861 q0
= figure_q
->vertices
[figure_q
->vertex_count
- 1];
862 for (l
= 0; l
< limit
; q0
= q1
, ++l
)
864 q1
= figure_q
->vertices
[l
];
865 d2d_point_subtract(&v_q
, &q1
, &q0
);
866 d2d_point_subtract(&v_qp
, &p0
, &q0
);
868 det
= v_p
.x
* v_q
.y
- v_p
.y
* v_q
.x
;
872 s
= (v_q
.x
* v_qp
.y
- v_q
.y
* v_qp
.x
) / det
;
873 t
= (v_p
.x
* v_qp
.y
- v_p
.y
* v_qp
.x
) / det
;
875 if (s
< 0.0f
|| s
> 1.0f
|| t
< 0.0f
|| t
> 1.0f
)
878 intersection
.x
= p0
.x
+ v_p
.x
* s
;
879 intersection
.y
= p0
.y
+ v_p
.y
* s
;
881 if (t
> 0.0f
&& t
< 1.0f
)
883 if (!d2d_figure_insert_vertex(figure_q
, l
, intersection
))
891 if (s
> 0.0f
&& s
< 1.0f
)
893 if (!d2d_figure_insert_vertex(figure_p
, k
, intersection
))
896 d2d_point_subtract(&v_p
, &p1
, &p0
);
906 static HRESULT
d2d_path_geometry_triangulate(struct d2d_geometry
*geometry
)
908 struct d2d_cdt_edge_ref left_edge
, right_edge
;
909 size_t vertex_count
, i
, j
;
910 struct d2d_cdt cdt
= {0};
911 D2D1_POINT_2F
*vertices
;
913 for (i
= 0, vertex_count
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
915 vertex_count
+= geometry
->u
.path
.figures
[i
].vertex_count
;
918 if (vertex_count
< 3)
920 WARN("Geometry has %lu vertices.\n", (long)vertex_count
);
924 if (!(vertices
= HeapAlloc(GetProcessHeap(), 0, vertex_count
* sizeof(*vertices
))))
925 return E_OUTOFMEMORY
;
927 for (i
= 0, j
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
929 memcpy(&vertices
[j
], geometry
->u
.path
.figures
[i
].vertices
,
930 geometry
->u
.path
.figures
[i
].vertex_count
* sizeof(*vertices
));
931 j
+= geometry
->u
.path
.figures
[i
].vertex_count
;
934 /* Sort vertices, eliminate duplicates. */
935 qsort(vertices
, vertex_count
, sizeof(*vertices
), d2d_cdt_compare_vertices
);
936 for (i
= 1; i
< vertex_count
; ++i
)
938 if (!memcmp(&vertices
[i
- 1], &vertices
[i
], sizeof(*vertices
)))
941 memmove(&vertices
[i
], &vertices
[i
+ 1], (vertex_count
- i
) * sizeof(*vertices
));
946 geometry
->vertices
= vertices
;
947 geometry
->vertex_count
= vertex_count
;
950 cdt
.vertices
= vertices
;
951 if (!d2d_cdt_triangulate(&cdt
, 0, vertex_count
, &left_edge
, &right_edge
))
953 if (!d2d_cdt_insert_segments(&cdt
, geometry
))
955 if (!d2d_cdt_generate_faces(&cdt
, geometry
))
958 HeapFree(GetProcessHeap(), 0, cdt
.edges
);
962 geometry
->vertices
= NULL
;
963 geometry
->vertex_count
= 0;
964 HeapFree(GetProcessHeap(), 0, vertices
);
965 HeapFree(GetProcessHeap(), 0, cdt
.edges
);
969 static BOOL
d2d_path_geometry_add_figure(struct d2d_geometry
*geometry
)
971 struct d2d_figure
*figure
;
973 if (!d2d_array_reserve((void **)&geometry
->u
.path
.figures
, &geometry
->u
.path
.figures_size
,
974 geometry
->u
.path
.figure_count
+ 1, sizeof(*geometry
->u
.path
.figures
)))
976 ERR("Failed to grow figures array.\n");
980 figure
= &geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
];
981 memset(figure
, 0, sizeof(*figure
));
983 ++geometry
->u
.path
.figure_count
;
987 static void d2d_geometry_cleanup(struct d2d_geometry
*geometry
)
989 HeapFree(GetProcessHeap(), 0, geometry
->beziers
);
990 HeapFree(GetProcessHeap(), 0, geometry
->faces
);
991 HeapFree(GetProcessHeap(), 0, geometry
->vertices
);
992 ID2D1Factory_Release(geometry
->factory
);
995 static void d2d_geometry_init(struct d2d_geometry
*geometry
, ID2D1Factory
*factory
,
996 const D2D1_MATRIX_3X2_F
*transform
, const struct ID2D1GeometryVtbl
*vtbl
)
998 geometry
->ID2D1Geometry_iface
.lpVtbl
= vtbl
;
999 geometry
->refcount
= 1;
1000 ID2D1Factory_AddRef(geometry
->factory
= factory
);
1001 geometry
->transform
= *transform
;
1004 static inline struct d2d_geometry
*impl_from_ID2D1GeometrySink(ID2D1GeometrySink
*iface
)
1006 return CONTAINING_RECORD(iface
, struct d2d_geometry
, u
.path
.ID2D1GeometrySink_iface
);
1009 static HRESULT STDMETHODCALLTYPE
d2d_geometry_sink_QueryInterface(ID2D1GeometrySink
*iface
, REFIID iid
, void **out
)
1011 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
1013 if (IsEqualGUID(iid
, &IID_ID2D1GeometrySink
)
1014 || IsEqualGUID(iid
, &IID_ID2D1SimplifiedGeometrySink
)
1015 || IsEqualGUID(iid
, &IID_IUnknown
))
1017 ID2D1GeometrySink_AddRef(iface
);
1022 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
1025 return E_NOINTERFACE
;
1028 static ULONG STDMETHODCALLTYPE
d2d_geometry_sink_AddRef(ID2D1GeometrySink
*iface
)
1030 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
1032 TRACE("iface %p.\n", iface
);
1034 return ID2D1Geometry_AddRef(&geometry
->ID2D1Geometry_iface
);
1037 static ULONG STDMETHODCALLTYPE
d2d_geometry_sink_Release(ID2D1GeometrySink
*iface
)
1039 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
1041 TRACE("iface %p.\n", iface
);
1043 return ID2D1Geometry_Release(&geometry
->ID2D1Geometry_iface
);
1046 static void STDMETHODCALLTYPE
d2d_geometry_sink_SetFillMode(ID2D1GeometrySink
*iface
, D2D1_FILL_MODE mode
)
1048 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
1050 TRACE("iface %p, mode %#x.\n", iface
, mode
);
1052 geometry
->u
.path
.fill_mode
= mode
;
1055 static void STDMETHODCALLTYPE
d2d_geometry_sink_SetSegmentFlags(ID2D1GeometrySink
*iface
, D2D1_PATH_SEGMENT flags
)
1057 FIXME("iface %p, flags %#x stub!\n", iface
, flags
);
1060 static void STDMETHODCALLTYPE
d2d_geometry_sink_BeginFigure(ID2D1GeometrySink
*iface
,
1061 D2D1_POINT_2F start_point
, D2D1_FIGURE_BEGIN figure_begin
)
1063 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
1065 TRACE("iface %p, start_point {%.8e, %.8e}, figure_begin %#x.\n",
1066 iface
, start_point
.x
, start_point
.y
, figure_begin
);
1068 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_OPEN
)
1070 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
1074 if (figure_begin
!= D2D1_FIGURE_BEGIN_FILLED
)
1075 FIXME("Ignoring figure_begin %#x.\n", figure_begin
);
1077 if (!d2d_path_geometry_add_figure(geometry
))
1079 ERR("Failed to add figure.\n");
1080 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
1084 if (!d2d_figure_add_vertex(&geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
- 1], start_point
))
1085 ERR("Failed to add vertex.\n");
1087 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_FIGURE
;
1088 ++geometry
->u
.path
.segment_count
;
1091 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddLines(ID2D1GeometrySink
*iface
,
1092 const D2D1_POINT_2F
*points
, UINT32 count
)
1094 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
1097 TRACE("iface %p, points %p, count %u.\n", iface
, points
, count
);
1099 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_FIGURE
)
1101 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
1105 for (i
= 0; i
< count
; ++i
)
1107 if (!d2d_figure_add_vertex(&geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
- 1], points
[i
]))
1109 ERR("Failed to add vertex.\n");
1114 geometry
->u
.path
.segment_count
+= count
;
1117 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddBeziers(ID2D1GeometrySink
*iface
,
1118 const D2D1_BEZIER_SEGMENT
*beziers
, UINT32 count
)
1120 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
1121 struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
- 1];
1125 TRACE("iface %p, beziers %p, count %u.\n", iface
, beziers
, count
);
1127 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_FIGURE
)
1129 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
1133 for (i
= 0; i
< count
; ++i
)
1135 /* FIXME: This tries to approximate a cubic bezier with a quadratic one. */
1136 p
.x
= (beziers
[i
].point1
.x
+ beziers
[i
].point2
.x
) * 0.75f
;
1137 p
.y
= (beziers
[i
].point1
.y
+ beziers
[i
].point2
.y
) * 0.75f
;
1138 p
.x
-= (figure
->vertices
[figure
->vertex_count
- 1].x
+ beziers
[i
].point3
.x
) * 0.25f
;
1139 p
.y
-= (figure
->vertices
[figure
->vertex_count
- 1].y
+ beziers
[i
].point3
.y
) * 0.25f
;
1140 if (!d2d_figure_add_bezier(figure
, figure
->vertices
[figure
->vertex_count
- 1], p
, beziers
[i
].point3
))
1142 ERR("Failed to add bezier.\n");
1147 geometry
->u
.path
.segment_count
+= count
;
1150 static void STDMETHODCALLTYPE
d2d_geometry_sink_EndFigure(ID2D1GeometrySink
*iface
, D2D1_FIGURE_END figure_end
)
1152 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
1154 TRACE("iface %p, figure_end %#x.\n", iface
, figure_end
);
1156 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_FIGURE
)
1158 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
1162 if (figure_end
!= D2D1_FIGURE_END_CLOSED
)
1163 FIXME("Ignoring figure_end %#x.\n", figure_end
);
1165 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_OPEN
;
1168 static void d2d_path_geometry_free_figures(struct d2d_geometry
*geometry
)
1172 if (!geometry
->u
.path
.figures
)
1175 for (i
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
1177 HeapFree(GetProcessHeap(), 0, geometry
->u
.path
.figures
[i
].beziers
);
1178 HeapFree(GetProcessHeap(), 0, geometry
->u
.path
.figures
[i
].vertices
);
1180 HeapFree(GetProcessHeap(), 0, geometry
->u
.path
.figures
);
1181 geometry
->u
.path
.figures
= NULL
;
1182 geometry
->u
.path
.figures_size
= 0;
1185 static HRESULT STDMETHODCALLTYPE
d2d_geometry_sink_Close(ID2D1GeometrySink
*iface
)
1187 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
1188 HRESULT hr
= E_FAIL
;
1191 TRACE("iface %p.\n", iface
);
1193 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_OPEN
)
1195 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_CLOSED
)
1196 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
1197 return D2DERR_WRONG_STATE
;
1199 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_CLOSED
;
1201 if (!d2d_geometry_intersect_self(geometry
))
1203 if (FAILED(hr
= d2d_path_geometry_triangulate(geometry
)))
1206 for (i
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
1208 geometry
->bezier_count
+= geometry
->u
.path
.figures
[i
].bezier_count
;
1211 if (!(geometry
->beziers
= HeapAlloc(GetProcessHeap(), 0,
1212 geometry
->bezier_count
* sizeof(*geometry
->beziers
))))
1214 ERR("Failed to allocate beziers array.\n");
1215 geometry
->bezier_count
= 0;
1220 for (i
= 0, start
= 0; i
< geometry
->u
.path
.figure_count
; ++i
)
1222 struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[i
];
1223 if (figure
->bezier_count
)
1225 memcpy(&geometry
->beziers
[start
], figure
->beziers
,
1226 figure
->bezier_count
* sizeof(*figure
->beziers
));
1227 start
+= figure
->bezier_count
;
1232 d2d_path_geometry_free_figures(geometry
);
1234 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
1238 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddLine(ID2D1GeometrySink
*iface
, D2D1_POINT_2F point
)
1240 TRACE("iface %p, point {%.8e, %.8e}.\n", iface
, point
.x
, point
.y
);
1242 d2d_geometry_sink_AddLines(iface
, &point
, 1);
1245 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddBezier(ID2D1GeometrySink
*iface
, const D2D1_BEZIER_SEGMENT
*bezier
)
1247 TRACE("iface %p, bezier %p.\n", iface
, bezier
);
1249 d2d_geometry_sink_AddBeziers(iface
, bezier
, 1);
1252 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddQuadraticBezier(ID2D1GeometrySink
*iface
,
1253 const D2D1_QUADRATIC_BEZIER_SEGMENT
*bezier
)
1255 TRACE("iface %p, bezier %p.\n", iface
, bezier
);
1257 ID2D1GeometrySink_AddQuadraticBeziers(iface
, bezier
, 1);
1260 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddQuadraticBeziers(ID2D1GeometrySink
*iface
,
1261 const D2D1_QUADRATIC_BEZIER_SEGMENT
*beziers
, UINT32 bezier_count
)
1263 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
1264 struct d2d_figure
*figure
= &geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
- 1];
1267 TRACE("iface %p, beziers %p, bezier_count %u.\n", iface
, beziers
, bezier_count
);
1269 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_FIGURE
)
1271 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
1275 for (i
= 0; i
< bezier_count
; ++i
)
1277 if (!d2d_figure_add_bezier(figure
, figure
->vertices
[figure
->vertex_count
- 1],
1278 beziers
[i
].point1
, beziers
[i
].point2
))
1280 ERR("Failed to add bezier.\n");
1285 geometry
->u
.path
.segment_count
+= bezier_count
;
1288 static void STDMETHODCALLTYPE
d2d_geometry_sink_AddArc(ID2D1GeometrySink
*iface
, const D2D1_ARC_SEGMENT
*arc
)
1290 struct d2d_geometry
*geometry
= impl_from_ID2D1GeometrySink(iface
);
1292 FIXME("iface %p, arc %p stub!\n", iface
, arc
);
1294 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_FIGURE
)
1296 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
1300 if (!d2d_figure_add_vertex(&geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
- 1], arc
->point
))
1302 ERR("Failed to add vertex.\n");
1306 ++geometry
->u
.path
.segment_count
;
1309 static const struct ID2D1GeometrySinkVtbl d2d_geometry_sink_vtbl
=
1311 d2d_geometry_sink_QueryInterface
,
1312 d2d_geometry_sink_AddRef
,
1313 d2d_geometry_sink_Release
,
1314 d2d_geometry_sink_SetFillMode
,
1315 d2d_geometry_sink_SetSegmentFlags
,
1316 d2d_geometry_sink_BeginFigure
,
1317 d2d_geometry_sink_AddLines
,
1318 d2d_geometry_sink_AddBeziers
,
1319 d2d_geometry_sink_EndFigure
,
1320 d2d_geometry_sink_Close
,
1321 d2d_geometry_sink_AddLine
,
1322 d2d_geometry_sink_AddBezier
,
1323 d2d_geometry_sink_AddQuadraticBezier
,
1324 d2d_geometry_sink_AddQuadraticBeziers
,
1325 d2d_geometry_sink_AddArc
,
1328 static inline struct d2d_geometry
*impl_from_ID2D1PathGeometry(ID2D1PathGeometry
*iface
)
1330 return CONTAINING_RECORD(iface
, struct d2d_geometry
, ID2D1Geometry_iface
);
1333 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_QueryInterface(ID2D1PathGeometry
*iface
, REFIID iid
, void **out
)
1335 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
1337 if (IsEqualGUID(iid
, &IID_ID2D1PathGeometry
)
1338 || IsEqualGUID(iid
, &IID_ID2D1Geometry
)
1339 || IsEqualGUID(iid
, &IID_ID2D1Resource
)
1340 || IsEqualGUID(iid
, &IID_IUnknown
))
1342 ID2D1PathGeometry_AddRef(iface
);
1347 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
1350 return E_NOINTERFACE
;
1353 static ULONG STDMETHODCALLTYPE
d2d_path_geometry_AddRef(ID2D1PathGeometry
*iface
)
1355 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
1356 ULONG refcount
= InterlockedIncrement(&geometry
->refcount
);
1358 TRACE("%p increasing refcount to %u.\n", iface
, refcount
);
1363 static ULONG STDMETHODCALLTYPE
d2d_path_geometry_Release(ID2D1PathGeometry
*iface
)
1365 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
1366 ULONG refcount
= InterlockedDecrement(&geometry
->refcount
);
1368 TRACE("%p decreasing refcount to %u.\n", iface
, refcount
);
1372 d2d_path_geometry_free_figures(geometry
);
1373 d2d_geometry_cleanup(geometry
);
1374 HeapFree(GetProcessHeap(), 0, geometry
);
1380 static void STDMETHODCALLTYPE
d2d_path_geometry_GetFactory(ID2D1PathGeometry
*iface
, ID2D1Factory
**factory
)
1382 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
1384 TRACE("iface %p, factory %p.\n", iface
, factory
);
1386 ID2D1Factory_AddRef(*factory
= geometry
->factory
);
1389 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_GetBounds(ID2D1PathGeometry
*iface
,
1390 const D2D1_MATRIX_3X2_F
*transform
, D2D1_RECT_F
*bounds
)
1392 FIXME("iface %p, transform %p, bounds %p stub!\n", iface
, transform
, bounds
);
1397 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_GetWidenedBounds(ID2D1PathGeometry
*iface
, float stroke_width
,
1398 ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_RECT_F
*bounds
)
1400 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
1401 iface
, stroke_width
, stroke_style
, transform
, tolerance
, bounds
);
1406 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_StrokeContainsPoint(ID2D1PathGeometry
*iface
,
1407 D2D1_POINT_2F point
, float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
1408 float tolerance
, BOOL
*contains
)
1410 FIXME("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
1411 "transform %p, tolerance %.8e, contains %p stub!\n",
1412 iface
, point
.x
, point
.y
, stroke_width
, stroke_style
, transform
, tolerance
, contains
);
1417 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_FillContainsPoint(ID2D1PathGeometry
*iface
,
1418 D2D1_POINT_2F point
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, BOOL
*contains
)
1420 FIXME("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p stub!\n",
1421 iface
, point
.x
, point
.y
, transform
, tolerance
, contains
);
1426 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_CompareWithGeometry(ID2D1PathGeometry
*iface
,
1427 ID2D1Geometry
*geometry
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_GEOMETRY_RELATION
*relation
)
1429 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
1430 iface
, geometry
, transform
, tolerance
, relation
);
1435 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Simplify(ID2D1PathGeometry
*iface
,
1436 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
1437 ID2D1SimplifiedGeometrySink
*sink
)
1439 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
1440 iface
, option
, transform
, tolerance
, sink
);
1445 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Tessellate(ID2D1PathGeometry
*iface
,
1446 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1TessellationSink
*sink
)
1448 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
1453 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_CombineWithGeometry(ID2D1PathGeometry
*iface
,
1454 ID2D1Geometry
*geometry
, D2D1_COMBINE_MODE combine_mode
, const D2D1_MATRIX_3X2_F
*transform
,
1455 float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
1457 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
1458 iface
, geometry
, combine_mode
, transform
, tolerance
, sink
);
1463 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Outline(ID2D1PathGeometry
*iface
,
1464 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
1466 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
1471 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_ComputeArea(ID2D1PathGeometry
*iface
,
1472 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *area
)
1474 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface
, transform
, tolerance
, area
);
1479 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_ComputeLength(ID2D1PathGeometry
*iface
,
1480 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *length
)
1482 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface
, transform
, tolerance
, length
);
1487 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_ComputePointAtLength(ID2D1PathGeometry
*iface
, float length
,
1488 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_POINT_2F
*point
, D2D1_POINT_2F
*tangent
)
1490 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
1491 iface
, length
, transform
, tolerance
, point
, tangent
);
1496 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Widen(ID2D1PathGeometry
*iface
, float stroke_width
,
1497 ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
1498 ID2D1SimplifiedGeometrySink
*sink
)
1500 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
1501 iface
, stroke_width
, stroke_style
, transform
, tolerance
, sink
);
1506 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Open(ID2D1PathGeometry
*iface
, ID2D1GeometrySink
**sink
)
1508 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
1510 TRACE("iface %p, sink %p.\n", iface
, sink
);
1512 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_INITIAL
)
1513 return D2DERR_WRONG_STATE
;
1515 *sink
= &geometry
->u
.path
.ID2D1GeometrySink_iface
;
1516 ID2D1GeometrySink_AddRef(*sink
);
1518 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_OPEN
;
1523 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Stream(ID2D1PathGeometry
*iface
, ID2D1GeometrySink
*sink
)
1525 FIXME("iface %p, sink %p stub!\n", iface
, sink
);
1530 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_GetSegmentCount(ID2D1PathGeometry
*iface
, UINT32
*count
)
1532 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
1534 TRACE("iface %p, count %p.\n", iface
, count
);
1536 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_CLOSED
)
1537 return D2DERR_WRONG_STATE
;
1539 *count
= geometry
->u
.path
.segment_count
;
1544 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_GetFigureCount(ID2D1PathGeometry
*iface
, UINT32
*count
)
1546 struct d2d_geometry
*geometry
= impl_from_ID2D1PathGeometry(iface
);
1548 TRACE("iface %p, count %p.\n", iface
, count
);
1550 if (geometry
->u
.path
.state
!= D2D_GEOMETRY_STATE_CLOSED
)
1551 return D2DERR_WRONG_STATE
;
1553 *count
= geometry
->u
.path
.figure_count
;
1558 static const struct ID2D1PathGeometryVtbl d2d_path_geometry_vtbl
=
1560 d2d_path_geometry_QueryInterface
,
1561 d2d_path_geometry_AddRef
,
1562 d2d_path_geometry_Release
,
1563 d2d_path_geometry_GetFactory
,
1564 d2d_path_geometry_GetBounds
,
1565 d2d_path_geometry_GetWidenedBounds
,
1566 d2d_path_geometry_StrokeContainsPoint
,
1567 d2d_path_geometry_FillContainsPoint
,
1568 d2d_path_geometry_CompareWithGeometry
,
1569 d2d_path_geometry_Simplify
,
1570 d2d_path_geometry_Tessellate
,
1571 d2d_path_geometry_CombineWithGeometry
,
1572 d2d_path_geometry_Outline
,
1573 d2d_path_geometry_ComputeArea
,
1574 d2d_path_geometry_ComputeLength
,
1575 d2d_path_geometry_ComputePointAtLength
,
1576 d2d_path_geometry_Widen
,
1577 d2d_path_geometry_Open
,
1578 d2d_path_geometry_Stream
,
1579 d2d_path_geometry_GetSegmentCount
,
1580 d2d_path_geometry_GetFigureCount
,
1583 void d2d_path_geometry_init(struct d2d_geometry
*geometry
, ID2D1Factory
*factory
)
1585 d2d_geometry_init(geometry
, factory
, &identity
, (ID2D1GeometryVtbl
*)&d2d_path_geometry_vtbl
);
1586 geometry
->u
.path
.ID2D1GeometrySink_iface
.lpVtbl
= &d2d_geometry_sink_vtbl
;
1589 static inline struct d2d_geometry
*impl_from_ID2D1RectangleGeometry(ID2D1RectangleGeometry
*iface
)
1591 return CONTAINING_RECORD(iface
, struct d2d_geometry
, ID2D1Geometry_iface
);
1594 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_QueryInterface(ID2D1RectangleGeometry
*iface
,
1595 REFIID iid
, void **out
)
1597 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
1599 if (IsEqualGUID(iid
, &IID_ID2D1RectangleGeometry
)
1600 || IsEqualGUID(iid
, &IID_ID2D1Geometry
)
1601 || IsEqualGUID(iid
, &IID_ID2D1Resource
)
1602 || IsEqualGUID(iid
, &IID_IUnknown
))
1604 ID2D1RectangleGeometry_AddRef(iface
);
1609 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
1612 return E_NOINTERFACE
;
1615 static ULONG STDMETHODCALLTYPE
d2d_rectangle_geometry_AddRef(ID2D1RectangleGeometry
*iface
)
1617 struct d2d_geometry
*geometry
= impl_from_ID2D1RectangleGeometry(iface
);
1618 ULONG refcount
= InterlockedIncrement(&geometry
->refcount
);
1620 TRACE("%p increasing refcount to %u.\n", iface
, refcount
);
1625 static ULONG STDMETHODCALLTYPE
d2d_rectangle_geometry_Release(ID2D1RectangleGeometry
*iface
)
1627 struct d2d_geometry
*geometry
= impl_from_ID2D1RectangleGeometry(iface
);
1628 ULONG refcount
= InterlockedDecrement(&geometry
->refcount
);
1630 TRACE("%p decreasing refcount to %u.\n", iface
, refcount
);
1634 d2d_geometry_cleanup(geometry
);
1635 HeapFree(GetProcessHeap(), 0, geometry
);
1641 static void STDMETHODCALLTYPE
d2d_rectangle_geometry_GetFactory(ID2D1RectangleGeometry
*iface
, ID2D1Factory
**factory
)
1643 struct d2d_geometry
*geometry
= impl_from_ID2D1RectangleGeometry(iface
);
1645 TRACE("iface %p, factory %p.\n", iface
, factory
);
1647 ID2D1Factory_AddRef(*factory
= geometry
->factory
);
1650 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_GetBounds(ID2D1RectangleGeometry
*iface
,
1651 const D2D1_MATRIX_3X2_F
*transform
, D2D1_RECT_F
*bounds
)
1653 FIXME("iface %p, transform %p, bounds %p stub!\n", iface
, transform
, bounds
);
1658 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_GetWidenedBounds(ID2D1RectangleGeometry
*iface
,
1659 float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
1660 float tolerance
, D2D1_RECT_F
*bounds
)
1662 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
1663 iface
, stroke_width
, stroke_style
, transform
, tolerance
, bounds
);
1668 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_StrokeContainsPoint(ID2D1RectangleGeometry
*iface
,
1669 D2D1_POINT_2F point
, float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
1670 float tolerance
, BOOL
*contains
)
1672 FIXME("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
1673 "transform %p, tolerance %.8e, contains %p stub!\n",
1674 iface
, point
.x
, point
.y
, stroke_width
, stroke_style
, transform
, tolerance
, contains
);
1679 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_FillContainsPoint(ID2D1RectangleGeometry
*iface
,
1680 D2D1_POINT_2F point
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, BOOL
*contains
)
1682 FIXME("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p stub!\n",
1683 iface
, point
.x
, point
.y
, transform
, tolerance
, contains
);
1688 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_CompareWithGeometry(ID2D1RectangleGeometry
*iface
,
1689 ID2D1Geometry
*geometry
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_GEOMETRY_RELATION
*relation
)
1691 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
1692 iface
, geometry
, transform
, tolerance
, relation
);
1697 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_Simplify(ID2D1RectangleGeometry
*iface
,
1698 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
1699 ID2D1SimplifiedGeometrySink
*sink
)
1701 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
1702 iface
, option
, transform
, tolerance
, sink
);
1707 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_Tessellate(ID2D1RectangleGeometry
*iface
,
1708 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1TessellationSink
*sink
)
1710 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
1715 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_CombineWithGeometry(ID2D1RectangleGeometry
*iface
,
1716 ID2D1Geometry
*geometry
, D2D1_COMBINE_MODE combine_mode
, const D2D1_MATRIX_3X2_F
*transform
,
1717 float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
1719 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
1720 iface
, geometry
, combine_mode
, transform
, tolerance
, sink
);
1725 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_Outline(ID2D1RectangleGeometry
*iface
,
1726 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
1728 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
1733 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_ComputeArea(ID2D1RectangleGeometry
*iface
,
1734 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *area
)
1736 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface
, transform
, tolerance
, area
);
1741 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_ComputeLength(ID2D1RectangleGeometry
*iface
,
1742 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *length
)
1744 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface
, transform
, tolerance
, length
);
1749 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_ComputePointAtLength(ID2D1RectangleGeometry
*iface
,
1750 float length
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_POINT_2F
*point
,
1751 D2D1_POINT_2F
*tangent
)
1753 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
1754 iface
, length
, transform
, tolerance
, point
, tangent
);
1759 static HRESULT STDMETHODCALLTYPE
d2d_rectangle_geometry_Widen(ID2D1RectangleGeometry
*iface
, float stroke_width
,
1760 ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
1761 ID2D1SimplifiedGeometrySink
*sink
)
1763 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
1764 iface
, stroke_width
, stroke_style
, transform
, tolerance
, sink
);
1769 static void STDMETHODCALLTYPE
d2d_rectangle_geometry_GetRect(ID2D1RectangleGeometry
*iface
, D2D1_RECT_F
*rect
)
1771 struct d2d_geometry
*geometry
= impl_from_ID2D1RectangleGeometry(iface
);
1773 TRACE("iface %p, rect %p.\n", iface
, rect
);
1775 *rect
= geometry
->u
.rectangle
.rect
;
1778 static const struct ID2D1RectangleGeometryVtbl d2d_rectangle_geometry_vtbl
=
1780 d2d_rectangle_geometry_QueryInterface
,
1781 d2d_rectangle_geometry_AddRef
,
1782 d2d_rectangle_geometry_Release
,
1783 d2d_rectangle_geometry_GetFactory
,
1784 d2d_rectangle_geometry_GetBounds
,
1785 d2d_rectangle_geometry_GetWidenedBounds
,
1786 d2d_rectangle_geometry_StrokeContainsPoint
,
1787 d2d_rectangle_geometry_FillContainsPoint
,
1788 d2d_rectangle_geometry_CompareWithGeometry
,
1789 d2d_rectangle_geometry_Simplify
,
1790 d2d_rectangle_geometry_Tessellate
,
1791 d2d_rectangle_geometry_CombineWithGeometry
,
1792 d2d_rectangle_geometry_Outline
,
1793 d2d_rectangle_geometry_ComputeArea
,
1794 d2d_rectangle_geometry_ComputeLength
,
1795 d2d_rectangle_geometry_ComputePointAtLength
,
1796 d2d_rectangle_geometry_Widen
,
1797 d2d_rectangle_geometry_GetRect
,
1800 HRESULT
d2d_rectangle_geometry_init(struct d2d_geometry
*geometry
, ID2D1Factory
*factory
, const D2D1_RECT_F
*rect
)
1802 d2d_geometry_init(geometry
, factory
, &identity
, (ID2D1GeometryVtbl
*)&d2d_rectangle_geometry_vtbl
);
1803 geometry
->u
.rectangle
.rect
= *rect
;
1805 if (!(geometry
->vertices
= HeapAlloc(GetProcessHeap(), 0, 4 * sizeof(*geometry
->vertices
))))
1807 d2d_geometry_cleanup(geometry
);
1808 return E_OUTOFMEMORY
;
1810 geometry
->vertex_count
= 4;
1811 if (!d2d_array_reserve((void **)&geometry
->faces
, &geometry
->faces_size
, 2, sizeof(*geometry
->faces
)))
1813 d2d_geometry_cleanup(geometry
);
1814 return E_OUTOFMEMORY
;
1816 geometry
->face_count
= 2;
1818 geometry
->vertices
[0].x
= min(rect
->left
, rect
->right
);
1819 geometry
->vertices
[0].y
= min(rect
->top
, rect
->bottom
);
1820 geometry
->vertices
[1].x
= min(rect
->left
, rect
->right
);
1821 geometry
->vertices
[1].y
= max(rect
->top
, rect
->bottom
);
1822 geometry
->vertices
[2].x
= max(rect
->left
, rect
->right
);
1823 geometry
->vertices
[2].y
= min(rect
->top
, rect
->bottom
);
1824 geometry
->vertices
[3].x
= max(rect
->left
, rect
->right
);
1825 geometry
->vertices
[3].y
= max(rect
->top
, rect
->bottom
);
1827 geometry
->faces
[0].v
[0] = 0;
1828 geometry
->faces
[0].v
[1] = 2;
1829 geometry
->faces
[0].v
[2] = 1;
1830 geometry
->faces
[1].v
[0] = 1;
1831 geometry
->faces
[1].v
[1] = 2;
1832 geometry
->faces
[1].v
[2] = 3;
1837 static inline struct d2d_geometry
*impl_from_ID2D1TransformedGeometry(ID2D1TransformedGeometry
*iface
)
1839 return CONTAINING_RECORD(iface
, struct d2d_geometry
, ID2D1Geometry_iface
);
1842 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_QueryInterface(ID2D1TransformedGeometry
*iface
,
1843 REFIID iid
, void **out
)
1845 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
1847 if (IsEqualGUID(iid
, &IID_ID2D1TransformedGeometry
)
1848 || IsEqualGUID(iid
, &IID_ID2D1Geometry
)
1849 || IsEqualGUID(iid
, &IID_ID2D1Resource
)
1850 || IsEqualGUID(iid
, &IID_IUnknown
))
1852 ID2D1TransformedGeometry_AddRef(iface
);
1857 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
1860 return E_NOINTERFACE
;
1863 static ULONG STDMETHODCALLTYPE
d2d_transformed_geometry_AddRef(ID2D1TransformedGeometry
*iface
)
1865 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
1866 ULONG refcount
= InterlockedIncrement(&geometry
->refcount
);
1868 TRACE("%p increasing refcount to %u.\n", iface
, refcount
);
1873 static ULONG STDMETHODCALLTYPE
d2d_transformed_geometry_Release(ID2D1TransformedGeometry
*iface
)
1875 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
1876 ULONG refcount
= InterlockedDecrement(&geometry
->refcount
);
1878 TRACE("%p decreasing refcount to %u.\n", iface
, refcount
);
1882 geometry
->beziers
= NULL
;
1883 geometry
->faces
= NULL
;
1884 geometry
->vertices
= NULL
;
1885 ID2D1Geometry_Release(geometry
->u
.transformed
.src_geometry
);
1886 d2d_geometry_cleanup(geometry
);
1887 HeapFree(GetProcessHeap(), 0, geometry
);
1893 static void STDMETHODCALLTYPE
d2d_transformed_geometry_GetFactory(ID2D1TransformedGeometry
*iface
,
1894 ID2D1Factory
**factory
)
1896 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
1898 TRACE("iface %p, factory %p.\n", iface
, factory
);
1900 ID2D1Factory_AddRef(*factory
= geometry
->factory
);
1903 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_GetBounds(ID2D1TransformedGeometry
*iface
,
1904 const D2D1_MATRIX_3X2_F
*transform
, D2D1_RECT_F
*bounds
)
1906 FIXME("iface %p, transform %p, bounds %p stub!\n", iface
, transform
, bounds
);
1911 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_GetWidenedBounds(ID2D1TransformedGeometry
*iface
,
1912 float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
1913 float tolerance
, D2D1_RECT_F
*bounds
)
1915 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
1916 iface
, stroke_width
, stroke_style
, transform
, tolerance
, bounds
);
1921 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_StrokeContainsPoint(ID2D1TransformedGeometry
*iface
,
1922 D2D1_POINT_2F point
, float stroke_width
, ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
,
1923 float tolerance
, BOOL
*contains
)
1925 FIXME("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
1926 "transform %p, tolerance %.8e, contains %p stub!\n",
1927 iface
, point
.x
, point
.y
, stroke_width
, stroke_style
, transform
, tolerance
, contains
);
1932 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_FillContainsPoint(ID2D1TransformedGeometry
*iface
,
1933 D2D1_POINT_2F point
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, BOOL
*contains
)
1935 FIXME("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p stub!\n",
1936 iface
, point
.x
, point
.y
, transform
, tolerance
, contains
);
1941 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_CompareWithGeometry(ID2D1TransformedGeometry
*iface
,
1942 ID2D1Geometry
*geometry
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_GEOMETRY_RELATION
*relation
)
1944 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
1945 iface
, geometry
, transform
, tolerance
, relation
);
1950 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_Simplify(ID2D1TransformedGeometry
*iface
,
1951 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
1952 ID2D1SimplifiedGeometrySink
*sink
)
1954 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
1955 iface
, option
, transform
, tolerance
, sink
);
1960 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_Tessellate(ID2D1TransformedGeometry
*iface
,
1961 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1TessellationSink
*sink
)
1963 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
1968 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_CombineWithGeometry(ID2D1TransformedGeometry
*iface
,
1969 ID2D1Geometry
*geometry
, D2D1_COMBINE_MODE combine_mode
, const D2D1_MATRIX_3X2_F
*transform
,
1970 float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
1972 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
1973 iface
, geometry
, combine_mode
, transform
, tolerance
, sink
);
1978 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_Outline(ID2D1TransformedGeometry
*iface
,
1979 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, ID2D1SimplifiedGeometrySink
*sink
)
1981 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface
, transform
, tolerance
, sink
);
1986 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_ComputeArea(ID2D1TransformedGeometry
*iface
,
1987 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *area
)
1989 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface
, transform
, tolerance
, area
);
1994 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_ComputeLength(ID2D1TransformedGeometry
*iface
,
1995 const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, float *length
)
1997 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface
, transform
, tolerance
, length
);
2002 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_ComputePointAtLength(ID2D1TransformedGeometry
*iface
,
2003 float length
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
, D2D1_POINT_2F
*point
,
2004 D2D1_POINT_2F
*tangent
)
2006 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
2007 iface
, length
, transform
, tolerance
, point
, tangent
);
2012 static HRESULT STDMETHODCALLTYPE
d2d_transformed_geometry_Widen(ID2D1TransformedGeometry
*iface
, float stroke_width
,
2013 ID2D1StrokeStyle
*stroke_style
, const D2D1_MATRIX_3X2_F
*transform
, float tolerance
,
2014 ID2D1SimplifiedGeometrySink
*sink
)
2016 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
2017 iface
, stroke_width
, stroke_style
, transform
, tolerance
, sink
);
2022 static void STDMETHODCALLTYPE
d2d_transformed_geometry_GetSourceGeometry(ID2D1TransformedGeometry
*iface
,
2023 ID2D1Geometry
**src_geometry
)
2025 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
2027 TRACE("iface %p, src_geometry %p.\n", iface
, src_geometry
);
2029 ID2D1Geometry_AddRef(*src_geometry
= geometry
->u
.transformed
.src_geometry
);
2032 static void STDMETHODCALLTYPE
d2d_transformed_geometry_GetTransform(ID2D1TransformedGeometry
*iface
,
2033 D2D1_MATRIX_3X2_F
*transform
)
2035 struct d2d_geometry
*geometry
= impl_from_ID2D1TransformedGeometry(iface
);
2037 TRACE("iface %p, transform %p.\n", iface
, transform
);
2039 *transform
= geometry
->transform
;
2042 static const struct ID2D1TransformedGeometryVtbl d2d_transformed_geometry_vtbl
=
2044 d2d_transformed_geometry_QueryInterface
,
2045 d2d_transformed_geometry_AddRef
,
2046 d2d_transformed_geometry_Release
,
2047 d2d_transformed_geometry_GetFactory
,
2048 d2d_transformed_geometry_GetBounds
,
2049 d2d_transformed_geometry_GetWidenedBounds
,
2050 d2d_transformed_geometry_StrokeContainsPoint
,
2051 d2d_transformed_geometry_FillContainsPoint
,
2052 d2d_transformed_geometry_CompareWithGeometry
,
2053 d2d_transformed_geometry_Simplify
,
2054 d2d_transformed_geometry_Tessellate
,
2055 d2d_transformed_geometry_CombineWithGeometry
,
2056 d2d_transformed_geometry_Outline
,
2057 d2d_transformed_geometry_ComputeArea
,
2058 d2d_transformed_geometry_ComputeLength
,
2059 d2d_transformed_geometry_ComputePointAtLength
,
2060 d2d_transformed_geometry_Widen
,
2061 d2d_transformed_geometry_GetSourceGeometry
,
2062 d2d_transformed_geometry_GetTransform
,
2065 void d2d_transformed_geometry_init(struct d2d_geometry
*geometry
, ID2D1Factory
*factory
,
2066 ID2D1Geometry
*src_geometry
, const D2D_MATRIX_3X2_F
*transform
)
2068 struct d2d_geometry
*src_impl
;
2070 d2d_geometry_init(geometry
, factory
, transform
, (ID2D1GeometryVtbl
*)&d2d_transformed_geometry_vtbl
);
2071 ID2D1Geometry_AddRef(geometry
->u
.transformed
.src_geometry
= src_geometry
);
2072 src_impl
= unsafe_impl_from_ID2D1Geometry(src_geometry
);
2073 geometry
->vertices
= src_impl
->vertices
;
2074 geometry
->vertex_count
= src_impl
->vertex_count
;
2075 geometry
->faces
= src_impl
->faces
;
2076 geometry
->face_count
= src_impl
->face_count
;
2077 geometry
->beziers
= src_impl
->beziers
;
2078 geometry
->bezier_count
= src_impl
->bezier_count
;
2081 struct d2d_geometry
*unsafe_impl_from_ID2D1Geometry(ID2D1Geometry
*iface
)
2085 assert(iface
->lpVtbl
== (const ID2D1GeometryVtbl
*)&d2d_path_geometry_vtbl
2086 || iface
->lpVtbl
== (const ID2D1GeometryVtbl
*)&d2d_rectangle_geometry_vtbl
2087 || iface
->lpVtbl
== (const ID2D1GeometryVtbl
*)&d2d_transformed_geometry_vtbl
);
2088 return CONTAINING_RECORD(iface
, struct d2d_geometry
, ID2D1Geometry_iface
);