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 95... | Line 95... | ||
95 | */ |
95 | */ |
96 | #include "cairoint.h" |
96 | #include "cairoint.h" |
97 | #include "cairo-spans-private.h" |
97 | #include "cairo-spans-private.h" |
98 | #include "cairo-error-private.h" |
98 | #include "cairo-error-private.h" |
Line 99... | Line -... | ||
99 | - | ||
100 | #include |
99 | |
101 | #include |
100 | #include |
102 | #include |
101 | #include |
- | 102 | #include |
|
Line 103... | Line 103... | ||
103 | #include |
103 | #include |
104 | 104 | ||
105 | /*------------------------------------------------------------------------- |
105 | /*------------------------------------------------------------------------- |
106 | * cairo specific config |
106 | * cairo specific config |
Line 121... | Line 121... | ||
121 | /* Set glitter up to use a cairo span renderer to do the coverage |
121 | /* Set glitter up to use a cairo span renderer to do the coverage |
122 | * blitting. */ |
122 | * blitting. */ |
123 | struct pool; |
123 | struct pool; |
124 | struct cell_list; |
124 | struct cell_list; |
Line 125... | Line -... | ||
125 | - | ||
126 | static glitter_status_t |
- | |
127 | blit_with_span_renderer( |
- | |
128 | struct cell_list *coverages, |
- | |
129 | cairo_span_renderer_t *span_renderer, |
- | |
130 | struct pool *span_pool, |
- | |
131 | int y, |
- | |
132 | int height, |
- | |
133 | int xmin, |
- | |
134 | int xmax); |
- | |
135 | - | ||
136 | static glitter_status_t |
- | |
137 | blit_empty_with_span_renderer (cairo_span_renderer_t *renderer, int y, int height); |
- | |
138 | - | ||
139 | #define GLITTER_BLIT_COVERAGES_ARGS \ |
- | |
140 | cairo_span_renderer_t *span_renderer, \ |
- | |
141 | struct pool *span_pool |
- | |
142 | - | ||
143 | #define GLITTER_BLIT_COVERAGES(cells, y, height,xmin, xmax) do { \ |
- | |
144 | cairo_status_t status = blit_with_span_renderer (cells, \ |
- | |
145 | span_renderer, \ |
- | |
146 | span_pool, \ |
- | |
147 | y, height, \ |
- | |
148 | xmin, xmax); \ |
- | |
149 | if (unlikely (status)) \ |
- | |
150 | return status; \ |
- | |
151 | } while (0) |
- | |
152 | - | ||
153 | #define GLITTER_BLIT_COVERAGES_EMPTY(y, height, xmin, xmax) do { \ |
- | |
154 | cairo_status_t status = blit_empty_with_span_renderer (span_renderer, y, height); \ |
- | |
155 | if (unlikely (status)) \ |
- | |
156 | return status; \ |
- | |
157 | } while (0) |
- | |
158 | 125 | ||
159 | /*------------------------------------------------------------------------- |
126 | /*------------------------------------------------------------------------- |
160 | * glitter-paths.h |
127 | * glitter-paths.h |
Line 161... | Line 128... | ||
161 | */ |
128 | */ |
Line 194... | Line 161... | ||
194 | glitter_scan_converter_reset( |
161 | glitter_scan_converter_reset( |
195 | glitter_scan_converter_t *converter, |
162 | glitter_scan_converter_t *converter, |
196 | int xmin, int ymin, |
163 | int xmin, int ymin, |
197 | int xmax, int ymax); |
164 | int xmax, int ymax); |
Line 198... | Line -... | ||
198 | - | ||
199 | /* Add a new polygon edge from pixel (x1,y1) to (x2,y2) to the scan |
- | |
200 | * converter. The coordinates represent pixel positions scaled by |
- | |
201 | * 2**GLITTER_PIXEL_BITS. If this function fails then the scan |
- | |
202 | * converter should be reset or destroyed. Dir must be +1 or -1, |
- | |
203 | * with the latter reversing the orientation of the edge. */ |
- | |
204 | I glitter_status_t |
- | |
205 | glitter_scan_converter_add_edge (glitter_scan_converter_t *converter, |
- | |
206 | const cairo_edge_t *edge); |
- | |
207 | 165 | ||
208 | /* Render the polygon in the scan converter to the given A8 format |
166 | /* Render the polygon in the scan converter to the given A8 format |
209 | * image raster. Only the pixels accessible as pixels[y*stride+x] for |
167 | * image raster. Only the pixels accessible as pixels[y*stride+x] for |
210 | * x,y inside the clip box are written to, where xmin <= x < xmax, |
168 | * x,y inside the clip box are written to, where xmin <= x < xmax, |
211 | * ymin <= y < ymax. The image is assumed to be clear on input. |
169 | * ymin <= y < ymax. The image is assumed to be clear on input. |
212 | * |
170 | * |
213 | * If nonzero_fill is true then the interior of the polygon is |
171 | * If nonzero_fill is true then the interior of the polygon is |
214 | * computed with the non-zero fill rule. Otherwise the even-odd fill |
172 | * computed with the non-zero fill rule. Otherwise the even-odd fill |
215 | * rule is used. |
173 | * rule is used. |
216 | * |
174 | * |
217 | * The scan converter must be reset or destroyed after this call. */ |
- | |
218 | #ifndef GLITTER_BLIT_COVERAGES_ARGS |
- | |
219 | # define GLITTER_BLIT_COVERAGES_ARGS unsigned char *raster_pixels, long raster_stride |
- | |
220 | #endif |
- | |
221 | I glitter_status_t |
- | |
222 | glitter_scan_converter_render( |
- | |
223 | glitter_scan_converter_t *converter, |
- | |
224 | int nonzero_fill, |
- | |
Line 225... | Line 175... | ||
225 | GLITTER_BLIT_COVERAGES_ARGS); |
175 | * The scan converter must be reset or destroyed after this call. */ |
226 | 176 | ||
227 | /*------------------------------------------------------------------------- |
177 | /*------------------------------------------------------------------------- |
228 | * glitter-paths.c: Implementation internal types |
178 | * glitter-paths.c: Implementation internal types |
Line 285... | Line 235... | ||
285 | /* A grid area is a real in [0,1] scaled by 2*GRID_X*GRID_Y. We want |
235 | /* A grid area is a real in [0,1] scaled by 2*GRID_X*GRID_Y. We want |
286 | * to be able to represent exactly areas of subpixel trapezoids whose |
236 | * to be able to represent exactly areas of subpixel trapezoids whose |
287 | * vertices are given in grid scaled coordinates. The scale factor |
237 | * vertices are given in grid scaled coordinates. The scale factor |
288 | * comes from needing to accurately represent the area 0.5*dx*dy of a |
238 | * comes from needing to accurately represent the area 0.5*dx*dy of a |
289 | * triangle with base dx and height dy in grid scaled numbers. */ |
239 | * triangle with base dx and height dy in grid scaled numbers. */ |
290 | typedef int grid_area_t; |
- | |
291 | #define GRID_XY (2*GRID_X*GRID_Y) /* Unit area on the grid. */ |
240 | #define GRID_XY (2*GRID_X*GRID_Y) /* Unit area on the grid. */ |
Line 292... | Line 241... | ||
292 | 241 | ||
293 | /* GRID_AREA_TO_ALPHA(area): map [0,GRID_XY] to [0,255]. */ |
242 | /* GRID_AREA_TO_ALPHA(area): map [0,GRID_XY] to [0,255]. */ |
294 | #if GRID_XY == 510 |
243 | #if GRID_XY == 510 |
Line 337... | Line 286... | ||
337 | * malloc needs to be called to allocate a first real chunk. */ |
286 | * malloc needs to be called to allocate a first real chunk. */ |
338 | struct pool { |
287 | struct pool { |
339 | /* Chunk we're allocating from. */ |
288 | /* Chunk we're allocating from. */ |
340 | struct _pool_chunk *current; |
289 | struct _pool_chunk *current; |
Line -... | Line 290... | ||
- | 290 | ||
- | 291 | jmp_buf *jmp; |
|
341 | 292 | ||
342 | /* Free list of previously allocated chunks. All have >= default |
293 | /* Free list of previously allocated chunks. All have >= default |
343 | * capacity. */ |
294 | * capacity. */ |
Line 344... | Line 295... | ||
344 | struct _pool_chunk *first_free; |
295 | struct _pool_chunk *first_free; |
Line 353... | Line 304... | ||
353 | }; |
304 | }; |
Line 354... | Line 305... | ||
354 | 305 | ||
355 | /* A polygon edge. */ |
306 | /* A polygon edge. */ |
356 | struct edge { |
307 | struct edge { |
357 | /* Next in y-bucket or active list. */ |
308 | /* Next in y-bucket or active list. */ |
- | 309 | struct edge *next, *prev; |
|
- | 310 | ||
- | 311 | /* Number of subsample rows remaining to scan convert of this |
|
- | 312 | * edge. */ |
|
- | 313 | grid_scaled_y_t height_left; |
|
- | 314 | ||
- | 315 | /* Original sign of the edge: +1 for downwards, -1 for upwards |
|
- | 316 | * edges. */ |
|
- | 317 | int dir; |
|
Line 358... | Line 318... | ||
358 | struct edge *next; |
318 | int vertical; |
359 | 319 | ||
360 | /* Current x coordinate while the edge is on the active |
320 | /* Current x coordinate while the edge is on the active |
361 | * list. Initialised to the x coordinate of the top of the |
321 | * list. Initialised to the x coordinate of the top of the |
Line 375... | Line 335... | ||
375 | /* The clipped y of the top of the edge. */ |
335 | /* The clipped y of the top of the edge. */ |
376 | grid_scaled_y_t ytop; |
336 | grid_scaled_y_t ytop; |
Line 377... | Line 337... | ||
377 | 337 | ||
378 | /* y2-y1 after orienting the edge downwards. */ |
338 | /* y2-y1 after orienting the edge downwards. */ |
379 | grid_scaled_y_t dy; |
- | |
380 | - | ||
381 | /* Number of subsample rows remaining to scan convert of this |
- | |
382 | * edge. */ |
- | |
383 | grid_scaled_y_t height_left; |
- | |
384 | - | ||
385 | /* Original sign of the edge: +1 for downwards, -1 for upwards |
- | |
386 | * edges. */ |
- | |
387 | int dir; |
- | |
388 | int vertical; |
339 | grid_scaled_y_t dy; |
Line 389... | Line -... | ||
389 | }; |
- | |
390 | - | ||
391 | /* Number of subsample rows per y-bucket. Must be GRID_Y. */ |
- | |
392 | #define EDGE_Y_BUCKET_HEIGHT GRID_Y |
340 | }; |
Line 393... | Line 341... | ||
393 | 341 | ||
394 | #define EDGE_Y_BUCKET_INDEX(y, ymin) (((y) - (ymin))/EDGE_Y_BUCKET_HEIGHT) |
342 | #define EDGE_Y_BUCKET_INDEX(y, ymin) (((y) - (ymin))/GRID_Y) |
395 | 343 | ||
396 | /* A collection of sorted and vertically clipped edges of the polygon. |
344 | /* A collection of sorted and vertically clipped edges of the polygon. |
Line 454... | Line 402... | ||
454 | * contribution above and below the intersection point must be |
402 | * contribution above and below the intersection point must be |
455 | * computed separately. */ |
403 | * computed separately. */ |
456 | struct cell { |
404 | struct cell { |
457 | struct cell *next; |
405 | struct cell *next; |
458 | int x; |
406 | int x; |
459 | grid_area_t uncovered_area; |
407 | int16_t uncovered_area; |
460 | grid_scaled_y_t covered_height; |
408 | int16_t covered_height; |
461 | }; |
409 | }; |
Line 462... | Line 410... | ||
462 | 410 | ||
463 | /* A cell list represents the scan line sparsely as cells ordered by |
411 | /* A cell list represents the scan line sparsely as cells ordered by |
464 | * ascending x. It is geared towards scanning the cells in order |
412 | * ascending x. It is geared towards scanning the cells in order |
465 | * using an internal cursor. */ |
413 | * using an internal cursor. */ |
466 | struct cell_list { |
- | |
467 | /* Points to the left-most cell in the scan line. */ |
- | |
468 | struct cell *head; |
414 | struct cell_list { |
469 | /* Sentinel node */ |
415 | /* Sentinel nodes */ |
470 | struct cell tail; |
416 | struct cell head, tail; |
471 | 417 | ||
472 | /* Cursor state for iterating through the cell list. Points to |
- | |
473 | * a pointer to the current cell: either &cell_list->head or the next |
- | |
474 | * field of the previous cell. */ |
418 | /* Cursor state for iterating through the cell list. */ |
Line 475... | Line 419... | ||
475 | struct cell **cursor; |
419 | struct cell *cursor, *rewind; |
476 | 420 | ||
477 | /* Cells in the cell list are owned by the cell list and are |
421 | /* Cells in the cell list are owned by the cell list and are |
478 | * allocated from this pool. */ |
422 | * allocated from this pool. */ |
Line 489... | Line 433... | ||
489 | 433 | ||
490 | /* The active list contains edges in the current scan line ordered by |
434 | /* The active list contains edges in the current scan line ordered by |
491 | * the x-coordinate of the intercept of the edge and the scan line. */ |
435 | * the x-coordinate of the intercept of the edge and the scan line. */ |
492 | struct active_list { |
436 | struct active_list { |
493 | /* Leftmost edge on the current scan line. */ |
437 | /* Leftmost edge on the current scan line. */ |
Line 494... | Line 438... | ||
494 | struct edge *head; |
438 | struct edge head, tail; |
495 | 439 | ||
496 | /* A lower bound on the height of the active edges is used to |
440 | /* A lower bound on the height of the active edges is used to |
497 | * estimate how soon some active edge ends. We can't advance the |
441 | * estimate how soon some active edge ends. We can't advance the |
498 | * scan conversion by a full pixel row if an edge ends somewhere |
442 | * scan conversion by a full pixel row if an edge ends somewhere |
- | 443 | * within it. */ |
|
499 | * within it. */ |
444 | grid_scaled_y_t min_height; |
Line 500... | Line 445... | ||
500 | grid_scaled_y_t min_height; |
445 | int is_vertical; |
501 | }; |
446 | }; |
502 | 447 | ||
503 | struct glitter_scan_converter { |
448 | struct glitter_scan_converter { |
Line -... | Line 449... | ||
- | 449 | struct polygon polygon[1]; |
|
- | 450 | struct active_list active[1]; |
|
- | 451 | struct cell_list coverages[1]; |
|
504 | struct polygon polygon[1]; |
452 | |
505 | struct active_list active[1]; |
453 | cairo_half_open_span_t *spans; |
506 | struct cell_list coverages[1]; |
454 | cairo_half_open_span_t spans_embedded[64]; |
507 | 455 | ||
Line 539... | Line 487... | ||
539 | qr.rem += b; |
487 | qr.rem += b; |
540 | } |
488 | } |
541 | return qr; |
489 | return qr; |
542 | } |
490 | } |
Line 543... | Line 491... | ||
543 | 491 | ||
544 | static void |
492 | static struct _pool_chunk * |
545 | _pool_chunk_init( |
493 | _pool_chunk_init( |
546 | struct _pool_chunk *p, |
494 | struct _pool_chunk *p, |
547 | struct _pool_chunk *prev_chunk, |
495 | struct _pool_chunk *prev_chunk, |
548 | size_t capacity) |
496 | size_t capacity) |
549 | { |
497 | { |
550 | p->prev_chunk = prev_chunk; |
498 | p->prev_chunk = prev_chunk; |
551 | p->size = 0; |
499 | p->size = 0; |
- | 500 | p->capacity = capacity; |
|
552 | p->capacity = capacity; |
501 | return p; |
Line 553... | Line 502... | ||
553 | } |
502 | } |
554 | 503 | ||
555 | static struct _pool_chunk * |
- | |
556 | _pool_chunk_create( |
- | |
557 | struct _pool_chunk *prev_chunk, |
504 | static struct _pool_chunk * |
558 | size_t size) |
505 | _pool_chunk_create(struct pool *pool, size_t size) |
- | 506 | { |
|
559 | { |
507 | struct _pool_chunk *p; |
560 | struct _pool_chunk *p; |
508 | |
561 | size_t size_with_head = size + sizeof(struct _pool_chunk); |
- | |
562 | if (size_with_head < size) |
509 | p = malloc(size + sizeof(struct _pool_chunk)); |
563 | return NULL; |
510 | if (unlikely (NULL == p)) |
564 | p = malloc(size_with_head); |
511 | longjmp (*pool->jmp, _cairo_error (CAIRO_STATUS_NO_MEMORY)); |
565 | if (p) |
- | |
566 | _pool_chunk_init(p, prev_chunk, size); |
512 | |
Line 567... | Line 513... | ||
567 | return p; |
513 | return _pool_chunk_init(p, pool->current, size); |
568 | } |
514 | } |
569 | 515 | ||
570 | static void |
516 | static void |
571 | pool_init( |
517 | pool_init(struct pool *pool, |
572 | struct pool *pool, |
518 | jmp_buf *jmp, |
- | 519 | size_t default_capacity, |
|
573 | size_t default_capacity, |
520 | size_t embedded_capacity) |
574 | size_t embedded_capacity) |
521 | { |
575 | { |
522 | pool->jmp = jmp; |
576 | pool->current = pool->sentinel; |
523 | pool->current = pool->sentinel; |
577 | pool->first_free = NULL; |
524 | pool->first_free = NULL; |
Line 591... | Line 538... | ||
591 | p = prev; |
538 | p = prev; |
592 | } |
539 | } |
593 | p = pool->first_free; |
540 | p = pool->first_free; |
594 | pool->first_free = NULL; |
541 | pool->first_free = NULL; |
595 | } while (NULL != p); |
542 | } while (NULL != p); |
596 | pool_init(pool, 0, 0); |
- | |
597 | } |
543 | } |
Line 598... | Line 544... | ||
598 | 544 | ||
599 | /* Satisfy an allocation by first allocating a new large enough chunk |
545 | /* Satisfy an allocation by first allocating a new large enough chunk |
600 | * and adding it to the head of the pool's chunk list. This function |
546 | * and adding it to the head of the pool's chunk list. This function |
Line 621... | Line 567... | ||
621 | pool->first_free = chunk->prev_chunk; |
567 | pool->first_free = chunk->prev_chunk; |
622 | _pool_chunk_init(chunk, pool->current, chunk->capacity); |
568 | _pool_chunk_init(chunk, pool->current, chunk->capacity); |
623 | } |
569 | } |
624 | } |
570 | } |
Line 625... | Line 571... | ||
625 | 571 | ||
626 | if (NULL == chunk) { |
572 | if (NULL == chunk) |
627 | chunk = _pool_chunk_create (pool->current, capacity); |
- | |
628 | if (unlikely (NULL == chunk)) |
- | |
629 | return NULL; |
- | |
630 | } |
573 | chunk = _pool_chunk_create (pool, capacity); |
Line 631... | Line 574... | ||
631 | pool->current = chunk; |
574 | pool->current = chunk; |
632 | 575 | ||
633 | obj = ((unsigned char*)chunk + sizeof(*chunk) + chunk->size); |
576 | obj = ((unsigned char*)chunk + sizeof(*chunk) + chunk->size); |
Line 679... | Line 622... | ||
679 | cell_list_rewind (struct cell_list *cells) |
622 | cell_list_rewind (struct cell_list *cells) |
680 | { |
623 | { |
681 | cells->cursor = &cells->head; |
624 | cells->cursor = &cells->head; |
682 | } |
625 | } |
Line 683... | Line -... | ||
683 | - | ||
684 | /* Rewind the cell list if its cursor has been advanced past x. */ |
626 | |
685 | inline static void |
627 | inline static void |
686 | cell_list_maybe_rewind (struct cell_list *cells, int x) |
628 | cell_list_maybe_rewind (struct cell_list *cells, int x) |
- | 629 | { |
|
- | 630 | if (x < cells->cursor->x) { |
|
- | 631 | cells->cursor = cells->rewind; |
|
687 | { |
632 | if (x < cells->cursor->x) |
- | 633 | cells->cursor = &cells->head; |
|
- | 634 | } |
|
- | 635 | } |
|
688 | struct cell *tail = *cells->cursor; |
636 | |
- | 637 | inline static void |
|
- | 638 | cell_list_set_rewind (struct cell_list *cells) |
|
689 | if (tail->x > x) |
639 | { |
690 | cell_list_rewind (cells); |
640 | cells->rewind = cells->cursor; |
Line 691... | Line 641... | ||
691 | } |
641 | } |
692 | 642 | ||
693 | static void |
643 | static void |
694 | cell_list_init(struct cell_list *cells) |
644 | cell_list_init(struct cell_list *cells, jmp_buf *jmp) |
695 | { |
645 | { |
696 | pool_init(cells->cell_pool.base, |
646 | pool_init(cells->cell_pool.base, jmp, |
697 | 256*sizeof(struct cell), |
647 | 256*sizeof(struct cell), |
698 | sizeof(cells->cell_pool.embedded)); |
648 | sizeof(cells->cell_pool.embedded)); |
- | 649 | cells->tail.next = NULL; |
|
699 | cells->tail.next = NULL; |
650 | cells->tail.x = INT_MAX; |
700 | cells->tail.x = INT_MAX; |
651 | cells->head.x = INT_MIN; |
701 | cells->head = &cells->tail; |
652 | cells->head.next = &cells->tail; |
Line 702... | Line 653... | ||
702 | cell_list_rewind (cells); |
653 | cell_list_rewind (cells); |
703 | } |
654 | } |
Line 712... | Line 663... | ||
712 | * row. */ |
663 | * row. */ |
713 | inline static void |
664 | inline static void |
714 | cell_list_reset (struct cell_list *cells) |
665 | cell_list_reset (struct cell_list *cells) |
715 | { |
666 | { |
716 | cell_list_rewind (cells); |
667 | cell_list_rewind (cells); |
717 | cells->head = &cells->tail; |
668 | cells->head.next = &cells->tail; |
718 | pool_reset (cells->cell_pool.base); |
669 | pool_reset (cells->cell_pool.base); |
719 | } |
670 | } |
Line 720... | Line 671... | ||
720 | 671 | ||
721 | static struct cell * |
672 | inline static struct cell * |
722 | cell_list_alloc (struct cell_list *cells, |
- | |
723 | struct cell **cursor, |
673 | cell_list_alloc (struct cell_list *cells, |
724 | struct cell *tail, |
674 | struct cell *tail, |
725 | int x) |
675 | int x) |
726 | { |
676 | { |
Line 727... | Line 677... | ||
727 | struct cell *cell; |
677 | struct cell *cell; |
728 | - | ||
729 | cell = pool_alloc (cells->cell_pool.base, sizeof (struct cell)); |
- | |
730 | if (unlikely (NULL == cell)) |
- | |
731 | return NULL; |
678 | |
732 | 679 | cell = pool_alloc (cells->cell_pool.base, sizeof (struct cell)); |
|
733 | *cursor = cell; |
680 | cell->next = tail->next; |
734 | cell->next = tail; |
681 | tail->next = cell; |
735 | cell->x = x; |
- | |
- | 682 | cell->x = x; |
|
736 | cell->uncovered_area = 0; |
683 | *(uint32_t *)&cell->uncovered_area = 0; |
737 | cell->covered_height = 0; |
684 | |
Line 738... | Line 685... | ||
738 | return cell; |
685 | return cell; |
739 | } |
686 | } |
Line 744... | Line 691... | ||
744 | * cell_list_rewind(). Ownership of the returned cell is retained by |
691 | * cell_list_rewind(). Ownership of the returned cell is retained by |
745 | * the cell list. */ |
692 | * the cell list. */ |
746 | inline static struct cell * |
693 | inline static struct cell * |
747 | cell_list_find (struct cell_list *cells, int x) |
694 | cell_list_find (struct cell_list *cells, int x) |
748 | { |
695 | { |
749 | struct cell **cursor = cells->cursor; |
696 | struct cell *tail = cells->cursor; |
- | 697 | ||
- | 698 | if (tail->x == x) |
|
750 | struct cell *tail; |
699 | return tail; |
Line 751... | Line 700... | ||
751 | 700 | ||
752 | while (1) { |
701 | while (1) { |
753 | UNROLL3({ |
- | |
754 | tail = *cursor; |
702 | UNROLL3({ |
755 | if (tail->x >= x) { |
703 | if (tail->next->x > x) |
756 | break; |
- | |
757 | } |
704 | break; |
758 | cursor = &tail->next; |
705 | tail = tail->next; |
759 | }); |
706 | }); |
760 | } |
- | |
Line 761... | Line 707... | ||
761 | cells->cursor = cursor; |
707 | } |
- | 708 | ||
762 | 709 | if (tail->x != x) |
|
Line 763... | Line -... | ||
763 | if (tail->x == x) |
- | |
764 | return tail; |
710 | tail = cell_list_alloc (cells, tail, x); |
Line 765... | Line 711... | ||
765 | 711 | return cells->cursor = tail; |
|
766 | return cell_list_alloc (cells, cursor, tail, x); |
712 | |
767 | } |
713 | } |
Line 775... | Line 721... | ||
775 | * except with less function call overhead. */ |
721 | * except with less function call overhead. */ |
776 | inline static struct cell_pair |
722 | inline static struct cell_pair |
777 | cell_list_find_pair(struct cell_list *cells, int x1, int x2) |
723 | cell_list_find_pair(struct cell_list *cells, int x1, int x2) |
778 | { |
724 | { |
779 | struct cell_pair pair; |
725 | struct cell_pair pair; |
780 | struct cell **cursor = cells->cursor; |
- | |
781 | struct cell *cell1; |
- | |
782 | struct cell *cell2; |
- | |
783 | struct cell *newcell; |
- | |
Line 784... | Line 726... | ||
784 | 726 | ||
785 | /* Find first cell at x1. */ |
727 | pair.cell1 = cells->cursor; |
786 | while (1) { |
728 | while (1) { |
787 | UNROLL3({ |
- | |
788 | cell1 = *cursor; |
729 | UNROLL3({ |
789 | if (cell1->x > x1) |
730 | if (pair.cell1->next->x > x1) |
790 | break; |
- | |
791 | - | ||
792 | if (cell1->x == x1) |
- | |
793 | goto found_first; |
- | |
794 | 731 | break; |
|
795 | cursor = &cell1->next; |
732 | pair.cell1 = pair.cell1->next; |
796 | }); |
733 | }); |
- | 734 | } |
|
- | 735 | if (pair.cell1->x != x1) |
|
Line 797... | Line -... | ||
797 | } |
- | |
798 | - | ||
799 | /* New first cell at x1. */ |
- | |
800 | newcell = pool_alloc (cells->cell_pool.base, |
- | |
801 | sizeof (struct cell)); |
- | |
802 | if (likely (NULL != newcell)) { |
- | |
803 | *cursor = newcell; |
- | |
804 | newcell->next = cell1; |
- | |
805 | newcell->x = x1; |
- | |
806 | newcell->uncovered_area = 0; |
- | |
807 | newcell->covered_height = 0; |
736 | pair.cell1 = cell_list_alloc (cells, pair.cell1, x1); |
808 | } |
- | |
809 | cell1 = newcell; |
- | |
810 | found_first: |
- | |
811 | 737 | ||
812 | /* Find second cell at x2. */ |
738 | pair.cell2 = pair.cell1; |
813 | while (1) { |
- | |
814 | UNROLL3({ |
739 | while (1) { |
815 | cell2 = *cursor; |
740 | UNROLL3({ |
816 | if (cell2->x > x2) |
- | |
817 | break; |
- | |
818 | if (cell2->x == x2) |
741 | if (pair.cell2->next->x > x2) |
819 | goto found_second; |
742 | break; |
820 | cursor = &cell2->next; |
743 | pair.cell2 = pair.cell2->next; |
- | 744 | }); |
|
- | 745 | } |
|
Line 821... | Line -... | ||
821 | }); |
- | |
822 | } |
- | |
823 | - | ||
824 | /* New second cell at x2. */ |
- | |
825 | newcell = pool_alloc (cells->cell_pool.base, |
- | |
826 | sizeof (struct cell)); |
- | |
827 | if (likely (NULL != newcell)) { |
- | |
828 | *cursor = newcell; |
- | |
829 | newcell->next = cell2; |
- | |
830 | newcell->x = x2; |
- | |
831 | newcell->uncovered_area = 0; |
- | |
832 | newcell->covered_height = 0; |
- | |
833 | } |
- | |
834 | cell2 = newcell; |
746 | if (pair.cell2->x != x2) |
835 | found_second: |
- | |
836 | - | ||
837 | cells->cursor = cursor; |
747 | pair.cell2 = cell_list_alloc (cells, pair.cell2, x2); |
838 | pair.cell1 = cell1; |
748 | |
Line 839... | Line -... | ||
839 | pair.cell2 = cell2; |
- | |
840 | return pair; |
- | |
841 | } |
- | |
842 | - | ||
843 | /* Add an unbounded subpixel span covering subpixels >= x to the |
- | |
844 | * coverage cells. */ |
- | |
845 | static glitter_status_t |
- | |
846 | cell_list_add_unbounded_subspan (struct cell_list *cells, |
- | |
847 | grid_scaled_x_t x) |
- | |
848 | { |
- | |
849 | struct cell *cell; |
- | |
850 | int ix, fx; |
- | |
851 | - | ||
852 | GRID_X_TO_INT_FRAC(x, ix, fx); |
- | |
853 | - | ||
854 | cell = cell_list_find (cells, ix); |
- | |
855 | if (likely (cell != NULL)) { |
- | |
856 | cell->uncovered_area += 2*fx; |
- | |
857 | cell->covered_height++; |
- | |
858 | return GLITTER_STATUS_SUCCESS; |
- | |
859 | } |
- | |
860 | 749 | cells->cursor = pair.cell2; |
|
861 | return GLITTER_STATUS_NO_MEMORY; |
750 | return pair; |
862 | } |
- | |
863 | 751 | } |
|
864 | /* Add a subpixel span covering [x1, x2) to the coverage cells. */ |
752 | |
865 | inline static glitter_status_t |
753 | /* Add a subpixel span covering [x1, x2) to the coverage cells. */ |
866 | cell_list_add_subspan( |
754 | inline static void |
867 | struct cell_list *cells, |
755 | cell_list_add_subspan(struct cell_list *cells, |
868 | grid_scaled_x_t x1, |
756 | grid_scaled_x_t x1, |
Line -... | Line 757... | ||
- | 757 | grid_scaled_x_t x2) |
|
- | 758 | { |
|
- | 759 | int ix1, fx1; |
|
869 | grid_scaled_x_t x2) |
760 | int ix2, fx2; |
870 | { |
761 | |
Line 871... | Line 762... | ||
871 | int ix1, fx1; |
762 | if (x1 == x2) |
872 | int ix2, fx2; |
763 | return; |
873 | 764 | ||
874 | GRID_X_TO_INT_FRAC(x1, ix1, fx1); |
- | |
875 | GRID_X_TO_INT_FRAC(x2, ix2, fx2); |
765 | GRID_X_TO_INT_FRAC(x1, ix1, fx1); |
876 | 766 | GRID_X_TO_INT_FRAC(x2, ix2, fx2); |
|
877 | if (ix1 != ix2) { |
767 | |
878 | struct cell_pair p; |
768 | if (ix1 != ix2) { |
879 | p = cell_list_find_pair(cells, ix1, ix2); |
- | |
880 | if (likely (p.cell1 != NULL && p.cell2 != NULL)) { |
- | |
881 | p.cell1->uncovered_area += 2*fx1; |
769 | struct cell_pair p; |
882 | ++p.cell1->covered_height; |
770 | p = cell_list_find_pair(cells, ix1, ix2); |
883 | p.cell2->uncovered_area -= 2*fx2; |
- | |
884 | --p.cell2->covered_height; |
771 | p.cell1->uncovered_area += 2*fx1; |
885 | return GLITTER_STATUS_SUCCESS; |
- | |
886 | } |
772 | ++p.cell1->covered_height; |
887 | } else { |
773 | p.cell2->uncovered_area -= 2*fx2; |
888 | struct cell *cell = cell_list_find(cells, ix1); |
- | |
889 | if (likely (cell != NULL)) { |
- | |
Line 890... | Line 774... | ||
890 | cell->uncovered_area += 2*(fx1-fx2); |
774 | --p.cell2->covered_height; |
891 | return GLITTER_STATUS_SUCCESS; |
775 | } else { |
892 | } |
776 | struct cell *cell = cell_list_find(cells, ix1); |
893 | } |
777 | cell->uncovered_area += 2*(fx1-fx2); |
Line 909... | Line 793... | ||
909 | * 3) No existing edges end mid-row. |
793 | * 3) No existing edges end mid-row. |
910 | * |
794 | * |
911 | * This function depends on being called with all edges from the |
795 | * This function depends on being called with all edges from the |
912 | * active list in the order they appear on the list (i.e. with |
796 | * active list in the order they appear on the list (i.e. with |
913 | * non-decreasing x-coordinate.) */ |
797 | * non-decreasing x-coordinate.) */ |
914 | static glitter_status_t |
798 | static void |
915 | cell_list_render_edge( |
- | |
916 | struct cell_list *cells, |
799 | cell_list_render_edge(struct cell_list *cells, |
917 | struct edge *edge, |
800 | struct edge *edge, |
918 | int sign) |
801 | int sign) |
919 | { |
802 | { |
920 | grid_scaled_y_t y1, y2, dy; |
803 | grid_scaled_y_t y1, y2, dy; |
921 | grid_scaled_x_t dx; |
804 | grid_scaled_x_t dx; |
Line 942... | Line 825... | ||
942 | /* Edge is entirely within a column? */ |
825 | /* Edge is entirely within a column? */ |
943 | if (ix1 == ix2) { |
826 | if (ix1 == ix2) { |
944 | /* We always know that ix1 is >= the cell list cursor in this |
827 | /* We always know that ix1 is >= the cell list cursor in this |
945 | * case due to the no-intersections precondition. */ |
828 | * case due to the no-intersections precondition. */ |
946 | struct cell *cell = cell_list_find(cells, ix1); |
829 | struct cell *cell = cell_list_find(cells, ix1); |
947 | if (unlikely (NULL == cell)) |
- | |
948 | return GLITTER_STATUS_NO_MEMORY; |
- | |
949 | - | ||
950 | cell->covered_height += sign*GRID_Y; |
830 | cell->covered_height += sign*GRID_Y; |
951 | cell->uncovered_area += sign*(fx1 + fx2)*GRID_Y; |
831 | cell->uncovered_area += sign*(fx1 + fx2)*GRID_Y; |
952 | return GLITTER_STATUS_SUCCESS; |
832 | return; |
953 | } |
833 | } |
Line 954... | Line 834... | ||
954 | 834 | ||
955 | /* Orient the edge left-to-right. */ |
835 | /* Orient the edge left-to-right. */ |
956 | dx = x2.quo - x1.quo; |
836 | dx = x2.quo - x1.quo; |
Line 993... | Line 873... | ||
993 | * within a single column because we've checked before calling |
873 | * within a single column because we've checked before calling |
994 | * this function that the active list order won't change. */ |
874 | * this function that the active list order won't change. */ |
995 | cell_list_maybe_rewind(cells, ix1); |
875 | cell_list_maybe_rewind(cells, ix1); |
Line 996... | Line 876... | ||
996 | 876 | ||
997 | pair = cell_list_find_pair(cells, ix1, ix1+1); |
- | |
998 | if (unlikely (!pair.cell1 || !pair.cell2)) |
- | |
999 | return GLITTER_STATUS_NO_MEMORY; |
- | |
1000 | 877 | pair = cell_list_find_pair(cells, ix1, ix1+1); |
|
1001 | pair.cell1->uncovered_area += sign*y.quo*(GRID_X + fx1); |
878 | pair.cell1->uncovered_area += sign*y.quo*(GRID_X + fx1); |
1002 | pair.cell1->covered_height += sign*y.quo; |
879 | pair.cell1->covered_height += sign*y.quo; |
Line 1003... | Line 880... | ||
1003 | y.quo += y1; |
880 | y.quo += y1; |
Line 1021... | Line 898... | ||
1021 | cell->uncovered_area += y_skip*GRID_X; |
898 | cell->uncovered_area += y_skip*GRID_X; |
1022 | cell->covered_height += y_skip; |
899 | cell->covered_height += y_skip; |
Line 1023... | Line 900... | ||
1023 | 900 | ||
1024 | ++ix1; |
901 | ++ix1; |
1025 | cell = cell_list_find(cells, ix1); |
- | |
1026 | if (unlikely (NULL == cell)) |
- | |
1027 | return GLITTER_STATUS_NO_MEMORY; |
902 | cell = cell_list_find(cells, ix1); |
Line 1028... | Line 903... | ||
1028 | } while (ix1 != ix2); |
903 | } while (ix1 != ix2); |
1029 | 904 | ||
1030 | pair.cell2 = cell; |
905 | pair.cell2 = cell; |
1031 | } |
906 | } |
1032 | pair.cell2->uncovered_area += sign*(y2 - y.quo)*fx2; |
907 | pair.cell2->uncovered_area += sign*(y2 - y.quo)*fx2; |
1033 | pair.cell2->covered_height += sign*(y2 - y.quo); |
- | |
1034 | } |
- | |
1035 | 908 | pair.cell2->covered_height += sign*(y2 - y.quo); |
|
Line 1036... | Line 909... | ||
1036 | return GLITTER_STATUS_SUCCESS; |
909 | } |
1037 | } |
910 | } |
1038 | 911 | ||
1039 | static void |
912 | static void |
1040 | polygon_init (struct polygon *polygon) |
913 | polygon_init (struct polygon *polygon, jmp_buf *jmp) |
1041 | { |
914 | { |
1042 | polygon->ymin = polygon->ymax = 0; |
915 | polygon->ymin = polygon->ymax = 0; |
1043 | polygon->y_buckets = polygon->y_buckets_embedded; |
916 | polygon->y_buckets = polygon->y_buckets_embedded; |
1044 | pool_init (polygon->edge_pool.base, |
917 | pool_init (polygon->edge_pool.base, jmp, |
Line 1045... | Line 918... | ||
1045 | 8192 - sizeof (struct _pool_chunk), |
918 | 8192 - sizeof (struct _pool_chunk), |
Line 1062... | Line 935... | ||
1062 | polygon_reset (struct polygon *polygon, |
935 | polygon_reset (struct polygon *polygon, |
1063 | grid_scaled_y_t ymin, |
936 | grid_scaled_y_t ymin, |
1064 | grid_scaled_y_t ymax) |
937 | grid_scaled_y_t ymax) |
1065 | { |
938 | { |
1066 | unsigned h = ymax - ymin; |
939 | unsigned h = ymax - ymin; |
1067 | unsigned num_buckets = EDGE_Y_BUCKET_INDEX(ymax + EDGE_Y_BUCKET_HEIGHT-1, |
940 | unsigned num_buckets = EDGE_Y_BUCKET_INDEX(ymax + GRID_Y-1, ymin); |
1068 | ymin); |
- | |
Line 1069... | Line 941... | ||
1069 | 941 | ||
Line 1070... | Line 942... | ||
1070 | pool_reset(polygon->edge_pool.base); |
942 | pool_reset(polygon->edge_pool.base); |
1071 | 943 | ||
Line 1072... | Line 944... | ||
1072 | if (unlikely (h > 0x7FFFFFFFU - EDGE_Y_BUCKET_HEIGHT)) |
944 | if (unlikely (h > 0x7FFFFFFFU - GRID_Y)) |
1073 | goto bail_no_mem; /* even if you could, you wouldn't want to. */ |
945 | goto bail_no_mem; /* even if you could, you wouldn't want to. */ |
Line 1093... | Line 965... | ||
1093 | polygon->ymax = 0; |
965 | polygon->ymax = 0; |
1094 | return GLITTER_STATUS_NO_MEMORY; |
966 | return GLITTER_STATUS_NO_MEMORY; |
1095 | } |
967 | } |
Line 1096... | Line 968... | ||
1096 | 968 | ||
1097 | static void |
969 | static void |
1098 | _polygon_insert_edge_into_its_y_bucket( |
- | |
1099 | struct polygon *polygon, |
970 | _polygon_insert_edge_into_its_y_bucket(struct polygon *polygon, |
1100 | struct edge *e) |
971 | struct edge *e) |
1101 | { |
972 | { |
1102 | unsigned ix = EDGE_Y_BUCKET_INDEX(e->ytop, polygon->ymin); |
973 | unsigned ix = EDGE_Y_BUCKET_INDEX(e->ytop, polygon->ymin); |
1103 | struct edge **ptail = &polygon->y_buckets[ix]; |
974 | struct edge **ptail = &polygon->y_buckets[ix]; |
1104 | e->next = *ptail; |
975 | e->next = *ptail; |
1105 | *ptail = e; |
976 | *ptail = e; |
Line 1106... | Line 977... | ||
1106 | } |
977 | } |
1107 | 978 | ||
1108 | inline static glitter_status_t |
979 | inline static void |
1109 | polygon_add_edge (struct polygon *polygon, |
980 | polygon_add_edge (struct polygon *polygon, |
1110 | const cairo_edge_t *edge) |
981 | const cairo_edge_t *edge) |
1111 | { |
982 | { |
1112 | struct edge *e; |
983 | struct edge *e; |
1113 | grid_scaled_x_t dx; |
984 | grid_scaled_x_t dx; |
1114 | grid_scaled_y_t dy; |
985 | grid_scaled_y_t dy; |
1115 | grid_scaled_y_t ytop, ybot; |
986 | grid_scaled_y_t ytop, ybot; |
Line 1116... | Line -... | ||
1116 | grid_scaled_y_t ymin = polygon->ymin; |
- | |
1117 | grid_scaled_y_t ymax = polygon->ymax; |
- | |
1118 | 987 | grid_scaled_y_t ymin = polygon->ymin; |
|
1119 | assert (edge->bottom > edge->top); |
988 | grid_scaled_y_t ymax = polygon->ymax; |
Line 1120... | Line 989... | ||
1120 | 989 | ||
1121 | if (unlikely (edge->top >= ymax || edge->bottom <= ymin)) |
- | |
1122 | return GLITTER_STATUS_SUCCESS; |
- | |
Line 1123... | Line 990... | ||
1123 | 990 | if (unlikely (edge->top >= ymax || edge->bottom <= ymin)) |
|
1124 | e = pool_alloc (polygon->edge_pool.base, sizeof (struct edge)); |
991 | return; |
1125 | if (unlikely (NULL == e)) |
992 | |
1126 | return GLITTER_STATUS_NO_MEMORY; |
993 | e = pool_alloc (polygon->edge_pool.base, sizeof (struct edge)); |
Line 1164... | Line 1031... | ||
1164 | 1031 | ||
Line 1165... | Line 1032... | ||
1165 | _polygon_insert_edge_into_its_y_bucket (polygon, e); |
1032 | _polygon_insert_edge_into_its_y_bucket (polygon, e); |
1166 | 1033 | ||
1167 | e->x.rem -= dy; /* Bias the remainder for faster |
- | |
1168 | * edge advancement. */ |
1034 | e->x.rem -= dy; /* Bias the remainder for faster |
Line 1169... | Line 1035... | ||
1169 | return GLITTER_STATUS_SUCCESS; |
1035 | * edge advancement. */ |
1170 | } |
1036 | } |
1171 | 1037 | ||
- | 1038 | static void |
|
- | 1039 | active_list_reset (struct active_list *active) |
|
- | 1040 | { |
|
1172 | static void |
1041 | active->head.vertical = 1; |
- | 1042 | active->head.height_left = INT_MAX; |
|
- | 1043 | active->head.x.quo = INT_MIN; |
|
- | 1044 | active->head.prev = NULL; |
|
- | 1045 | active->head.next = &active->tail; |
|
- | 1046 | active->tail.prev = &active->head; |
|
- | 1047 | active->tail.next = NULL; |
|
1173 | active_list_reset (struct active_list *active) |
1048 | active->tail.x.quo = INT_MAX; |
- | 1049 | active->tail.height_left = INT_MAX; |
|
1174 | { |
1050 | active->tail.vertical = 1; |
Line 1175... | Line 1051... | ||
1175 | active->head = NULL; |
1051 | active->min_height = 0; |
1176 | active->min_height = 0; |
1052 | active->is_vertical = 1; |
1177 | } |
1053 | } |
Line 1201... | Line 1077... | ||
1201 | * to attach the last non-empty list. |
1077 | * to attach the last non-empty list. |
1202 | */ |
1078 | */ |
1203 | static struct edge * |
1079 | static struct edge * |
1204 | merge_sorted_edges (struct edge *head_a, struct edge *head_b) |
1080 | merge_sorted_edges (struct edge *head_a, struct edge *head_b) |
1205 | { |
1081 | { |
1206 | struct edge *head, **next; |
1082 | struct edge *head, **next, *prev; |
- | 1083 | int32_t x; |
|
Line 1207... | Line 1084... | ||
1207 | 1084 | ||
1208 | head = head_a; |
1085 | prev = head_a->prev; |
- | 1086 | next = &head; |
|
- | 1087 | if (head_a->x.quo <= head_b->x.quo) { |
|
- | 1088 | head = head_a; |
|
- | 1089 | } else { |
|
- | 1090 | head = head_b; |
|
- | 1091 | head_b->prev = prev; |
|
- | 1092 | goto start_with_b; |
|
Line 1209... | Line 1093... | ||
1209 | next = &head; |
1093 | } |
- | 1094 | ||
1210 | 1095 | do { |
|
- | 1096 | x = head_b->x.quo; |
|
1211 | while (1) { |
1097 | while (head_a != NULL && head_a->x.quo <= x) { |
1212 | while (head_a != NULL && head_a->x.quo <= head_b->x.quo) { |
1098 | prev = head_a; |
1213 | next = &head_a->next; |
1099 | next = &head_a->next; |
Line -... | Line 1100... | ||
- | 1100 | head_a = head_a->next; |
|
1214 | head_a = head_a->next; |
1101 | } |
1215 | } |
1102 | |
1216 | 1103 | head_b->prev = prev; |
|
Line -... | Line 1104... | ||
- | 1104 | *next = head_b; |
|
- | 1105 | if (head_a == NULL) |
|
1217 | *next = head_b; |
1106 | return head; |
- | 1107 | ||
1218 | if (head_a == NULL) |
1108 | start_with_b: |
1219 | return head; |
1109 | x = head_a->x.quo; |
1220 | 1110 | while (head_b != NULL && head_b->x.quo <= x) { |
|
Line -... | Line 1111... | ||
- | 1111 | prev = head_b; |
|
1221 | while (head_b != NULL && head_b->x.quo <= head_a->x.quo) { |
1112 | next = &head_b->next; |
1222 | next = &head_b->next; |
1113 | head_b = head_b->next; |
1223 | head_b = head_b->next; |
1114 | } |
1224 | } |
1115 | |
1225 | 1116 | head_a->prev = prev; |
|
Line 1226... | Line 1117... | ||
1226 | *next = head_a; |
1117 | *next = head_a; |
1227 | if (head_b == NULL) |
1118 | if (head_b == NULL) |
1228 | return head; |
1119 | return head; |
Line 1254... | Line 1145... | ||
1254 | struct edge *head_other, *remaining; |
1145 | struct edge *head_other, *remaining; |
1255 | unsigned int i; |
1146 | unsigned int i; |
Line 1256... | Line 1147... | ||
1256 | 1147 | ||
Line 1257... | Line -... | ||
1257 | head_other = list->next; |
- | |
1258 | 1148 | head_other = list->next; |
|
1259 | /* Single element list -> return */ |
1149 | |
1260 | if (head_other == NULL) { |
1150 | if (head_other == NULL) { |
1261 | *head_out = list; |
1151 | *head_out = list; |
Line 1262... | Line -... | ||
1262 | return NULL; |
- | |
1263 | } |
- | |
1264 | - | ||
1265 | /* Unroll the first iteration of the following loop (halves the number of calls to merge_sorted_edges): |
- | |
1266 | * - Initialize remaining to be the list containing the elements after the second in the input list. |
1152 | return NULL; |
1267 | * - Initialize *head_out to be the sorted list containing the first two element. |
1153 | } |
1268 | */ |
1154 | |
1269 | remaining = head_other->next; |
- | |
1270 | if (list->x.quo <= head_other->x.quo) { |
1155 | remaining = head_other->next; |
1271 | *head_out = list; |
1156 | if (list->x.quo <= head_other->x.quo) { |
1272 | /* list->next = head_other; */ /* The input list is already like this. */ |
1157 | *head_out = list; |
- | 1158 | head_other->next = NULL; |
|
1273 | head_other->next = NULL; |
1159 | } else { |
- | 1160 | *head_out = head_other; |
|
1274 | } else { |
1161 | head_other->prev = list->prev; |
1275 | *head_out = head_other; |
1162 | head_other->next = list; |
Line 1276... | Line 1163... | ||
1276 | head_other->next = list; |
1163 | list->prev = head_other; |
1277 | list->next = NULL; |
- | |
1278 | } |
- | |
1279 | 1164 | list->next = NULL; |
|
1280 | for (i = 0; i < level && remaining; i++) { |
1165 | } |
1281 | /* Extract a sorted list of the same size as *head_out |
1166 | |
Line 1282... | Line -... | ||
1282 | * (2^(i+1) elements) from the list of remaining elements. */ |
- | |
1283 | remaining = sort_edges (remaining, i, &head_other); |
- | |
1284 | *head_out = merge_sorted_edges (*head_out, head_other); |
1167 | for (i = 0; i < level && remaining; i++) { |
1285 | } |
1168 | remaining = sort_edges (remaining, i, &head_other); |
Line -... | Line 1169... | ||
- | 1169 | *head_out = merge_sorted_edges (*head_out, head_other); |
|
- | 1170 | } |
|
- | 1171 | ||
- | 1172 | return remaining; |
|
- | 1173 | } |
|
- | 1174 | ||
- | 1175 | static struct edge * |
|
1286 | 1176 | merge_unsorted_edges (struct edge *head, struct edge *unsorted) |
|
1287 | /* *head_out now contains (at most) 2^(level+1) elements. */ |
1177 | { |
1288 | 1178 | sort_edges (unsorted, UINT_MAX, &unsorted); |
|
1289 | return remaining; |
1179 | return merge_sorted_edges (head, unsorted); |
1290 | } |
1180 | } |
1291 | 1181 | ||
1292 | /* Test if the edges on the active list can be safely advanced by a |
1182 | /* Test if the edges on the active list can be safely advanced by a |
Line 1293... | Line 1183... | ||
1293 | * full row without intersections or any edges ending. */ |
1183 | * full row without intersections or any edges ending. */ |
1294 | inline static int |
1184 | inline static int |
1295 | active_list_can_step_full_row (struct active_list *active) |
1185 | can_do_full_row (struct active_list *active) |
1296 | { |
1186 | { |
- | 1187 | const struct edge *e; |
|
Line 1297... | Line 1188... | ||
1297 | const struct edge *e; |
1188 | int prev_x = INT_MIN; |
1298 | int prev_x = INT_MIN; |
1189 | |
1299 | 1190 | /* Recomputes the minimum height of all edges on the active |
|
1300 | /* Recomputes the minimum height of all edges on the active |
1191 | * list if we have been dropping edges. */ |
- | 1192 | if (active->min_height <= 0) { |
|
1301 | * list if we have been dropping edges. */ |
1193 | int min_height = INT_MAX; |
1302 | if (active->min_height <= 0) { |
1194 | int is_vertical = 1; |
Line -... | Line 1195... | ||
- | 1195 | ||
1303 | int min_height = INT_MAX; |
1196 | e = active->head.next; |
1304 | 1197 | while (NULL != e) { |
|
Line 1305... | Line 1198... | ||
1305 | e = active->head; |
1198 | if (e->height_left < min_height) |
1306 | while (NULL != e) { |
1199 | min_height = e->height_left; |
Line 1307... | Line 1200... | ||
1307 | if (e->height_left < min_height) |
1200 | is_vertical &= e->vertical; |
1308 | min_height = e->height_left; |
1201 | e = e->next; |
1309 | e = e->next; |
- | |
1310 | } |
1202 | } |
Line 1311... | Line 1203... | ||
1311 | 1203 | ||
1312 | active->min_height = min_height; |
1204 | active->is_vertical = is_vertical; |
1313 | } |
1205 | active->min_height = min_height; |
1314 | 1206 | } |
|
1315 | if (active->min_height < GRID_Y) |
1207 | |
1316 | return 0; |
1208 | if (active->min_height < GRID_Y) |
Line 1317... | Line 1209... | ||
1317 | 1209 | return 0; |
|
1318 | /* Check for intersections as no edges end during the next row. */ |
1210 | |
Line 1319... | Line 1211... | ||
1319 | e = active->head; |
1211 | /* Check for intersections as no edges end during the next row. */ |
1320 | while (NULL != e) { |
- | |
1321 | struct quorem x = e->x; |
1212 | for (e = active->head.next; e != &active->tail; e = e->next) { |
Line 1322... | Line 1213... | ||
1322 | 1213 | struct quorem x = e->x; |
|
1323 | if (! e->vertical) { |
1214 | |
Line 1324... | Line 1215... | ||
1324 | x.quo += e->dxdy_full.quo; |
1215 | if (! e->vertical) { |
1325 | x.rem += e->dxdy_full.rem; |
1216 | x.quo += e->dxdy_full.quo; |
1326 | if (x.rem >= 0) |
1217 | x.rem += e->dxdy_full.rem; |
1327 | ++x.quo; |
1218 | if (x.rem >= 0) |
1328 | } |
- | |
1329 | - | ||
1330 | if (x.quo <= prev_x) |
1219 | ++x.quo; |
1331 | return 0; |
1220 | } |
1332 | 1221 | ||
1333 | prev_x = x.quo; |
- | |
1334 | e = e->next; |
- | |
1335 | } |
- | |
1336 | - | ||
1337 | return 1; |
- | |
- | 1222 | if (x.quo < prev_x) |
|
Line -... | Line 1223... | ||
- | 1223 | return 0; |
|
- | 1224 | ||
- | 1225 | prev_x = x.quo; |
|
1338 | } |
1226 | } |
1339 | 1227 | ||
- | 1228 | return 1; |
|
- | 1229 | } |
|
1340 | /* Merges edges on the given subpixel row from the polygon to the |
1230 | |
Line -... | Line 1231... | ||
- | 1231 | /* Merges edges on the given subpixel row from the polygon to the |
|
- | 1232 | * active_list. */ |
|
1341 | * active_list. */ |
1233 | inline static void |
- | 1234 | active_list_merge_edges_from_bucket(struct active_list *active, |
|
1342 | inline static void |
1235 | struct edge *edges) |
1343 | active_list_merge_edges_from_polygon( |
1236 | { |
1344 | struct active_list *active, |
1237 | active->head.next = merge_unsorted_edges (active->head.next, edges); |
- | 1238 | } |
|
1345 | grid_scaled_y_t y, |
1239 | |
1346 | struct polygon *polygon) |
1240 | inline static void |
1347 | { |
- | |
1348 | /* Split off the edges on the current subrow and merge them into |
1241 | polygon_fill_buckets (struct active_list *active, |
1349 | * the active list. */ |
1242 | struct edge *edge, |
1350 | unsigned ix = EDGE_Y_BUCKET_INDEX(y, polygon->ymin); |
1243 | int y, |
- | 1244 | struct edge **buckets) |
|
1351 | int min_height = active->min_height; |
1245 | { |
1352 | struct edge *subrow_edges = NULL; |
- | |
1353 | struct edge **ptail = &polygon->y_buckets[ix]; |
- | |
1354 | 1246 | grid_scaled_y_t min_height = active->min_height; |
|
1355 | while (1) { |
1247 | int is_vertical = active->is_vertical; |
1356 | struct edge *tail = *ptail; |
- | |
Line 1357... | Line -... | ||
1357 | if (NULL == tail) break; |
- | |
1358 | - | ||
1359 | if (y == tail->ytop) { |
1248 | |
1360 | *ptail = tail->next; |
1249 | while (edge) { |
1361 | tail->next = subrow_edges; |
1250 | struct edge *next = edge->next; |
- | 1251 | int suby = edge->ytop - y; |
|
1362 | subrow_edges = tail; |
1252 | if (buckets[suby]) |
1363 | if (tail->height_left < min_height) |
1253 | buckets[suby]->prev = edge; |
1364 | min_height = tail->height_left; |
1254 | edge->next = buckets[suby]; |
1365 | } else { |
1255 | edge->prev = NULL; |
Line 1366... | Line -... | ||
1366 | ptail = &tail->next; |
- | |
1367 | } |
1256 | buckets[suby] = edge; |
Line 1368... | Line -... | ||
1368 | } |
- | |
1369 | if (subrow_edges) { |
1257 | if (edge->height_left < min_height) |
1370 | sort_edges (subrow_edges, UINT_MAX, &subrow_edges); |
1258 | min_height = edge->height_left; |
1371 | active->head = merge_sorted_edges (active->head, subrow_edges); |
1259 | is_vertical &= edge->vertical; |
Line 1372... | Line 1260... | ||
1372 | active->min_height = min_height; |
1260 | edge = next; |
1373 | } |
1261 | } |
1374 | } |
1262 | |
1375 | 1263 | active->is_vertical = is_vertical; |
|
1376 | /* Advance the edges on the active list by one subsample row by |
1264 | active->min_height = min_height; |
1377 | * updating their x positions. Drop edges from the list that end. */ |
1265 | } |
1378 | inline static void |
1266 | |
Line 1379... | Line 1267... | ||
1379 | active_list_substep_edges( |
1267 | inline static void |
- | 1268 | sub_row (struct active_list *active, |
|
- | 1269 | struct cell_list *coverages, |
|
- | 1270 | unsigned int mask) |
|
- | 1271 | { |
|
1380 | struct active_list *active) |
1272 | struct edge *edge = active->head.next; |
- | 1273 | int xstart = INT_MIN, prev_x = INT_MIN; |
|
- | 1274 | int winding = 0; |
|
1381 | { |
1275 | |
- | 1276 | cell_list_rewind (coverages); |
|
1382 | struct edge **cursor = &active->head; |
1277 | |
1383 | grid_scaled_x_t prev_x = INT_MIN; |
1278 | while (&active->tail != edge) { |
1384 | struct edge *unsorted = NULL; |
1279 | struct edge *next = edge->next; |
1385 | 1280 | int xend = edge->x.quo; |
|
1386 | while (1) { |
- | |
1387 | struct edge *edge; |
- | |
1388 | 1281 | ||
- | 1282 | if (--edge->height_left) { |
|
1389 | UNROLL3({ |
1283 | edge->x.quo += edge->dxdy.quo; |
1390 | edge = *cursor; |
1284 | edge->x.rem += edge->dxdy.rem; |
1391 | if (NULL == edge) |
- | |
1392 | break; |
- | |
1393 | - | ||
1394 | if (0 != --edge->height_left) { |
- | |
1395 | edge->x.quo += edge->dxdy.quo; |
- | |
1396 | edge->x.rem += edge->dxdy.rem; |
- | |
1397 | if (edge->x.rem >= 0) { |
- | |
1398 | ++edge->x.quo; |
- | |
1399 | edge->x.rem -= edge->dy; |
- | |
1400 | } |
- | |
1401 | - | ||
1402 | if (edge->x.quo < prev_x) { |
- | |
1403 | *cursor = edge->next; |
- | |
1404 | edge->next = unsorted; |
- | |
1405 | unsorted = edge; |
- | |
1406 | } else { |
- | |
1407 | prev_x = edge->x.quo; |
- | |
1408 | cursor = &edge->next; |
- | |
1409 | } |
- | |
1410 | - | ||
1411 | } else { |
- | |
1412 | *cursor = edge->next; |
- | |
1413 | } |
- | |
1414 | }); |
- | |
1415 | } |
- | |
1416 | - | ||
1417 | if (unsorted) { |
- | |
1418 | sort_edges (unsorted, UINT_MAX, &unsorted); |
- | |
Line 1419... | Line 1285... | ||
1419 | active->head = merge_sorted_edges (active->head, unsorted); |
1285 | if (edge->x.rem >= 0) { |
- | 1286 | ++edge->x.quo; |
|
1420 | } |
1287 | edge->x.rem -= edge->dy; |
1421 | } |
1288 | } |
1422 | 1289 | ||
1423 | inline static glitter_status_t |
- | |
1424 | apply_nonzero_fill_rule_for_subrow (struct active_list *active, |
1290 | if (edge->x.quo < prev_x) { |
- | 1291 | struct edge *pos = edge->prev; |
|
- | 1292 | pos->next = next; |
|
Line 1425... | Line -... | ||
1425 | struct cell_list *coverages) |
- | |
1426 | { |
- | |
1427 | struct edge *edge = active->head; |
- | |
1428 | int winding = 0; |
- | |
1429 | int xstart; |
- | |
1430 | int xend; |
1293 | next->prev = pos; |
1431 | int status; |
1294 | do { |
1432 | - | ||
1433 | cell_list_rewind (coverages); |
- | |
1434 | 1295 | pos = pos->prev; |
|
Line 1435... | Line -... | ||
1435 | while (NULL != edge) { |
- | |
1436 | xstart = edge->x.quo; |
1296 | } while (edge->x.quo < pos->x.quo); |
1437 | winding = edge->dir; |
- | |
1438 | while (1) { |
1297 | pos->next->prev = edge; |
1439 | edge = edge->next; |
- | |
1440 | if (NULL == edge) |
- | |
1441 | return cell_list_add_unbounded_subspan (coverages, xstart); |
- | |
1442 | 1298 | edge->next = pos->next; |
|
1443 | winding += edge->dir; |
- | |
1444 | if (0 == winding) { |
- | |
1445 | if (edge->next == NULL || edge->next->x.quo != edge->x.quo) |
- | |
1446 | break; |
1299 | edge->prev = pos; |
1447 | } |
- | |
1448 | } |
- | |
1449 | - | ||
1450 | xend = edge->x.quo; |
1300 | pos->next = edge; |
1451 | status = cell_list_add_subspan (coverages, xstart, xend); |
1301 | } else |
1452 | if (unlikely (status)) |
- | |
1453 | return status; |
- | |
1454 | - | ||
1455 | edge = edge->next; |
- | |
1456 | } |
- | |
1457 | 1302 | prev_x = edge->x.quo; |
|
1458 | return GLITTER_STATUS_SUCCESS; |
1303 | active->min_height = -1; |
1459 | } |
- | |
1460 | - | ||
1461 | static glitter_status_t |
- | |
1462 | apply_evenodd_fill_rule_for_subrow (struct active_list *active, |
- | |
1463 | struct cell_list *coverages) |
- | |
1464 | { |
- | |
1465 | struct edge *edge = active->head; |
- | |
1466 | int xstart; |
1304 | } else { |
Line 1467... | Line -... | ||
1467 | int xend; |
- | |
1468 | int status; |
- | |
1469 | - | ||
1470 | cell_list_rewind (coverages); |
- | |
1471 | - | ||
1472 | while (NULL != edge) { |
1305 | edge->prev->next = next; |
1473 | xstart = edge->x.quo; |
- | |
1474 | - | ||
1475 | while (1) { |
- | |
1476 | edge = edge->next; |
- | |
1477 | if (NULL == edge) |
- | |
1478 | return cell_list_add_unbounded_subspan (coverages, xstart); |
- | |
1479 | - | ||
1480 | if (edge->next == NULL || edge->next->x.quo != edge->x.quo) |
- | |
1481 | break; |
- | |
1482 | - | ||
1483 | edge = edge->next; |
- | |
1484 | } |
- | |
1485 | - | ||
1486 | xend = edge->x.quo; |
- | |
1487 | status = cell_list_add_subspan (coverages, xstart, xend); |
- | |
1488 | if (unlikely (status)) |
- | |
1489 | return status; |
- | |
1490 | - | ||
1491 | edge = edge->next; |
- | |
1492 | } |
- | |
1493 | - | ||
1494 | return GLITTER_STATUS_SUCCESS; |
- | |
1495 | } |
- | |
1496 | - | ||
1497 | static glitter_status_t |
- | |
1498 | apply_nonzero_fill_rule_and_step_edges (struct active_list *active, |
- | |
1499 | struct cell_list *coverages) |
- | |
1500 | { |
- | |
1501 | struct edge **cursor = &active->head; |
- | |
1502 | struct edge *left_edge; |
- | |
1503 | int status; |
- | |
1504 | 1306 | next->prev = edge->prev; |
|
1505 | left_edge = *cursor; |
- | |
1506 | while (NULL != left_edge) { |
- | |
1507 | struct edge *right_edge; |
- | |
1508 | int winding = left_edge->dir; |
- | |
1509 | 1307 | } |
|
1510 | left_edge->height_left -= GRID_Y; |
1308 | |
1511 | if (left_edge->height_left) |
1309 | winding += edge->dir; |
1512 | cursor = &left_edge->next; |
1310 | if ((winding & mask) == 0) { |
1513 | else |
1311 | if (next->x.quo != xend) { |
1514 | *cursor = left_edge->next; |
1312 | cell_list_add_subspan (coverages, xstart, xend); |
1515 | - | ||
1516 | while (1) { |
- | |
1517 | right_edge = *cursor; |
1313 | xstart = INT_MIN; |
1518 | if (NULL == right_edge) |
- | |
1519 | return cell_list_render_edge (coverages, left_edge, +1); |
- | |
1520 | - | ||
1521 | right_edge->height_left -= GRID_Y; |
- | |
1522 | if (right_edge->height_left) |
- | |
1523 | cursor = &right_edge->next; |
- | |
1524 | else |
- | |
1525 | *cursor = right_edge->next; |
- | |
1526 | - | ||
1527 | winding += right_edge->dir; |
- | |
1528 | if (0 == winding) { |
1314 | } |
1529 | if (right_edge->next == NULL || |
- | |
1530 | right_edge->next->x.quo != right_edge->x.quo) |
- | |
1531 | { |
1315 | } else if (xstart == INT_MIN) |
Line 1532... | Line 1316... | ||
1532 | break; |
1316 | xstart = xend; |
1533 | } |
1317 | |
1534 | } |
1318 | edge = next; |
1535 | - | ||
1536 | if (! right_edge->vertical) { |
- | |
1537 | right_edge->x.quo += right_edge->dxdy_full.quo; |
- | |
1538 | right_edge->x.rem += right_edge->dxdy_full.rem; |
- | |
1539 | if (right_edge->x.rem >= 0) { |
- | |
1540 | ++right_edge->x.quo; |
- | |
1541 | right_edge->x.rem -= right_edge->dy; |
- | |
1542 | } |
- | |
1543 | } |
- | |
1544 | } |
- | |
1545 | - | ||
1546 | status = cell_list_render_edge (coverages, left_edge, +1); |
- | |
1547 | if (unlikely (status)) |
- | |
1548 | return status; |
- | |
1549 | - | ||
1550 | status = cell_list_render_edge (coverages, right_edge, -1); |
- | |
1551 | if (unlikely (status)) |
1319 | } |
1552 | return status; |
- | |
1553 | - | ||
1554 | left_edge = *cursor; |
- | |
1555 | } |
- | |
1556 | - | ||
1557 | return GLITTER_STATUS_SUCCESS; |
- | |
1558 | } |
- | |
1559 | - | ||
1560 | static glitter_status_t |
- | |
1561 | apply_evenodd_fill_rule_and_step_edges (struct active_list *active, |
- | |
1562 | struct cell_list *coverages) |
- | |
1563 | { |
1320 | } |
1564 | struct edge **cursor = &active->head; |
- | |
1565 | struct edge *left_edge; |
- | |
1566 | int status; |
- | |
1567 | - | ||
1568 | left_edge = *cursor; |
- | |
1569 | while (NULL != left_edge) { |
- | |
1570 | struct edge *right_edge; |
- | |
1571 | - | ||
1572 | left_edge->height_left -= GRID_Y; |
1321 | |
1573 | if (left_edge->height_left) |
- | |
1574 | cursor = &left_edge->next; |
- | |
1575 | else |
- | |
Line 1576... | Line 1322... | ||
1576 | *cursor = left_edge->next; |
1322 | inline static void dec (struct active_list *a, struct edge *e, int h) |
1577 | 1323 | { |
|
1578 | while (1) { |
1324 | e->height_left -= h; |
Line 1579... | Line -... | ||
1579 | right_edge = *cursor; |
- | |
1580 | if (NULL == right_edge) |
1325 | if (e->height_left == 0) { |
1581 | return cell_list_render_edge (coverages, left_edge, +1); |
- | |
Line 1582... | Line 1326... | ||
1582 | 1326 | e->prev->next = e->next; |
|
1583 | right_edge->height_left -= GRID_Y; |
- | |
1584 | if (right_edge->height_left) |
- | |
1585 | cursor = &right_edge->next; |
- | |
1586 | else |
- | |
1587 | *cursor = right_edge->next; |
- | |
1588 | - | ||
1589 | if (right_edge->next == NULL || |
- | |
1590 | right_edge->next->x.quo != right_edge->x.quo) |
- | |
1591 | { |
- | |
1592 | break; |
- | |
1593 | } |
- | |
1594 | - | ||
1595 | if (! right_edge->vertical) { |
- | |
1596 | right_edge->x.quo += right_edge->dxdy_full.quo; |
- | |
1597 | right_edge->x.rem += right_edge->dxdy_full.rem; |
- | |
1598 | if (right_edge->x.rem >= 0) { |
- | |
1599 | ++right_edge->x.quo; |
- | |
1600 | right_edge->x.rem -= right_edge->dy; |
- | |
1601 | } |
- | |
1602 | } |
- | |
1603 | } |
- | |
1604 | - | ||
1605 | status = cell_list_render_edge (coverages, left_edge, +1); |
- | |
1606 | if (unlikely (status)) |
- | |
1607 | return status; |
- | |
1608 | - | ||
1609 | status = cell_list_render_edge (coverages, right_edge, -1); |
- | |
1610 | if (unlikely (status)) |
1327 | e->next->prev = e->prev; |
1611 | return status; |
1328 | a->min_height = -1; |
1612 | - | ||
1613 | left_edge = *cursor; |
- | |
1614 | } |
1329 | } |
Line 1615... | Line -... | ||
1615 | - | ||
1616 | return GLITTER_STATUS_SUCCESS; |
- | |
1617 | } |
- | |
1618 | - | ||
1619 | /* If the user hasn't configured a coverage blitter, use a default one |
1330 | } |
1620 | * that blits spans directly to an A8 raster. */ |
- | |
1621 | #ifndef GLITTER_BLIT_COVERAGES |
1331 | |
1622 | - | ||
1623 | inline static void |
- | |
1624 | blit_span( |
- | |
1625 | unsigned char *row_pixels, |
1332 | inline static void full_step (struct edge *e) |
Line 1626... | Line -... | ||
1626 | int x, unsigned len, |
- | |
1627 | grid_area_t coverage) |
- | |
1628 | { |
- | |
1629 | int alpha = GRID_AREA_TO_ALPHA(coverage); |
- | |
1630 | if (1 == len) { |
1333 | { |
Line 1631... | Line -... | ||
1631 | row_pixels[x] = alpha; |
- | |
1632 | } |
1334 | if (! e->vertical) { |
1633 | else { |
- | |
1634 | memset(row_pixels + x, alpha, len); |
- | |
1635 | } |
1335 | e->x.quo += e->dxdy_full.quo; |
1636 | } |
- | |
1637 | - | ||
1638 | #define GLITTER_BLIT_COVERAGES(coverages, y, height, xmin, xmax) \ |
- | |
Line 1639... | Line 1336... | ||
1639 | do { \ |
1336 | e->x.rem += e->dxdy_full.rem; |
1640 | int __y = y; \ |
1337 | if (e->x.rem >= 0) { |
1641 | int __h = height; \ |
- | |
1642 | do { \ |
1338 | ++e->x.quo; |
1643 | blit_cells(coverages, raster_pixels + (__y)*raster_stride, xmin, xmax); \ |
- | |
1644 | } while (--__h); \ |
- | |
1645 | } while (0) |
- | |
Line 1646... | Line 1339... | ||
1646 | 1339 | e->x.rem -= e->dy; |
|
1647 | static void |
- | |
1648 | blit_cells( |
1340 | } |
1649 | struct cell_list *cells, |
1341 | } |
1650 | unsigned char *row_pixels, |
- | |
Line 1651... | Line 1342... | ||
1651 | int xmin, int xmax) |
1342 | } |
1652 | { |
1343 | |
1653 | struct cell *cell = cells->head; |
1344 | static void |
1654 | int prev_x = xmin; |
1345 | full_row (struct active_list *active, |
1655 | int coverage = 0; |
1346 | struct cell_list *coverages, |
1656 | if (NULL == cell) |
1347 | unsigned int mask) |
1657 | return; |
1348 | { |
1658 | 1349 | struct edge *left = active->head.next; |
|
1659 | while (NULL != cell && cell->x < xmin) { |
1350 | |
1660 | coverage += cell->covered_height; |
1351 | while (&active->tail != left) { |
1661 | cell = cell->next; |
1352 | struct edge *right; |
Line 1662... | Line 1353... | ||
1662 | } |
1353 | int winding; |
1663 | coverage *= GRID_X*2; |
1354 | |
1664 | 1355 | dec (active, left, GRID_Y); |
|
- | 1356 | ||
- | 1357 | winding = left->dir; |
|
- | 1358 | right = left->next; |
|
1665 | for (; NULL != cell; cell = cell->next) { |
1359 | do { |
1666 | int x = cell->x; |
1360 | dec (active, right, GRID_Y); |
- | 1361 | ||
1667 | int area; |
1362 | winding += right->dir; |
1668 | if (x >= xmax) |
1363 | if ((winding & mask) == 0 && right->next->x.quo != right->x.quo) |
1669 | break; |
1364 | break; |
1670 | if (x > prev_x && 0 != coverage) { |
1365 | |
1671 | blit_span(row_pixels, prev_x, x - prev_x, coverage); |
1366 | full_step (right); |
Line 1672... | Line 1367... | ||
1672 | } |
1367 | |
1673 | 1368 | right = right->next; |
|
1674 | coverage += cell->covered_height * GRID_X*2; |
1369 | } while (1); |
Line 1731... | Line 1426... | ||
1731 | glitter_scan_converter_t *converter, |
1426 | glitter_scan_converter_t *converter, |
1732 | int xmin, int ymin, |
1427 | int xmin, int ymin, |
1733 | int xmax, int ymax) |
1428 | int xmax, int ymax) |
1734 | { |
1429 | { |
1735 | glitter_status_t status; |
1430 | glitter_status_t status; |
- | 1431 | int max_num_spans; |
|
Line 1736... | Line 1432... | ||
1736 | 1432 | ||
1737 | converter->xmin = 0; converter->xmax = 0; |
1433 | converter->xmin = 0; converter->xmax = 0; |
Line -... | Line 1434... | ||
- | 1434 | converter->ymin = 0; converter->ymax = 0; |
|
- | 1435 | ||
- | 1436 | max_num_spans = xmax - xmin + 1; |
|
- | 1437 | ||
- | 1438 | if (max_num_spans > ARRAY_LENGTH(converter->spans_embedded)) { |
|
- | 1439 | converter->spans = _cairo_malloc_ab (max_num_spans, |
|
- | 1440 | sizeof (cairo_half_open_span_t)); |
|
- | 1441 | if (unlikely (converter->spans == NULL)) |
|
- | 1442 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
|
- | 1443 | } else |
|
1738 | converter->ymin = 0; converter->ymax = 0; |
1444 | converter->spans = converter->spans_embedded; |
1739 | 1445 | ||
1740 | xmin = int_to_grid_scaled_x(xmin); |
1446 | xmin = int_to_grid_scaled_x(xmin); |
1741 | ymin = int_to_grid_scaled_y(ymin); |
1447 | ymin = int_to_grid_scaled_y(ymin); |
Line 1778... | Line 1484... | ||
1778 | long long tmp__ = (long long)(grid_scale) * (in); \ |
1484 | long long tmp__ = (long long)(grid_scale) * (in); \ |
1779 | tmp__ >>= GLITTER_INPUT_BITS; \ |
1485 | tmp__ >>= GLITTER_INPUT_BITS; \ |
1780 | (out) = tmp__; \ |
1486 | (out) = tmp__; \ |
1781 | } while (0) |
1487 | } while (0) |
Line -... | Line 1488... | ||
- | 1488 | ||
- | 1489 | /* Add a new polygon edge from pixel (x1,y1) to (x2,y2) to the scan |
|
- | 1490 | * converter. The coordinates represent pixel positions scaled by |
|
- | 1491 | * 2**GLITTER_PIXEL_BITS. If this function fails then the scan |
|
- | 1492 | * converter should be reset or destroyed. Dir must be +1 or -1, |
|
1782 | 1493 | * with the latter reversing the orientation of the edge. */ |
|
1783 | I glitter_status_t |
1494 | I void |
1784 | glitter_scan_converter_add_edge (glitter_scan_converter_t *converter, |
1495 | glitter_scan_converter_add_edge (glitter_scan_converter_t *converter, |
1785 | const cairo_edge_t *edge) |
1496 | const cairo_edge_t *edge) |
1786 | { |
1497 | { |
Line 1787... | Line 1498... | ||
1787 | cairo_edge_t e; |
1498 | cairo_edge_t e; |
1788 | 1499 | ||
1789 | INPUT_TO_GRID_Y (edge->top, e.top); |
1500 | INPUT_TO_GRID_Y (edge->top, e.top); |
1790 | INPUT_TO_GRID_Y (edge->bottom, e.bottom); |
1501 | INPUT_TO_GRID_Y (edge->bottom, e.bottom); |
Line 1791... | Line 1502... | ||
1791 | if (e.top >= e.bottom) |
1502 | if (e.top >= e.bottom) |
1792 | return GLITTER_STATUS_SUCCESS; |
1503 | return; |
1793 | 1504 | ||
1794 | /* XXX: possible overflows if GRID_X/Y > 2**GLITTER_INPUT_BITS */ |
1505 | /* XXX: possible overflows if GRID_X/Y > 2**GLITTER_INPUT_BITS */ |
1795 | INPUT_TO_GRID_Y (edge->line.p1.y, e.line.p1.y); |
1506 | INPUT_TO_GRID_Y (edge->line.p1.y, e.line.p1.y); |
Line 1796... | Line 1507... | ||
1796 | INPUT_TO_GRID_Y (edge->line.p2.y, e.line.p2.y); |
1507 | INPUT_TO_GRID_Y (edge->line.p2.y, e.line.p2.y); |
1797 | if (e.line.p1.y == e.line.p2.y) |
1508 | if (e.line.p1.y == e.line.p2.y) |
Line 1798... | Line 1509... | ||
1798 | return GLITTER_STATUS_SUCCESS; |
1509 | e.line.p2.y++; /* little fudge to prevent a div-by-zero */ |
Line 1799... | Line 1510... | ||
1799 | 1510 | ||
1800 | INPUT_TO_GRID_X (edge->line.p1.x, e.line.p1.x); |
- | |
1801 | INPUT_TO_GRID_X (edge->line.p2.x, e.line.p2.x); |
- | |
1802 | - | ||
1803 | e.dir = edge->dir; |
- | |
1804 | - | ||
1805 | return polygon_add_edge (converter->polygon, &e); |
- | |
1806 | } |
- | |
1807 | - | ||
1808 | #ifndef GLITTER_BLIT_COVERAGES_BEGIN |
- | |
1809 | # define GLITTER_BLIT_COVERAGES_BEGIN |
- | |
1810 | #endif |
- | |
1811 | - | ||
1812 | #ifndef GLITTER_BLIT_COVERAGES_END |
- | |
1813 | # define GLITTER_BLIT_COVERAGES_END |
- | |
1814 | #endif |
- | |
1815 | - | ||
1816 | #ifndef GLITTER_BLIT_COVERAGES_EMPTY |
- | |
1817 | # define GLITTER_BLIT_COVERAGES_EMPTY(y0, y1, xmin, xmax) |
- | |
1818 | #endif |
- | |
1819 | - | ||
1820 | static cairo_bool_t |
- | |
1821 | active_list_is_vertical (struct active_list *active) |
- | |
1822 | { |
- | |
1823 | struct edge *e; |
- | |
1824 | - | ||
1825 | for (e = active->head; e != NULL; e = e->next) { |
1511 | INPUT_TO_GRID_X (edge->line.p1.x, e.line.p1.x); |
Line 1826... | Line 1512... | ||
1826 | if (! e->vertical) |
1512 | INPUT_TO_GRID_X (edge->line.p2.x, e.line.p2.x); |
1827 | return FALSE; |
1513 | |
1828 | } |
1514 | e.dir = edge->dir; |
1829 | - | ||
1830 | return TRUE; |
1515 | |
Line -... | Line 1516... | ||
- | 1516 | polygon_add_edge (converter->polygon, &e); |
|
1831 | } |
1517 | } |
1832 | 1518 | ||
1833 | static void |
1519 | static void |
1834 | step_edges (struct active_list *active, int count) |
1520 | step_edges (struct active_list *active, int count) |
1835 | { |
1521 | { |
1836 | struct edge **cursor = &active->head; |
1522 | struct edge *edge; |
- | 1523 | ||
1837 | struct edge *edge; |
1524 | count *= GRID_Y; |
1838 | 1525 | for (edge = active->head.next; edge != &active->tail; edge = edge->next) { |
|
Line 1839... | Line 1526... | ||
1839 | for (edge = *cursor; edge != NULL; edge = *cursor) { |
1526 | edge->height_left -= count; |
1840 | edge->height_left -= GRID_Y * count; |
1527 | if (! edge->height_left) { |
1841 | if (edge->height_left) |
1528 | edge->prev->next = edge->next; |
- | 1529 | edge->next->prev = edge->prev; |
|
1842 | cursor = &edge->next; |
1530 | active->min_height = -1; |
1843 | else |
1531 | } |
1844 | *cursor = edge->next; |
1532 | } |
1845 | } |
- | |
1846 | } |
- | |
1847 | - | ||
1848 | I glitter_status_t |
- | |
1849 | glitter_scan_converter_render( |
- | |
1850 | glitter_scan_converter_t *converter, |
- | |
1851 | int nonzero_fill, |
1533 | } |
1852 | GLITTER_BLIT_COVERAGES_ARGS) |
- | |
1853 | { |
- | |
1854 | int i, j; |
1534 | |
1855 | int ymax_i = converter->ymax / GRID_Y; |
1535 | static glitter_status_t |
1856 | int ymin_i = converter->ymin / GRID_Y; |
1536 | blit_a8 (struct cell_list *cells, |
1857 | int xmin_i, xmax_i; |
- | |
1858 | int h = ymax_i - ymin_i; |
- | |
1859 | struct polygon *polygon = converter->polygon; |
- | |
1860 | struct cell_list *coverages = converter->coverages; |
- | |
1861 | struct active_list *active = converter->active; |
- | |
1862 | - | ||
1863 | xmin_i = converter->xmin / GRID_X; |
- | |
1864 | xmax_i = converter->xmax / GRID_X; |
- | |
1865 | if (xmin_i >= xmax_i) |
- | |
1866 | return GLITTER_STATUS_SUCCESS; |
- | |
1867 | - | ||
Line 1868... | Line -... | ||
1868 | /* Let the coverage blitter initialise itself. */ |
- | |
1869 | GLITTER_BLIT_COVERAGES_BEGIN; |
- | |
1870 | - | ||
1871 | /* Render each pixel row. */ |
1537 | cairo_span_renderer_t *renderer, |
1872 | for (i = 0; i < h; i = j) { |
1538 | cairo_half_open_span_t *spans, |
1873 | int do_full_step = 0; |
- | |
1874 | glitter_status_t status = 0; |
- | |
1875 | - | ||
1876 | j = i + 1; |
- | |
Line 1877... | Line 1539... | ||
1877 | 1539 | int y, int height, |
|
- | 1540 | int xmin, int xmax) |
|
- | 1541 | { |
|
- | 1542 | struct cell *cell = cells->head.next; |
|
1878 | /* Determine if we can ignore this row or use the full pixel |
1543 | int prev_x = xmin, last_x = -1; |
- | 1544 | int16_t cover = 0, last_cover = 0; |
|
Line 1879... | Line -... | ||
1879 | * stepper. */ |
- | |
1880 | if (GRID_Y == EDGE_Y_BUCKET_HEIGHT && ! polygon->y_buckets[i]) { |
1545 | unsigned num_spans; |
1881 | if (! active->head) { |
1546 | |
1882 | for (; j < h && ! polygon->y_buckets[j]; j++) |
1547 | if (cell == &cells->tail) |
1883 | ; |
- | |
1884 | GLITTER_BLIT_COVERAGES_EMPTY (i+ymin_i, j-i, xmin_i, xmax_i); |
1548 | return CAIRO_STATUS_SUCCESS; |
1885 | continue; |
- | |
1886 | } |
1549 | |
1887 | - | ||
Line 1888... | Line 1550... | ||
1888 | do_full_step = active_list_can_step_full_row (active); |
1550 | /* Skip cells to the left of the clip region. */ |
1889 | } |
- | |
1890 | 1551 | while (cell->x < xmin) { |
|
1891 | if (do_full_step) { |
1552 | cover += cell->covered_height; |
1892 | /* Step by a full pixel row's worth. */ |
- | |
1893 | if (nonzero_fill) { |
1553 | cell = cell->next; |
1894 | status = apply_nonzero_fill_rule_and_step_edges (active, |
1554 | } |
1895 | coverages); |
- | |
1896 | } else { |
1555 | cover *= GRID_X*2; |
1897 | status = apply_evenodd_fill_rule_and_step_edges (active, |
- | |
1898 | coverages); |
1556 | |
1899 | } |
- | |
1900 | - | ||
1901 | if (active_list_is_vertical (active)) { |
- | |
1902 | while (j < h && |
- | |
1903 | polygon->y_buckets[j] == NULL && |
- | |
1904 | active->min_height >= 2*GRID_Y) |
- | |
Line 1905... | Line 1557... | ||
1905 | { |
1557 | /* Form the spans from the coverages and areas. */ |
- | 1558 | num_spans = 0; |
|
Line 1906... | Line 1559... | ||
1906 | active->min_height -= GRID_Y; |
1559 | for (; cell->x < xmax; cell = cell->next) { |
- | 1560 | int x = cell->x; |
|
1907 | j++; |
1561 | int16_t area; |
1908 | } |
1562 | |
1909 | if (j != i + 1) |
1563 | if (x > prev_x && cover != last_cover) { |
1910 | step_edges (active, j - (i + 1)); |
- | |
1911 | } |
1564 | spans[num_spans].x = prev_x; |
1912 | } else { |
1565 | spans[num_spans].coverage = GRID_AREA_TO_ALPHA (cover); |
Line 1913... | Line -... | ||
1913 | grid_scaled_y_t suby; |
- | |
1914 | 1566 | last_cover = cover; |
|
1915 | /* Subsample this row. */ |
1567 | last_x = prev_x; |
Line 1916... | Line 1568... | ||
1916 | for (suby = 0; suby < GRID_Y; suby++) { |
1568 | ++num_spans; |
1917 | grid_scaled_y_t y = (i+ymin_i)*GRID_Y + suby; |
1569 | } |
1918 | - | ||
1919 | active_list_merge_edges_from_polygon (active, y, polygon); |
1570 | |
1920 | 1571 | cover += cell->covered_height*GRID_X*2; |
|
1921 | if (nonzero_fill) { |
- | |
1922 | status |= apply_nonzero_fill_rule_for_subrow (active, |
1572 | area = cover - cell->uncovered_area; |
1923 | coverages); |
- | |
1924 | } else { |
1573 | |
1925 | status |= apply_evenodd_fill_rule_for_subrow (active, |
- | |
1926 | coverages); |
1574 | if (area != last_cover) { |
Line 1927... | Line 1575... | ||
1927 | } |
1575 | spans[num_spans].x = x; |
1928 | 1576 | spans[num_spans].coverage = GRID_AREA_TO_ALPHA (area); |
|
1929 | active_list_substep_edges(active); |
- | |
1930 | } |
1577 | last_cover = area; |
- | 1578 | last_x = x; |
|
1931 | } |
1579 | ++num_spans; |
Line 1932... | Line -... | ||
1932 | - | ||
1933 | if (unlikely (status)) |
1580 | } |
1934 | return status; |
1581 | |
- | 1582 | prev_x = x+1; |
|
Line -... | Line 1583... | ||
- | 1583 | } |
|
1935 | 1584 | ||
1936 | GLITTER_BLIT_COVERAGES(coverages, i+ymin_i, j-i, xmin_i, xmax_i); |
1585 | if (prev_x <= xmax && cover != last_cover) { |
1937 | cell_list_reset (coverages); |
1586 | spans[num_spans].x = prev_x; |
1938 | 1587 | spans[num_spans].coverage = GRID_AREA_TO_ALPHA (cover); |
|
1939 | if (! active->head) |
1588 | last_cover = cover; |
1940 | active->min_height = INT_MAX; |
1589 | last_x = prev_x; |
1941 | else |
1590 | ++num_spans; |
1942 | active->min_height -= GRID_Y; |
1591 | } |
1943 | } |
1592 | |
1944 | 1593 | if (last_x < xmax && last_cover) { |
|
1945 | /* Clean up the coverage blitter. */ |
1594 | spans[num_spans].x = xmax; |
1946 | GLITTER_BLIT_COVERAGES_END; |
1595 | spans[num_spans].coverage = 0; |
Line 1947... | Line 1596... | ||
1947 | 1596 | ++num_spans; |
|
1948 | return GLITTER_STATUS_SUCCESS; |
1597 | } |
Line 1949... | Line 1598... | ||
1949 | } |
1598 | |
1950 | 1599 | /* Dump them into the renderer. */ |
|
1951 | /*------------------------------------------------------------------------- |
1600 | return renderer->render_rows (renderer, y, height, spans, num_spans); |
1952 | * cairo specific implementation: the coverage blitter and |
1601 | } |
1953 | * scan converter subclass. */ |
1602 | |
1954 | 1603 | #define GRID_AREA_TO_A1(A) ((GRID_AREA_TO_ALPHA (A) > 127) ? 255 : 0) |
|
Line 1955... | Line -... | ||
1955 | static glitter_status_t |
- | |
1956 | blit_with_span_renderer (struct cell_list *cells, |
- | |
1957 | cairo_span_renderer_t *renderer, |
- | |
1958 | struct pool *span_pool, |
- | |
1959 | int y, int height, |
- | |
1960 | int xmin, int xmax) |
- | |
1961 | { |
- | |
1962 | struct cell *cell = cells->head; |
- | |
1963 | int prev_x = xmin; |
- | |
1964 | int cover = 0; |
- | |
1965 | cairo_half_open_span_t *spans; |
- | |
1966 | unsigned num_spans; |
- | |
1967 | - | ||
1968 | if (cell == NULL) |
- | |
1969 | return blit_empty_with_span_renderer (renderer, y, height); |
- | |
1970 | - | ||
1971 | /* Skip cells to the left of the clip region. */ |
- | |
1972 | while (cell != NULL && cell->x < xmin) { |
- | |
1973 | cover += cell->covered_height; |
- | |
1974 | cell = cell->next; |
1604 | static glitter_status_t |
- | 1605 | blit_a1 (struct cell_list *cells, |
|
1975 | } |
1606 | cairo_span_renderer_t *renderer, |
1976 | cover *= GRID_X*2; |
1607 | cairo_half_open_span_t *spans, |
1977 | 1608 | int y, int height, |
|
1978 | /* Count number of cells remaining. */ |
- | |
1979 | { |
- | |
1980 | struct cell *next = cell; |
- | |
Line -... | Line 1609... | ||
- | 1609 | int xmin, int xmax) |
|
1981 | num_spans = 1; |
1610 | { |
1982 | while (next != NULL) { |
1611 | struct cell *cell = cells->head.next; |
1983 | next = next->next; |
1612 | int prev_x = xmin, last_x = -1; |
1984 | ++num_spans; |
1613 | int16_t cover = 0; |
1985 | } |
1614 | uint8_t coverage, last_cover = 0; |
Line 1986... | Line 1615... | ||
1986 | num_spans = 2*num_spans; |
1615 | unsigned num_spans; |
1987 | } |
1616 | |
Line -... | Line 1617... | ||
- | 1617 | if (cell == &cells->tail) |
|
- | 1618 | return CAIRO_STATUS_SUCCESS; |
|
1988 | 1619 | ||
1989 | /* Allocate enough spans for the row. */ |
1620 | /* Skip cells to the left of the clip region. */ |
1990 | pool_reset (span_pool); |
1621 | while (cell->x < xmin) { |
- | 1622 | cover += cell->covered_height; |
|
Line 1991... | Line 1623... | ||
1991 | spans = pool_alloc (span_pool, sizeof(spans[0])*num_spans); |
1623 | cell = cell->next; |
1992 | if (unlikely (spans == NULL)) |
1624 | } |
Line -... | Line 1625... | ||
- | 1625 | cover *= GRID_X*2; |
|
1993 | return GLITTER_STATUS_NO_MEMORY; |
1626 | |
1994 | 1627 | /* Form the spans from the coverages and areas. */ |
|
1995 | num_spans = 0; |
1628 | num_spans = 0; |
1996 | 1629 | for (; cell->x < xmax; cell = cell->next) { |
|
1997 | /* Form the spans from the coverages and areas. */ |
1630 | int x = cell->x; |
Line 1998... | Line 1631... | ||
1998 | for (; cell != NULL; cell = cell->next) { |
1631 | int16_t area; |
1999 | int x = cell->x; |
1632 | |
2000 | int area; |
1633 | coverage = GRID_AREA_TO_A1 (cover); |
2001 | 1634 | if (x > prev_x && coverage != last_cover) { |
|
2002 | if (x >= xmax) |
1635 | last_x = spans[num_spans].x = prev_x; |
- | 1636 | last_cover = spans[num_spans].coverage = coverage; |
|
- | 1637 | ++num_spans; |
|
Line 2003... | Line 1638... | ||
2003 | break; |
1638 | } |
2004 | 1639 | ||
2005 | if (x > prev_x) { |
1640 | cover += cell->covered_height*GRID_X*2; |
Line -... | Line 1641... | ||
- | 1641 | area = cover - cell->uncovered_area; |
|
- | 1642 | ||
- | 1643 | coverage = GRID_AREA_TO_A1 (area); |
|
- | 1644 | if (coverage != last_cover) { |
|
2006 | spans[num_spans].x = prev_x; |
1645 | last_x = spans[num_spans].x = x; |
2007 | spans[num_spans].coverage = GRID_AREA_TO_ALPHA (cover); |
1646 | last_cover = spans[num_spans].coverage = coverage; |
2008 | ++num_spans; |
1647 | ++num_spans; |
- | 1648 | } |
|
- | 1649 | ||
- | 1650 | prev_x = x+1; |
|
- | 1651 | } |
|
- | 1652 | ||
- | 1653 | coverage = GRID_AREA_TO_A1 (cover); |
|
- | 1654 | if (prev_x <= xmax && coverage != last_cover) { |
|
- | 1655 | last_x = spans[num_spans].x = prev_x; |
|
- | 1656 | last_cover = spans[num_spans].coverage = coverage; |
|
- | 1657 | ++num_spans; |
|
- | 1658 | } |
|
- | 1659 | ||
- | 1660 | if (last_x < xmax && last_cover) { |
|
- | 1661 | spans[num_spans].x = xmax; |
|
- | 1662 | spans[num_spans].coverage = 0; |
|
- | 1663 | ++num_spans; |
|
- | 1664 | } |
|
- | 1665 | if (num_spans == 1) |
|
- | 1666 | return CAIRO_STATUS_SUCCESS; |
|
- | 1667 | ||
- | 1668 | /* Dump them into the renderer. */ |
|
- | 1669 | return renderer->render_rows (renderer, y, height, spans, num_spans); |
|
- | 1670 | } |
|
- | 1671 | ||
- | 1672 | ||
- | 1673 | I void |
|
- | 1674 | glitter_scan_converter_render(glitter_scan_converter_t *converter, |
|
- | 1675 | unsigned int winding_mask, |
|
- | 1676 | int antialias, |
|
- | 1677 | cairo_span_renderer_t *renderer) |
|
- | 1678 | { |
|
- | 1679 | int i, j; |
|
- | 1680 | int ymax_i = converter->ymax / GRID_Y; |
|
- | 1681 | int ymin_i = converter->ymin / GRID_Y; |
|
- | 1682 | int xmin_i, xmax_i; |
|
- | 1683 | int h = ymax_i - ymin_i; |
|
- | 1684 | struct polygon *polygon = converter->polygon; |
|
- | 1685 | struct cell_list *coverages = converter->coverages; |
|
- | 1686 | struct active_list *active = converter->active; |
|
- | 1687 | struct edge *buckets[GRID_Y] = { 0 }; |
|
- | 1688 | ||
- | 1689 | xmin_i = converter->xmin / GRID_X; |
|
- | 1690 | xmax_i = converter->xmax / GRID_X; |
|
- | 1691 | if (xmin_i >= xmax_i) |
|
- | 1692 | return; |
|
- | 1693 | ||
- | 1694 | /* Render each pixel row. */ |
|
- | 1695 | for (i = 0; i < h; i = j) { |
|
- | 1696 | int do_full_row = 0; |
|
- | 1697 | ||
- | 1698 | j = i + 1; |
|
- | 1699 | ||
- | 1700 | /* Determine if we can ignore this row or use the full pixel |
|
- | 1701 | * stepper. */ |
|
- | 1702 | if (! polygon->y_buckets[i]) { |
|
- | 1703 | if (active->head.next == &active->tail) { |
|
- | 1704 | active->min_height = INT_MAX; |
|
- | 1705 | active->is_vertical = 1; |
|
- | 1706 | for (; j < h && ! polygon->y_buckets[j]; j++) |
|
- | 1707 | ; |
|
- | 1708 | continue; |
|
- | 1709 | } |
|
- | 1710 | ||
- | 1711 | do_full_row = can_do_full_row (active); |
|
- | 1712 | } |
|
- | 1713 | ||
- | 1714 | if (do_full_row) { |
|
- | 1715 | /* Step by a full pixel row's worth. */ |
|
- | 1716 | full_row (active, coverages, winding_mask); |
|
- | 1717 | ||
- | 1718 | if (active->is_vertical) { |
|
- | 1719 | while (j < h && |
|
- | 1720 | polygon->y_buckets[j] == NULL && |
|
2009 | } |
1721 | active->min_height >= 2*GRID_Y) |
- | 1722 | { |
|
- | 1723 | active->min_height -= GRID_Y; |
|
- | 1724 | j++; |
|
- | 1725 | } |
|
- | 1726 | if (j != i + 1) |
|
2010 | 1727 | step_edges (active, j - (i + 1)); |
|
Line 2011... | Line 1728... | ||
2011 | cover += cell->covered_height*GRID_X*2; |
1728 | } |
2012 | area = cover - cell->uncovered_area; |
1729 | } else { |
Line 2013... | Line 1730... | ||
2013 | 1730 | int sub; |
|
2014 | spans[num_spans].x = x; |
1731 | |
- | 1732 | polygon_fill_buckets (active, |
|
Line 2015... | Line -... | ||
2015 | spans[num_spans].coverage = GRID_AREA_TO_ALPHA (area); |
- | |
2016 | ++num_spans; |
- | |
2017 | - | ||
2018 | prev_x = x+1; |
1733 | polygon->y_buckets[i], |
2019 | } |
1734 | (i+ymin_i)*GRID_Y, |
Line 2020... | Line 1735... | ||
2020 | 1735 | buckets); |
|
Line 2021... | Line 1736... | ||
2021 | if (prev_x <= xmax) { |
1736 | |
Line 2060... | Line 1775... | ||
2060 | cairo_tor_scan_converter_t *self = converter; |
1775 | cairo_tor_scan_converter_t *self = converter; |
2061 | if (self == NULL) { |
1776 | if (self == NULL) { |
2062 | return; |
1777 | return; |
2063 | } |
1778 | } |
2064 | _glitter_scan_converter_fini (self->converter); |
1779 | _glitter_scan_converter_fini (self->converter); |
2065 | pool_fini (self->span_pool.base); |
- | |
2066 | free(self); |
1780 | free(self); |
2067 | } |
1781 | } |
Line 2068... | Line 1782... | ||
2068 | 1782 | ||
2069 | static cairo_status_t |
- | |
2070 | _cairo_tor_scan_converter_add_edge (void *converter, |
- | |
2071 | const cairo_point_t *p1, |
- | |
2072 | const cairo_point_t *p2, |
- | |
2073 | int top, int bottom, |
- | |
2074 | int dir) |
- | |
2075 | { |
- | |
2076 | cairo_tor_scan_converter_t *self = converter; |
- | |
2077 | cairo_status_t status; |
- | |
2078 | cairo_edge_t edge; |
- | |
2079 | - | ||
2080 | edge.line.p1 = *p1; |
- | |
2081 | edge.line.p2 = *p2; |
- | |
2082 | edge.top = top; |
- | |
2083 | edge.bottom = bottom; |
- | |
2084 | edge.dir = dir; |
- | |
2085 | - | ||
2086 | status = glitter_scan_converter_add_edge (self->converter, &edge); |
- | |
2087 | if (unlikely (status)) |
- | |
2088 | return _cairo_scan_converter_set_error (self, _cairo_error (status)); |
- | |
2089 | - | ||
2090 | return CAIRO_STATUS_SUCCESS; |
- | |
2091 | } |
- | |
2092 | - | ||
2093 | static cairo_status_t |
1783 | cairo_status_t |
2094 | _cairo_tor_scan_converter_add_polygon (void *converter, |
1784 | _cairo_tor_scan_converter_add_polygon (void *converter, |
2095 | const cairo_polygon_t *polygon) |
1785 | const cairo_polygon_t *polygon) |
2096 | { |
1786 | { |
2097 | cairo_tor_scan_converter_t *self = converter; |
- | |
2098 | cairo_status_t status; |
1787 | cairo_tor_scan_converter_t *self = converter; |
Line -... | Line 1788... | ||
- | 1788 | int i; |
|
2099 | int i; |
1789 | |
2100 | 1790 | #if 0 |
|
2101 | for (i = 0; i < polygon->num_edges; i++) { |
1791 | FILE *file = fopen ("polygon.txt", "w"); |
2102 | status = glitter_scan_converter_add_edge (self->converter, |
1792 | _cairo_debug_print_polygon (file, polygon); |
- | 1793 | fclose (file); |
|
2103 | &polygon->edges[i]); |
1794 | #endif |
2104 | if (unlikely (status)) { |
1795 | |
2105 | return _cairo_scan_converter_set_error (self, |
- | |
2106 | _cairo_error (status)); |
- | |
Line 2107... | Line 1796... | ||
2107 | } |
1796 | for (i = 0; i < polygon->num_edges; i++) |
2108 | } |
1797 | glitter_scan_converter_add_edge (self->converter, &polygon->edges[i]); |
Line 2109... | Line 1798... | ||
2109 | 1798 | ||
Line 2115... | Line 1804... | ||
2115 | cairo_span_renderer_t *renderer) |
1804 | cairo_span_renderer_t *renderer) |
2116 | { |
1805 | { |
2117 | cairo_tor_scan_converter_t *self = converter; |
1806 | cairo_tor_scan_converter_t *self = converter; |
2118 | cairo_status_t status; |
1807 | cairo_status_t status; |
Line 2119... | Line -... | ||
2119 | - | ||
2120 | status = glitter_scan_converter_render (self->converter, |
- | |
2121 | self->fill_rule == CAIRO_FILL_RULE_WINDING, |
- | |
2122 | renderer, |
- | |
2123 | self->span_pool.base); |
1808 | |
2124 | if (unlikely (status)) |
1809 | if ((status = setjmp (self->jmp))) |
Line -... | Line 1810... | ||
- | 1810 | return _cairo_scan_converter_set_error (self, _cairo_error (status)); |
|
- | 1811 | ||
- | 1812 | glitter_scan_converter_render (self->converter, |
|
- | 1813 | self->fill_rule == CAIRO_FILL_RULE_WINDING ? ~0 : 1, |
|
2125 | return _cairo_scan_converter_set_error (self, _cairo_error (status)); |
1814 | self->antialias != CAIRO_ANTIALIAS_NONE, |
2126 | 1815 | renderer); |
|
Line 2127... | Line 1816... | ||
2127 | return CAIRO_STATUS_SUCCESS; |
1816 | return CAIRO_STATUS_SUCCESS; |
2128 | } |
1817 | } |
2129 | 1818 | ||
2130 | cairo_scan_converter_t * |
1819 | cairo_scan_converter_t * |
2131 | _cairo_tor_scan_converter_create (int xmin, |
1820 | _cairo_tor_scan_converter_create (int xmin, |
2132 | int ymin, |
1821 | int ymin, |
- | 1822 | int xmax, |
|
2133 | int xmax, |
1823 | int ymax, |
2134 | int ymax, |
1824 | cairo_fill_rule_t fill_rule, |
2135 | cairo_fill_rule_t fill_rule) |
1825 | cairo_antialias_t antialias) |
Line 2136... | Line 1826... | ||
2136 | { |
1826 | { |
2137 | cairo_tor_scan_converter_t *self; |
1827 | cairo_tor_scan_converter_t *self; |
2138 | cairo_status_t status; |
1828 | cairo_status_t status; |
2139 | 1829 | ||
2140 | self = calloc (1, sizeof(struct _cairo_tor_scan_converter)); |
1830 | self = malloc (sizeof(struct _cairo_tor_scan_converter)); |
Line 2141... | Line 1831... | ||
2141 | if (unlikely (self == NULL)) { |
1831 | if (unlikely (self == NULL)) { |
2142 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
- | |
2143 | goto bail_nomem; |
- | |
2144 | } |
1832 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
Line 2145... | Line -... | ||
2145 | - | ||
2146 | self->base.destroy = _cairo_tor_scan_converter_destroy; |
- | |
2147 | self->base.add_edge = _cairo_tor_scan_converter_add_edge; |
- | |
2148 | self->base.add_polygon = _cairo_tor_scan_converter_add_polygon; |
- | |
2149 | self->base.generate = _cairo_tor_scan_converter_generate; |
1833 | goto bail_nomem; |
2150 | 1834 | } |
|
2151 | pool_init (self->span_pool.base, |
1835 | |
2152 | 250 * sizeof(self->span_pool.embedded[0]), |
1836 | self->base.destroy = _cairo_tor_scan_converter_destroy; |
2153 | sizeof(self->span_pool.embedded)); |
1837 | self->base.generate = _cairo_tor_scan_converter_generate; |
Line 2154... | Line 1838... | ||
2154 | 1838 | ||
- | 1839 | _glitter_scan_converter_init (self->converter, &self->jmp); |
|
Line 2155... | Line 1840... | ||
2155 | _glitter_scan_converter_init (self->converter); |
1840 | status = glitter_scan_converter_reset (self->converter, |
Line 2156... | Line 1841... | ||
2156 | status = glitter_scan_converter_reset (self->converter, |
1841 | xmin, ymin, xmax, ymax); |
2157 | xmin, ymin, xmax, ymax); |
1842 | if (unlikely (status)) |