d2d1: Implement d2d_factory_CreateTransformedGeometry().
[wine.git] / dlls / d2d1 / geometry.c
blob41af05a0aeeb00712903248ceef77c76436a3d73
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 static const D2D1_MATRIX_3X2_F identity =
31 1.0f, 0.0f,
32 0.0f, 1.0f,
33 0.0f, 0.0f,
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,
44 struct d2d_figure
46 D2D1_POINT_2F *vertices;
47 size_t vertices_size;
48 size_t vertex_count;
50 struct d2d_bezier *beziers;
51 size_t beziers_size;
52 size_t bezier_count;
55 struct d2d_cdt_edge_ref
57 size_t idx;
58 enum d2d_cdt_edge_next r;
61 struct d2d_cdt_edge
63 struct d2d_cdt_edge_ref next[4];
64 size_t vertex[2];
65 unsigned int flags;
68 struct d2d_cdt
70 struct d2d_cdt_edge *edges;
71 size_t edges_size;
72 size_t edge_count;
73 size_t free_edge;
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)
81 out->x = a->x - b->x;
82 out->y = a->y - b->y;
85 static float d2d_point_ccw(const D2D1_POINT_2F *a, const D2D1_POINT_2F *b, const D2D1_POINT_2F *c)
87 D2D1_POINT_2F ab, ac;
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;
98 void *new_elements;
100 if (element_count <= *capacity)
101 return TRUE;
103 max_capacity = ~(size_t)0 / element_size;
104 if (max_capacity < element_count)
105 return FALSE;
107 new_capacity = max(*capacity, 4);
108 while (new_capacity < element_count && new_capacity <= max_capacity / 2)
109 new_capacity *= 2;
111 if (new_capacity < element_count)
112 new_capacity = max_capacity;
114 if (*elements)
115 new_elements = HeapReAlloc(GetProcessHeap(), 0, *elements, new_capacity * element_size);
116 else
117 new_elements = HeapAlloc(GetProcessHeap(), 0, new_capacity * element_size);
119 if (!new_elements)
120 return FALSE;
122 *elements = new_elements;
123 *capacity = new_capacity;
124 return TRUE;
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");
133 return FALSE;
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;
140 return TRUE;
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");
149 return FALSE;
152 figure->vertices[figure->vertex_count] = vertex;
153 ++figure->vertex_count;
154 return TRUE;
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;
162 float sign;
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");
168 return FALSE;
171 if (d2d_point_ccw(&p0, &p1, &p2) > 0.0f)
173 sign = -1.0f;
174 idx1 = 1;
175 idx2 = 2;
177 else
179 sign = 1.0f;
180 idx1 = 2;
181 idx2 = 1;
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))
200 return FALSE;
201 if (!d2d_figure_add_vertex(figure, p2))
202 return FALSE;
203 return TRUE;
206 static void d2d_cdt_edge_rot(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
208 dst->idx = src->idx;
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)
214 dst->idx = src->idx;
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)
220 dst->idx = src->idx;
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
285 * |λ(A) 1|
286 * |λ(B) 1| > 0
287 * |λ(C) 1|
288 * |λ(D) 1|
290 * After translating D to the origin, that becomes:
292 * |λ(A-D)|
293 * |λ(B-D)| > 0
294 * |λ(C-D)| */
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;
298 const struct
300 double x, y;
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;
339 else
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");
344 return FALSE;
346 e->idx = cdt->edge_count++;
348 e->r = 0;
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);
355 edge->flags = 0;
357 return TRUE;
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))
391 return FALSE;
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);
399 return TRUE;
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. */
409 for (;;)
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);
420 else
422 break;
426 d2d_cdt_edge_sym(&tmp, right_inner);
427 if (!d2d_cdt_connect(cdt, &base_edge, &tmp, left_inner))
428 return FALSE;
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;
434 for (;;)
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)
474 break;
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))
482 return FALSE;
484 else
486 if (!d2d_cdt_connect(cdt, &base_edge, &sym_base_edge, &left_candidate))
487 return FALSE;
491 return TRUE;
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;
501 size_t cut;
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))
509 return FALSE;
510 d2d_cdt_edge_set_origin(cdt, &a, start_vertex);
511 d2d_cdt_edge_set_destination(cdt, &a, start_vertex + 1);
513 *left_edge = a;
514 d2d_cdt_edge_sym(right_edge, &a);
516 return TRUE;
519 /* Three vertices, create a triangle. */
520 if (vertex_count == 3)
522 struct d2d_cdt_edge_ref a, b, c;
523 float det;
525 if (!d2d_cdt_create_edge(cdt, &a))
526 return FALSE;
527 if (!d2d_cdt_create_edge(cdt, &b))
528 return FALSE;
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))
539 return FALSE;
541 if (det < 0.0f)
543 d2d_cdt_edge_sym(left_edge, &c);
544 *right_edge = c;
546 else
548 *left_edge = a;
549 d2d_cdt_edge_sym(right_edge, &b);
552 return TRUE;
555 /* More than tree vertices, divide. */
556 cut = vertex_count / 2;
557 if (!d2d_cdt_triangulate(cdt, start_vertex, cut, &left_outer, &left_inner))
558 return FALSE;
559 if (!d2d_cdt_triangulate(cdt, start_vertex + cut, vertex_count - cut, &right_inner, &right_outer))
560 return FALSE;
561 /* Merge the left and right parts. */
562 if (!d2d_cdt_merge(cdt, &left_outer, &left_inner, &right_inner, &right_outer))
563 return FALSE;
565 *left_edge = left_outer;
566 *right_edge = right_outer;
567 return TRUE;
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;
576 if (diff == 0.0f)
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
583 * fill mode rule. */
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;
588 unsigned int score;
589 size_t i, j;
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))
605 ++score;
606 else
607 --score;
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;
620 D2D1_POINT_2F probe;
622 if (cdt->edges[base_edge->idx].flags & D2D_CDT_EDGE_FLAG_VISITED(base_edge->r))
623 return TRUE;
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");
629 return FALSE;
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. */
637 tmp = *base_edge;
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;
659 return TRUE;
662 static BOOL d2d_cdt_generate_faces(const struct d2d_cdt *cdt, struct d2d_geometry *geometry)
664 struct d2d_cdt_edge_ref base_edge;
665 size_t i;
667 for (i = 0; i < cdt->edge_count; ++i)
669 if (cdt->edges[i].flags & D2D_CDT_EDGE_FLAG_FREED)
670 continue;
672 base_edge.idx = i;
673 base_edge.r = 0;
674 if (!d2d_path_geometry_add_face(geometry, cdt, &base_edge))
675 goto fail;
676 d2d_cdt_edge_sym(&base_edge, &base_edge);
677 if (!d2d_path_geometry_add_face(geometry, cdt, &base_edge))
678 goto fail;
681 return TRUE;
683 fail:
684 HeapFree(GetProcessHeap(), 0, geometry->faces);
685 geometry->faces = NULL;
686 geometry->faces_size = 0;
687 geometry->face_count = 0;
688 return FALSE;
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");
700 return FALSE;
703 candidate = next;
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)))
708 candidate = next;
709 d2d_cdt_edge_next_left(cdt, &next, &next);
710 ++count;
713 if (count > 1)
715 if (!d2d_cdt_connect(cdt, &new_base, &candidate, base_edge))
716 return FALSE;
717 if (!d2d_cdt_fixup(cdt, &new_base))
718 return FALSE;
719 d2d_cdt_edge_sym(&new_base, &new_base);
720 if (!d2d_cdt_fixup(cdt, &new_base))
721 return FALSE;
724 return TRUE;
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)
735 *end_edge = next;
736 return;
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, &current);
756 if (d2d_cdt_edge_destination(cdt, &current) == end_vertex)
757 return TRUE;
759 if (d2d_cdt_rightof(cdt, end_vertex, &next) && d2d_cdt_leftof(cdt, end_vertex, &current))
761 d2d_cdt_edge_next_left(cdt, &base_edge, &current);
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, &current))
768 return FALSE;
769 if (!d2d_cdt_fixup(cdt, &base_edge))
770 return FALSE;
771 d2d_cdt_edge_sym(&base_edge, &base_edge);
772 if (!d2d_cdt_fixup(cdt, &base_edge))
773 return FALSE;
775 return TRUE;
778 if (next.idx == origin->idx)
780 ERR("Triangle not found.\n");
781 return FALSE;
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)
808 continue;
810 for (k = 0; k < cdt->edge_count; ++k)
812 if (cdt->edges[k].flags & D2D_CDT_EDGE_FLAG_FREED)
813 continue;
815 edge.idx = k;
816 edge.r = 0;
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;
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))
828 return FALSE;
829 break;
835 return TRUE;
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;
847 float s, t, det;
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;
869 if (det == 0.0f)
870 continue;
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)
876 continue;
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))
884 return FALSE;
885 if (j == i)
886 ++k;
887 ++limit;
888 ++l;
891 if (s > 0.0f && s < 1.0f)
893 if (!d2d_figure_insert_vertex(figure_p, k, intersection))
894 return FALSE;
895 p1 = intersection;
896 d2d_point_subtract(&v_p, &p1, &p0);
903 return TRUE;
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);
921 return S_OK;
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)))
940 --vertex_count;
941 memmove(&vertices[i], &vertices[i + 1], (vertex_count - i) * sizeof(*vertices));
942 --i;
946 geometry->vertices = vertices;
947 geometry->vertex_count = vertex_count;
949 cdt.free_edge = ~0u;
950 cdt.vertices = vertices;
951 if (!d2d_cdt_triangulate(&cdt, 0, vertex_count, &left_edge, &right_edge))
952 goto fail;
953 if (!d2d_cdt_insert_segments(&cdt, geometry))
954 goto fail;
955 if (!d2d_cdt_generate_faces(&cdt, geometry))
956 goto fail;
958 HeapFree(GetProcessHeap(), 0, cdt.edges);
959 return S_OK;
961 fail:
962 geometry->vertices = NULL;
963 geometry->vertex_count = 0;
964 HeapFree(GetProcessHeap(), 0, vertices);
965 HeapFree(GetProcessHeap(), 0, cdt.edges);
966 return E_FAIL;
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");
977 return FALSE;
980 figure = &geometry->u.path.figures[geometry->u.path.figure_count];
981 memset(figure, 0, sizeof(*figure));
983 ++geometry->u.path.figure_count;
984 return TRUE;
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);
1018 *out = iface;
1019 return S_OK;
1022 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
1024 *out = NULL;
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;
1071 return;
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;
1081 return;
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);
1095 unsigned int i;
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;
1102 return;
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");
1110 return;
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];
1122 D2D1_POINT_2F p;
1123 unsigned int i;
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;
1130 return;
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");
1143 return;
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;
1159 return;
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)
1170 size_t i;
1172 if (!geometry->u.path.figures)
1173 return;
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;
1189 size_t i, start;
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))
1202 goto done;
1203 if (FAILED(hr = d2d_path_geometry_triangulate(geometry)))
1204 goto done;
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;
1216 hr = E_OUTOFMEMORY;
1217 goto done;
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;
1231 done:
1232 d2d_path_geometry_free_figures(geometry);
1233 if (FAILED(hr))
1234 geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
1235 return hr;
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];
1265 unsigned int i;
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;
1272 return;
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");
1281 return;
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;
1297 return;
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");
1303 return;
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);
1343 *out = iface;
1344 return S_OK;
1347 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
1349 *out = NULL;
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);
1360 return 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);
1370 if (!refcount)
1372 d2d_path_geometry_free_figures(geometry);
1373 d2d_geometry_cleanup(geometry);
1374 HeapFree(GetProcessHeap(), 0, geometry);
1377 return refcount;
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);
1394 return E_NOTIMPL;
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);
1403 return E_NOTIMPL;
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);
1414 return E_NOTIMPL;
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);
1423 return E_NOTIMPL;
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);
1432 return E_NOTIMPL;
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);
1442 return E_NOTIMPL;
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);
1450 return E_NOTIMPL;
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);
1460 return E_NOTIMPL;
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);
1468 return E_NOTIMPL;
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);
1476 return E_NOTIMPL;
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);
1484 return E_NOTIMPL;
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);
1493 return E_NOTIMPL;
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);
1503 return E_NOTIMPL;
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;
1520 return S_OK;
1523 static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Stream(ID2D1PathGeometry *iface, ID2D1GeometrySink *sink)
1525 FIXME("iface %p, sink %p stub!\n", iface, sink);
1527 return E_NOTIMPL;
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;
1541 return S_OK;
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;
1555 return S_OK;
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);
1605 *out = iface;
1606 return S_OK;
1609 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
1611 *out = NULL;
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);
1622 return 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);
1632 if (!refcount)
1634 d2d_geometry_cleanup(geometry);
1635 HeapFree(GetProcessHeap(), 0, geometry);
1638 return refcount;
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);
1655 return E_NOTIMPL;
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);
1665 return E_NOTIMPL;
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);
1676 return E_NOTIMPL;
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);
1685 return E_NOTIMPL;
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);
1694 return E_NOTIMPL;
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);
1704 return E_NOTIMPL;
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);
1712 return E_NOTIMPL;
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);
1722 return E_NOTIMPL;
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);
1730 return E_NOTIMPL;
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);
1738 return E_NOTIMPL;
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);
1746 return E_NOTIMPL;
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);
1756 return E_NOTIMPL;
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);
1766 return E_NOTIMPL;
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;
1834 return S_OK;
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);
1853 *out = iface;
1854 return S_OK;
1857 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
1859 *out = NULL;
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);
1870 return 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);
1880 if (!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);
1890 return refcount;
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);
1908 return E_NOTIMPL;
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);
1918 return E_NOTIMPL;
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);
1929 return E_NOTIMPL;
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);
1938 return E_NOTIMPL;
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);
1947 return E_NOTIMPL;
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);
1957 return E_NOTIMPL;
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);
1965 return E_NOTIMPL;
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);
1975 return E_NOTIMPL;
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);
1983 return E_NOTIMPL;
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);
1991 return E_NOTIMPL;
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);
1999 return E_NOTIMPL;
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);
2009 return E_NOTIMPL;
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);
2019 return E_NOTIMPL;
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)
2083 if (!iface)
2084 return NULL;
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);