Subversion Repositories Kolibri OS

Rev

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,