File: | root/firefox-clang/gfx/cairo/cairo/src/cairo-bentley-ottmann-rectangular.c |
Warning: | line 568, column 2 Access to field 'dir' results in a dereference of a null pointer (loaded from field 'prev') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * Copyright © 2004 Carl Worth | |||
3 | * Copyright © 2006 Red Hat, Inc. | |||
4 | * Copyright © 2009 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-error-private.h" | |||
43 | #include "cairo-combsort-inline.h" | |||
44 | #include "cairo-list-private.h" | |||
45 | #include "cairo-traps-private.h" | |||
46 | ||||
47 | #include <setjmp.h> | |||
48 | ||||
49 | typedef struct _rectangle rectangle_t; | |||
50 | typedef struct _edge edge_t; | |||
51 | ||||
52 | struct _edge { | |||
53 | edge_t *next, *prev; | |||
54 | edge_t *right; | |||
55 | cairo_fixed_t x, top; | |||
56 | int dir; | |||
57 | }; | |||
58 | ||||
59 | struct _rectangle { | |||
60 | edge_t left, right; | |||
61 | int32_t top, bottom; | |||
62 | }; | |||
63 | ||||
64 | #define UNROLL3(x)x x x x x x | |||
65 | ||||
66 | /* the parent is always given by index/2 */ | |||
67 | #define PQ_PARENT_INDEX(i)((i) >> 1) ((i) >> 1) | |||
68 | #define PQ_FIRST_ENTRY1 1 | |||
69 | ||||
70 | /* left and right children are index * 2 and (index * 2) +1 respectively */ | |||
71 | #define PQ_LEFT_CHILD_INDEX(i)((i) << 1) ((i) << 1) | |||
72 | ||||
73 | typedef struct _sweep_line { | |||
74 | rectangle_t **rectangles; | |||
75 | rectangle_t **stop; | |||
76 | edge_t head, tail, *insert, *cursor; | |||
77 | int32_t current_y; | |||
78 | int32_t last_y; | |||
79 | int stop_size; | |||
80 | ||||
81 | int32_t insert_x; | |||
82 | cairo_fill_rule_t fill_rule; | |||
83 | ||||
84 | cairo_bool_t do_traps; | |||
85 | void *container; | |||
86 | ||||
87 | jmp_buf unwind; | |||
88 | } sweep_line_t; | |||
89 | ||||
90 | #define DEBUG_TRAPS0 0 | |||
91 | ||||
92 | #if DEBUG_TRAPS0 | |||
93 | static void | |||
94 | dump_traps (cairo_traps_t *traps, const char *filename) | |||
95 | { | |||
96 | FILE *file; | |||
97 | int n; | |||
98 | ||||
99 | if (getenv ("CAIRO_DEBUG_TRAPS") == NULL((void*)0)) | |||
100 | return; | |||
101 | ||||
102 | file = fopen (filename, "a"); | |||
103 | if (file != NULL((void*)0)) { | |||
104 | for (n = 0; n < traps->num_traps; n++) { | |||
105 | fprintf (file, "%d %d L:(%d, %d), (%d, %d) R:(%d, %d), (%d, %d)\n", | |||
106 | traps->traps[n].top, | |||
107 | traps->traps[n].bottom, | |||
108 | traps->traps[n].left.p1.x, | |||
109 | traps->traps[n].left.p1.y, | |||
110 | traps->traps[n].left.p2.x, | |||
111 | traps->traps[n].left.p2.y, | |||
112 | traps->traps[n].right.p1.x, | |||
113 | traps->traps[n].right.p1.y, | |||
114 | traps->traps[n].right.p2.x, | |||
115 | traps->traps[n].right.p2.y); | |||
116 | } | |||
117 | fprintf (file, "\n"); | |||
118 | fclose (file); | |||
119 | } | |||
120 | } | |||
121 | #else | |||
122 | #define dump_traps(traps, filename) | |||
123 | #endif | |||
124 | ||||
125 | static inline int | |||
126 | rectangle_compare_start (const rectangle_t *a, | |||
127 | const rectangle_t *b) | |||
128 | { | |||
129 | return a->top - b->top; | |||
130 | } | |||
131 | ||||
132 | static inline int | |||
133 | rectangle_compare_stop (const rectangle_t *a, | |||
134 | const rectangle_t *b) | |||
135 | { | |||
136 | return a->bottom - b->bottom; | |||
137 | } | |||
138 | ||||
139 | static inline void | |||
140 | pqueue_push (sweep_line_t *sweep, rectangle_t *rectangle) | |||
141 | { | |||
142 | rectangle_t **elements; | |||
143 | int i, parent; | |||
144 | ||||
145 | elements = sweep->stop; | |||
146 | for (i = ++sweep->stop_size; | |||
147 | i != PQ_FIRST_ENTRY1 && | |||
148 | rectangle_compare_stop (rectangle, | |||
149 | elements[parent = PQ_PARENT_INDEX (i)((i) >> 1)]) < 0; | |||
150 | i = parent) | |||
151 | { | |||
152 | elements[i] = elements[parent]; | |||
153 | } | |||
154 | ||||
155 | elements[i] = rectangle; | |||
156 | } | |||
157 | ||||
158 | static inline void | |||
159 | rectangle_pop_stop (sweep_line_t *sweep) | |||
160 | { | |||
161 | rectangle_t **elements = sweep->stop; | |||
162 | rectangle_t *tail; | |||
163 | int child, i; | |||
164 | ||||
165 | tail = elements[sweep->stop_size--]; | |||
166 | if (sweep->stop_size == 0) { | |||
167 | elements[PQ_FIRST_ENTRY1] = NULL((void*)0); | |||
168 | return; | |||
169 | } | |||
170 | ||||
171 | for (i = PQ_FIRST_ENTRY1; | |||
172 | (child = PQ_LEFT_CHILD_INDEX (i)((i) << 1)) <= sweep->stop_size; | |||
173 | i = child) | |||
174 | { | |||
175 | if (child != sweep->stop_size && | |||
176 | rectangle_compare_stop (elements[child+1], | |||
177 | elements[child]) < 0) | |||
178 | { | |||
179 | child++; | |||
180 | } | |||
181 | ||||
182 | if (rectangle_compare_stop (elements[child], tail) >= 0) | |||
183 | break; | |||
184 | ||||
185 | elements[i] = elements[child]; | |||
186 | } | |||
187 | elements[i] = tail; | |||
188 | } | |||
189 | ||||
190 | static inline rectangle_t * | |||
191 | rectangle_pop_start (sweep_line_t *sweep_line) | |||
192 | { | |||
193 | return *sweep_line->rectangles++; | |||
194 | } | |||
195 | ||||
196 | static inline rectangle_t * | |||
197 | rectangle_peek_stop (sweep_line_t *sweep_line) | |||
198 | { | |||
199 | return sweep_line->stop[PQ_FIRST_ENTRY1]; | |||
200 | } | |||
201 | ||||
202 | CAIRO_COMBSORT_DECLARE (_rectangle_sort,static void _rectangle_sort (rectangle_t * *base, unsigned int nmemb) { unsigned int gap = nmemb; unsigned int i, j; int swapped ; do { gap = _cairo_combsort_newgap (gap); swapped = gap > 1; for (i = 0; i < nmemb-gap ; i++) { j = i + gap; if (rectangle_compare_start (base[i], base[j]) > 0 ) { rectangle_t * tmp; tmp = base[ i]; base[i] = base[j]; base[j] = tmp; swapped = 1; } } } while (swapped); } | |||
203 | rectangle_t *,static void _rectangle_sort (rectangle_t * *base, unsigned int nmemb) { unsigned int gap = nmemb; unsigned int i, j; int swapped ; do { gap = _cairo_combsort_newgap (gap); swapped = gap > 1; for (i = 0; i < nmemb-gap ; i++) { j = i + gap; if (rectangle_compare_start (base[i], base[j]) > 0 ) { rectangle_t * tmp; tmp = base[ i]; base[i] = base[j]; base[j] = tmp; swapped = 1; } } } while (swapped); } | |||
204 | rectangle_compare_start)static void _rectangle_sort (rectangle_t * *base, unsigned int nmemb) { unsigned int gap = nmemb; unsigned int i, j; int swapped ; do { gap = _cairo_combsort_newgap (gap); swapped = gap > 1; for (i = 0; i < nmemb-gap ; i++) { j = i + gap; if (rectangle_compare_start (base[i], base[j]) > 0 ) { rectangle_t * tmp; tmp = base[ i]; base[i] = base[j]; base[j] = tmp; swapped = 1; } } } while (swapped); } | |||
205 | ||||
206 | static void | |||
207 | sweep_line_init (sweep_line_t *sweep_line, | |||
208 | rectangle_t **rectangles, | |||
209 | int num_rectangles, | |||
210 | cairo_fill_rule_t fill_rule, | |||
211 | cairo_bool_t do_traps, | |||
212 | void *container) | |||
213 | { | |||
214 | rectangles[-2] = NULL((void*)0); | |||
215 | rectangles[-1] = NULL((void*)0); | |||
216 | rectangles[num_rectangles] = NULL((void*)0); | |||
217 | sweep_line->rectangles = rectangles; | |||
218 | sweep_line->stop = rectangles - 2; | |||
219 | sweep_line->stop_size = 0; | |||
220 | ||||
221 | sweep_line->insert = NULL((void*)0); | |||
222 | sweep_line->insert_x = INT_MAX2147483647; | |||
223 | sweep_line->cursor = &sweep_line->tail; | |||
224 | ||||
225 | sweep_line->head.dir = 0; | |||
226 | sweep_line->head.x = INT32_MIN(-2147483647-1); | |||
227 | sweep_line->head.right = NULL((void*)0); | |||
228 | sweep_line->head.prev = NULL((void*)0); | |||
229 | sweep_line->head.next = &sweep_line->tail; | |||
230 | sweep_line->tail.prev = &sweep_line->head; | |||
231 | sweep_line->tail.next = NULL((void*)0); | |||
232 | sweep_line->tail.right = NULL((void*)0); | |||
233 | sweep_line->tail.x = INT32_MAX(2147483647); | |||
234 | sweep_line->tail.dir = 0; | |||
235 | ||||
236 | sweep_line->current_y = INT32_MIN(-2147483647-1); | |||
237 | sweep_line->last_y = INT32_MIN(-2147483647-1); | |||
238 | ||||
239 | sweep_line->fill_rule = fill_rule; | |||
240 | sweep_line->container = container; | |||
241 | sweep_line->do_traps = do_traps; | |||
242 | } | |||
243 | ||||
244 | static void | |||
245 | edge_end_box (sweep_line_t *sweep_line, edge_t *left, int32_t bot) | |||
246 | { | |||
247 | cairo_status_t status = CAIRO_STATUS_SUCCESS; | |||
248 | ||||
249 | /* Only emit (trivial) non-degenerate trapezoids with positive height. */ | |||
250 | if (likely (left->top < bot)(__builtin_expect (!!(left->top < bot), 1))) { | |||
251 | if (sweep_line->do_traps) { | |||
252 | cairo_line_t _left = { | |||
253 | { left->x, left->top }, | |||
254 | { left->x, bot }, | |||
255 | }, _right = { | |||
256 | { left->right->x, left->top }, | |||
257 | { left->right->x, bot }, | |||
258 | }; | |||
259 | _cairo_traps_add_trap (sweep_line->container, left->top, bot, &_left, &_right); | |||
260 | status = _cairo_traps_status ((cairo_traps_t *) sweep_line->container)((cairo_traps_t *) sweep_line->container)->status; | |||
261 | } else { | |||
262 | cairo_box_t box; | |||
263 | ||||
264 | box.p1.x = left->x; | |||
265 | box.p1.y = left->top; | |||
266 | box.p2.x = left->right->x; | |||
267 | box.p2.y = bot; | |||
268 | ||||
269 | status = _cairo_boxes_add (sweep_line->container, | |||
270 | CAIRO_ANTIALIAS_DEFAULT, | |||
271 | &box); | |||
272 | } | |||
273 | } | |||
274 | if (unlikely (status)(__builtin_expect (!!(status), 0))) | |||
275 | longjmp (sweep_line->unwind, status); | |||
276 | ||||
277 | left->right = NULL((void*)0); | |||
278 | } | |||
279 | ||||
280 | /* Start a new trapezoid at the given top y coordinate, whose edges | |||
281 | * are `edge' and `edge->next'. If `edge' already has a trapezoid, | |||
282 | * then either add it to the traps in `traps', if the trapezoid's | |||
283 | * right edge differs from `edge->next', or do nothing if the new | |||
284 | * trapezoid would be a continuation of the existing one. */ | |||
285 | static inline void | |||
286 | edge_start_or_continue_box (sweep_line_t *sweep_line, | |||
287 | edge_t *left, | |||
288 | edge_t *right, | |||
289 | int top) | |||
290 | { | |||
291 | if (left->right == right) | |||
292 | return; | |||
293 | ||||
294 | if (left->right != NULL((void*)0)) { | |||
295 | if (left->right->x == right->x) { | |||
296 | /* continuation on right, so just swap edges */ | |||
297 | left->right = right; | |||
298 | return; | |||
299 | } | |||
300 | ||||
301 | edge_end_box (sweep_line, left, top); | |||
302 | } | |||
303 | ||||
304 | if (left->x != right->x) { | |||
305 | left->top = top; | |||
306 | left->right = right; | |||
307 | } | |||
308 | } | |||
309 | /* | |||
310 | * Merge two sorted edge lists. | |||
311 | * Input: | |||
312 | * - head_a: The head of the first list. | |||
313 | * - head_b: The head of the second list; head_b cannot be NULL. | |||
314 | * Output: | |||
315 | * Returns the head of the merged list. | |||
316 | * | |||
317 | * Implementation notes: | |||
318 | * To make it fast (in particular, to reduce to an insertion sort whenever | |||
319 | * one of the two input lists only has a single element) we iterate through | |||
320 | * a list until its head becomes greater than the head of the other list, | |||
321 | * then we switch their roles. As soon as one of the two lists is empty, we | |||
322 | * just attach the other one to the current list and exit. | |||
323 | * Writes to memory are only needed to "switch" lists (as it also requires | |||
324 | * attaching to the output list the list which we will be iterating next) and | |||
325 | * to attach the last non-empty list. | |||
326 | */ | |||
327 | static edge_t * | |||
328 | merge_sorted_edges (edge_t *head_a, edge_t *head_b) | |||
329 | { | |||
330 | edge_t *head, *prev; | |||
331 | int32_t x; | |||
332 | ||||
333 | prev = head_a->prev; | |||
334 | if (head_a->x <= head_b->x) { | |||
335 | head = head_a; | |||
336 | } else { | |||
337 | head_b->prev = prev; | |||
338 | head = head_b; | |||
339 | goto start_with_b; | |||
340 | } | |||
341 | ||||
342 | do { | |||
343 | x = head_b->x; | |||
344 | while (head_a != NULL((void*)0) && head_a->x <= x) { | |||
345 | prev = head_a; | |||
346 | head_a = head_a->next; | |||
347 | } | |||
348 | ||||
349 | head_b->prev = prev; | |||
350 | prev->next = head_b; | |||
351 | if (head_a == NULL((void*)0)) | |||
352 | return head; | |||
353 | ||||
354 | start_with_b: | |||
355 | x = head_a->x; | |||
356 | while (head_b != NULL((void*)0) && head_b->x <= x) { | |||
357 | prev = head_b; | |||
358 | head_b = head_b->next; | |||
359 | } | |||
360 | ||||
361 | head_a->prev = prev; | |||
362 | prev->next = head_a; | |||
363 | if (head_b == NULL((void*)0)) | |||
364 | return head; | |||
365 | } while (1); | |||
366 | } | |||
367 | ||||
368 | /* | |||
369 | * Sort (part of) a list. | |||
370 | * Input: | |||
371 | * - list: The list to be sorted; list cannot be NULL. | |||
372 | * - limit: Recursion limit. | |||
373 | * Output: | |||
374 | * - head_out: The head of the sorted list containing the first 2^(level+1) elements of the | |||
375 | * input list; if the input list has fewer elements, head_out be a sorted list | |||
376 | * containing all the elements of the input list. | |||
377 | * Returns the head of the list of unprocessed elements (NULL if the sorted list contains | |||
378 | * all the elements of the input list). | |||
379 | * | |||
380 | * Implementation notes: | |||
381 | * Special case single element list, unroll/inline the sorting of the first two elements. | |||
382 | * Some tail recursion is used since we iterate on the bottom-up solution of the problem | |||
383 | * (we start with a small sorted list and keep merging other lists of the same size to it). | |||
384 | */ | |||
385 | static edge_t * | |||
386 | sort_edges (edge_t *list, | |||
387 | unsigned int level, | |||
388 | edge_t **head_out) | |||
389 | { | |||
390 | edge_t *head_other, *remaining; | |||
391 | unsigned int i; | |||
392 | ||||
393 | head_other = list->next; | |||
394 | ||||
395 | if (head_other == NULL((void*)0)) { | |||
396 | *head_out = list; | |||
397 | return NULL((void*)0); | |||
398 | } | |||
399 | ||||
400 | remaining = head_other->next; | |||
401 | if (list->x <= head_other->x) { | |||
402 | *head_out = list; | |||
403 | head_other->next = NULL((void*)0); | |||
404 | } else { | |||
405 | *head_out = head_other; | |||
406 | head_other->prev = list->prev; | |||
407 | head_other->next = list; | |||
408 | list->prev = head_other; | |||
409 | list->next = NULL((void*)0); | |||
410 | } | |||
411 | ||||
412 | for (i = 0; i < level && remaining; i++) { | |||
413 | remaining = sort_edges (remaining, i, &head_other); | |||
414 | *head_out = merge_sorted_edges (*head_out, head_other); | |||
415 | } | |||
416 | ||||
417 | return remaining; | |||
418 | } | |||
419 | ||||
420 | static edge_t * | |||
421 | merge_unsorted_edges (edge_t *head, edge_t *unsorted) | |||
422 | { | |||
423 | sort_edges (unsorted, UINT_MAX(2147483647 *2U +1U), &unsorted); | |||
424 | return merge_sorted_edges (head, unsorted); | |||
425 | } | |||
426 | ||||
427 | static void | |||
428 | active_edges_insert (sweep_line_t *sweep) | |||
429 | { | |||
430 | edge_t *prev; | |||
431 | int x; | |||
432 | ||||
433 | x = sweep->insert_x; | |||
434 | prev = sweep->cursor; | |||
435 | if (prev->x > x) { | |||
436 | do { | |||
437 | prev = prev->prev; | |||
438 | } while (prev->x > x); | |||
439 | } else { | |||
440 | while (prev->next->x < x) | |||
441 | prev = prev->next; | |||
442 | } | |||
443 | ||||
444 | prev->next = merge_unsorted_edges (prev->next, sweep->insert); | |||
445 | sweep->cursor = sweep->insert; | |||
446 | sweep->insert = NULL((void*)0); | |||
447 | sweep->insert_x = INT_MAX2147483647; | |||
448 | } | |||
449 | ||||
450 | static inline void | |||
451 | active_edges_to_traps (sweep_line_t *sweep) | |||
452 | { | |||
453 | int top = sweep->current_y; | |||
454 | edge_t *pos; | |||
455 | ||||
456 | if (sweep->last_y == sweep->current_y) | |||
457 | return; | |||
458 | ||||
459 | if (sweep->insert) | |||
460 | active_edges_insert (sweep); | |||
461 | ||||
462 | pos = sweep->head.next; | |||
463 | if (pos == &sweep->tail) | |||
464 | return; | |||
465 | ||||
466 | if (sweep->fill_rule == CAIRO_FILL_RULE_WINDING) { | |||
467 | do { | |||
468 | edge_t *left, *right; | |||
469 | int winding; | |||
470 | ||||
471 | left = pos; | |||
472 | winding = left->dir; | |||
473 | ||||
474 | right = left->next; | |||
475 | ||||
476 | /* Check if there is a co-linear edge with an existing trap */ | |||
477 | while (right->x == left->x) { | |||
478 | if (right->right != NULL((void*)0)) { | |||
479 | assert (left->right == NULL)((void) sizeof ((left->right == ((void*)0)) ? 1 : 0), __extension__ ({ if (left->right == ((void*)0)) ; else __assert_fail ("left->right == NULL" , "/root/firefox-clang/gfx/cairo/cairo/src/cairo-bentley-ottmann-rectangular.c" , 479, __extension__ __PRETTY_FUNCTION__); })); | |||
480 | /* continuation on left */ | |||
481 | left->top = right->top; | |||
482 | left->right = right->right; | |||
483 | right->right = NULL((void*)0); | |||
484 | } | |||
485 | winding += right->dir; | |||
486 | right = right->next; | |||
487 | } | |||
488 | ||||
489 | if (winding == 0) { | |||
490 | if (left->right != NULL((void*)0)) | |||
491 | edge_end_box (sweep, left, top); | |||
492 | pos = right; | |||
493 | continue; | |||
494 | } | |||
495 | ||||
496 | do { | |||
497 | /* End all subsumed traps */ | |||
498 | if (unlikely (right->right != NULL)(__builtin_expect (!!(right->right != ((void*)0)), 0))) | |||
499 | edge_end_box (sweep, right, top); | |||
500 | ||||
501 | /* Greedily search for the closing edge, so that we generate | |||
502 | * the * maximal span width with the minimal number of | |||
503 | * boxes. | |||
504 | */ | |||
505 | winding += right->dir; | |||
506 | if (winding == 0 && right->x != right->next->x) | |||
507 | break; | |||
508 | ||||
509 | right = right->next; | |||
510 | } while (TRUE1); | |||
511 | ||||
512 | edge_start_or_continue_box (sweep, left, right, top); | |||
513 | ||||
514 | pos = right->next; | |||
515 | } while (pos != &sweep->tail); | |||
516 | } else { | |||
517 | do { | |||
518 | edge_t *right = pos->next; | |||
519 | int count = 0; | |||
520 | ||||
521 | do { | |||
522 | /* End all subsumed traps */ | |||
523 | if (unlikely (right->right != NULL)(__builtin_expect (!!(right->right != ((void*)0)), 0))) | |||
524 | edge_end_box (sweep, right, top); | |||
525 | ||||
526 | /* skip co-linear edges */ | |||
527 | if (++count & 1 && right->x != right->next->x) | |||
528 | break; | |||
529 | ||||
530 | right = right->next; | |||
531 | } while (TRUE1); | |||
532 | ||||
533 | edge_start_or_continue_box (sweep, pos, right, top); | |||
534 | ||||
535 | pos = right->next; | |||
536 | } while (pos != &sweep->tail); | |||
537 | } | |||
538 | ||||
539 | sweep->last_y = sweep->current_y; | |||
540 | } | |||
541 | ||||
542 | static inline void | |||
543 | sweep_line_delete_edge (sweep_line_t *sweep, edge_t *edge) | |||
544 | { | |||
545 | if (edge->right != NULL((void*)0)) { | |||
546 | edge_t *next = edge->next; | |||
547 | if (next->x == edge->x) { | |||
548 | next->top = edge->top; | |||
549 | next->right = edge->right; | |||
550 | } else | |||
551 | edge_end_box (sweep, edge, sweep->current_y); | |||
552 | } | |||
553 | ||||
554 | if (sweep->cursor == edge) | |||
555 | sweep->cursor = edge->prev; | |||
556 | ||||
557 | edge->prev->next = edge->next; | |||
558 | edge->next->prev = edge->prev; | |||
559 | } | |||
560 | ||||
561 | static inline cairo_bool_t | |||
562 | sweep_line_delete (sweep_line_t *sweep, rectangle_t *rectangle) | |||
563 | { | |||
564 | cairo_bool_t update; | |||
565 | ||||
566 | update = TRUE1; | |||
567 | if (sweep->fill_rule == CAIRO_FILL_RULE_WINDING && | |||
568 | rectangle->left.prev->dir == rectangle->left.dir) | |||
| ||||
569 | { | |||
570 | update = rectangle->left.next != &rectangle->right; | |||
571 | } | |||
572 | ||||
573 | sweep_line_delete_edge (sweep, &rectangle->left); | |||
574 | sweep_line_delete_edge (sweep, &rectangle->right); | |||
575 | ||||
576 | rectangle_pop_stop (sweep); | |||
577 | return update; | |||
578 | } | |||
579 | ||||
580 | static inline void | |||
581 | sweep_line_insert (sweep_line_t *sweep, rectangle_t *rectangle) | |||
582 | { | |||
583 | if (sweep->insert) | |||
584 | sweep->insert->prev = &rectangle->right; | |||
585 | rectangle->right.next = sweep->insert; | |||
586 | rectangle->right.prev = &rectangle->left; | |||
587 | rectangle->left.next = &rectangle->right; | |||
588 | rectangle->left.prev = NULL((void*)0); | |||
589 | sweep->insert = &rectangle->left; | |||
590 | if (rectangle->left.x < sweep->insert_x) | |||
591 | sweep->insert_x = rectangle->left.x; | |||
592 | ||||
593 | pqueue_push (sweep, rectangle); | |||
594 | } | |||
595 | ||||
596 | static cairo_status_t | |||
597 | _cairo_bentley_ottmann_tessellate_rectangular (rectangle_t **rectangles, | |||
598 | int num_rectangles, | |||
599 | cairo_fill_rule_t fill_rule, | |||
600 | cairo_bool_t do_traps, | |||
601 | void *container) | |||
602 | { | |||
603 | sweep_line_t sweep_line; | |||
604 | rectangle_t *rectangle; | |||
605 | cairo_status_t status; | |||
606 | cairo_bool_t update; | |||
607 | ||||
608 | sweep_line_init (&sweep_line, | |||
609 | rectangles, num_rectangles, | |||
610 | fill_rule, | |||
611 | do_traps, container); | |||
612 | if ((status = setjmp (sweep_line.unwind)_setjmp (sweep_line.unwind))) | |||
613 | return status; | |||
614 | ||||
615 | update = FALSE0; | |||
616 | ||||
617 | rectangle = rectangle_pop_start (&sweep_line); | |||
618 | do { | |||
619 | if (rectangle->top != sweep_line.current_y) { | |||
620 | rectangle_t *stop; | |||
621 | ||||
622 | stop = rectangle_peek_stop (&sweep_line); | |||
623 | while (stop != NULL((void*)0) && stop->bottom < rectangle->top) { | |||
624 | if (stop->bottom != sweep_line.current_y) { | |||
625 | if (update) { | |||
626 | active_edges_to_traps (&sweep_line); | |||
627 | update = FALSE0; | |||
628 | } | |||
629 | ||||
630 | sweep_line.current_y = stop->bottom; | |||
631 | } | |||
632 | ||||
633 | update |= sweep_line_delete (&sweep_line, stop); | |||
634 | stop = rectangle_peek_stop (&sweep_line); | |||
635 | } | |||
636 | ||||
637 | if (update) { | |||
638 | active_edges_to_traps (&sweep_line); | |||
639 | update = FALSE0; | |||
640 | } | |||
641 | ||||
642 | sweep_line.current_y = rectangle->top; | |||
643 | } | |||
644 | ||||
645 | do { | |||
646 | sweep_line_insert (&sweep_line, rectangle); | |||
647 | } while ((rectangle = rectangle_pop_start (&sweep_line)) != NULL((void*)0) && | |||
648 | sweep_line.current_y == rectangle->top); | |||
649 | update = TRUE1; | |||
650 | } while (rectangle); | |||
651 | ||||
652 | while ((rectangle = rectangle_peek_stop (&sweep_line)) != NULL((void*)0)) { | |||
653 | if (rectangle->bottom != sweep_line.current_y) { | |||
654 | if (update) { | |||
655 | active_edges_to_traps (&sweep_line); | |||
656 | update = FALSE0; | |||
657 | } | |||
658 | sweep_line.current_y = rectangle->bottom; | |||
659 | } | |||
660 | ||||
661 | update |= sweep_line_delete (&sweep_line, rectangle); | |||
662 | } | |||
663 | ||||
664 | return CAIRO_STATUS_SUCCESS; | |||
665 | } | |||
666 | ||||
667 | cairo_status_t | |||
668 | _cairo_bentley_ottmann_tessellate_rectangular_traps (cairo_traps_t *traps, | |||
669 | cairo_fill_rule_t fill_rule) | |||
670 | { | |||
671 | rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (rectangle_t)((512 * sizeof (int)) / sizeof(rectangle_t))]; | |||
672 | rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles)((int) (sizeof (stack_rectangles) / sizeof (stack_rectangles[ 0]))) + 3]; | |||
673 | rectangle_t *rectangles, **rectangles_ptrs; | |||
674 | cairo_status_t status; | |||
675 | int i; | |||
676 | ||||
677 | assert (traps->is_rectangular)((void) sizeof ((traps->is_rectangular) ? 1 : 0), __extension__ ({ if (traps->is_rectangular) ; else __assert_fail ("traps->is_rectangular" , "/root/firefox-clang/gfx/cairo/cairo/src/cairo-bentley-ottmann-rectangular.c" , 677, __extension__ __PRETTY_FUNCTION__); })); | |||
678 | ||||
679 | if (unlikely (traps->num_traps <= 1)(__builtin_expect (!!(traps->num_traps <= 1), 0))) { | |||
680 | if (traps->num_traps == 1) { | |||
681 | cairo_trapezoid_t *trap = traps->traps; | |||
682 | if (trap->left.p1.x > trap->right.p1.x) { | |||
683 | cairo_line_t tmp = trap->left; | |||
684 | trap->left = trap->right; | |||
685 | trap->right = tmp; | |||
686 | } | |||
687 | } | |||
688 | return CAIRO_STATUS_SUCCESS; | |||
689 | } | |||
690 | ||||
691 | dump_traps (traps, "bo-rects-traps-in.txt"); | |||
692 | ||||
693 | rectangles = stack_rectangles; | |||
694 | rectangles_ptrs = stack_rectangles_ptrs; | |||
695 | if (traps->num_traps > ARRAY_LENGTH (stack_rectangles)((int) (sizeof (stack_rectangles) / sizeof (stack_rectangles[ 0])))) { | |||
696 | rectangles = _cairo_malloc_ab_plus_c (traps->num_traps, | |||
697 | sizeof (rectangle_t) + | |||
698 | sizeof (rectangle_t *), | |||
699 | 3*sizeof (rectangle_t *)); | |||
700 | if (unlikely (rectangles == NULL)(__builtin_expect (!!(rectangles == ((void*)0)), 0))) | |||
701 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
702 | ||||
703 | rectangles_ptrs = (rectangle_t **) (rectangles + traps->num_traps); | |||
704 | } | |||
705 | ||||
706 | for (i = 0; i < traps->num_traps; i++) { | |||
707 | if (traps->traps[i].left.p1.x < traps->traps[i].right.p1.x) { | |||
708 | rectangles[i].left.x = traps->traps[i].left.p1.x; | |||
709 | rectangles[i].left.dir = 1; | |||
710 | ||||
711 | rectangles[i].right.x = traps->traps[i].right.p1.x; | |||
712 | rectangles[i].right.dir = -1; | |||
713 | } else { | |||
714 | rectangles[i].right.x = traps->traps[i].left.p1.x; | |||
715 | rectangles[i].right.dir = 1; | |||
716 | ||||
717 | rectangles[i].left.x = traps->traps[i].right.p1.x; | |||
718 | rectangles[i].left.dir = -1; | |||
719 | } | |||
720 | ||||
721 | rectangles[i].left.right = NULL((void*)0); | |||
722 | rectangles[i].right.right = NULL((void*)0); | |||
723 | ||||
724 | rectangles[i].top = traps->traps[i].top; | |||
725 | rectangles[i].bottom = traps->traps[i].bottom; | |||
726 | ||||
727 | rectangles_ptrs[i+2] = &rectangles[i]; | |||
728 | } | |||
729 | /* XXX incremental sort */ | |||
730 | _rectangle_sort (rectangles_ptrs+2, i); | |||
731 | ||||
732 | _cairo_traps_clear (traps); | |||
733 | status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs+2, i, | |||
734 | fill_rule, | |||
735 | TRUE1, traps); | |||
736 | traps->is_rectilinear = TRUE1; | |||
737 | traps->is_rectangular = TRUE1; | |||
738 | ||||
739 | if (rectangles != stack_rectangles) | |||
740 | free (rectangles); | |||
741 | ||||
742 | dump_traps (traps, "bo-rects-traps-out.txt"); | |||
743 | ||||
744 | return status; | |||
745 | } | |||
746 | ||||
747 | cairo_status_t | |||
748 | _cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in, | |||
749 | cairo_fill_rule_t fill_rule, | |||
750 | cairo_boxes_t *out) | |||
751 | { | |||
752 | rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (rectangle_t)((512 * sizeof (int)) / sizeof(rectangle_t))]; | |||
753 | rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles)((int) (sizeof (stack_rectangles) / sizeof (stack_rectangles[ 0]))) + 3]; | |||
754 | rectangle_t *rectangles, **rectangles_ptrs; | |||
755 | rectangle_t *stack_rectangles_chain[CAIRO_STACK_ARRAY_LENGTH (rectangle_t *)((512 * sizeof (int)) / sizeof(rectangle_t *)) ]; | |||
756 | rectangle_t **rectangles_chain = NULL((void*)0); | |||
757 | const struct _cairo_boxes_chunk *chunk; | |||
758 | cairo_status_t status; | |||
759 | int i, j, y_min, y_max; | |||
760 | ||||
761 | if (unlikely (in->num_boxes == 0)(__builtin_expect (!!(in->num_boxes == 0), 0))) { | |||
| ||||
762 | _cairo_boxes_clear (out); | |||
763 | return CAIRO_STATUS_SUCCESS; | |||
764 | } | |||
765 | ||||
766 | if (in->num_boxes == 1) { | |||
767 | if (in == out) { | |||
768 | cairo_box_t *box = &in->chunks.base[0]; | |||
769 | ||||
770 | if (box->p1.x > box->p2.x) { | |||
771 | cairo_fixed_t tmp = box->p1.x; | |||
772 | box->p1.x = box->p2.x; | |||
773 | box->p2.x = tmp; | |||
774 | } | |||
775 | } else { | |||
776 | cairo_box_t box = in->chunks.base[0]; | |||
777 | ||||
778 | if (box.p1.x > box.p2.x) { | |||
779 | cairo_fixed_t tmp = box.p1.x; | |||
780 | box.p1.x = box.p2.x; | |||
781 | box.p2.x = tmp; | |||
782 | } | |||
783 | ||||
784 | _cairo_boxes_clear (out); | |||
785 | status = _cairo_boxes_add (out, CAIRO_ANTIALIAS_DEFAULT, &box); | |||
786 | assert (status == CAIRO_STATUS_SUCCESS)((void) sizeof ((status == CAIRO_STATUS_SUCCESS) ? 1 : 0), __extension__ ({ if (status == CAIRO_STATUS_SUCCESS) ; else __assert_fail ( "status == CAIRO_STATUS_SUCCESS", "/root/firefox-clang/gfx/cairo/cairo/src/cairo-bentley-ottmann-rectangular.c" , 786, __extension__ __PRETTY_FUNCTION__); })); | |||
787 | } | |||
788 | return CAIRO_STATUS_SUCCESS; | |||
789 | } | |||
790 | ||||
791 | y_min = INT_MAX2147483647; y_max = INT_MIN(-2147483647 -1); | |||
792 | for (chunk = &in->chunks; chunk
| |||
793 | const cairo_box_t *box = chunk->base; | |||
794 | for (i = 0; i < chunk->count; i++) { | |||
795 | if (box[i].p1.y < y_min) | |||
796 | y_min = box[i].p1.y; | |||
797 | if (box[i].p1.y > y_max) | |||
798 | y_max = box[i].p1.y; | |||
799 | } | |||
800 | } | |||
801 | y_min = _cairo_fixed_integer_floor (y_min); | |||
802 | y_max = _cairo_fixed_integer_floor (y_max) + 1; | |||
803 | y_max -= y_min; | |||
804 | ||||
805 | if (y_max < in->num_boxes) { | |||
806 | rectangles_chain = stack_rectangles_chain; | |||
807 | if (y_max > ARRAY_LENGTH (stack_rectangles_chain)((int) (sizeof (stack_rectangles_chain) / sizeof (stack_rectangles_chain [0])))) { | |||
808 | rectangles_chain = _cairo_malloc_ab (y_max, sizeof (rectangle_t *)); | |||
809 | if (unlikely (rectangles_chain == NULL)(__builtin_expect (!!(rectangles_chain == ((void*)0)), 0))) | |||
810 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
811 | } | |||
812 | memset (rectangles_chain, 0, y_max * sizeof (rectangle_t*)); | |||
813 | } | |||
814 | ||||
815 | rectangles = stack_rectangles; | |||
816 | rectangles_ptrs = stack_rectangles_ptrs; | |||
817 | if (in->num_boxes > ARRAY_LENGTH (stack_rectangles)((int) (sizeof (stack_rectangles) / sizeof (stack_rectangles[ 0])))) { | |||
818 | rectangles = _cairo_malloc_ab_plus_c (in->num_boxes, | |||
819 | sizeof (rectangle_t) + | |||
820 | sizeof (rectangle_t *), | |||
821 | 3*sizeof (rectangle_t *)); | |||
822 | if (unlikely (rectangles == NULL)(__builtin_expect (!!(rectangles == ((void*)0)), 0))) { | |||
823 | if (rectangles_chain != stack_rectangles_chain) | |||
824 | free (rectangles_chain); | |||
825 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
826 | } | |||
827 | ||||
828 | rectangles_ptrs = (rectangle_t **) (rectangles + in->num_boxes); | |||
829 | } | |||
830 | ||||
831 | j = 0; | |||
832 | for (chunk = &in->chunks; chunk
| |||
833 | const cairo_box_t *box = chunk->base; | |||
834 | for (i = 0; i
| |||
835 | int h; | |||
836 | ||||
837 | if (box[i].p1.x < box[i].p2.x) { | |||
838 | rectangles[j].left.x = box[i].p1.x; | |||
839 | rectangles[j].left.dir = 1; | |||
840 | ||||
841 | rectangles[j].right.x = box[i].p2.x; | |||
842 | rectangles[j].right.dir = -1; | |||
843 | } else { | |||
844 | rectangles[j].right.x = box[i].p1.x; | |||
845 | rectangles[j].right.dir = 1; | |||
846 | ||||
847 | rectangles[j].left.x = box[i].p2.x; | |||
848 | rectangles[j].left.dir = -1; | |||
849 | } | |||
850 | ||||
851 | rectangles[j].left.right = NULL((void*)0); | |||
852 | rectangles[j].right.right = NULL((void*)0); | |||
853 | ||||
854 | rectangles[j].top = box[i].p1.y; | |||
855 | rectangles[j].bottom = box[i].p2.y; | |||
856 | ||||
857 | if (rectangles_chain) { | |||
858 | h = _cairo_fixed_integer_floor (box[i].p1.y) - y_min; | |||
859 | rectangles[j].left.next = (edge_t *)rectangles_chain[h]; | |||
860 | rectangles_chain[h] = &rectangles[j]; | |||
861 | } else { | |||
862 | rectangles_ptrs[j+2] = &rectangles[j]; | |||
863 | } | |||
864 | j++; | |||
865 | } | |||
866 | } | |||
867 | ||||
868 | if (rectangles_chain
| |||
869 | j = 2; | |||
870 | for (y_min = 0; y_min < y_max; y_min++) { | |||
871 | rectangle_t *r; | |||
872 | int start = j; | |||
873 | for (r = rectangles_chain[y_min]; r; r = (rectangle_t *)r->left.next) | |||
874 | rectangles_ptrs[j++] = r; | |||
875 | if (j > start + 1) | |||
876 | _rectangle_sort (rectangles_ptrs + start, j - start); | |||
877 | } | |||
878 | ||||
879 | if (rectangles_chain
| |||
880 | free (rectangles_chain); | |||
881 | ||||
882 | j -= 2; | |||
883 | } else { | |||
884 | _rectangle_sort (rectangles_ptrs + 2, j); | |||
885 | } | |||
886 | ||||
887 | _cairo_boxes_clear (out); | |||
888 | status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs+2, j, | |||
889 | fill_rule, | |||
890 | FALSE0, out); | |||
891 | if (rectangles != stack_rectangles) | |||
892 | free (rectangles); | |||
893 | ||||
894 | return status; | |||
895 | } |