Rev 1892 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1892 | Rev 3959 | ||
---|---|---|---|
Line 38... | Line 38... | ||
38 | /* Provide definitions for standalone compilation */ |
38 | /* Provide definitions for standalone compilation */ |
39 | #include "cairoint.h" |
39 | #include "cairoint.h" |
Line 40... | Line 40... | ||
40 | 40 | ||
41 | #include "cairo-boxes-private.h" |
41 | #include "cairo-boxes-private.h" |
42 | #include "cairo-error-private.h" |
42 | #include "cairo-error-private.h" |
43 | #include "cairo-combsort-private.h" |
43 | #include "cairo-combsort-inline.h" |
- | 44 | #include "cairo-list-private.h" |
|
Line 44... | Line 45... | ||
44 | #include "cairo-list-private.h" |
45 | #include "cairo-traps-private.h" |
Line 45... | Line 46... | ||
45 | 46 | ||
46 | #include |
47 | #include |
Line 67... | Line 68... | ||
67 | #define PQ_FIRST_ENTRY 1 |
68 | #define PQ_FIRST_ENTRY 1 |
Line 68... | Line 69... | ||
68 | 69 | ||
69 | /* left and right children are index * 2 and (index * 2) +1 respectively */ |
70 | /* left and right children are index * 2 and (index * 2) +1 respectively */ |
Line 70... | Line -... | ||
70 | #define PQ_LEFT_CHILD_INDEX(i) ((i) << 1) |
- | |
71 | - | ||
72 | typedef struct _pqueue { |
- | |
73 | int size, max_size; |
- | |
74 | - | ||
75 | rectangle_t **elements; |
- | |
76 | rectangle_t *elements_embedded[1024]; |
- | |
77 | } pqueue_t; |
71 | #define PQ_LEFT_CHILD_INDEX(i) ((i) << 1) |
78 | 72 | ||
79 | typedef struct _sweep_line { |
- | |
80 | rectangle_t **rectangles; |
73 | typedef struct _sweep_line { |
81 | pqueue_t pq; |
74 | rectangle_t **rectangles; |
82 | edge_t head, tail; |
75 | rectangle_t **stop; |
83 | edge_t *insert_left, *insert_right; |
76 | edge_t head, tail, *insert, *cursor; |
- | 77 | int32_t current_y; |
|
Line -... | Line 78... | ||
- | 78 | int32_t last_y; |
|
84 | int32_t current_y; |
79 | int stop_size; |
Line -... | Line 80... | ||
- | 80 | ||
- | 81 | int32_t insert_x; |
|
- | 82 | cairo_fill_rule_t fill_rule; |
|
85 | int32_t last_y; |
83 | |
86 | 84 | cairo_bool_t do_traps; |
|
Line 87... | Line 85... | ||
87 | cairo_fill_rule_t fill_rule; |
85 | void *container; |
Line 137... | Line 135... | ||
137 | { |
135 | { |
138 | return a->bottom - b->bottom; |
136 | return a->bottom - b->bottom; |
139 | } |
137 | } |
Line 140... | Line 138... | ||
140 | 138 | ||
141 | static inline void |
- | |
142 | pqueue_init (pqueue_t *pq) |
- | |
143 | { |
- | |
144 | pq->max_size = ARRAY_LENGTH (pq->elements_embedded); |
- | |
145 | pq->size = 0; |
- | |
146 | - | ||
147 | pq->elements = pq->elements_embedded; |
- | |
148 | pq->elements[PQ_FIRST_ENTRY] = NULL; |
- | |
149 | } |
- | |
150 | - | ||
151 | static inline void |
- | |
152 | pqueue_fini (pqueue_t *pq) |
- | |
153 | { |
- | |
154 | if (pq->elements != pq->elements_embedded) |
- | |
155 | free (pq->elements); |
- | |
156 | } |
- | |
157 | - | ||
158 | static cairo_bool_t |
- | |
159 | pqueue_grow (pqueue_t *pq) |
- | |
160 | { |
- | |
161 | rectangle_t **new_elements; |
- | |
162 | pq->max_size *= 2; |
- | |
163 | - | ||
164 | if (pq->elements == pq->elements_embedded) { |
- | |
165 | new_elements = _cairo_malloc_ab (pq->max_size, |
- | |
166 | sizeof (rectangle_t *)); |
- | |
167 | if (unlikely (new_elements == NULL)) |
- | |
168 | return FALSE; |
- | |
169 | - | ||
170 | memcpy (new_elements, pq->elements_embedded, |
- | |
171 | sizeof (pq->elements_embedded)); |
- | |
172 | } else { |
- | |
173 | new_elements = _cairo_realloc_ab (pq->elements, |
- | |
174 | pq->max_size, |
- | |
175 | sizeof (rectangle_t *)); |
- | |
176 | if (unlikely (new_elements == NULL)) |
- | |
177 | return FALSE; |
- | |
178 | } |
- | |
179 | - | ||
180 | pq->elements = new_elements; |
- | |
181 | return TRUE; |
- | |
182 | } |
- | |
183 | - | ||
184 | static inline void |
139 | static inline void |
185 | pqueue_push (sweep_line_t *sweep, rectangle_t *rectangle) |
140 | pqueue_push (sweep_line_t *sweep, rectangle_t *rectangle) |
186 | { |
141 | { |
187 | rectangle_t **elements; |
142 | rectangle_t **elements; |
Line 188... | Line -... | ||
188 | int i, parent; |
- | |
189 | - | ||
190 | if (unlikely (sweep->pq.size + 1 == sweep->pq.max_size)) { |
- | |
191 | if (unlikely (! pqueue_grow (&sweep->pq))) { |
- | |
192 | longjmp (sweep->unwind, |
- | |
193 | _cairo_error (CAIRO_STATUS_NO_MEMORY)); |
- | |
194 | } |
- | |
195 | } |
143 | int i, parent; |
196 | 144 | ||
197 | elements = sweep->pq.elements; |
145 | elements = sweep->stop; |
198 | for (i = ++sweep->pq.size; |
146 | for (i = ++sweep->stop_size; |
199 | i != PQ_FIRST_ENTRY && |
147 | i != PQ_FIRST_ENTRY && |
200 | rectangle_compare_stop (rectangle, |
148 | rectangle_compare_stop (rectangle, |
201 | elements[parent = PQ_PARENT_INDEX (i)]) < 0; |
149 | elements[parent = PQ_PARENT_INDEX (i)]) < 0; |
Line 206... | Line 154... | ||
206 | 154 | ||
207 | elements[i] = rectangle; |
155 | elements[i] = rectangle; |
Line 208... | Line 156... | ||
208 | } |
156 | } |
209 | 157 | ||
210 | static inline void |
158 | static inline void |
211 | pqueue_pop (pqueue_t *pq) |
159 | rectangle_pop_stop (sweep_line_t *sweep) |
212 | { |
160 | { |
213 | rectangle_t **elements = pq->elements; |
161 | rectangle_t **elements = sweep->stop; |
Line 214... | Line 162... | ||
214 | rectangle_t *tail; |
162 | rectangle_t *tail; |
215 | int child, i; |
163 | int child, i; |
216 | 164 | ||
217 | tail = elements[pq->size--]; |
165 | tail = elements[sweep->stop_size--]; |
218 | if (pq->size == 0) { |
166 | if (sweep->stop_size == 0) { |
Line 219... | Line 167... | ||
219 | elements[PQ_FIRST_ENTRY] = NULL; |
167 | elements[PQ_FIRST_ENTRY] = NULL; |
220 | return; |
168 | return; |
221 | } |
169 | } |
222 | 170 | ||
223 | for (i = PQ_FIRST_ENTRY; |
171 | for (i = PQ_FIRST_ENTRY; |
224 | (child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size; |
172 | (child = PQ_LEFT_CHILD_INDEX (i)) <= sweep->stop_size; |
225 | i = child) |
173 | i = child) |
226 | { |
174 | { |
227 | if (child != pq->size && |
175 | if (child != sweep->stop_size && |
228 | rectangle_compare_stop (elements[child+1], |
176 | rectangle_compare_stop (elements[child+1], |
Line 246... | Line 194... | ||
246 | } |
194 | } |
Line 247... | Line 195... | ||
247 | 195 | ||
248 | static inline rectangle_t * |
196 | static inline rectangle_t * |
249 | rectangle_peek_stop (sweep_line_t *sweep_line) |
197 | rectangle_peek_stop (sweep_line_t *sweep_line) |
250 | { |
198 | { |
251 | return sweep_line->pq.elements[PQ_FIRST_ENTRY]; |
199 | return sweep_line->stop[PQ_FIRST_ENTRY]; |
Line 252... | Line 200... | ||
252 | } |
200 | } |
253 | 201 | ||
254 | CAIRO_COMBSORT_DECLARE (_rectangle_sort, |
202 | CAIRO_COMBSORT_DECLARE (_rectangle_sort, |
Line 255... | Line 203... | ||
255 | rectangle_t *, |
203 | rectangle_t *, |
256 | rectangle_compare_start) |
204 | rectangle_compare_start) |
257 | 205 | ||
258 | static void |
206 | static void |
259 | sweep_line_init (sweep_line_t *sweep_line, |
207 | sweep_line_init (sweep_line_t *sweep_line, |
- | 208 | rectangle_t **rectangles, |
|
- | 209 | int num_rectangles, |
|
260 | rectangle_t **rectangles, |
210 | cairo_fill_rule_t fill_rule, |
- | 211 | cairo_bool_t do_traps, |
|
261 | int num_rectangles, |
212 | void *container) |
262 | cairo_fill_rule_t fill_rule) |
213 | { |
263 | { |
214 | rectangles[-2] = NULL; |
- | 215 | rectangles[-1] = NULL; |
|
- | 216 | rectangles[num_rectangles] = NULL; |
|
Line -... | Line 217... | ||
- | 217 | sweep_line->rectangles = rectangles; |
|
- | 218 | sweep_line->stop = rectangles - 2; |
|
- | 219 | sweep_line->stop_size = 0; |
|
- | 220 | ||
- | 221 | sweep_line->insert = NULL; |
|
264 | _rectangle_sort (rectangles, num_rectangles); |
222 | sweep_line->insert_x = INT_MAX; |
265 | rectangles[num_rectangles] = NULL; |
223 | sweep_line->cursor = &sweep_line->tail; |
266 | sweep_line->rectangles = rectangles; |
224 | |
267 | 225 | sweep_line->head.dir = 0; |
|
- | 226 | sweep_line->head.x = INT32_MIN; |
|
268 | sweep_line->head.x = INT32_MIN; |
227 | sweep_line->head.right = NULL; |
269 | sweep_line->head.right = NULL; |
228 | sweep_line->head.prev = NULL; |
- | 229 | sweep_line->head.next = &sweep_line->tail; |
|
270 | sweep_line->head.dir = 0; |
230 | sweep_line->tail.prev = &sweep_line->head; |
271 | sweep_line->head.next = &sweep_line->tail; |
- | |
272 | sweep_line->tail.x = INT32_MAX; |
- | |
273 | sweep_line->tail.right = NULL; |
- | |
274 | sweep_line->tail.dir = 0; |
- | |
Line 275... | Line 231... | ||
275 | sweep_line->tail.prev = &sweep_line->head; |
231 | sweep_line->tail.next = NULL; |
276 | 232 | sweep_line->tail.right = NULL; |
|
Line 277... | Line 233... | ||
277 | sweep_line->insert_left = &sweep_line->tail; |
233 | sweep_line->tail.x = INT32_MAX; |
278 | sweep_line->insert_right = &sweep_line->tail; |
- | |
- | 234 | sweep_line->tail.dir = 0; |
|
279 | 235 | ||
280 | sweep_line->current_y = INT32_MIN; |
236 | sweep_line->current_y = INT32_MIN; |
Line 281... | Line 237... | ||
281 | sweep_line->last_y = INT32_MIN; |
237 | sweep_line->last_y = INT32_MIN; |
282 | - | ||
283 | sweep_line->fill_rule = fill_rule; |
- | |
284 | - | ||
285 | pqueue_init (&sweep_line->pq); |
- | |
286 | } |
- | |
287 | - | ||
288 | static void |
238 | |
289 | sweep_line_fini (sweep_line_t *sweep_line) |
- | |
290 | { |
- | |
291 | pqueue_fini (&sweep_line->pq); |
- | |
292 | } |
- | |
293 | 239 | sweep_line->fill_rule = fill_rule; |
|
294 | static void |
240 | sweep_line->container = container; |
Line 295... | Line 241... | ||
295 | edge_end_box (sweep_line_t *sweep_line, |
241 | sweep_line->do_traps = do_traps; |
296 | edge_t *left, |
242 | } |
297 | int32_t bot, |
243 | |
298 | cairo_bool_t do_traps, |
244 | static void |
299 | void *container) |
245 | edge_end_box (sweep_line_t *sweep_line, edge_t *left, int32_t bot) |
300 | { |
246 | { |
301 | cairo_status_t status = CAIRO_STATUS_SUCCESS; |
247 | cairo_status_t status = CAIRO_STATUS_SUCCESS; |
302 | 248 | ||
303 | /* Only emit (trivial) non-degenerate trapezoids with positive height. */ |
249 | /* Only emit (trivial) non-degenerate trapezoids with positive height. */ |
304 | if (likely (left->top < bot)) { |
250 | if (likely (left->top < bot)) { |
305 | if (do_traps) { |
251 | if (sweep_line->do_traps) { |
306 | cairo_line_t _left = { |
252 | cairo_line_t _left = { |
307 | { left->x, left->top }, |
253 | { left->x, left->top }, |
308 | { left->x, bot }, |
254 | { left->x, bot }, |
Line 309... | Line 255... | ||
309 | }, _right = { |
255 | }, _right = { |
310 | { left->right->x, left->top }, |
256 | { left->right->x, left->top }, |
311 | { left->right->x, bot }, |
257 | { left->right->x, bot }, |
312 | }; |
258 | }; |
Line 313... | Line 259... | ||
313 | _cairo_traps_add_trap (container, left->top, bot, &_left, &_right); |
259 | _cairo_traps_add_trap (sweep_line->container, left->top, bot, &_left, &_right); |
- | 260 | status = _cairo_traps_status ((cairo_traps_t *) sweep_line->container); |
|
- | 261 | } else { |
|
314 | status = _cairo_traps_status ((cairo_traps_t *) container); |
262 | cairo_box_t box; |
315 | } else { |
263 | |
316 | cairo_box_t box; |
264 | box.p1.x = left->x; |
317 | 265 | box.p1.y = left->top; |
|
Line 336... | Line 284... | ||
336 | * trapezoid would be a continuation of the existing one. */ |
284 | * trapezoid would be a continuation of the existing one. */ |
337 | static inline void |
285 | static inline void |
338 | edge_start_or_continue_box (sweep_line_t *sweep_line, |
286 | edge_start_or_continue_box (sweep_line_t *sweep_line, |
339 | edge_t *left, |
287 | edge_t *left, |
340 | edge_t *right, |
288 | edge_t *right, |
341 | int top, |
289 | int top) |
342 | cairo_bool_t do_traps, |
- | |
343 | void *container) |
- | |
344 | { |
290 | { |
345 | if (left->right == right) |
291 | if (left->right == right) |
346 | return; |
292 | return; |
Line 347... | Line 293... | ||
347 | 293 | ||
348 | if (left->right != NULL) { |
294 | if (left->right != NULL) { |
349 | if (right != NULL && left->right->x == right->x) { |
295 | if (left->right->x == right->x) { |
350 | /* continuation on right, so just swap edges */ |
296 | /* continuation on right, so just swap edges */ |
351 | left->right = right; |
297 | left->right = right; |
352 | return; |
298 | return; |
Line 353... | Line 299... | ||
353 | } |
299 | } |
354 | - | ||
355 | edge_end_box (sweep_line, |
300 | |
Line 356... | Line 301... | ||
356 | left, top, do_traps, container); |
301 | edge_end_box (sweep_line, left, top); |
357 | } |
302 | } |
358 | 303 | ||
359 | if (right != NULL && left->x != right->x) { |
304 | if (left->x != right->x) { |
360 | left->top = top; |
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 && 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) |
|
- | 352 | return head; |
|
- | 353 | ||
- | 354 | start_with_b: |
|
- | 355 | x = head_a->x; |
|
- | 356 | while (head_b != NULL && 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) |
|
- | 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) { |
|
- | 396 | *head_out = list; |
|
- | 397 | return NULL; |
|
- | 398 | } |
|
- | 399 | ||
- | 400 | remaining = head_other->next; |
|
- | 401 | if (list->x <= head_other->x) { |
|
- | 402 | *head_out = list; |
|
- | 403 | head_other->next = NULL; |
|
- | 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; |
|
- | 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, &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; |
|
Line 361... | Line 446... | ||
361 | left->right = right; |
446 | sweep->insert = NULL; |
362 | } |
447 | sweep->insert_x = INT_MAX; |
363 | } |
- | |
364 | - | ||
365 | static inline void |
448 | } |
366 | active_edges_to_traps (sweep_line_t *sweep, |
449 | |
367 | cairo_bool_t do_traps, |
450 | static inline void |
Line 368... | Line 451... | ||
368 | void *container) |
451 | active_edges_to_traps (sweep_line_t *sweep) |
369 | { |
452 | { |
Line -... | Line 453... | ||
- | 453 | int top = sweep->current_y; |
|
- | 454 | edge_t *pos; |
|
- | 455 | ||
370 | int top = sweep->current_y; |
456 | if (sweep->last_y == sweep->current_y) |
371 | edge_t *pos; |
457 | return; |
372 | 458 | ||
Line 373... | Line 459... | ||
373 | if (sweep->last_y == sweep->current_y) |
459 | if (sweep->insert) |
Line 386... | Line 472... | ||
386 | winding = left->dir; |
472 | winding = left->dir; |
Line 387... | Line 473... | ||
387 | 473 | ||
Line 388... | Line 474... | ||
388 | right = left->next; |
474 | right = left->next; |
389 | - | ||
390 | /* Check if there is a co-linear edge with an existing trap */ |
475 | |
391 | if (left->right == NULL) { |
- | |
392 | while (unlikely (right->x == left->x)) { |
476 | /* Check if there is a co-linear edge with an existing trap */ |
- | 477 | while (right->x == left->x) { |
|
393 | winding += right->dir; |
478 | if (right->right != NULL) { |
394 | if (right->right != NULL) { |
479 | assert (left->right == NULL); |
395 | /* continuation on left */ |
480 | /* continuation on left */ |
396 | left->top = right->top; |
481 | left->top = right->top; |
397 | left->right = right->right; |
- | |
398 | right->right = NULL; |
- | |
399 | winding -= right->dir; |
482 | left->right = right->right; |
400 | break; |
- | |
- | 483 | right->right = NULL; |
|
401 | } |
484 | } |
402 | 485 | winding += right->dir; |
|
Line 403... | Line 486... | ||
403 | right = right->next; |
486 | right = right->next; |
- | 487 | } |
|
- | 488 | ||
404 | } |
489 | if (winding == 0) { |
405 | 490 | if (left->right != NULL) |
|
406 | if (winding == 0) { |
491 | edge_end_box (sweep, left, top); |
407 | pos = right; |
- | |
408 | continue; |
- | |
409 | } |
- | |
410 | } |
- | |
411 | - | ||
Line 412... | Line 492... | ||
412 | /* Greedily search for the closing edge, so that we generate the |
492 | pos = right; |
413 | * maximal span width with the minimal number of trapezoids. |
493 | continue; |
414 | */ |
494 | } |
415 | 495 | ||
416 | do { |
- | |
417 | /* End all subsumed traps */ |
- | |
Line -... | Line 496... | ||
- | 496 | do { |
|
- | 497 | /* End all subsumed traps */ |
|
- | 498 | if (unlikely (right->right != NULL)) |
|
- | 499 | edge_end_box (sweep, right, top); |
|
418 | if (unlikely (right->right != NULL)) { |
500 | |
419 | edge_end_box (sweep, |
- | |
420 | right, top, do_traps, container); |
- | |
421 | } |
501 | /* Greedily search for the closing edge, so that we generate |
422 | 502 | * the * maximal span width with the minimal number of |
|
423 | winding += right->dir; |
- | |
Line 424... | Line 503... | ||
424 | if (winding == 0) { |
503 | * boxes. |
425 | /* skip co-linear edges */ |
504 | */ |
Line 426... | Line 505... | ||
426 | if (likely (right->x != right->next->x)) |
505 | winding += right->dir; |
427 | break; |
- | |
428 | } |
- | |
Line 429... | Line 506... | ||
429 | 506 | if (winding == 0 && right->x != right->next->x) |
|
430 | right = right->next; |
507 | break; |
431 | } while (TRUE); |
508 | |
432 | 509 | right = right->next; |
|
433 | edge_start_or_continue_box (sweep, |
510 | } while (TRUE); |
434 | left, right, top, |
511 | |
Line 435... | Line 512... | ||
435 | do_traps, container); |
512 | edge_start_or_continue_box (sweep, left, right, top); |
436 | 513 | ||
437 | pos = right->next; |
514 | pos = right->next; |
438 | } while (pos != &sweep->tail); |
515 | } while (pos != &sweep->tail); |
439 | } else { |
- | |
440 | do { |
- | |
Line 441... | Line -... | ||
441 | edge_t *right = pos->next; |
- | |
442 | int count = 0; |
516 | } else { |
443 | 517 | do { |
|
444 | do { |
518 | edge_t *right = pos->next; |
445 | /* End all subsumed traps */ |
- | |
Line 446... | Line 519... | ||
446 | if (unlikely (right->right != NULL)) { |
519 | int count = 0; |
447 | edge_end_box (sweep, |
520 | |
Line 448... | Line 521... | ||
448 | right, top, do_traps, container); |
521 | do { |
449 | } |
- | |
450 | - | ||
Line 451... | Line 522... | ||
451 | if (++count & 1) { |
522 | /* End all subsumed traps */ |
452 | /* skip co-linear edges */ |
523 | if (unlikely (right->right != NULL)) |
453 | if (likely (right->x != right->next->x)) |
524 | edge_end_box (sweep, right, top); |
Line 454... | Line 525... | ||
454 | break; |
525 | |
455 | } |
526 | /* skip co-linear edges */ |
Line 456... | Line 527... | ||
456 | 527 | if (++count & 1 && right->x != right->next->x) |
|
457 | right = right->next; |
528 | break; |
458 | } while (TRUE); |
- | |
459 | - | ||
460 | edge_start_or_continue_box (sweep, |
- | |
461 | pos, right, top, |
529 | |
462 | do_traps, container); |
530 | right = right->next; |
463 | 531 | } while (TRUE); |
|
464 | pos = right->next; |
532 | |
465 | } while (pos != &sweep->tail); |
533 | edge_start_or_continue_box (sweep, pos, right, top); |
466 | } |
534 | |
467 | 535 | pos = right->next; |
|
468 | sweep->last_y = sweep->current_y; |
536 | } while (pos != &sweep->tail); |
469 | } |
- | |
470 | - | ||
471 | static inline void |
- | |
472 | sweep_line_delete_edge (sweep_line_t *sweep_line, |
- | |
473 | edge_t *edge, |
537 | } |
Line 474... | Line -... | ||
474 | cairo_bool_t do_traps, |
- | |
475 | void *container) |
- | |
476 | { |
538 | |
477 | if (edge->right != NULL) { |
539 | sweep->last_y = sweep->current_y; |
Line 478... | Line 540... | ||
478 | edge_t *next = edge->next; |
540 | } |
479 | if (next->x == edge->x) { |
541 | |
480 | next->top = edge->top; |
542 | static inline void |
Line 481... | Line 543... | ||
481 | next->right = edge->right; |
543 | sweep_line_delete_edge (sweep_line_t *sweep, edge_t *edge) |
482 | } else { |
544 | { |
483 | edge_end_box (sweep_line, |
- | |
484 | edge, |
- | |
485 | sweep_line->current_y, |
- | |
486 | do_traps, container); |
545 | if (edge->right != NULL) { |
487 | } |
546 | edge_t *next = edge->next; |
Line 488... | Line 547... | ||
488 | } |
547 | if (next->x == edge->x) { |
489 | 548 | next->top = edge->top; |
|
490 | if (sweep_line->insert_left == edge) |
549 | next->right = edge->right; |
491 | sweep_line->insert_left = edge->next; |
550 | } else |
492 | if (sweep_line->insert_right == edge) |
551 | edge_end_box (sweep, edge, sweep->current_y); |
493 | sweep_line->insert_right = edge->next; |
552 | } |
Line 494... | Line 553... | ||
494 | 553 | ||
495 | edge->prev->next = edge->next; |
554 | if (sweep->cursor == edge) |
496 | edge->next->prev = edge->prev; |
- | |
Line 497... | Line -... | ||
497 | } |
- | |
498 | - | ||
499 | static inline cairo_bool_t |
- | |
500 | sweep_line_delete (sweep_line_t *sweep, |
- | |
501 | rectangle_t *rectangle, |
555 | sweep->cursor = edge->prev; |
502 | cairo_bool_t do_traps, |
556 | |
503 | void *container) |
557 | edge->prev->next = edge->next; |
Line 504... | Line 558... | ||
504 | { |
558 | edge->next->prev = edge->prev; |
505 | cairo_bool_t update; |
559 | } |
506 | 560 | ||
507 | update = TRUE; |
561 | static inline cairo_bool_t |
508 | if (sweep->fill_rule == CAIRO_FILL_RULE_WINDING && |
- | |
509 | rectangle->left.prev->dir == rectangle->left.dir) |
- | |
510 | { |
- | |
511 | update = rectangle->left.next != &rectangle->right; |
562 | sweep_line_delete (sweep_line_t *sweep, rectangle_t *rectangle) |
512 | } |
- | |
513 | - | ||
514 | sweep_line_delete_edge (sweep, |
- | |
515 | &rectangle->left, |
- | |
516 | do_traps, container); |
- | |
517 | - | ||
518 | sweep_line_delete_edge (sweep, |
- | |
519 | &rectangle->right, |
- | |
520 | do_traps, container); |
- | |
521 | - | ||
522 | pqueue_pop (&sweep->pq); |
- | |
523 | return update; |
- | |
524 | } |
- | |
525 | - | ||
526 | static inline void |
- | |
527 | insert_edge (edge_t *edge, edge_t *pos) |
563 | { |
528 | { |
564 | cairo_bool_t update; |
529 | if (pos->x != edge->x) { |
565 | |
530 | if (pos->x > edge->x) { |
- | |
531 | do { |
- | |
532 | UNROLL3({ |
- | |
533 | if (pos->prev->x <= edge->x) |
- | |
534 | break; |
- | |
535 | pos = pos->prev; |
566 | update = TRUE; |
536 | }) |
- | |
537 | } while (TRUE); |
- | |
538 | } else { |
- | |
539 | do { |
- | |
540 | UNROLL3({ |
- | |
541 | pos = pos->next; |
- | |
542 | if (pos->x >= edge->x) |
567 | if (sweep->fill_rule == CAIRO_FILL_RULE_WINDING && |
543 | break; |
- | |
544 | }) |
- | |
545 | } while (TRUE); |
- | |
546 | } |
568 | rectangle->left.prev->dir == rectangle->left.dir) |
547 | } |
- | |
548 | - | ||
549 | pos->prev->next = edge; |
569 | { |
Line 550... | Line 570... | ||
550 | edge->prev = pos->prev; |
570 | update = rectangle->left.next != &rectangle->right; |
551 | edge->next = pos; |
- | |
552 | pos->prev = edge; |
- | |
553 | } |
- | |
554 | - | ||
555 | static inline cairo_bool_t |
- | |
556 | sweep_line_insert (sweep_line_t *sweep, |
- | |
557 | rectangle_t *rectangle) |
- | |
558 | { |
- | |
559 | edge_t *pos; |
571 | } |
Line 560... | Line 572... | ||
560 | 572 | ||
561 | /* right edge */ |
573 | sweep_line_delete_edge (sweep, &rectangle->left); |
562 | pos = sweep->insert_right; |
574 | sweep_line_delete_edge (sweep, &rectangle->right); |
Line 591... | Line 603... | ||
591 | sweep_line_t sweep_line; |
603 | sweep_line_t sweep_line; |
592 | rectangle_t *rectangle; |
604 | rectangle_t *rectangle; |
593 | cairo_status_t status; |
605 | cairo_status_t status; |
594 | cairo_bool_t update = FALSE; |
606 | cairo_bool_t update = FALSE; |
Line 595... | Line 607... | ||
595 | 607 | ||
- | 608 | sweep_line_init (&sweep_line, |
|
- | 609 | rectangles, num_rectangles, |
|
- | 610 | fill_rule, |
|
596 | sweep_line_init (&sweep_line, rectangles, num_rectangles, fill_rule); |
611 | do_traps, container); |
597 | if ((status = setjmp (sweep_line.unwind))) |
612 | if ((status = setjmp (sweep_line.unwind))) |
Line 598... | Line 613... | ||
598 | goto unwind; |
613 | return status; |
599 | 614 | ||
600 | rectangle = rectangle_pop_start (&sweep_line); |
615 | rectangle = rectangle_pop_start (&sweep_line); |
601 | do { |
616 | do { |
Line 602... | Line 617... | ||
602 | if (rectangle->top != sweep_line.current_y) { |
617 | if (rectangle->top != sweep_line.current_y) { |
603 | rectangle_t *stop; |
618 | rectangle_t *stop; |
604 | 619 | ||
605 | stop = rectangle_peek_stop (&sweep_line); |
620 | stop = rectangle_peek_stop (&sweep_line); |
606 | while (stop != NULL && stop->bottom < rectangle->top) { |
621 | while (stop != NULL && stop->bottom < rectangle->top) { |
607 | if (stop->bottom != sweep_line.current_y) { |
- | |
608 | if (update) { |
622 | if (stop->bottom != sweep_line.current_y) { |
609 | active_edges_to_traps (&sweep_line, |
623 | if (update) { |
Line 610... | Line 624... | ||
610 | do_traps, container); |
624 | active_edges_to_traps (&sweep_line); |
611 | update = FALSE; |
625 | update = FALSE; |
Line 612... | Line 626... | ||
612 | } |
626 | } |
613 | - | ||
614 | sweep_line.current_y = stop->bottom; |
627 | |
615 | } |
628 | sweep_line.current_y = stop->bottom; |
Line 616... | Line 629... | ||
616 | 629 | } |
|
617 | update |= sweep_line_delete (&sweep_line, stop, do_traps, container); |
630 | |
618 | 631 | update |= sweep_line_delete (&sweep_line, stop); |
|
619 | stop = rectangle_peek_stop (&sweep_line); |
632 | stop = rectangle_peek_stop (&sweep_line); |
Line 620... | Line 633... | ||
620 | } |
633 | } |
621 | 634 | ||
Line -... | Line 635... | ||
- | 635 | if (update) { |
|
622 | if (update) { |
636 | active_edges_to_traps (&sweep_line); |
623 | active_edges_to_traps (&sweep_line, do_traps, container); |
637 | update = FALSE; |
- | 638 | } |
|
- | 639 | ||
- | 640 | sweep_line.current_y = rectangle->top; |
|
Line 624... | Line 641... | ||
624 | update = FALSE; |
641 | } |
625 | } |
642 | |
626 | 643 | do { |
|
627 | sweep_line.current_y = rectangle->top; |
644 | sweep_line_insert (&sweep_line, rectangle); |
628 | } |
645 | } while ((rectangle = rectangle_pop_start (&sweep_line)) != NULL && |
629 | 646 | sweep_line.current_y == rectangle->top); |
|
630 | update |= sweep_line_insert (&sweep_line, rectangle); |
- | |
631 | } while ((rectangle = rectangle_pop_start (&sweep_line)) != NULL); |
647 | update = TRUE; |
632 | 648 | } while (rectangle); |
|
Line 633... | Line 649... | ||
633 | while ((rectangle = rectangle_peek_stop (&sweep_line)) != NULL) { |
649 | |
634 | if (rectangle->bottom != sweep_line.current_y) { |
650 | while ((rectangle = rectangle_peek_stop (&sweep_line)) != NULL) { |
Line 635... | Line -... | ||
635 | if (update) { |
- | |
636 | active_edges_to_traps (&sweep_line, do_traps, container); |
- | |
637 | update = FALSE; |
651 | if (rectangle->bottom != sweep_line.current_y) { |
638 | } |
652 | if (update) { |
Line 639... | Line 653... | ||
639 | 653 | active_edges_to_traps (&sweep_line); |
|
640 | sweep_line.current_y = rectangle->bottom; |
654 | update = FALSE; |
641 | } |
655 | } |
642 | 656 | sweep_line.current_y = rectangle->bottom; |
|
643 | update |= sweep_line_delete (&sweep_line, rectangle, do_traps, container); |
657 | } |
644 | } |
- | |
645 | 658 | ||
646 | unwind: |
659 | update |= sweep_line_delete (&sweep_line, rectangle); |
647 | sweep_line_fini (&sweep_line); |
660 | } |
648 | return status; |
661 | |
Line 649... | Line 662... | ||
649 | } |
662 | return CAIRO_STATUS_SUCCESS; |
650 | 663 | } |
|
Line 670... | Line 683... | ||
670 | rectangles_ptrs = stack_rectangles_ptrs; |
683 | rectangles_ptrs = stack_rectangles_ptrs; |
671 | if (traps->num_traps > ARRAY_LENGTH (stack_rectangles)) { |
684 | if (traps->num_traps > ARRAY_LENGTH (stack_rectangles)) { |
672 | rectangles = _cairo_malloc_ab_plus_c (traps->num_traps, |
685 | rectangles = _cairo_malloc_ab_plus_c (traps->num_traps, |
673 | sizeof (rectangle_t) + |
686 | sizeof (rectangle_t) + |
674 | sizeof (rectangle_t *), |
687 | sizeof (rectangle_t *), |
675 | sizeof (rectangle_t *)); |
688 | 3*sizeof (rectangle_t *)); |
676 | if (unlikely (rectangles == NULL)) |
689 | if (unlikely (rectangles == NULL)) |
677 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
690 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
Line 678... | Line 691... | ||
678 | 691 | ||
679 | rectangles_ptrs = (rectangle_t **) (rectangles + traps->num_traps); |
692 | rectangles_ptrs = (rectangle_t **) (rectangles + traps->num_traps); |
Line 698... | Line 711... | ||
698 | rectangles[i].right.right = NULL; |
711 | rectangles[i].right.right = NULL; |
Line 699... | Line 712... | ||
699 | 712 | ||
700 | rectangles[i].top = traps->traps[i].top; |
713 | rectangles[i].top = traps->traps[i].top; |
Line 701... | Line 714... | ||
701 | rectangles[i].bottom = traps->traps[i].bottom; |
714 | rectangles[i].bottom = traps->traps[i].bottom; |
702 | 715 | ||
- | 716 | rectangles_ptrs[i+2] = &rectangles[i]; |
|
- | 717 | } |
|
Line 703... | Line 718... | ||
703 | rectangles_ptrs[i] = &rectangles[i]; |
718 | /* XXX incremental sort */ |
704 | } |
719 | _rectangle_sort (rectangles_ptrs+2, i); |
705 | 720 | ||
706 | _cairo_traps_clear (traps); |
721 | _cairo_traps_clear (traps); |
707 | status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs, i, |
722 | status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs+2, i, |
708 | fill_rule, |
723 | fill_rule, |
Line 722... | Line 737... | ||
722 | _cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in, |
737 | _cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in, |
723 | cairo_fill_rule_t fill_rule, |
738 | cairo_fill_rule_t fill_rule, |
724 | cairo_boxes_t *out) |
739 | cairo_boxes_t *out) |
725 | { |
740 | { |
726 | rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (rectangle_t)]; |
741 | rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (rectangle_t)]; |
- | 742 | rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 3]; |
|
727 | rectangle_t *rectangles; |
743 | rectangle_t *rectangles, **rectangles_ptrs; |
728 | rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 1]; |
744 | rectangle_t *stack_rectangles_chain[CAIRO_STACK_ARRAY_LENGTH (rectangle_t *) ]; |
729 | rectangle_t **rectangles_ptrs; |
745 | rectangle_t **rectangles_chain = NULL; |
730 | const struct _cairo_boxes_chunk *chunk; |
746 | const struct _cairo_boxes_chunk *chunk; |
731 | cairo_status_t status; |
747 | cairo_status_t status; |
732 | int i, j; |
748 | int i, j, y_min, y_max; |
Line 733... | Line 749... | ||
733 | 749 | ||
- | 750 | if (unlikely (in->num_boxes == 0)) { |
|
- | 751 | _cairo_boxes_clear (out); |
|
- | 752 | return CAIRO_STATUS_SUCCESS; |
|
- | 753 | } |
|
- | 754 | ||
- | 755 | if (in->num_boxes == 1) { |
|
- | 756 | if (in == out) { |
|
- | 757 | cairo_box_t *box = &in->chunks.base[0]; |
|
- | 758 | ||
- | 759 | if (box->p1.x > box->p2.x) { |
|
- | 760 | cairo_fixed_t tmp = box->p1.x; |
|
- | 761 | box->p1.x = box->p2.x; |
|
- | 762 | box->p2.x = tmp; |
|
- | 763 | } |
|
- | 764 | } else { |
|
- | 765 | cairo_box_t box = in->chunks.base[0]; |
|
- | 766 | ||
- | 767 | if (box.p1.x > box.p2.x) { |
|
- | 768 | cairo_fixed_t tmp = box.p1.x; |
|
- | 769 | box.p1.x = box.p2.x; |
|
- | 770 | box.p2.x = tmp; |
|
- | 771 | } |
|
- | 772 | ||
- | 773 | _cairo_boxes_clear (out); |
|
- | 774 | status = _cairo_boxes_add (out, CAIRO_ANTIALIAS_DEFAULT, &box); |
|
- | 775 | assert (status == CAIRO_STATUS_SUCCESS); |
|
734 | if (unlikely (in->num_boxes <= 1)) |
776 | } |
- | 777 | return CAIRO_STATUS_SUCCESS; |
|
- | 778 | } |
|
- | 779 | ||
- | 780 | y_min = INT_MAX; y_max = INT_MIN; |
|
- | 781 | for (chunk = &in->chunks; chunk != NULL; chunk = chunk->next) { |
|
- | 782 | const cairo_box_t *box = chunk->base; |
|
- | 783 | for (i = 0; i < chunk->count; i++) { |
|
- | 784 | if (box[i].p1.y < y_min) |
|
- | 785 | y_min = box[i].p1.y; |
|
- | 786 | if (box[i].p1.y > y_max) |
|
- | 787 | y_max = box[i].p1.y; |
|
- | 788 | } |
|
- | 789 | } |
|
- | 790 | y_min = _cairo_fixed_integer_floor (y_min); |
|
- | 791 | y_max = _cairo_fixed_integer_floor (y_max) + 1; |
|
- | 792 | y_max -= y_min; |
|
- | 793 | ||
- | 794 | if (y_max < in->num_boxes) { |
|
- | 795 | rectangles_chain = stack_rectangles_chain; |
|
- | 796 | if (y_max > ARRAY_LENGTH (stack_rectangles_chain)) { |
|
- | 797 | rectangles_chain = _cairo_malloc_ab (y_max, sizeof (rectangle_t *)); |
|
- | 798 | if (unlikely (rectangles_chain == NULL)) |
|
- | 799 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
|
- | 800 | } |
|
- | 801 | memset (rectangles_chain, 0, y_max * sizeof (rectangle_t*)); |
|
Line 735... | Line 802... | ||
735 | return CAIRO_STATUS_SUCCESS; |
802 | } |
736 | 803 | ||
737 | rectangles = stack_rectangles; |
804 | rectangles = stack_rectangles; |
738 | rectangles_ptrs = stack_rectangles_ptrs; |
805 | rectangles_ptrs = stack_rectangles_ptrs; |
739 | if (in->num_boxes > ARRAY_LENGTH (stack_rectangles)) { |
806 | if (in->num_boxes > ARRAY_LENGTH (stack_rectangles)) { |
740 | rectangles = _cairo_malloc_ab_plus_c (in->num_boxes, |
807 | rectangles = _cairo_malloc_ab_plus_c (in->num_boxes, |
741 | sizeof (rectangle_t) + |
808 | sizeof (rectangle_t) + |
742 | sizeof (rectangle_t *), |
809 | sizeof (rectangle_t *), |
- | 810 | 3*sizeof (rectangle_t *)); |
|
- | 811 | if (unlikely (rectangles == NULL)) { |
|
743 | sizeof (rectangle_t *)); |
812 | if (rectangles_chain != stack_rectangles_chain) |
- | 813 | free (rectangles_chain); |
|
Line 744... | Line 814... | ||
744 | if (unlikely (rectangles == NULL)) |
814 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
745 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
815 | } |
Line 746... | Line 816... | ||
746 | 816 | ||
747 | rectangles_ptrs = (rectangle_t **) (rectangles + in->num_boxes); |
817 | rectangles_ptrs = (rectangle_t **) (rectangles + in->num_boxes); |
748 | } |
818 | } |
749 | 819 | ||
- | 820 | j = 0; |
|
- | 821 | for (chunk = &in->chunks; chunk != NULL; chunk = chunk->next) { |
|
750 | j = 0; |
822 | const cairo_box_t *box = chunk->base; |
751 | for (chunk = &in->chunks; chunk != NULL; chunk = chunk->next) { |
823 | for (i = 0; i < chunk->count; i++) { |
752 | const cairo_box_t *box = chunk->base; |
824 | int h; |
Line 753... | Line 825... | ||
753 | for (i = 0; i < chunk->count; i++) { |
825 | |
Line 769... | Line 841... | ||
769 | rectangles[j].right.right = NULL; |
841 | rectangles[j].right.right = NULL; |
Line 770... | Line 842... | ||
770 | 842 | ||
771 | rectangles[j].top = box[i].p1.y; |
843 | rectangles[j].top = box[i].p1.y; |
Line -... | Line 844... | ||
- | 844 | rectangles[j].bottom = box[i].p2.y; |
|
- | 845 | ||
- | 846 | if (rectangles_chain) { |
|
- | 847 | h = _cairo_fixed_integer_floor (box[i].p1.y) - y_min; |
|
- | 848 | rectangles[j].left.next = (edge_t *)rectangles_chain[h]; |
|
772 | rectangles[j].bottom = box[i].p2.y; |
849 | rectangles_chain[h] = &rectangles[j]; |
- | 850 | } else { |
|
773 | 851 | rectangles_ptrs[j+2] = &rectangles[j]; |
|
774 | rectangles_ptrs[j] = &rectangles[j]; |
852 | } |
775 | j++; |
853 | j++; |
Line -... | Line 854... | ||
- | 854 | } |
|
- | 855 | } |
|
- | 856 | ||
- | 857 | if (rectangles_chain) { |
|
- | 858 | j = 2; |
|
- | 859 | for (y_min = 0; y_min < y_max; y_min++) { |
|
- | 860 | rectangle_t *r; |
|
- | 861 | int start = j; |
|
- | 862 | for (r = rectangles_chain[y_min]; r; r = (rectangle_t *)r->left.next) |
|
- | 863 | rectangles_ptrs[j++] = r; |
|
- | 864 | if (j > start + 1) |
|
- | 865 | _rectangle_sort (rectangles_ptrs + start, j - start); |
|
- | 866 | } |
|
- | 867 | ||
- | 868 | if (rectangles_chain != stack_rectangles_chain) |
|
- | 869 | free (rectangles_chain); |
|
- | 870 | ||
- | 871 | j -= 2; |
|
- | 872 | } else { |
|
776 | } |
873 | _rectangle_sort (rectangles_ptrs + 2, j); |
777 | } |
874 | } |
778 | 875 | ||
779 | _cairo_boxes_clear (out); |
876 | _cairo_boxes_clear (out); |
780 | status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs, j, |
877 | status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs+2, j, |
781 | fill_rule, |
878 | fill_rule, |