ntdll: Add support for Win 10.
[wine/multimedia.git] / dlls / d2d1 / geometry.c
blob056923e6fab36ffa47b2064ea3bdc93585b7dc0d
1 /*
2 * Copyright 2015 Henri Verbeet for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "config.h"
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 enum d2d_cdt_edge_next
31 D2D_EDGE_NEXT_ORIGIN = 0,
32 D2D_EDGE_NEXT_ROT = 1,
33 D2D_EDGE_NEXT_SYM = 2,
34 D2D_EDGE_NEXT_TOR = 3,
37 struct d2d_figure
39 D2D1_POINT_2F *vertices;
40 size_t vertices_size;
41 size_t vertex_count;
43 struct d2d_bezier *beziers;
44 size_t beziers_size;
45 size_t bezier_count;
48 struct d2d_cdt_edge_ref
50 size_t idx;
51 enum d2d_cdt_edge_next r;
54 struct d2d_cdt_edge
56 struct d2d_cdt_edge_ref next[4];
57 size_t vertex[2];
58 unsigned int flags;
61 struct d2d_cdt
63 struct d2d_cdt_edge *edges;
64 size_t edges_size;
65 size_t edge_count;
66 size_t free_edge;
68 const D2D1_POINT_2F *vertices;
71 static void d2d_point_subtract(D2D1_POINT_2F *out,
72 const D2D1_POINT_2F *a, const D2D1_POINT_2F *b)
74 out->x = a->x - b->x;
75 out->y = a->y - b->y;
78 static float d2d_point_ccw(const D2D1_POINT_2F *a, const D2D1_POINT_2F *b, const D2D1_POINT_2F *c)
80 D2D1_POINT_2F ab, ac;
82 d2d_point_subtract(&ab, b, a);
83 d2d_point_subtract(&ac, c, a);
85 return ab.x * ac.y - ab.y * ac.x;
88 static BOOL d2d_array_reserve(void **elements, size_t *capacity, size_t element_count, size_t element_size)
90 size_t new_capacity, max_capacity;
91 void *new_elements;
93 if (element_count <= *capacity)
94 return TRUE;
96 max_capacity = ~(size_t)0 / element_size;
97 if (max_capacity < element_count)
98 return FALSE;
100 new_capacity = max(*capacity, 4);
101 while (new_capacity < element_count && new_capacity <= max_capacity / 2)
102 new_capacity *= 2;
104 if (new_capacity < element_count)
105 new_capacity = max_capacity;
107 if (*elements)
108 new_elements = HeapReAlloc(GetProcessHeap(), 0, *elements, new_capacity * element_size);
109 else
110 new_elements = HeapAlloc(GetProcessHeap(), 0, new_capacity * element_size);
112 if (!new_elements)
113 return FALSE;
115 *elements = new_elements;
116 *capacity = new_capacity;
117 return TRUE;
120 static BOOL d2d_figure_insert_vertex(struct d2d_figure *figure, size_t idx, D2D1_POINT_2F vertex)
122 if (!d2d_array_reserve((void **)&figure->vertices, &figure->vertices_size,
123 figure->vertex_count + 1, sizeof(*figure->vertices)))
125 ERR("Failed to grow vertices array.\n");
126 return FALSE;
129 memmove(&figure->vertices[idx + 1], &figure->vertices[idx],
130 (figure->vertex_count - idx) * sizeof(*figure->vertices));
131 figure->vertices[idx] = vertex;
132 ++figure->vertex_count;
133 return TRUE;
136 static BOOL d2d_figure_add_vertex(struct d2d_figure *figure, D2D1_POINT_2F vertex)
138 if (!d2d_array_reserve((void **)&figure->vertices, &figure->vertices_size,
139 figure->vertex_count + 1, sizeof(*figure->vertices)))
141 ERR("Failed to grow vertices array.\n");
142 return FALSE;
145 figure->vertices[figure->vertex_count] = vertex;
146 ++figure->vertex_count;
147 return TRUE;
150 /* FIXME: No inside/outside testing is done for beziers. */
151 static BOOL d2d_figure_add_bezier(struct d2d_figure *figure, D2D1_POINT_2F p0, D2D1_POINT_2F p1, D2D1_POINT_2F p2)
153 struct d2d_bezier *b;
154 unsigned int idx1, idx2;
155 float sign;
157 if (!d2d_array_reserve((void **)&figure->beziers, &figure->beziers_size,
158 figure->bezier_count + 1, sizeof(*figure->beziers)))
160 ERR("Failed to grow beziers array.\n");
161 return FALSE;
164 if (d2d_point_ccw(&p0, &p1, &p2) > 0.0f)
166 sign = -1.0f;
167 idx1 = 1;
168 idx2 = 2;
170 else
172 sign = 1.0f;
173 idx1 = 2;
174 idx2 = 1;
177 b = &figure->beziers[figure->bezier_count];
178 b->v[0].position = p0;
179 b->v[0].texcoord.u = 0.0f;
180 b->v[0].texcoord.v = 0.0f;
181 b->v[0].texcoord.sign = sign;
182 b->v[idx1].position = p1;
183 b->v[idx1].texcoord.u = 0.5f;
184 b->v[idx1].texcoord.v = 0.0f;
185 b->v[idx1].texcoord.sign = sign;
186 b->v[idx2].position = p2;
187 b->v[idx2].texcoord.u = 1.0f;
188 b->v[idx2].texcoord.v = 1.0f;
189 b->v[idx2].texcoord.sign = sign;
190 ++figure->bezier_count;
192 if (sign > 0.0f && !d2d_figure_add_vertex(figure, p1))
193 return FALSE;
194 if (!d2d_figure_add_vertex(figure, p2))
195 return FALSE;
196 return TRUE;
199 static void d2d_cdt_edge_rot(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
201 dst->idx = src->idx;
202 dst->r = (src->r + D2D_EDGE_NEXT_ROT) & 3;
205 static void d2d_cdt_edge_sym(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
207 dst->idx = src->idx;
208 dst->r = (src->r + D2D_EDGE_NEXT_SYM) & 3;
211 static void d2d_cdt_edge_tor(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
213 dst->idx = src->idx;
214 dst->r = (src->r + D2D_EDGE_NEXT_TOR) & 3;
217 static void d2d_cdt_edge_next_left(const struct d2d_cdt *cdt,
218 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
220 d2d_cdt_edge_rot(dst, &cdt->edges[src->idx].next[(src->r + D2D_EDGE_NEXT_TOR) & 3]);
223 static void d2d_cdt_edge_next_origin(const struct d2d_cdt *cdt,
224 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
226 *dst = cdt->edges[src->idx].next[src->r];
229 static void d2d_cdt_edge_prev_origin(const struct d2d_cdt *cdt,
230 struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
232 d2d_cdt_edge_rot(dst, &cdt->edges[src->idx].next[(src->r + D2D_EDGE_NEXT_ROT) & 3]);
235 static size_t d2d_cdt_edge_origin(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
237 return cdt->edges[e->idx].vertex[e->r >> 1];
240 static size_t d2d_cdt_edge_destination(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
242 return cdt->edges[e->idx].vertex[!(e->r >> 1)];
245 static void d2d_cdt_edge_set_origin(const struct d2d_cdt *cdt,
246 const struct d2d_cdt_edge_ref *e, size_t vertex)
248 cdt->edges[e->idx].vertex[e->r >> 1] = vertex;
251 static void d2d_cdt_edge_set_destination(const struct d2d_cdt *cdt,
252 const struct d2d_cdt_edge_ref *e, size_t vertex)
254 cdt->edges[e->idx].vertex[!(e->r >> 1)] = vertex;
257 static float d2d_cdt_ccw(const struct d2d_cdt *cdt, size_t a, size_t b, size_t c)
259 return d2d_point_ccw(&cdt->vertices[a], &cdt->vertices[b], &cdt->vertices[c]);
262 static BOOL d2d_cdt_rightof(const struct d2d_cdt *cdt, size_t p, const struct d2d_cdt_edge_ref *e)
264 return d2d_cdt_ccw(cdt, p, d2d_cdt_edge_destination(cdt, e), d2d_cdt_edge_origin(cdt, e)) > 0.0f;
267 static BOOL d2d_cdt_leftof(const struct d2d_cdt *cdt, size_t p, const struct d2d_cdt_edge_ref *e)
269 return d2d_cdt_ccw(cdt, p, d2d_cdt_edge_origin(cdt, e), d2d_cdt_edge_destination(cdt, e)) > 0.0f;
272 /* Determine if point D is inside or outside the circle defined by points A,
273 * B, C. As explained in the paper by Guibas and Stolfi, this is equivalent to
274 * calculating the signed volume of the tetrahedron defined by projecting the
275 * points onto the paraboloid of revolution x = x² + y²,
276 * λ:(x, y) → (x, y, x² + y²). I.e., D is inside the cirlce if
278 * |λ(A) 1|
279 * |λ(B) 1| > 0
280 * |λ(C) 1|
281 * |λ(D) 1|
283 * After translating D to the origin, that becomes:
285 * |λ(A-D)|
286 * |λ(B-D)| > 0
287 * |λ(C-D)| */
288 static BOOL d2d_cdt_incircle(const struct d2d_cdt *cdt, size_t a, size_t b, size_t c, size_t d)
290 const D2D1_POINT_2F *p = cdt->vertices;
291 const struct
293 double x, y;
295 da = {p[a].x - p[d].x, p[a].y - p[d].y},
296 db = {p[b].x - p[d].x, p[b].y - p[d].y},
297 dc = {p[c].x - p[d].x, p[c].y - p[d].y};
299 return (da.x * da.x + da.y * da.y) * (db.x * dc.y - db.y * dc.x)
300 + (db.x * db.x + db.y * db.y) * (dc.x * da.y - dc.y * da.x)
301 + (dc.x * dc.x + dc.y * dc.y) * (da.x * db.y - da.y * db.x) > 0.0;
304 static void d2d_cdt_splice(const struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *a,
305 const struct d2d_cdt_edge_ref *b)
307 struct d2d_cdt_edge_ref ta, tb, alpha, beta;
309 ta = cdt->edges[a->idx].next[a->r];
310 tb = cdt->edges[b->idx].next[b->r];
311 cdt->edges[a->idx].next[a->r] = tb;
312 cdt->edges[b->idx].next[b->r] = ta;
314 d2d_cdt_edge_rot(&alpha, &ta);
315 d2d_cdt_edge_rot(&beta, &tb);
317 ta = cdt->edges[alpha.idx].next[alpha.r];
318 tb = cdt->edges[beta.idx].next[beta.r];
319 cdt->edges[alpha.idx].next[alpha.r] = tb;
320 cdt->edges[beta.idx].next[beta.r] = ta;
323 static BOOL d2d_cdt_create_edge(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *e)
325 struct d2d_cdt_edge *edge;
327 if (cdt->free_edge != ~0u)
329 e->idx = cdt->free_edge;
330 cdt->free_edge = cdt->edges[e->idx].next[D2D_EDGE_NEXT_ORIGIN].idx;
332 else
334 if (!d2d_array_reserve((void **)&cdt->edges, &cdt->edges_size, cdt->edge_count + 1, sizeof(*cdt->edges)))
336 ERR("Failed to grow edges array.\n");
337 return FALSE;
339 e->idx = cdt->edge_count++;
341 e->r = 0;
343 edge = &cdt->edges[e->idx];
344 edge->next[D2D_EDGE_NEXT_ORIGIN] = *e;
345 d2d_cdt_edge_tor(&edge->next[D2D_EDGE_NEXT_ROT], e);
346 d2d_cdt_edge_sym(&edge->next[D2D_EDGE_NEXT_SYM], e);
347 d2d_cdt_edge_rot(&edge->next[D2D_EDGE_NEXT_TOR], e);
348 edge->flags = 0;
350 return TRUE;
353 static void d2d_cdt_destroy_edge(struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *e)
355 struct d2d_cdt_edge_ref next, sym, prev;
357 d2d_cdt_edge_next_origin(cdt, &next, e);
358 if (next.idx != e->idx || next.r != e->r)
360 d2d_cdt_edge_prev_origin(cdt, &prev, e);
361 d2d_cdt_splice(cdt, e, &prev);
364 d2d_cdt_edge_sym(&sym, e);
366 d2d_cdt_edge_next_origin(cdt, &next, &sym);
367 if (next.idx != sym.idx || next.r != sym.r)
369 d2d_cdt_edge_prev_origin(cdt, &prev, &sym);
370 d2d_cdt_splice(cdt, &sym, &prev);
373 cdt->edges[e->idx].flags |= D2D_CDT_EDGE_FLAG_FREED;
374 cdt->edges[e->idx].next[D2D_EDGE_NEXT_ORIGIN].idx = cdt->free_edge;
375 cdt->free_edge = e->idx;
378 static BOOL d2d_cdt_connect(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *e,
379 const struct d2d_cdt_edge_ref *a, const struct d2d_cdt_edge_ref *b)
381 struct d2d_cdt_edge_ref tmp;
383 if (!d2d_cdt_create_edge(cdt, e))
384 return FALSE;
385 d2d_cdt_edge_set_origin(cdt, e, d2d_cdt_edge_destination(cdt, a));
386 d2d_cdt_edge_set_destination(cdt, e, d2d_cdt_edge_origin(cdt, b));
387 d2d_cdt_edge_next_left(cdt, &tmp, a);
388 d2d_cdt_splice(cdt, e, &tmp);
389 d2d_cdt_edge_sym(&tmp, e);
390 d2d_cdt_splice(cdt, &tmp, b);
392 return TRUE;
395 static BOOL d2d_cdt_merge(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *left_outer,
396 struct d2d_cdt_edge_ref *left_inner, struct d2d_cdt_edge_ref *right_inner,
397 struct d2d_cdt_edge_ref *right_outer)
399 struct d2d_cdt_edge_ref base_edge, tmp;
401 /* Create the base edge between both parts. */
402 for (;;)
404 if (d2d_cdt_leftof(cdt, d2d_cdt_edge_origin(cdt, right_inner), left_inner))
406 d2d_cdt_edge_next_left(cdt, left_inner, left_inner);
408 else if (d2d_cdt_rightof(cdt, d2d_cdt_edge_origin(cdt, left_inner), right_inner))
410 d2d_cdt_edge_sym(&tmp, right_inner);
411 d2d_cdt_edge_next_origin(cdt, right_inner, &tmp);
413 else
415 break;
419 d2d_cdt_edge_sym(&tmp, right_inner);
420 if (!d2d_cdt_connect(cdt, &base_edge, &tmp, left_inner))
421 return FALSE;
422 if (d2d_cdt_edge_origin(cdt, left_inner) == d2d_cdt_edge_origin(cdt, left_outer))
423 d2d_cdt_edge_sym(left_outer, &base_edge);
424 if (d2d_cdt_edge_origin(cdt, right_inner) == d2d_cdt_edge_origin(cdt, right_outer))
425 *right_outer = base_edge;
427 for (;;)
429 struct d2d_cdt_edge_ref left_candidate, right_candidate, sym_base_edge;
430 BOOL left_valid, right_valid;
432 /* Find the left candidate. */
433 d2d_cdt_edge_sym(&sym_base_edge, &base_edge);
434 d2d_cdt_edge_next_origin(cdt, &left_candidate, &sym_base_edge);
435 if ((left_valid = d2d_cdt_leftof(cdt, d2d_cdt_edge_destination(cdt, &left_candidate), &sym_base_edge)))
437 d2d_cdt_edge_next_origin(cdt, &tmp, &left_candidate);
438 while (d2d_cdt_edge_destination(cdt, &tmp) != d2d_cdt_edge_destination(cdt, &sym_base_edge)
439 && d2d_cdt_incircle(cdt,
440 d2d_cdt_edge_origin(cdt, &sym_base_edge), d2d_cdt_edge_destination(cdt, &sym_base_edge),
441 d2d_cdt_edge_destination(cdt, &left_candidate), d2d_cdt_edge_destination(cdt, &tmp)))
443 d2d_cdt_destroy_edge(cdt, &left_candidate);
444 left_candidate = tmp;
445 d2d_cdt_edge_next_origin(cdt, &tmp, &left_candidate);
448 d2d_cdt_edge_sym(&left_candidate, &left_candidate);
450 /* Find the right candidate. */
451 d2d_cdt_edge_prev_origin(cdt, &right_candidate, &base_edge);
452 if ((right_valid = d2d_cdt_rightof(cdt, d2d_cdt_edge_destination(cdt, &right_candidate), &base_edge)))
454 d2d_cdt_edge_prev_origin(cdt, &tmp, &right_candidate);
455 while (d2d_cdt_edge_destination(cdt, &tmp) != d2d_cdt_edge_destination(cdt, &base_edge)
456 && d2d_cdt_incircle(cdt,
457 d2d_cdt_edge_origin(cdt, &sym_base_edge), d2d_cdt_edge_destination(cdt, &sym_base_edge),
458 d2d_cdt_edge_destination(cdt, &right_candidate), d2d_cdt_edge_destination(cdt, &tmp)))
460 d2d_cdt_destroy_edge(cdt, &right_candidate);
461 right_candidate = tmp;
462 d2d_cdt_edge_prev_origin(cdt, &tmp, &right_candidate);
466 if (!left_valid && !right_valid)
467 break;
469 /* Connect the appropriate candidate with the base edge. */
470 if (!left_valid || (right_valid && d2d_cdt_incircle(cdt,
471 d2d_cdt_edge_origin(cdt, &left_candidate), d2d_cdt_edge_destination(cdt, &left_candidate),
472 d2d_cdt_edge_origin(cdt, &right_candidate), d2d_cdt_edge_destination(cdt, &right_candidate))))
474 if (!d2d_cdt_connect(cdt, &base_edge, &right_candidate, &sym_base_edge))
475 return FALSE;
477 else
479 if (!d2d_cdt_connect(cdt, &base_edge, &sym_base_edge, &left_candidate))
480 return FALSE;
484 return TRUE;
487 /* Create a Delaunay triangulation from a set of vertices. This is an
488 * implementation of the divide-and-conquer algorithm described by Guibas and
489 * Stolfi. Should be called with at least two vertices. */
490 static BOOL d2d_cdt_triangulate(struct d2d_cdt *cdt, size_t start_vertex, size_t vertex_count,
491 struct d2d_cdt_edge_ref *left_edge, struct d2d_cdt_edge_ref *right_edge)
493 struct d2d_cdt_edge_ref left_inner, left_outer, right_inner, right_outer, tmp;
494 size_t cut;
496 /* Only two vertices, create a single edge. */
497 if (vertex_count == 2)
499 struct d2d_cdt_edge_ref a;
501 if (!d2d_cdt_create_edge(cdt, &a))
502 return FALSE;
503 d2d_cdt_edge_set_origin(cdt, &a, start_vertex);
504 d2d_cdt_edge_set_destination(cdt, &a, start_vertex + 1);
506 *left_edge = a;
507 d2d_cdt_edge_sym(right_edge, &a);
509 return TRUE;
512 /* Three vertices, create a triangle. */
513 if (vertex_count == 3)
515 struct d2d_cdt_edge_ref a, b, c;
516 float det;
518 if (!d2d_cdt_create_edge(cdt, &a))
519 return FALSE;
520 if (!d2d_cdt_create_edge(cdt, &b))
521 return FALSE;
522 d2d_cdt_edge_sym(&tmp, &a);
523 d2d_cdt_splice(cdt, &tmp, &b);
525 d2d_cdt_edge_set_origin(cdt, &a, start_vertex);
526 d2d_cdt_edge_set_destination(cdt, &a, start_vertex + 1);
527 d2d_cdt_edge_set_origin(cdt, &b, start_vertex + 1);
528 d2d_cdt_edge_set_destination(cdt, &b, start_vertex + 2);
530 det = d2d_cdt_ccw(cdt, start_vertex, start_vertex + 1, start_vertex + 2);
531 if (det != 0.0f && !d2d_cdt_connect(cdt, &c, &b, &a))
532 return FALSE;
534 if (det < 0.0f)
536 d2d_cdt_edge_sym(left_edge, &c);
537 *right_edge = c;
539 else
541 *left_edge = a;
542 d2d_cdt_edge_sym(right_edge, &b);
545 return TRUE;
548 /* More than tree vertices, divide. */
549 cut = vertex_count / 2;
550 if (!d2d_cdt_triangulate(cdt, start_vertex, cut, &left_outer, &left_inner))
551 return FALSE;
552 if (!d2d_cdt_triangulate(cdt, start_vertex + cut, vertex_count - cut, &right_inner, &right_outer))
553 return FALSE;
554 /* Merge the left and right parts. */
555 if (!d2d_cdt_merge(cdt, &left_outer, &left_inner, &right_inner, &right_outer))
556 return FALSE;
558 *left_edge = left_outer;
559 *right_edge = right_outer;
560 return TRUE;
563 static int d2d_cdt_compare_vertices(const void *a, const void *b)
565 const D2D1_POINT_2F *p0 = a;
566 const D2D1_POINT_2F *p1 = b;
567 float diff = p0->x - p1->x;
569 if (diff == 0.0f)
570 diff = p0->y - p1->y;
572 return diff == 0.0f ? 0 : (diff > 0.0f ? 1 : -1);
575 /* Determine whether a given point is inside the geometry, using the current
576 * fill mode rule. */
577 static BOOL d2d_path_geometry_point_inside(const struct d2d_geometry *geometry, const D2D1_POINT_2F *probe)
579 const D2D1_POINT_2F *p0, *p1;
580 D2D1_POINT_2F v_p, v_probe;
581 unsigned int score;
582 size_t i, j;
584 for (i = 0, score = 0; i < geometry->u.path.figure_count; ++i)
586 const struct d2d_figure *figure = &geometry->u.path.figures[i];
588 p0 = &figure->vertices[figure->vertex_count - 1];
589 for (j = 0; j < figure->vertex_count; p0 = p1, ++j)
591 p1 = &figure->vertices[j];
592 d2d_point_subtract(&v_p, p1, p0);
593 d2d_point_subtract(&v_probe, probe, p0);
595 if ((probe->y < p0->y) != (probe->y < p1->y) && v_probe.x < v_p.x * (v_probe.y / v_p.y))
597 if (geometry->u.path.fill_mode == D2D1_FILL_MODE_ALTERNATE || (probe->y < p0->y))
598 ++score;
599 else
600 --score;
605 return geometry->u.path.fill_mode == D2D1_FILL_MODE_ALTERNATE ? score & 1 : score;
608 static BOOL d2d_path_geometry_add_face(struct d2d_geometry *geometry, const struct d2d_cdt *cdt,
609 const struct d2d_cdt_edge_ref *base_edge)
611 struct d2d_cdt_edge_ref tmp;
612 struct d2d_face *face;
613 D2D1_POINT_2F probe;
615 if (cdt->edges[base_edge->idx].flags & D2D_CDT_EDGE_FLAG_VISITED(base_edge->r))
616 return TRUE;
618 if (!d2d_array_reserve((void **)&geometry->faces, &geometry->faces_size,
619 geometry->face_count + 1, sizeof(*geometry->faces)))
621 ERR("Failed to grow faces array.\n");
622 return FALSE;
625 face = &geometry->faces[geometry->face_count];
627 /* It may seem tempting to use the center of the face as probe origin, but
628 * multiplying by powers of two works much better for preserving accuracy. */
630 tmp = *base_edge;
631 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
632 face->v[0] = d2d_cdt_edge_origin(cdt, &tmp);
633 probe.x = cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.25f;
634 probe.y = cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.25f;
636 d2d_cdt_edge_next_left(cdt, &tmp, &tmp);
637 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
638 face->v[1] = d2d_cdt_edge_origin(cdt, &tmp);
639 probe.x += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.25f;
640 probe.y += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.25f;
642 d2d_cdt_edge_next_left(cdt, &tmp, &tmp);
643 cdt->edges[tmp.idx].flags |= D2D_CDT_EDGE_FLAG_VISITED(tmp.r);
644 face->v[2] = d2d_cdt_edge_origin(cdt, &tmp);
645 probe.x += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].x * 0.50f;
646 probe.y += cdt->vertices[d2d_cdt_edge_origin(cdt, &tmp)].y * 0.50f;
648 d2d_cdt_edge_next_left(cdt, &tmp, &tmp);
649 if (tmp.idx == base_edge->idx && d2d_path_geometry_point_inside(geometry, &probe))
650 ++geometry->face_count;
652 return TRUE;
655 static BOOL d2d_cdt_generate_faces(const struct d2d_cdt *cdt, struct d2d_geometry *geometry)
657 struct d2d_cdt_edge_ref base_edge;
658 size_t i;
660 for (i = 0; i < cdt->edge_count; ++i)
662 if (cdt->edges[i].flags & D2D_CDT_EDGE_FLAG_FREED)
663 continue;
665 base_edge.idx = i;
666 base_edge.r = 0;
667 if (!d2d_path_geometry_add_face(geometry, cdt, &base_edge))
668 goto fail;
669 d2d_cdt_edge_sym(&base_edge, &base_edge);
670 if (!d2d_path_geometry_add_face(geometry, cdt, &base_edge))
671 goto fail;
674 return TRUE;
676 fail:
677 HeapFree(GetProcessHeap(), 0, geometry->faces);
678 geometry->faces = NULL;
679 geometry->faces_size = 0;
680 geometry->face_count = 0;
681 return FALSE;
684 static BOOL d2d_cdt_fixup(struct d2d_cdt *cdt, const struct d2d_cdt_edge_ref *base_edge)
686 struct d2d_cdt_edge_ref candidate, next, new_base;
687 unsigned int count = 0;
689 d2d_cdt_edge_next_left(cdt, &next, base_edge);
690 if (next.idx == base_edge->idx)
692 ERR("Degenerate face.\n");
693 return FALSE;
696 candidate = next;
697 while (d2d_cdt_edge_destination(cdt, &next) != d2d_cdt_edge_origin(cdt, base_edge))
699 if (d2d_cdt_incircle(cdt, d2d_cdt_edge_origin(cdt, base_edge), d2d_cdt_edge_destination(cdt, base_edge),
700 d2d_cdt_edge_destination(cdt, &candidate), d2d_cdt_edge_destination(cdt, &next)))
701 candidate = next;
702 d2d_cdt_edge_next_left(cdt, &next, &next);
703 ++count;
706 if (count > 1)
708 if (!d2d_cdt_connect(cdt, &new_base, &candidate, base_edge))
709 return FALSE;
710 if (!d2d_cdt_fixup(cdt, &new_base))
711 return FALSE;
712 d2d_cdt_edge_sym(&new_base, &new_base);
713 if (!d2d_cdt_fixup(cdt, &new_base))
714 return FALSE;
717 return TRUE;
720 static void d2d_cdt_cut_edges(struct d2d_cdt *cdt, struct d2d_cdt_edge_ref *end_edge,
721 const struct d2d_cdt_edge_ref *base_edge, size_t start_vertex, size_t end_vertex)
723 struct d2d_cdt_edge_ref next;
725 d2d_cdt_edge_next_left(cdt, &next, base_edge);
726 if (d2d_cdt_edge_destination(cdt, &next) == end_vertex)
728 *end_edge = next;
729 return;
732 if (d2d_cdt_ccw(cdt, d2d_cdt_edge_destination(cdt, &next), end_vertex, start_vertex) > 0.0f)
733 d2d_cdt_edge_next_left(cdt, &next, &next);
735 d2d_cdt_edge_sym(&next, &next);
736 d2d_cdt_cut_edges(cdt, end_edge, &next, start_vertex, end_vertex);
737 d2d_cdt_destroy_edge(cdt, &next);
740 static BOOL d2d_cdt_insert_segment(struct d2d_cdt *cdt, struct d2d_geometry *geometry,
741 const struct d2d_cdt_edge_ref *origin, size_t end_vertex)
743 struct d2d_cdt_edge_ref base_edge, current, next, target;
745 for (current = *origin;; current = next)
747 d2d_cdt_edge_next_origin(cdt, &next, &current);
749 if (d2d_cdt_edge_destination(cdt, &current) == end_vertex)
750 return TRUE;
752 if (d2d_cdt_rightof(cdt, end_vertex, &next) && d2d_cdt_leftof(cdt, end_vertex, &current))
754 d2d_cdt_edge_next_left(cdt, &base_edge, &current);
756 d2d_cdt_edge_sym(&base_edge, &base_edge);
757 d2d_cdt_cut_edges(cdt, &target, &base_edge, d2d_cdt_edge_origin(cdt, origin), end_vertex);
758 d2d_cdt_destroy_edge(cdt, &base_edge);
760 if (!d2d_cdt_connect(cdt, &base_edge, &target, &current))
761 return FALSE;
762 if (!d2d_cdt_fixup(cdt, &base_edge))
763 return FALSE;
764 d2d_cdt_edge_sym(&base_edge, &base_edge);
765 if (!d2d_cdt_fixup(cdt, &base_edge))
766 return FALSE;
768 return TRUE;
771 if (next.idx == origin->idx)
773 ERR("Triangle not found.\n");
774 return FALSE;
779 static BOOL d2d_cdt_insert_segments(struct d2d_cdt *cdt, struct d2d_geometry *geometry)
781 size_t start_vertex, end_vertex, i, j, k;
782 const struct d2d_figure *figure;
783 struct d2d_cdt_edge_ref edge;
784 const D2D1_POINT_2F *p;
786 for (i = 0; i < geometry->u.path.figure_count; ++i)
788 figure = &geometry->u.path.figures[i];
790 p = bsearch(&figure->vertices[figure->vertex_count - 1], cdt->vertices,
791 geometry->vertex_count, sizeof(*p), d2d_cdt_compare_vertices);
792 start_vertex = p - cdt->vertices;
794 for (j = 0; j < figure->vertex_count; start_vertex = end_vertex, ++j)
796 p = bsearch(&figure->vertices[j], cdt->vertices,
797 geometry->vertex_count, sizeof(*p), d2d_cdt_compare_vertices);
798 end_vertex = p - cdt->vertices;
800 if (start_vertex == end_vertex)
801 continue;
803 for (k = 0; k < cdt->edge_count; ++k)
805 if (cdt->edges[k].flags & D2D_CDT_EDGE_FLAG_FREED)
806 continue;
808 edge.idx = k;
809 edge.r = 0;
811 if (d2d_cdt_edge_origin(cdt, &edge) == start_vertex)
813 if (!d2d_cdt_insert_segment(cdt, geometry, &edge, end_vertex))
814 return FALSE;
815 break;
817 d2d_cdt_edge_sym(&edge, &edge);
818 if (d2d_cdt_edge_origin(cdt, &edge) == start_vertex)
820 if (!d2d_cdt_insert_segment(cdt, geometry, &edge, end_vertex))
821 return FALSE;
822 break;
828 return TRUE;
831 /* Intersect the geometry's segments with themselves. This uses the
832 * straightforward approach of testing everything against everything, but
833 * there certainly exist more scalable algorithms for this. */
834 /* FIXME: Beziers can't currently self-intersect. */
835 static BOOL d2d_geometry_intersect_self(struct d2d_geometry *geometry)
837 D2D1_POINT_2F p0, p1, q0, q1, v_p, v_q, v_qp, intersection;
838 struct d2d_figure *figure_p, *figure_q;
839 size_t i, j, k, l, limit;
840 float s, t, det;
842 for (i = 0; i < geometry->u.path.figure_count; ++i)
844 figure_p = &geometry->u.path.figures[i];
845 p0 = figure_p->vertices[figure_p->vertex_count - 1];
846 for (k = 0; k < figure_p->vertex_count; p0 = p1, ++k)
848 p1 = figure_p->vertices[k];
849 d2d_point_subtract(&v_p, &p1, &p0);
850 for (j = 0; j < i || (j == i && k); ++j)
852 figure_q = &geometry->u.path.figures[j];
853 limit = j == i ? k - 1 : figure_q->vertex_count;
854 q0 = figure_q->vertices[figure_q->vertex_count - 1];
855 for (l = 0; l < limit; q0 = q1, ++l)
857 q1 = figure_q->vertices[l];
858 d2d_point_subtract(&v_q, &q1, &q0);
859 d2d_point_subtract(&v_qp, &p0, &q0);
861 det = v_p.x * v_q.y - v_p.y * v_q.x;
862 if (det == 0.0f)
863 continue;
865 s = (v_q.x * v_qp.y - v_q.y * v_qp.x) / det;
866 t = (v_p.x * v_qp.y - v_p.y * v_qp.x) / det;
868 if (s < 0.0f || s > 1.0f || t < 0.0f || t > 1.0f)
869 continue;
871 intersection.x = p0.x + v_p.x * s;
872 intersection.y = p0.y + v_p.y * s;
874 if (t > 0.0f && t < 1.0f)
876 if (!d2d_figure_insert_vertex(figure_q, l, intersection))
877 return FALSE;
878 if (j == i)
879 ++k;
880 ++limit;
881 ++l;
884 if (s > 0.0f && s < 1.0f)
886 if (!d2d_figure_insert_vertex(figure_p, k, intersection))
887 return FALSE;
888 p1 = intersection;
889 d2d_point_subtract(&v_p, &p1, &p0);
896 return TRUE;
899 static HRESULT d2d_path_geometry_triangulate(struct d2d_geometry *geometry)
901 struct d2d_cdt_edge_ref left_edge, right_edge;
902 size_t vertex_count, i, j;
903 struct d2d_cdt cdt = {0};
904 D2D1_POINT_2F *vertices;
906 for (i = 0, vertex_count = 0; i < geometry->u.path.figure_count; ++i)
908 vertex_count += geometry->u.path.figures[i].vertex_count;
911 if (vertex_count < 3)
913 WARN("Geometry has %lu vertices.\n", (long)vertex_count);
914 return S_OK;
917 if (!(vertices = HeapAlloc(GetProcessHeap(), 0, vertex_count * sizeof(*vertices))))
918 return E_OUTOFMEMORY;
920 for (i = 0, j = 0; i < geometry->u.path.figure_count; ++i)
922 memcpy(&vertices[j], geometry->u.path.figures[i].vertices,
923 geometry->u.path.figures[i].vertex_count * sizeof(*vertices));
924 j += geometry->u.path.figures[i].vertex_count;
927 /* Sort vertices, eliminate duplicates. */
928 qsort(vertices, vertex_count, sizeof(*vertices), d2d_cdt_compare_vertices);
929 for (i = 1; i < vertex_count; ++i)
931 if (!memcmp(&vertices[i - 1], &vertices[i], sizeof(*vertices)))
933 --vertex_count;
934 memmove(&vertices[i], &vertices[i + 1], (vertex_count - i) * sizeof(*vertices));
935 --i;
939 geometry->vertices = vertices;
940 geometry->vertex_count = vertex_count;
942 cdt.free_edge = ~0u;
943 cdt.vertices = vertices;
944 if (!d2d_cdt_triangulate(&cdt, 0, vertex_count, &left_edge, &right_edge))
945 goto fail;
946 if (!d2d_cdt_insert_segments(&cdt, geometry))
947 goto fail;
948 if (!d2d_cdt_generate_faces(&cdt, geometry))
949 goto fail;
951 HeapFree(GetProcessHeap(), 0, cdt.edges);
952 return S_OK;
954 fail:
955 geometry->vertices = NULL;
956 geometry->vertex_count = 0;
957 HeapFree(GetProcessHeap(), 0, vertices);
958 HeapFree(GetProcessHeap(), 0, cdt.edges);
959 return E_FAIL;
962 static BOOL d2d_path_geometry_add_figure(struct d2d_geometry *geometry)
964 struct d2d_figure *figure;
966 if (!d2d_array_reserve((void **)&geometry->u.path.figures, &geometry->u.path.figures_size,
967 geometry->u.path.figure_count + 1, sizeof(*geometry->u.path.figures)))
969 ERR("Failed to grow figures array.\n");
970 return FALSE;
973 figure = &geometry->u.path.figures[geometry->u.path.figure_count];
974 memset(figure, 0, sizeof(*figure));
976 ++geometry->u.path.figure_count;
977 return TRUE;
980 static void d2d_geometry_destroy(struct d2d_geometry *geometry)
982 HeapFree(GetProcessHeap(), 0, geometry->beziers);
983 HeapFree(GetProcessHeap(), 0, geometry->faces);
984 HeapFree(GetProcessHeap(), 0, geometry->vertices);
985 ID2D1Factory_Release(geometry->factory);
986 HeapFree(GetProcessHeap(), 0, geometry);
989 static void d2d_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory,
990 const struct ID2D1GeometryVtbl *vtbl)
992 geometry->ID2D1Geometry_iface.lpVtbl = vtbl;
993 geometry->refcount = 1;
994 ID2D1Factory_AddRef(geometry->factory = factory);
997 static inline struct d2d_geometry *impl_from_ID2D1GeometrySink(ID2D1GeometrySink *iface)
999 return CONTAINING_RECORD(iface, struct d2d_geometry, u.path.ID2D1GeometrySink_iface);
1002 static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_QueryInterface(ID2D1GeometrySink *iface, REFIID iid, void **out)
1004 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
1006 if (IsEqualGUID(iid, &IID_ID2D1GeometrySink)
1007 || IsEqualGUID(iid, &IID_ID2D1SimplifiedGeometrySink)
1008 || IsEqualGUID(iid, &IID_IUnknown))
1010 ID2D1GeometrySink_AddRef(iface);
1011 *out = iface;
1012 return S_OK;
1015 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
1017 *out = NULL;
1018 return E_NOINTERFACE;
1021 static ULONG STDMETHODCALLTYPE d2d_geometry_sink_AddRef(ID2D1GeometrySink *iface)
1023 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1025 TRACE("iface %p.\n", iface);
1027 return ID2D1Geometry_AddRef(&geometry->ID2D1Geometry_iface);
1030 static ULONG STDMETHODCALLTYPE d2d_geometry_sink_Release(ID2D1GeometrySink *iface)
1032 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1034 TRACE("iface %p.\n", iface);
1036 return ID2D1Geometry_Release(&geometry->ID2D1Geometry_iface);
1039 static void STDMETHODCALLTYPE d2d_geometry_sink_SetFillMode(ID2D1GeometrySink *iface, D2D1_FILL_MODE mode)
1041 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1043 TRACE("iface %p, mode %#x.\n", iface, mode);
1045 geometry->u.path.fill_mode = mode;
1048 static void STDMETHODCALLTYPE d2d_geometry_sink_SetSegmentFlags(ID2D1GeometrySink *iface, D2D1_PATH_SEGMENT flags)
1050 FIXME("iface %p, flags %#x stub!\n", iface, flags);
1053 static void STDMETHODCALLTYPE d2d_geometry_sink_BeginFigure(ID2D1GeometrySink *iface,
1054 D2D1_POINT_2F start_point, D2D1_FIGURE_BEGIN figure_begin)
1056 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1058 TRACE("iface %p, start_point {%.8e, %.8e}, figure_begin %#x.\n",
1059 iface, start_point.x, start_point.y, figure_begin);
1061 if (geometry->u.path.state != D2D_GEOMETRY_STATE_OPEN)
1063 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1064 return;
1067 if (figure_begin != D2D1_FIGURE_BEGIN_FILLED)
1068 FIXME("Ignoring figure_begin %#x.\n", figure_begin);
1070 if (!d2d_path_geometry_add_figure(geometry))
1072 ERR("Failed to add figure.\n");
1073 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1074 return;
1077 if (!d2d_figure_add_vertex(&geometry->u.path.figures[geometry->u.path.figure_count - 1], start_point))
1078 ERR("Failed to add vertex.\n");
1080 geometry->u.path.state = D2D_GEOMETRY_STATE_FIGURE;
1081 ++geometry->u.path.segment_count;
1084 static void STDMETHODCALLTYPE d2d_geometry_sink_AddLines(ID2D1GeometrySink *iface,
1085 const D2D1_POINT_2F *points, UINT32 count)
1087 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1088 unsigned int i;
1090 TRACE("iface %p, points %p, count %u.\n", iface, points, count);
1092 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
1094 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1095 return;
1098 for (i = 0; i < count; ++i)
1100 if (!d2d_figure_add_vertex(&geometry->u.path.figures[geometry->u.path.figure_count - 1], points[i]))
1102 ERR("Failed to add vertex.\n");
1103 return;
1107 geometry->u.path.segment_count += count;
1110 static void STDMETHODCALLTYPE d2d_geometry_sink_AddBeziers(ID2D1GeometrySink *iface,
1111 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
1113 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1114 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
1115 D2D1_POINT_2F p;
1116 unsigned int i;
1118 TRACE("iface %p, beziers %p, count %u.\n", iface, beziers, count);
1120 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
1122 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1123 return;
1126 for (i = 0; i < count; ++i)
1128 /* FIXME: This tries to approximate a cubic bezier with a quadratic one. */
1129 p.x = (beziers[i].point1.x + beziers[i].point2.x) * 0.75f;
1130 p.y = (beziers[i].point1.y + beziers[i].point2.y) * 0.75f;
1131 p.x -= (figure->vertices[figure->vertex_count - 1].x + beziers[i].point3.x) * 0.25f;
1132 p.y -= (figure->vertices[figure->vertex_count - 1].y + beziers[i].point3.y) * 0.25f;
1133 if (!d2d_figure_add_bezier(figure, figure->vertices[figure->vertex_count - 1], p, beziers[i].point3))
1135 ERR("Failed to add bezier.\n");
1136 return;
1140 geometry->u.path.segment_count += count;
1143 static void STDMETHODCALLTYPE d2d_geometry_sink_EndFigure(ID2D1GeometrySink *iface, D2D1_FIGURE_END figure_end)
1145 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1147 TRACE("iface %p, figure_end %#x.\n", iface, figure_end);
1149 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
1151 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1152 return;
1155 if (figure_end != D2D1_FIGURE_END_CLOSED)
1156 FIXME("Ignoring figure_end %#x.\n", figure_end);
1158 geometry->u.path.state = D2D_GEOMETRY_STATE_OPEN;
1161 static void d2d_path_geometry_free_figures(struct d2d_geometry *geometry)
1163 size_t i;
1165 if (!geometry->u.path.figures)
1166 return;
1168 for (i = 0; i < geometry->u.path.figure_count; ++i)
1170 HeapFree(GetProcessHeap(), 0, geometry->u.path.figures[i].beziers);
1171 HeapFree(GetProcessHeap(), 0, geometry->u.path.figures[i].vertices);
1173 HeapFree(GetProcessHeap(), 0, geometry->u.path.figures);
1174 geometry->u.path.figures = NULL;
1175 geometry->u.path.figures_size = 0;
1178 static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_Close(ID2D1GeometrySink *iface)
1180 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1181 HRESULT hr = E_FAIL;
1182 size_t i, start;
1184 TRACE("iface %p.\n", iface);
1186 if (geometry->u.path.state != D2D_GEOMETRY_STATE_OPEN)
1188 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
1189 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1190 return D2DERR_WRONG_STATE;
1192 geometry->u.path.state = D2D_GEOMETRY_STATE_CLOSED;
1194 if (!d2d_geometry_intersect_self(geometry))
1195 goto done;
1196 if (FAILED(hr = d2d_path_geometry_triangulate(geometry)))
1197 goto done;
1199 for (i = 0; i < geometry->u.path.figure_count; ++i)
1201 geometry->bezier_count += geometry->u.path.figures[i].bezier_count;
1204 if (!(geometry->beziers = HeapAlloc(GetProcessHeap(), 0,
1205 geometry->bezier_count * sizeof(*geometry->beziers))))
1207 ERR("Failed to allocate beziers array.\n");
1208 geometry->bezier_count = 0;
1209 hr = E_OUTOFMEMORY;
1210 goto done;
1213 for (i = 0, start = 0; i < geometry->u.path.figure_count; ++i)
1215 struct d2d_figure *figure = &geometry->u.path.figures[i];
1216 if (figure->bezier_count)
1218 memcpy(&geometry->beziers[start], figure->beziers,
1219 figure->bezier_count * sizeof(*figure->beziers));
1220 start += figure->bezier_count;
1224 done:
1225 d2d_path_geometry_free_figures(geometry);
1226 if (FAILED(hr))
1227 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1228 return hr;
1231 static void STDMETHODCALLTYPE d2d_geometry_sink_AddLine(ID2D1GeometrySink *iface, D2D1_POINT_2F point)
1233 TRACE("iface %p, point {%.8e, %.8e}.\n", iface, point.x, point.y);
1235 d2d_geometry_sink_AddLines(iface, &point, 1);
1238 static void STDMETHODCALLTYPE d2d_geometry_sink_AddBezier(ID2D1GeometrySink *iface, const D2D1_BEZIER_SEGMENT *bezier)
1240 TRACE("iface %p, bezier %p.\n", iface, bezier);
1242 d2d_geometry_sink_AddBeziers(iface, bezier, 1);
1245 static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBezier(ID2D1GeometrySink *iface,
1246 const D2D1_QUADRATIC_BEZIER_SEGMENT *bezier)
1248 TRACE("iface %p, bezier %p.\n", iface, bezier);
1250 ID2D1GeometrySink_AddQuadraticBeziers(iface, bezier, 1);
1253 static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBeziers(ID2D1GeometrySink *iface,
1254 const D2D1_QUADRATIC_BEZIER_SEGMENT *beziers, UINT32 bezier_count)
1256 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1257 struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
1258 unsigned int i;
1260 TRACE("iface %p, beziers %p, bezier_count %u.\n", iface, beziers, bezier_count);
1262 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
1264 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1265 return;
1268 for (i = 0; i < bezier_count; ++i)
1270 if (!d2d_figure_add_bezier(figure, figure->vertices[figure->vertex_count - 1],
1271 beziers[i].point1, beziers[i].point2))
1273 ERR("Failed to add bezier.\n");
1274 return;
1278 geometry->u.path.segment_count += bezier_count;
1281 static void STDMETHODCALLTYPE d2d_geometry_sink_AddArc(ID2D1GeometrySink *iface, const D2D1_ARC_SEGMENT *arc)
1283 struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
1285 FIXME("iface %p, arc %p stub!\n", iface, arc);
1287 if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
1289 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1290 return;
1293 if (!d2d_figure_add_vertex(&geometry->u.path.figures[geometry->u.path.figure_count - 1], arc->point))
1295 ERR("Failed to add vertex.\n");
1296 return;
1299 ++geometry->u.path.segment_count;
1302 struct ID2D1GeometrySinkVtbl d2d_geometry_sink_vtbl =
1304 d2d_geometry_sink_QueryInterface,
1305 d2d_geometry_sink_AddRef,
1306 d2d_geometry_sink_Release,
1307 d2d_geometry_sink_SetFillMode,
1308 d2d_geometry_sink_SetSegmentFlags,
1309 d2d_geometry_sink_BeginFigure,
1310 d2d_geometry_sink_AddLines,
1311 d2d_geometry_sink_AddBeziers,
1312 d2d_geometry_sink_EndFigure,
1313 d2d_geometry_sink_Close,
1314 d2d_geometry_sink_AddLine,
1315 d2d_geometry_sink_AddBezier,
1316 d2d_geometry_sink_AddQuadraticBezier,
1317 d2d_geometry_sink_AddQuadraticBeziers,
1318 d2d_geometry_sink_AddArc,
1321 static inline struct d2d_geometry *impl_from_ID2D1PathGeometry(ID2D1PathGeometry *iface)
1323 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
1326 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_QueryInterface(ID2D1PathGeometry *iface, REFIID iid, void **out)
1328 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
1330 if (IsEqualGUID(iid, &IID_ID2D1PathGeometry)
1331 || IsEqualGUID(iid, &IID_ID2D1Geometry)
1332 || IsEqualGUID(iid, &IID_ID2D1Resource)
1333 || IsEqualGUID(iid, &IID_IUnknown))
1335 ID2D1PathGeometry_AddRef(iface);
1336 *out = iface;
1337 return S_OK;
1340 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
1342 *out = NULL;
1343 return E_NOINTERFACE;
1346 static ULONG STDMETHODCALLTYPE d2d_path_geometry_AddRef(ID2D1PathGeometry *iface)
1348 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
1349 ULONG refcount = InterlockedIncrement(&geometry->refcount);
1351 TRACE("%p increasing refcount to %u.\n", iface, refcount);
1353 return refcount;
1356 static ULONG STDMETHODCALLTYPE d2d_path_geometry_Release(ID2D1PathGeometry *iface)
1358 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
1359 ULONG refcount = InterlockedDecrement(&geometry->refcount);
1361 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
1363 if (!refcount)
1365 d2d_path_geometry_free_figures(geometry);
1366 d2d_geometry_destroy(geometry);
1369 return refcount;
1372 static void STDMETHODCALLTYPE d2d_path_geometry_GetFactory(ID2D1PathGeometry *iface, ID2D1Factory **factory)
1374 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
1376 TRACE("iface %p, factory %p.\n", iface, factory);
1378 ID2D1Factory_AddRef(*factory = geometry->factory);
1381 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetBounds(ID2D1PathGeometry *iface,
1382 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
1384 FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
1386 return E_NOTIMPL;
1389 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetWidenedBounds(ID2D1PathGeometry *iface, float stroke_width,
1390 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_RECT_F *bounds)
1392 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
1393 iface, stroke_width, stroke_style, transform, tolerance, bounds);
1395 return E_NOTIMPL;
1398 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_StrokeContainsPoint(ID2D1PathGeometry *iface,
1399 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
1400 float tolerance, BOOL *contains)
1402 FIXME("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
1403 "transform %p, tolerance %.8e, contains %p stub!\n",
1404 iface, point.x, point.y, stroke_width, stroke_style, transform, tolerance, contains);
1406 return E_NOTIMPL;
1409 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_FillContainsPoint(ID2D1PathGeometry *iface,
1410 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
1412 FIXME("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p stub!\n",
1413 iface, point.x, point.y, transform, tolerance, contains);
1415 return E_NOTIMPL;
1418 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_CompareWithGeometry(ID2D1PathGeometry *iface,
1419 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
1421 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
1422 iface, geometry, transform, tolerance, relation);
1424 return E_NOTIMPL;
1427 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *iface,
1428 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
1429 ID2D1SimplifiedGeometrySink *sink)
1431 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
1432 iface, option, transform, tolerance, sink);
1434 return E_NOTIMPL;
1437 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Tessellate(ID2D1PathGeometry *iface,
1438 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
1440 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
1442 return E_NOTIMPL;
1445 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_CombineWithGeometry(ID2D1PathGeometry *iface,
1446 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
1447 float tolerance, ID2D1SimplifiedGeometrySink *sink)
1449 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
1450 iface, geometry, combine_mode, transform, tolerance, sink);
1452 return E_NOTIMPL;
1455 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Outline(ID2D1PathGeometry *iface,
1456 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
1458 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
1460 return E_NOTIMPL;
1463 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeArea(ID2D1PathGeometry *iface,
1464 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
1466 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
1468 return E_NOTIMPL;
1471 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeLength(ID2D1PathGeometry *iface,
1472 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
1474 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
1476 return E_NOTIMPL;
1479 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputePointAtLength(ID2D1PathGeometry *iface, float length,
1480 const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point, D2D1_POINT_2F *tangent)
1482 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
1483 iface, length, transform, tolerance, point, tangent);
1485 return E_NOTIMPL;
1488 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Widen(ID2D1PathGeometry *iface, float stroke_width,
1489 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
1490 ID2D1SimplifiedGeometrySink *sink)
1492 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
1493 iface, stroke_width, stroke_style, transform, tolerance, sink);
1495 return E_NOTIMPL;
1498 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Open(ID2D1PathGeometry *iface, ID2D1GeometrySink **sink)
1500 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
1502 TRACE("iface %p, sink %p.\n", iface, sink);
1504 if (geometry->u.path.state != D2D_GEOMETRY_STATE_INITIAL)
1505 return D2DERR_WRONG_STATE;
1507 *sink = &geometry->u.path.ID2D1GeometrySink_iface;
1508 ID2D1GeometrySink_AddRef(*sink);
1510 geometry->u.path.state = D2D_GEOMETRY_STATE_OPEN;
1512 return S_OK;
1515 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Stream(ID2D1PathGeometry *iface, ID2D1GeometrySink *sink)
1517 FIXME("iface %p, sink %p stub!\n", iface, sink);
1519 return E_NOTIMPL;
1522 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetSegmentCount(ID2D1PathGeometry *iface, UINT32 *count)
1524 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
1526 TRACE("iface %p, count %p.\n", iface, count);
1528 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
1529 return D2DERR_WRONG_STATE;
1531 *count = geometry->u.path.segment_count;
1533 return S_OK;
1536 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetFigureCount(ID2D1PathGeometry *iface, UINT32 *count)
1538 struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
1540 TRACE("iface %p, count %p.\n", iface, count);
1542 if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
1543 return D2DERR_WRONG_STATE;
1545 *count = geometry->u.path.figure_count;
1547 return S_OK;
1550 static const struct ID2D1PathGeometryVtbl d2d_path_geometry_vtbl =
1552 d2d_path_geometry_QueryInterface,
1553 d2d_path_geometry_AddRef,
1554 d2d_path_geometry_Release,
1555 d2d_path_geometry_GetFactory,
1556 d2d_path_geometry_GetBounds,
1557 d2d_path_geometry_GetWidenedBounds,
1558 d2d_path_geometry_StrokeContainsPoint,
1559 d2d_path_geometry_FillContainsPoint,
1560 d2d_path_geometry_CompareWithGeometry,
1561 d2d_path_geometry_Simplify,
1562 d2d_path_geometry_Tessellate,
1563 d2d_path_geometry_CombineWithGeometry,
1564 d2d_path_geometry_Outline,
1565 d2d_path_geometry_ComputeArea,
1566 d2d_path_geometry_ComputeLength,
1567 d2d_path_geometry_ComputePointAtLength,
1568 d2d_path_geometry_Widen,
1569 d2d_path_geometry_Open,
1570 d2d_path_geometry_Stream,
1571 d2d_path_geometry_GetSegmentCount,
1572 d2d_path_geometry_GetFigureCount,
1575 void d2d_path_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory)
1577 d2d_geometry_init(geometry, factory, (ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl);
1578 geometry->u.path.ID2D1GeometrySink_iface.lpVtbl = &d2d_geometry_sink_vtbl;
1581 static inline struct d2d_geometry *impl_from_ID2D1RectangleGeometry(ID2D1RectangleGeometry *iface)
1583 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);
1586 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_QueryInterface(ID2D1RectangleGeometry *iface,
1587 REFIID iid, void **out)
1589 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
1591 if (IsEqualGUID(iid, &IID_ID2D1RectangleGeometry)
1592 || IsEqualGUID(iid, &IID_ID2D1Geometry)
1593 || IsEqualGUID(iid, &IID_ID2D1Resource)
1594 || IsEqualGUID(iid, &IID_IUnknown))
1596 ID2D1RectangleGeometry_AddRef(iface);
1597 *out = iface;
1598 return S_OK;
1601 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
1603 *out = NULL;
1604 return E_NOINTERFACE;
1607 static ULONG STDMETHODCALLTYPE d2d_rectangle_geometry_AddRef(ID2D1RectangleGeometry *iface)
1609 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
1610 ULONG refcount = InterlockedIncrement(&geometry->refcount);
1612 TRACE("%p increasing refcount to %u.\n", iface, refcount);
1614 return refcount;
1617 static ULONG STDMETHODCALLTYPE d2d_rectangle_geometry_Release(ID2D1RectangleGeometry *iface)
1619 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
1620 ULONG refcount = InterlockedDecrement(&geometry->refcount);
1622 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
1624 if (!refcount)
1625 d2d_geometry_destroy(geometry);
1627 return refcount;
1630 static void STDMETHODCALLTYPE d2d_rectangle_geometry_GetFactory(ID2D1RectangleGeometry *iface, ID2D1Factory **factory)
1632 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
1634 TRACE("iface %p, factory %p.\n", iface, factory);
1636 ID2D1Factory_AddRef(*factory = geometry->factory);
1639 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_GetBounds(ID2D1RectangleGeometry *iface,
1640 const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
1642 FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
1644 return E_NOTIMPL;
1647 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_GetWidenedBounds(ID2D1RectangleGeometry *iface,
1648 float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
1649 float tolerance, D2D1_RECT_F *bounds)
1651 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, bounds %p stub!\n",
1652 iface, stroke_width, stroke_style, transform, tolerance, bounds);
1654 return E_NOTIMPL;
1657 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_StrokeContainsPoint(ID2D1RectangleGeometry *iface,
1658 D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
1659 float tolerance, BOOL *contains)
1661 FIXME("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
1662 "transform %p, tolerance %.8e, contains %p stub!\n",
1663 iface, point.x, point.y, stroke_width, stroke_style, transform, tolerance, contains);
1665 return E_NOTIMPL;
1668 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_FillContainsPoint(ID2D1RectangleGeometry *iface,
1669 D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
1671 FIXME("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p stub!\n",
1672 iface, point.x, point.y, transform, tolerance, contains);
1674 return E_NOTIMPL;
1677 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_CompareWithGeometry(ID2D1RectangleGeometry *iface,
1678 ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_GEOMETRY_RELATION *relation)
1680 FIXME("iface %p, geometry %p, transform %p, tolerance %.8e, relation %p stub!\n",
1681 iface, geometry, transform, tolerance, relation);
1683 return E_NOTIMPL;
1686 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Simplify(ID2D1RectangleGeometry *iface,
1687 D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
1688 ID2D1SimplifiedGeometrySink *sink)
1690 FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
1691 iface, option, transform, tolerance, sink);
1693 return E_NOTIMPL;
1696 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Tessellate(ID2D1RectangleGeometry *iface,
1697 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink)
1699 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
1701 return E_NOTIMPL;
1704 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_CombineWithGeometry(ID2D1RectangleGeometry *iface,
1705 ID2D1Geometry *geometry, D2D1_COMBINE_MODE combine_mode, const D2D1_MATRIX_3X2_F *transform,
1706 float tolerance, ID2D1SimplifiedGeometrySink *sink)
1708 FIXME("iface %p, geometry %p, combine_mode %#x, transform %p, tolerance %.8e, sink %p stub!\n",
1709 iface, geometry, combine_mode, transform, tolerance, sink);
1711 return E_NOTIMPL;
1714 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Outline(ID2D1RectangleGeometry *iface,
1715 const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1SimplifiedGeometrySink *sink)
1717 FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink);
1719 return E_NOTIMPL;
1722 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputeArea(ID2D1RectangleGeometry *iface,
1723 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area)
1725 FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area);
1727 return E_NOTIMPL;
1730 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputeLength(ID2D1RectangleGeometry *iface,
1731 const D2D1_MATRIX_3X2_F *transform, float tolerance, float *length)
1733 FIXME("iface %p, transform %p, tolerance %.8e, length %p stub!\n", iface, transform, tolerance, length);
1735 return E_NOTIMPL;
1738 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputePointAtLength(ID2D1RectangleGeometry *iface,
1739 float length, const D2D1_MATRIX_3X2_F *transform, float tolerance, D2D1_POINT_2F *point,
1740 D2D1_POINT_2F *tangent)
1742 FIXME("iface %p, length %.8e, transform %p, tolerance %.8e, point %p, tangent %p stub!\n",
1743 iface, length, transform, tolerance, point, tangent);
1745 return E_NOTIMPL;
1748 static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Widen(ID2D1RectangleGeometry *iface, float stroke_width,
1749 ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform, float tolerance,
1750 ID2D1SimplifiedGeometrySink *sink)
1752 FIXME("iface %p, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, sink %p stub!\n",
1753 iface, stroke_width, stroke_style, transform, tolerance, sink);
1755 return E_NOTIMPL;
1758 static void STDMETHODCALLTYPE d2d_rectangle_geometry_GetRect(ID2D1RectangleGeometry *iface, D2D1_RECT_F *rect)
1760 struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
1762 TRACE("iface %p, rect %p.\n", iface, rect);
1764 *rect = geometry->u.rectangle.rect;
1767 static const struct ID2D1RectangleGeometryVtbl d2d_rectangle_geometry_vtbl =
1769 d2d_rectangle_geometry_QueryInterface,
1770 d2d_rectangle_geometry_AddRef,
1771 d2d_rectangle_geometry_Release,
1772 d2d_rectangle_geometry_GetFactory,
1773 d2d_rectangle_geometry_GetBounds,
1774 d2d_rectangle_geometry_GetWidenedBounds,
1775 d2d_rectangle_geometry_StrokeContainsPoint,
1776 d2d_rectangle_geometry_FillContainsPoint,
1777 d2d_rectangle_geometry_CompareWithGeometry,
1778 d2d_rectangle_geometry_Simplify,
1779 d2d_rectangle_geometry_Tessellate,
1780 d2d_rectangle_geometry_CombineWithGeometry,
1781 d2d_rectangle_geometry_Outline,
1782 d2d_rectangle_geometry_ComputeArea,
1783 d2d_rectangle_geometry_ComputeLength,
1784 d2d_rectangle_geometry_ComputePointAtLength,
1785 d2d_rectangle_geometry_Widen,
1786 d2d_rectangle_geometry_GetRect,
1789 HRESULT d2d_rectangle_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_RECT_F *rect)
1791 d2d_geometry_init(geometry, factory, (ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl);
1792 geometry->u.rectangle.rect = *rect;
1794 if (!(geometry->vertices = HeapAlloc(GetProcessHeap(), 0, 4 * sizeof(*geometry->vertices))))
1795 return E_OUTOFMEMORY;
1796 geometry->vertex_count = 4;
1797 if (!d2d_array_reserve((void **)&geometry->faces, &geometry->faces_size, 2, sizeof(*geometry->faces)))
1799 HeapFree(GetProcessHeap(), 0, geometry->vertices);
1800 return E_OUTOFMEMORY;
1802 geometry->face_count = 2;
1804 geometry->vertices[0].x = min(rect->left, rect->right);
1805 geometry->vertices[0].y = min(rect->top, rect->bottom);
1806 geometry->vertices[1].x = min(rect->left, rect->right);
1807 geometry->vertices[1].y = max(rect->top, rect->bottom);
1808 geometry->vertices[2].x = max(rect->left, rect->right);
1809 geometry->vertices[2].y = min(rect->top, rect->bottom);
1810 geometry->vertices[3].x = max(rect->left, rect->right);
1811 geometry->vertices[3].y = max(rect->top, rect->bottom);
1813 geometry->faces[0].v[0] = 0;
1814 geometry->faces[0].v[1] = 2;
1815 geometry->faces[0].v[2] = 1;
1816 geometry->faces[1].v[0] = 1;
1817 geometry->faces[1].v[1] = 2;
1818 geometry->faces[1].v[2] = 3;
1820 return S_OK;
1823 struct d2d_geometry *unsafe_impl_from_ID2D1Geometry(ID2D1Geometry *iface)
1825 if (!iface)
1826 return NULL;
1827 assert(iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl
1828 || iface->lpVtbl == (const ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl);
1829 return CONTAINING_RECORD(iface, struct d2d_geometry, ID2D1Geometry_iface);