2 * Copyright 2015 Henri Verbeet for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "wine/port.h"
22 #include "d2d1_private.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(d2d
);
26 #define D2D_CDT_EDGE_FLAG_FREED 0x80000000u
27 #define D2D_CDT_EDGE_FLAG_VISITED(r) (1u << (r))
29 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,
39 D2D1_POINT_2F
*vertices
;
43 struct d2d_bezier
*beziers
;
48 struct d2d_cdt_edge_ref
51 enum d2d_cdt_edge_next r
;
56 struct d2d_cdt_edge_ref next
[4];
63 struct d2d_cdt_edge
*edges
;
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
)
78 static float d2d_point_ccw(const D2D1_POINT_2F
*a
, const D2D1_POINT_2F
*b
, const D2D1_POINT_2F
*c
)
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
;
93 if (element_count
<= *capacity
)
96 max_capacity
= ~(size_t)0 / element_size
;
97 if (max_capacity
< element_count
)
100 new_capacity
= max(*capacity
, 4);
101 while (new_capacity
< element_count
&& new_capacity
<= max_capacity
/ 2)
104 if (new_capacity
< element_count
)
105 new_capacity
= max_capacity
;
108 new_elements
= HeapReAlloc(GetProcessHeap(), 0, *elements
, new_capacity
* element_size
);
110 new_elements
= HeapAlloc(GetProcessHeap(), 0, new_capacity
* element_size
);
115 *elements
= new_elements
;
116 *capacity
= new_capacity
;
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");
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
;
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");
145 figure
->vertices
[figure
->vertex_count
] = vertex
;
146 ++figure
->vertex_count
;
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
;
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");
164 if (d2d_point_ccw(&p0
, &p1
, &p2
) > 0.0f
)
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
))
194 if (!d2d_figure_add_vertex(figure
, p2
))
199 static void d2d_cdt_edge_rot(struct d2d_cdt_edge_ref
*dst
, const struct d2d_cdt_edge_ref
*src
)
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
)
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
)
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
283 * After translating D to the origin, that becomes:
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
;
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
;
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");
339 e
->idx
= cdt
->edge_count
++;
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
);
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
))
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
);
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. */
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
);
419 d2d_cdt_edge_sym(&tmp
, right_inner
);
420 if (!d2d_cdt_connect(cdt
, &base_edge
, &tmp
, left_inner
))
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
;
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
)
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
))
479 if (!d2d_cdt_connect(cdt
, &base_edge
, &sym_base_edge
, &left_candidate
))
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
;
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
))
503 d2d_cdt_edge_set_origin(cdt
, &a
, start_vertex
);
504 d2d_cdt_edge_set_destination(cdt
, &a
, start_vertex
+ 1);
507 d2d_cdt_edge_sym(right_edge
, &a
);
512 /* Three vertices, create a triangle. */
513 if (vertex_count
== 3)
515 struct d2d_cdt_edge_ref a
, b
, c
;
518 if (!d2d_cdt_create_edge(cdt
, &a
))
520 if (!d2d_cdt_create_edge(cdt
, &b
))
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
))
536 d2d_cdt_edge_sym(left_edge
, &c
);
542 d2d_cdt_edge_sym(right_edge
, &b
);
548 /* More than tree vertices, divide. */
549 cut
= vertex_count
/ 2;
550 if (!d2d_cdt_triangulate(cdt
, start_vertex
, cut
, &left_outer
, &left_inner
))
552 if (!d2d_cdt_triangulate(cdt
, start_vertex
+ cut
, vertex_count
- cut
, &right_inner
, &right_outer
))
554 /* Merge the left and right parts. */
555 if (!d2d_cdt_merge(cdt
, &left_outer
, &left_inner
, &right_inner
, &right_outer
))
558 *left_edge
= left_outer
;
559 *right_edge
= right_outer
;
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
;
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
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
;
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
))
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
;
615 if (cdt
->edges
[base_edge
->idx
].flags
& D2D_CDT_EDGE_FLAG_VISITED(base_edge
->r
))
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");
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. */
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
;
655 static BOOL
d2d_cdt_generate_faces(const struct d2d_cdt
*cdt
, struct d2d_geometry
*geometry
)
657 struct d2d_cdt_edge_ref base_edge
;
660 for (i
= 0; i
< cdt
->edge_count
; ++i
)
662 if (cdt
->edges
[i
].flags
& D2D_CDT_EDGE_FLAG_FREED
)
667 if (!d2d_path_geometry_add_face(geometry
, cdt
, &base_edge
))
669 d2d_cdt_edge_sym(&base_edge
, &base_edge
);
670 if (!d2d_path_geometry_add_face(geometry
, cdt
, &base_edge
))
677 HeapFree(GetProcessHeap(), 0, geometry
->faces
);
678 geometry
->faces
= NULL
;
679 geometry
->faces_size
= 0;
680 geometry
->face_count
= 0;
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");
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
)))
702 d2d_cdt_edge_next_left(cdt
, &next
, &next
);
708 if (!d2d_cdt_connect(cdt
, &new_base
, &candidate
, base_edge
))
710 if (!d2d_cdt_fixup(cdt
, &new_base
))
712 d2d_cdt_edge_sym(&new_base
, &new_base
);
713 if (!d2d_cdt_fixup(cdt
, &new_base
))
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
)
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
, ¤t
);
749 if (d2d_cdt_edge_destination(cdt
, ¤t
) == end_vertex
)
752 if (d2d_cdt_rightof(cdt
, end_vertex
, &next
) && d2d_cdt_leftof(cdt
, end_vertex
, ¤t
))
754 d2d_cdt_edge_next_left(cdt
, &base_edge
, ¤t
);
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
, ¤t
))
762 if (!d2d_cdt_fixup(cdt
, &base_edge
))
764 d2d_cdt_edge_sym(&base_edge
, &base_edge
);
765 if (!d2d_cdt_fixup(cdt
, &base_edge
))
771 if (next
.idx
== origin
->idx
)
773 ERR("Triangle not found.\n");
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
)
803 for (k
= 0; k
< cdt
->edge_count
; ++k
)
805 if (cdt
->edges
[k
].flags
& D2D_CDT_EDGE_FLAG_FREED
)
811 if (d2d_cdt_edge_origin(cdt
, &edge
) == start_vertex
)
813 if (!d2d_cdt_insert_segment(cdt
, geometry
, &edge
, end_vertex
))
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
))
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
;
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
;
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
)
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
))
884 if (s
> 0.0f
&& s
< 1.0f
)
886 if (!d2d_figure_insert_vertex(figure_p
, k
, intersection
))
889 d2d_point_subtract(&v_p
, &p1
, &p0
);
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
);
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
)))
934 memmove(&vertices
[i
], &vertices
[i
+ 1], (vertex_count
- i
) * sizeof(*vertices
));
939 geometry
->vertices
= vertices
;
940 geometry
->vertex_count
= vertex_count
;
943 cdt
.vertices
= vertices
;
944 if (!d2d_cdt_triangulate(&cdt
, 0, vertex_count
, &left_edge
, &right_edge
))
946 if (!d2d_cdt_insert_segments(&cdt
, geometry
))
948 if (!d2d_cdt_generate_faces(&cdt
, geometry
))
951 HeapFree(GetProcessHeap(), 0, cdt
.edges
);
955 geometry
->vertices
= NULL
;
956 geometry
->vertex_count
= 0;
957 HeapFree(GetProcessHeap(), 0, vertices
);
958 HeapFree(GetProcessHeap(), 0, cdt
.edges
);
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");
973 figure
= &geometry
->u
.path
.figures
[geometry
->u
.path
.figure_count
];
974 memset(figure
, 0, sizeof(*figure
));
976 ++geometry
->u
.path
.figure_count
;
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
);
1015 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
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
;
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
;
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
);
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
;
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");
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];
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
;
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");
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
;
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
)
1165 if (!geometry
->u
.path
.figures
)
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
;
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
))
1196 if (FAILED(hr
= d2d_path_geometry_triangulate(geometry
)))
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;
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
;
1225 d2d_path_geometry_free_figures(geometry
);
1227 geometry
->u
.path
.state
= D2D_GEOMETRY_STATE_ERROR
;
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];
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
;
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");
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
;
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");
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
);
1340 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
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
);
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
);
1365 d2d_path_geometry_free_figures(geometry
);
1366 d2d_geometry_destroy(geometry
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
;
1515 static HRESULT STDMETHODCALLTYPE
d2d_path_geometry_Stream(ID2D1PathGeometry
*iface
, ID2D1GeometrySink
*sink
)
1517 FIXME("iface %p, sink %p stub!\n", iface
, sink
);
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
;
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
;
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
);
1601 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
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
);
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
);
1625 d2d_geometry_destroy(geometry
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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;
1823 struct d2d_geometry
*unsafe_impl_from_ID2D1Geometry(ID2D1Geometry
*iface
)
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
);