/work/workdir/UnpackedTarball/cairo/src/cairo-bentley-ottmann-rectilinear.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright © 2004 Carl Worth |
3 | | * Copyright © 2006 Red Hat, Inc. |
4 | | * Copyright © 2008 Chris Wilson |
5 | | * |
6 | | * This library is free software; you can redistribute it and/or |
7 | | * modify it either under the terms of the GNU Lesser General Public |
8 | | * License version 2.1 as published by the Free Software Foundation |
9 | | * (the "LGPL") or, at your option, under the terms of the Mozilla |
10 | | * Public License Version 1.1 (the "MPL"). If you do not alter this |
11 | | * notice, a recipient may use your version of this file under either |
12 | | * the MPL or the LGPL. |
13 | | * |
14 | | * You should have received a copy of the LGPL along with this library |
15 | | * in the file COPYING-LGPL-2.1; if not, write to the Free Software |
16 | | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA |
17 | | * You should have received a copy of the MPL along with this library |
18 | | * in the file COPYING-MPL-1.1 |
19 | | * |
20 | | * The contents of this file are subject to the Mozilla Public License |
21 | | * Version 1.1 (the "License"); you may not use this file except in |
22 | | * compliance with the License. You may obtain a copy of the License at |
23 | | * http://www.mozilla.org/MPL/ |
24 | | * |
25 | | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
26 | | * OF ANY KIND, either express or implied. See the LGPL or the MPL for |
27 | | * the specific language governing rights and limitations. |
28 | | * |
29 | | * The Original Code is the cairo graphics library. |
30 | | * |
31 | | * The Initial Developer of the Original Code is Carl Worth |
32 | | * |
33 | | * Contributor(s): |
34 | | * Carl D. Worth <cworth@cworth.org> |
35 | | * Chris Wilson <chris@chris-wilson.co.uk> |
36 | | */ |
37 | | |
38 | | /* Provide definitions for standalone compilation */ |
39 | | #include "cairoint.h" |
40 | | |
41 | | #include "cairo-boxes-private.h" |
42 | | #include "cairo-combsort-inline.h" |
43 | | #include "cairo-error-private.h" |
44 | | #include "cairo-traps-private.h" |
45 | | |
46 | | typedef struct _cairo_bo_edge cairo_bo_edge_t; |
47 | | typedef struct _cairo_bo_trap cairo_bo_trap_t; |
48 | | |
49 | | /* A deferred trapezoid of an edge */ |
50 | | struct _cairo_bo_trap { |
51 | | cairo_bo_edge_t *right; |
52 | | int32_t top; |
53 | | }; |
54 | | |
55 | | struct _cairo_bo_edge { |
56 | | cairo_edge_t edge; |
57 | | cairo_bo_edge_t *prev; |
58 | | cairo_bo_edge_t *next; |
59 | | cairo_bo_trap_t deferred_trap; |
60 | | }; |
61 | | |
62 | | typedef enum { |
63 | | CAIRO_BO_EVENT_TYPE_START, |
64 | | CAIRO_BO_EVENT_TYPE_STOP |
65 | | } cairo_bo_event_type_t; |
66 | | |
67 | | typedef struct _cairo_bo_event { |
68 | | cairo_bo_event_type_t type; |
69 | | cairo_point_t point; |
70 | | cairo_bo_edge_t *edge; |
71 | | } cairo_bo_event_t; |
72 | | |
73 | | typedef struct _cairo_bo_sweep_line { |
74 | | cairo_bo_event_t **events; |
75 | | cairo_bo_edge_t *head; |
76 | | cairo_bo_edge_t *stopped; |
77 | | int32_t current_y; |
78 | | cairo_bo_edge_t *current_edge; |
79 | | } cairo_bo_sweep_line_t; |
80 | | |
81 | | static inline int |
82 | | _cairo_point_compare (const cairo_point_t *a, |
83 | | const cairo_point_t *b) |
84 | 57.3k | { |
85 | 57.3k | int cmp; |
86 | | |
87 | 57.3k | cmp = a->y - b->y; |
88 | 57.3k | if (likely (cmp)) |
89 | 23.0k | return cmp; |
90 | | |
91 | 34.3k | return a->x - b->x; |
92 | 57.3k | } |
93 | | |
94 | | static inline int |
95 | | _cairo_bo_edge_compare (const cairo_bo_edge_t *a, |
96 | | const cairo_bo_edge_t *b) |
97 | 5.83k | { |
98 | 5.83k | int cmp; |
99 | | |
100 | 5.83k | cmp = a->edge.line.p1.x - b->edge.line.p1.x; |
101 | 5.83k | if (likely (cmp)) |
102 | 2.28k | return cmp; |
103 | | |
104 | 3.54k | return b->edge.bottom - a->edge.bottom; |
105 | 5.83k | } |
106 | | |
107 | | static inline int |
108 | | cairo_bo_event_compare (const cairo_bo_event_t *a, |
109 | | const cairo_bo_event_t *b) |
110 | 57.3k | { |
111 | 57.3k | int cmp; |
112 | | |
113 | 57.3k | cmp = _cairo_point_compare (&a->point, &b->point); |
114 | 57.3k | if (likely (cmp)) |
115 | 34.4k | return cmp; |
116 | | |
117 | 22.9k | cmp = a->type - b->type; |
118 | 22.9k | if (cmp) |
119 | 0 | return cmp; |
120 | | |
121 | 22.9k | return a - b; |
122 | 22.9k | } |
123 | | |
124 | | static inline cairo_bo_event_t * |
125 | | _cairo_bo_event_dequeue (cairo_bo_sweep_line_t *sweep_line) |
126 | 27.8k | { |
127 | 27.8k | return *sweep_line->events++; |
128 | 27.8k | } |
129 | | |
130 | | CAIRO_COMBSORT_DECLARE (_cairo_bo_event_queue_sort, |
131 | | cairo_bo_event_t *, |
132 | | cairo_bo_event_compare) |
133 | | |
134 | | static void |
135 | | _cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line, |
136 | | cairo_bo_event_t **events, |
137 | | int num_events) |
138 | 5.39k | { |
139 | 5.39k | _cairo_bo_event_queue_sort (events, num_events); |
140 | 5.39k | events[num_events] = NULL; |
141 | 5.39k | sweep_line->events = events; |
142 | | |
143 | 5.39k | sweep_line->head = NULL; |
144 | 5.39k | sweep_line->current_y = INT32_MIN; |
145 | 5.39k | sweep_line->current_edge = NULL; |
146 | 5.39k | } |
147 | | |
148 | | static void |
149 | | _cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line, |
150 | | cairo_bo_edge_t *edge) |
151 | 11.2k | { |
152 | 11.2k | if (sweep_line->current_edge != NULL) { |
153 | 5.82k | cairo_bo_edge_t *prev, *next; |
154 | 5.82k | int cmp; |
155 | | |
156 | 5.82k | cmp = _cairo_bo_edge_compare (sweep_line->current_edge, edge); |
157 | 5.82k | if (cmp < 0) { |
158 | 2.26k | prev = sweep_line->current_edge; |
159 | 2.26k | next = prev->next; |
160 | 2.26k | while (next != NULL && _cairo_bo_edge_compare (next, edge) < 0) |
161 | 0 | prev = next, next = prev->next; |
162 | | |
163 | 2.26k | prev->next = edge; |
164 | 2.26k | edge->prev = prev; |
165 | 2.26k | edge->next = next; |
166 | 2.26k | if (next != NULL) |
167 | 5 | next->prev = edge; |
168 | 3.55k | } else if (cmp > 0) { |
169 | 10 | next = sweep_line->current_edge; |
170 | 10 | prev = next->prev; |
171 | 15 | while (prev != NULL && _cairo_bo_edge_compare (prev, edge) > 0) |
172 | 5 | next = prev, prev = next->prev; |
173 | | |
174 | 10 | next->prev = edge; |
175 | 10 | edge->next = next; |
176 | 10 | edge->prev = prev; |
177 | 10 | if (prev != NULL) |
178 | 0 | prev->next = edge; |
179 | 10 | else |
180 | 10 | sweep_line->head = edge; |
181 | 3.54k | } else { |
182 | 3.54k | prev = sweep_line->current_edge; |
183 | 3.54k | edge->prev = prev; |
184 | 3.54k | edge->next = prev->next; |
185 | 3.54k | if (prev->next != NULL) |
186 | 0 | prev->next->prev = edge; |
187 | 3.54k | prev->next = edge; |
188 | 3.54k | } |
189 | 5.82k | } else { |
190 | 5.39k | sweep_line->head = edge; |
191 | 5.39k | } |
192 | | |
193 | 11.2k | sweep_line->current_edge = edge; |
194 | 11.2k | } |
195 | | |
196 | | static void |
197 | | _cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t *sweep_line, |
198 | | cairo_bo_edge_t *edge) |
199 | 11.2k | { |
200 | 11.2k | if (edge->prev != NULL) |
201 | 15 | edge->prev->next = edge->next; |
202 | 11.2k | else |
203 | 11.2k | sweep_line->head = edge->next; |
204 | | |
205 | 11.2k | if (edge->next != NULL) |
206 | 5.81k | edge->next->prev = edge->prev; |
207 | | |
208 | 11.2k | if (sweep_line->current_edge == edge) |
209 | 5.39k | sweep_line->current_edge = edge->prev ? edge->prev : edge->next; |
210 | 11.2k | } |
211 | | |
212 | | static inline cairo_bool_t |
213 | | edges_collinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b) |
214 | 5.60k | { |
215 | 5.60k | return a->edge.line.p1.x == b->edge.line.p1.x; |
216 | 5.60k | } |
217 | | |
218 | | static cairo_status_t |
219 | | _cairo_bo_edge_end_trap (cairo_bo_edge_t *left, |
220 | | int32_t bot, |
221 | | cairo_bool_t do_traps, |
222 | | void *container) |
223 | 2.26k | { |
224 | 2.26k | cairo_bo_trap_t *trap = &left->deferred_trap; |
225 | 2.26k | cairo_status_t status = CAIRO_STATUS_SUCCESS; |
226 | | |
227 | | /* Only emit (trivial) non-degenerate trapezoids with positive height. */ |
228 | 2.26k | if (likely (trap->top < bot)) { |
229 | 2.26k | if (do_traps) { |
230 | 0 | _cairo_traps_add_trap (container, |
231 | 0 | trap->top, bot, |
232 | 0 | &left->edge.line, &trap->right->edge.line); |
233 | 0 | status = _cairo_traps_status ((cairo_traps_t *) container); |
234 | 2.26k | } else { |
235 | 2.26k | cairo_box_t box; |
236 | | |
237 | 2.26k | box.p1.x = left->edge.line.p1.x; |
238 | 2.26k | box.p1.y = trap->top; |
239 | 2.26k | box.p2.x = trap->right->edge.line.p1.x; |
240 | 2.26k | box.p2.y = bot; |
241 | 2.26k | status = _cairo_boxes_add (container, CAIRO_ANTIALIAS_DEFAULT, &box); |
242 | 2.26k | } |
243 | 2.26k | } |
244 | | |
245 | 2.26k | trap->right = NULL; |
246 | | |
247 | 2.26k | return status; |
248 | 2.26k | } |
249 | | |
250 | | /* Start a new trapezoid at the given top y coordinate, whose edges |
251 | | * are `edge' and `edge->next'. If `edge' already has a trapezoid, |
252 | | * then either add it to the traps in `traps', if the trapezoid's |
253 | | * right edge differs from `edge->next', or do nothing if the new |
254 | | * trapezoid would be a continuation of the existing one. */ |
255 | | static inline cairo_status_t |
256 | | _cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left, |
257 | | cairo_bo_edge_t *right, |
258 | | int top, |
259 | | cairo_bool_t do_traps, |
260 | | void *container) |
261 | 5.40k | { |
262 | 5.40k | cairo_status_t status; |
263 | | |
264 | 5.40k | if (left->deferred_trap.right == right) |
265 | 0 | return CAIRO_STATUS_SUCCESS; |
266 | | |
267 | 5.40k | if (left->deferred_trap.right != NULL) { |
268 | 0 | if (right != NULL && edges_collinear (left->deferred_trap.right, right)) |
269 | 0 | { |
270 | | /* continuation on right, so just swap edges */ |
271 | 0 | left->deferred_trap.right = right; |
272 | 0 | return CAIRO_STATUS_SUCCESS; |
273 | 0 | } |
274 | | |
275 | 0 | status = _cairo_bo_edge_end_trap (left, top, do_traps, container); |
276 | 0 | if (unlikely (status)) |
277 | 0 | return status; |
278 | 0 | } |
279 | | |
280 | 5.40k | if (right != NULL && ! edges_collinear (left, right)) { |
281 | 2.26k | left->deferred_trap.top = top; |
282 | 2.26k | left->deferred_trap.right = right; |
283 | 2.26k | } |
284 | | |
285 | 5.40k | return CAIRO_STATUS_SUCCESS; |
286 | 5.40k | } |
287 | | |
288 | | static inline cairo_status_t |
289 | | _active_edges_to_traps (cairo_bo_edge_t *left, |
290 | | int32_t top, |
291 | | cairo_fill_rule_t fill_rule, |
292 | | cairo_bool_t do_traps, |
293 | | void *container) |
294 | 10.7k | { |
295 | 10.7k | cairo_bo_edge_t *right; |
296 | 10.7k | cairo_status_t status; |
297 | | |
298 | 10.7k | if (fill_rule == CAIRO_FILL_RULE_WINDING) { |
299 | 0 | while (left != NULL) { |
300 | 0 | int in_out; |
301 | | |
302 | | /* Greedily search for the closing edge, so that we generate the |
303 | | * maximal span width with the minimal number of trapezoids. |
304 | | */ |
305 | 0 | in_out = left->edge.dir; |
306 | | |
307 | | /* Check if there is a co-linear edge with an existing trap */ |
308 | 0 | right = left->next; |
309 | 0 | if (left->deferred_trap.right == NULL) { |
310 | 0 | while (right != NULL && right->deferred_trap.right == NULL) |
311 | 0 | right = right->next; |
312 | |
|
313 | 0 | if (right != NULL && edges_collinear (left, right)) { |
314 | | /* continuation on left */ |
315 | 0 | left->deferred_trap = right->deferred_trap; |
316 | 0 | right->deferred_trap.right = NULL; |
317 | 0 | } |
318 | 0 | } |
319 | | |
320 | | /* End all subsumed traps */ |
321 | 0 | right = left->next; |
322 | 0 | while (right != NULL) { |
323 | 0 | if (right->deferred_trap.right != NULL) { |
324 | 0 | status = _cairo_bo_edge_end_trap (right, top, do_traps, container); |
325 | 0 | if (unlikely (status)) |
326 | 0 | return status; |
327 | 0 | } |
328 | | |
329 | 0 | in_out += right->edge.dir; |
330 | 0 | if (in_out == 0) { |
331 | | /* skip co-linear edges */ |
332 | 0 | if (right->next == NULL || |
333 | 0 | ! edges_collinear (right, right->next)) |
334 | 0 | { |
335 | 0 | break; |
336 | 0 | } |
337 | 0 | } |
338 | | |
339 | 0 | right = right->next; |
340 | 0 | } |
341 | | |
342 | 0 | status = _cairo_bo_edge_start_or_continue_trap (left, right, top, |
343 | 0 | do_traps, container); |
344 | 0 | if (unlikely (status)) |
345 | 0 | return status; |
346 | | |
347 | 0 | left = right; |
348 | 0 | if (left != NULL) |
349 | 0 | left = left->next; |
350 | 0 | } |
351 | 10.7k | } else { |
352 | 16.2k | while (left != NULL) { |
353 | 5.40k | int in_out = 0; |
354 | | |
355 | 5.40k | right = left->next; |
356 | 5.81k | while (right != NULL) { |
357 | 5.81k | if (right->deferred_trap.right != NULL) { |
358 | 0 | status = _cairo_bo_edge_end_trap (right, top, do_traps, container); |
359 | 0 | if (unlikely (status)) |
360 | 0 | return status; |
361 | 0 | } |
362 | | |
363 | 5.81k | if ((in_out++ & 1) == 0) { |
364 | 5.60k | cairo_bo_edge_t *next; |
365 | 5.60k | cairo_bool_t skip = FALSE; |
366 | | |
367 | | /* skip co-linear edges */ |
368 | 5.60k | next = right->next; |
369 | 5.60k | if (next != NULL) |
370 | 205 | skip = edges_collinear (right, next); |
371 | | |
372 | 5.60k | if (! skip) |
373 | 5.40k | break; |
374 | 5.60k | } |
375 | | |
376 | 410 | right = right->next; |
377 | 410 | } |
378 | | |
379 | 5.40k | status = _cairo_bo_edge_start_or_continue_trap (left, right, top, |
380 | 5.40k | do_traps, container); |
381 | 5.40k | if (unlikely (status)) |
382 | 0 | return status; |
383 | | |
384 | 5.40k | left = right; |
385 | 5.40k | if (left != NULL) |
386 | 5.40k | left = left->next; |
387 | 5.40k | } |
388 | 10.7k | } |
389 | | |
390 | 10.7k | return CAIRO_STATUS_SUCCESS; |
391 | 10.7k | } |
392 | | |
393 | | static cairo_status_t |
394 | | _cairo_bentley_ottmann_tessellate_rectilinear (cairo_bo_event_t **start_events, |
395 | | int num_events, |
396 | | cairo_fill_rule_t fill_rule, |
397 | | cairo_bool_t do_traps, |
398 | | void *container) |
399 | 5.39k | { |
400 | 5.39k | cairo_bo_sweep_line_t sweep_line; |
401 | 5.39k | cairo_bo_event_t *event; |
402 | 5.39k | cairo_status_t status; |
403 | | |
404 | 5.39k | _cairo_bo_sweep_line_init (&sweep_line, start_events, num_events); |
405 | | |
406 | 27.8k | while ((event = _cairo_bo_event_dequeue (&sweep_line))) { |
407 | 22.4k | if (event->point.y != sweep_line.current_y) { |
408 | 10.7k | status = _active_edges_to_traps (sweep_line.head, |
409 | 10.7k | sweep_line.current_y, |
410 | 10.7k | fill_rule, do_traps, container); |
411 | 10.7k | if (unlikely (status)) |
412 | 0 | return status; |
413 | | |
414 | 10.7k | sweep_line.current_y = event->point.y; |
415 | 10.7k | } |
416 | | |
417 | 22.4k | switch (event->type) { |
418 | 11.2k | case CAIRO_BO_EVENT_TYPE_START: |
419 | 11.2k | _cairo_bo_sweep_line_insert (&sweep_line, event->edge); |
420 | 11.2k | break; |
421 | | |
422 | 11.2k | case CAIRO_BO_EVENT_TYPE_STOP: |
423 | 11.2k | _cairo_bo_sweep_line_delete (&sweep_line, event->edge); |
424 | | |
425 | 11.2k | if (event->edge->deferred_trap.right != NULL) { |
426 | 2.26k | status = _cairo_bo_edge_end_trap (event->edge, |
427 | 2.26k | sweep_line.current_y, |
428 | 2.26k | do_traps, container); |
429 | 2.26k | if (unlikely (status)) |
430 | 0 | return status; |
431 | 2.26k | } |
432 | | |
433 | 11.2k | break; |
434 | 22.4k | } |
435 | 22.4k | } |
436 | | |
437 | 5.39k | return CAIRO_STATUS_SUCCESS; |
438 | 5.39k | } |
439 | | |
440 | | cairo_status_t |
441 | | _cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (const cairo_polygon_t *polygon, |
442 | | cairo_fill_rule_t fill_rule, |
443 | | cairo_boxes_t *boxes) |
444 | 5.39k | { |
445 | 5.39k | cairo_status_t status; |
446 | 5.39k | cairo_bo_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_event_t)]; |
447 | 5.39k | cairo_bo_event_t *events; |
448 | 5.39k | cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1]; |
449 | 5.39k | cairo_bo_event_t **event_ptrs; |
450 | 5.39k | cairo_bo_edge_t stack_edges[ARRAY_LENGTH (stack_events)]; |
451 | 5.39k | cairo_bo_edge_t *edges; |
452 | 5.39k | int num_events; |
453 | 5.39k | int i, j; |
454 | | |
455 | 5.39k | if (unlikely (polygon->num_edges == 0)) |
456 | 1 | return CAIRO_STATUS_SUCCESS; |
457 | | |
458 | 5.39k | #if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) |
459 | 5.39k | if (unlikely (polygon->num_edges > 100000)) |
460 | 0 | return CAIRO_STATUS_SUCCESS; |
461 | 5.39k | #endif |
462 | | |
463 | 5.39k | num_events = 2 * polygon->num_edges; |
464 | | |
465 | 5.39k | events = stack_events; |
466 | 5.39k | event_ptrs = stack_event_ptrs; |
467 | 5.39k | edges = stack_edges; |
468 | 5.39k | if (num_events > ARRAY_LENGTH (stack_events)) { |
469 | 3 | events = _cairo_malloc_ab_plus_c (num_events, |
470 | 3 | sizeof (cairo_bo_event_t) + |
471 | 3 | sizeof (cairo_bo_edge_t) + |
472 | 3 | sizeof (cairo_bo_event_t *), |
473 | 3 | sizeof (cairo_bo_event_t *)); |
474 | 3 | if (unlikely (events == NULL)) |
475 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
476 | | |
477 | 3 | event_ptrs = (cairo_bo_event_t **) (events + num_events); |
478 | 3 | edges = (cairo_bo_edge_t *) (event_ptrs + num_events + 1); |
479 | 3 | } |
480 | | |
481 | 16.6k | for (i = j = 0; i < polygon->num_edges; i++) { |
482 | 11.2k | edges[i].edge = polygon->edges[i]; |
483 | 11.2k | edges[i].deferred_trap.right = NULL; |
484 | 11.2k | edges[i].prev = NULL; |
485 | 11.2k | edges[i].next = NULL; |
486 | | |
487 | 11.2k | event_ptrs[j] = &events[j]; |
488 | 11.2k | events[j].type = CAIRO_BO_EVENT_TYPE_START; |
489 | 11.2k | events[j].point.y = polygon->edges[i].top; |
490 | 11.2k | events[j].point.x = polygon->edges[i].line.p1.x; |
491 | 11.2k | events[j].edge = &edges[i]; |
492 | 11.2k | j++; |
493 | | |
494 | 11.2k | event_ptrs[j] = &events[j]; |
495 | 11.2k | events[j].type = CAIRO_BO_EVENT_TYPE_STOP; |
496 | 11.2k | events[j].point.y = polygon->edges[i].bottom; |
497 | 11.2k | events[j].point.x = polygon->edges[i].line.p1.x; |
498 | 11.2k | events[j].edge = &edges[i]; |
499 | 11.2k | j++; |
500 | 11.2k | } |
501 | | |
502 | 5.39k | status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j, |
503 | 5.39k | fill_rule, |
504 | 5.39k | FALSE, boxes); |
505 | 5.39k | if (events != stack_events) |
506 | 3 | free (events); |
507 | | |
508 | 5.39k | return status; |
509 | 5.39k | } |
510 | | |
511 | | cairo_status_t |
512 | | _cairo_bentley_ottmann_tessellate_rectilinear_traps (cairo_traps_t *traps, |
513 | | cairo_fill_rule_t fill_rule) |
514 | 0 | { |
515 | 0 | cairo_bo_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_event_t)]; |
516 | 0 | cairo_bo_event_t *events; |
517 | 0 | cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1]; |
518 | 0 | cairo_bo_event_t **event_ptrs; |
519 | 0 | cairo_bo_edge_t stack_edges[ARRAY_LENGTH (stack_events)]; |
520 | 0 | cairo_bo_edge_t *edges; |
521 | 0 | cairo_status_t status; |
522 | 0 | int i, j, k; |
523 | |
|
524 | 0 | if (unlikely (traps->num_traps == 0)) |
525 | 0 | return CAIRO_STATUS_SUCCESS; |
526 | | |
527 | 0 | assert (traps->is_rectilinear); |
528 | | |
529 | 0 | i = 4 * traps->num_traps; |
530 | |
|
531 | 0 | events = stack_events; |
532 | 0 | event_ptrs = stack_event_ptrs; |
533 | 0 | edges = stack_edges; |
534 | 0 | if (i > ARRAY_LENGTH (stack_events)) { |
535 | 0 | events = _cairo_malloc_ab_plus_c (i, |
536 | 0 | sizeof (cairo_bo_event_t) + |
537 | 0 | sizeof (cairo_bo_edge_t) + |
538 | 0 | sizeof (cairo_bo_event_t *), |
539 | 0 | sizeof (cairo_bo_event_t *)); |
540 | 0 | if (unlikely (events == NULL)) |
541 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
542 | | |
543 | 0 | event_ptrs = (cairo_bo_event_t **) (events + i); |
544 | 0 | edges = (cairo_bo_edge_t *) (event_ptrs + i + 1); |
545 | 0 | } |
546 | | |
547 | 0 | for (i = j = k = 0; i < traps->num_traps; i++) { |
548 | 0 | edges[k].edge.top = traps->traps[i].top; |
549 | 0 | edges[k].edge.bottom = traps->traps[i].bottom; |
550 | 0 | edges[k].edge.line = traps->traps[i].left; |
551 | 0 | edges[k].edge.dir = 1; |
552 | 0 | edges[k].deferred_trap.right = NULL; |
553 | 0 | edges[k].prev = NULL; |
554 | 0 | edges[k].next = NULL; |
555 | |
|
556 | 0 | event_ptrs[j] = &events[j]; |
557 | 0 | events[j].type = CAIRO_BO_EVENT_TYPE_START; |
558 | 0 | events[j].point.y = traps->traps[i].top; |
559 | 0 | events[j].point.x = traps->traps[i].left.p1.x; |
560 | 0 | events[j].edge = &edges[k]; |
561 | 0 | j++; |
562 | |
|
563 | 0 | event_ptrs[j] = &events[j]; |
564 | 0 | events[j].type = CAIRO_BO_EVENT_TYPE_STOP; |
565 | 0 | events[j].point.y = traps->traps[i].bottom; |
566 | 0 | events[j].point.x = traps->traps[i].left.p1.x; |
567 | 0 | events[j].edge = &edges[k]; |
568 | 0 | j++; |
569 | 0 | k++; |
570 | |
|
571 | 0 | edges[k].edge.top = traps->traps[i].top; |
572 | 0 | edges[k].edge.bottom = traps->traps[i].bottom; |
573 | 0 | edges[k].edge.line = traps->traps[i].right; |
574 | 0 | edges[k].edge.dir = -1; |
575 | 0 | edges[k].deferred_trap.right = NULL; |
576 | 0 | edges[k].prev = NULL; |
577 | 0 | edges[k].next = NULL; |
578 | |
|
579 | 0 | event_ptrs[j] = &events[j]; |
580 | 0 | events[j].type = CAIRO_BO_EVENT_TYPE_START; |
581 | 0 | events[j].point.y = traps->traps[i].top; |
582 | 0 | events[j].point.x = traps->traps[i].right.p1.x; |
583 | 0 | events[j].edge = &edges[k]; |
584 | 0 | j++; |
585 | |
|
586 | 0 | event_ptrs[j] = &events[j]; |
587 | 0 | events[j].type = CAIRO_BO_EVENT_TYPE_STOP; |
588 | 0 | events[j].point.y = traps->traps[i].bottom; |
589 | 0 | events[j].point.x = traps->traps[i].right.p1.x; |
590 | 0 | events[j].edge = &edges[k]; |
591 | 0 | j++; |
592 | 0 | k++; |
593 | 0 | } |
594 | |
|
595 | 0 | _cairo_traps_clear (traps); |
596 | 0 | status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j, |
597 | 0 | fill_rule, |
598 | 0 | TRUE, traps); |
599 | 0 | traps->is_rectilinear = TRUE; |
600 | |
|
601 | 0 | if (events != stack_events) |
602 | 0 | free (events); |
603 | |
|
604 | 0 | return status; |
605 | 0 | } |