/* Use GRID_X/Y_BITS to define GRID_X/Y if they're available. */ #ifdef GRID_X_BITS # define GRID_X (1 << GRID_X_BITS) #endif #ifdef GRID_Y_BITS # define GRID_Y (1 << GRID_Y_BITS) #endif
/* The GRID_X_TO_INT_FRAC macro splits a grid scaled coordinate into
* integer and fractional parts. The integer part is floored. */ #ifdefined(GRID_X_TO_INT_FRAC) /* do nothing */ #elifdefined(GRID_X_BITS) # define GRID_X_TO_INT_FRAC(x, i, f) \
_GRID_TO_INT_FRAC_shift(x, i, f, GRID_X_BITS) #else # define GRID_X_TO_INT_FRAC(x, i, f) \
_GRID_TO_INT_FRAC_general(x, i, f, GRID_X) #endif
#define _GRID_TO_INT_FRAC_general(t, i, f, m) do { \
(i) = (t) / (m); \
(f) = (t) % (m); \ if ((f) < 0) { \
--(i); \
(f) += (m); \
} \
} while (0)
#define _GRID_TO_INT_FRAC_shift(t, i, f, b) do { \
(f) = (t) & ((1 << (b)) - 1); \
(i) = (t) >> (b); \
} while (0)
/* A grid area is a real in [0,1] scaled by 2*GRID_X*GRID_Y. We want *tobeabletorepresentexactlyareasofsubpixeltrapezoidswhose *verticesaregiveningridscaledcoordinates.Thescalefactor *comesfromneedingtoaccuratelyrepresentthearea0.5*dx*dyofa
* triangle with base dx and height dy in grid scaled numbers. */ typedefint grid_area_t; #define GRID_XY (2*GRID_X*GRID_Y) /* Unit area on the grid. */
/* Header for a chunk of memory in a memory pool. */ struct _pool_chunk { /* # bytes used in this chunk. */
size_t size;
/* # bytes total in this chunk */
size_t capacity;
/* Pointer to the previous chunk or %NULL if this is the sentinel
* chunk in the pool header. */ struct _pool_chunk *prev_chunk;
/* Actual data starts here. Well aligned for pointers. */
};
/* A memory pool. This is supposed to be embedded on the stack or *withinsomeotherstructure.Itmayoptionallybefollowedbyan *embeddedarrayfromwhichrequestsarefulfilleduntil
* malloc needs to be called to allocate a first real chunk. */ struct pool { /* Chunk we're allocating from. */ struct _pool_chunk *current;
jmp_buf *jmp;
/* Free list of previously allocated chunks. All have >= default
* capacity. */ struct _pool_chunk *first_free;
/* The default capacity of a chunk. */
size_t default_capacity;
/* Header for the sentinel chunk. Directly following the pool *structshouldbesomespaceforembeddedelementsfromwhich
* the sentinel chunk allocates from. */ struct _pool_chunk sentinel[1];
};
/* A polygon edge. */ struct edge { /* Next in y-bucket or active list. */ struct edge *next;
/* Current x coordinate while the edge is on the active *list.Initialisedtothexcoordinateofthetopofthe *edge.Thequotientisingrid_scaled_x_tunitsandthe
* remainder is mod dy in grid_scaled_y_t units.*/ struct quorem x;
/* Advance of the current x when moving down a subsample line. */ struct quorem dxdy;
/* Advance of the current x when moving down a full pixel *row.Onlyinitialisedwhentheheightoftheedgeislarge *enoughthatthere'sachancetheedgecouldbesteppedbya
* full row's worth of subsample rows at a time. */ struct quorem dxdy_full;
/* The clipped y of the top of the edge. */
grid_scaled_y_t ytop;
/* y2-y1 after orienting the edge downwards. */
grid_scaled_y_t dy;
/* Number of subsample rows remaining to scan convert of this
* edge. */
grid_scaled_y_t height_left;
/* Original sign of the edge: +1 for downwards, -1 for upwards
* edges. */ int dir; int vertical; int clip;
};
/* Number of subsample rows per y-bucket. Must be GRID_Y. */ #define EDGE_Y_BUCKET_HEIGHT GRID_Y
/* A collection of sorted and vertically clipped edges of the polygon. *Edgesaremovedfromthepolygontoanactivelistwhilescan
* converting. */ struct polygon { /* The vertical clip extents. */
grid_scaled_y_t ymin, ymax;
/* Array of edges all starting in the same bucket. An edge is put *intobucketEDGE_BUCKET_INDEX(edge->ytop,polygon->ymin)when
* it is added to the polygon. */ struct edge **y_buckets; struct edge *y_buckets_embedded[64];
/* A cell list represents the scan line sparsely as cells ordered by *ascendingx.Itisgearedtowardsscanningthecellsinorder
* using an internal cursor. */ struct cell_list { /* Sentinel nodes */ struct cell head, tail;
/* Cursor state for iterating through the cell list. */ struct cell *cursor;
/* Cells in the cell list are owned by the cell list and are
* allocated from this pool. */ struct { struct pool base[1]; struct cell embedded[32];
} cell_pool;
};
/* The active list contains edges in the current scan line ordered by
* the x-coordinate of the intercept of the edge and the scan line. */ struct active_list { /* Leftmost edge on the current scan line. */ struct edge *head;
/* A lower bound on the height of the active edges is used to *estimatehowsoonsomeactiveedgeends.Wecan'tadvancethe *scanconversionbyafullpixelrowifanedgeendssomewhere
* within it. */
grid_scaled_y_t min_height;
};
staticvoid
pool_fini(struct pool *pool)
{ struct _pool_chunk *p = pool->current; do { while (NULL != p) { struct _pool_chunk *prev = p->prev_chunk; if (p != pool->sentinel)
free(p);
p = prev;
}
p = pool->first_free;
pool->first_free = NULL;
} while (NULL != p);
}
/* Satisfy an allocation by first allocating a new large enough chunk *andaddingittotheheadofthepool'schunklist.Thisfunction *iscalledasafallbackifpool_alloc()couldn'tdoaquick
* allocation from the current chunk in the pool. */ staticvoid *
_pool_alloc_from_new_chunk( struct pool *pool,
size_t size)
{ struct _pool_chunk *chunk; void *obj;
size_t capacity;
/* If the allocation is smaller than the default chunk size then *trygettingachunkoffthefreelist.Forceallocofanew
* chunk for large requests. */
capacity = size;
chunk = NULL; if (size < pool->default_capacity) {
capacity = pool->default_capacity;
chunk = pool->first_free; if (chunk) {
pool->first_free = chunk->prev_chunk;
_pool_chunk_init(chunk, pool->current, chunk->capacity);
}
}
/* Relinquish all pool_alloced memory back to the pool. */ staticvoid
pool_reset (struct pool *pool)
{ /* Transfer all used chunks to the chunk free list. */ struct _pool_chunk *chunk = pool->current; if (chunk != pool->sentinel) { while (chunk->prev_chunk != pool->sentinel) {
chunk = chunk->prev_chunk;
}
chunk->prev_chunk = pool->first_free;
pool->first_free = pool->current;
} /* Reset the sentinel as the current chunk. */
pool->current = pool->sentinel;
pool->sentinel->size = 0;
}
/* Rewinds the cell list's cursor to the beginning. After rewinding
* we're good to cell_list_find() the cell any x coordinate. */ inlinestaticvoid
cell_list_rewind (struct cell_list *cells)
{
cells->cursor = &cells->head;
}
/* Rewind the cell list if its cursor has been advanced past x. */ inlinestaticvoid
cell_list_maybe_rewind (struct cell_list *cells, int x)
{ struct cell *tail = cells->cursor; if (tail->x > x)
cell_list_rewind (cells);
}
/* Empty the cell list. This is called at the start of every pixel
* row. */ inlinestaticvoid
cell_list_reset (struct cell_list *cells)
{
cell_list_rewind (cells);
cells->head.next = &cells->tail;
pool_reset (cells->cell_pool.base);
}
/* Find a cell at the given x-coordinate. Returns %NULL if a new cell *neededtobeallocatedbutcouldn'tbe.Cellsmustbefoundwith *non-decreasingx-coordinateuntilthecelllistisrewoundusing *cell_list_rewind().Ownershipofthereturnedcellisretainedby
* the cell list. */ inlinestaticstruct cell *
cell_list_find (struct cell_list *cells, int x)
{ struct cell *tail = cells->cursor;
while (1) {
UNROLL3({ if (tail->next->x > x) break;
tail = tail->next;
});
}
/* Find two cells at x1 and x2. This is exactly equivalent *to * *pair.cell1=cell_list_find(cells,x1); *pair.cell2=cell_list_find(cells,x2); *
* except with less function call overhead. */ inlinestaticstruct cell_pair
cell_list_find_pair(struct cell_list *cells, int x1, int x2)
{ struct cell_pair pair;
/* Edge is entirely within a column? */ if (ix1 == ix2) { /* We always know that ix1 is >= the cell list cursor in this
* case due to the no-intersections precondition. */ struct cell *cell = cell_list_find(cells, ix1);
cell->covered_height += sign*GRID_Y;
cell->uncovered_area += sign*(fx1 + fx2)*GRID_Y; return;
}
/* Add coverage for all pixels [ix1,ix2] on this row crossed
* by the edge. */
{ struct cell_pair pair; struct quorem y = floored_divrem((GRID_X - fx1)*dy, dx);
/* When rendering a previous edge on the active list we may *advancethecelllistcursorpasttheleftmostpixelofthe *currentedgeeventhoughthetwoedgesdon'tintersect. *e.g.considertwoedgesgoingdownandrightwards: * *--\_+---\_+-----+-----+---- *\_\_|| *|\_|\_|| *|\_|\_|| *|\_\_| *----+-----+-\---+-\---+---- * *Theleftedgetouchescellspastthestartingcellofthe *rightedge.Fortunatelysuchcasesarerare. * *Therewindingisnevernecessaryifthecurrentedgestays *withinasinglecolumnbecausewe'vecheckedbeforecalling
* this function that the active list order won't change. */
cell_list_maybe_rewind(cells, ix1);
/* Single element list -> return */ if (head_other == NULL) {
*head_out = list; return NULL;
}
/* Unroll the first iteration of the following loop (halves the number of calls to merge_sorted_edges): *-Initializeremainingtobethelistcontainingtheelementsafterthesecondintheinputlist. *-Initialize*head_outtobethesortedlistcontainingthefirsttwoelement.
*/
remaining = head_other->next; if (list->x.quo <= head_other->x.quo) {
*head_out = list; /* list->next = head_other; */ /* The input list is already like this. */
head_other->next = NULL;
} else {
*head_out = head_other;
head_other->next = list;
list->next = NULL;
}
for (i = 0; i < level && remaining; i++) { /* Extract a sorted list of the same size as *head_out
* (2^(i+1) elements) from the list of remaining elements. */
remaining = sort_edges (remaining, i, &head_other);
*head_out = merge_sorted_edges (*head_out, head_other);
}
/* *head_out now contains (at most) 2^(level+1) elements. */
return remaining;
}
/* Test if the edges on the active list can be safely advanced by a
* full row without intersections or any edges ending. */ inlinestaticint
active_list_can_step_full_row (struct active_list *active)
{ conststruct edge *e; int prev_x = INT_MIN;
/* Recomputes the minimum height of all edges on the active
* list if we have been dropping edges. */ if (active->min_height <= 0) { int min_height = INT_MAX;
e = active->head; while (NULL != e) { if (e->height_left < min_height)
min_height = e->height_left;
e = e->next;
}
active->min_height = min_height;
}
if (active->min_height < GRID_Y) return0;
/* Check for intersections as no edges end during the next row. */
e = active->head; while (NULL != e) { struct quorem x = e->x;
if (! e->vertical) {
x.quo += e->dxdy_full.quo;
x.rem += e->dxdy_full.rem; if (x.rem >= 0)
++x.quo;
}
if (x.quo <= prev_x) return0;
prev_x = x.quo;
e = e->next;
}
return1;
}
/* Merges edges on the given subpixel row from the polygon to the
* active_list. */ inlinestaticvoid
active_list_merge_edges_from_polygon(struct active_list *active, struct edge **ptail,
grid_scaled_y_t y, struct polygon *polygon)
{ /* Split off the edges on the current subrow and merge them into
* the active list. */ int min_height = active->min_height; struct edge *subrow_edges = NULL; struct edge *tail = *ptail;
/* Advance the edges on the active list by one subsample row by
* updating their x positions. Drop edges from the list that end. */ inlinestaticvoid
active_list_substep_edges(struct active_list *active)
{ struct edge **cursor = &active->head;
grid_scaled_x_t prev_x = INT_MIN; struct edge *unsorted = NULL; struct edge *edge = *cursor;
do {
UNROLL3({ struct edge *next;
if (NULL == edge) break;
next = edge->next; if (--edge->height_left) {
edge->x.quo += edge->dxdy.quo;
edge->x.rem += edge->dxdy.rem; if (edge->x.rem >= 0) {
++edge->x.quo;
edge->x.rem -= edge->dy;
}
static grid_scaled_t
int_to_grid_scaled(int i, int scale)
{ /* Clamp to max/min representable scaled number. */ if (i >= 0) { if (i >= INT_MAX/scale)
i = INT_MAX/scale;
} else { if (i <= INT_MIN/scale)
i = INT_MIN/scale;
} return i*scale;
}
/* Dump them into the renderer. */ return renderer->render_rows (renderer, y, height, spans, num_spans);
}
staticvoid
glitter_scan_converter_render(glitter_scan_converter_t *converter, int nonzero_fill,
cairo_span_renderer_t *span_renderer, struct pool *span_pool)
{ int i, j; int ymax_i = converter->ymax / GRID_Y; int ymin_i = converter->ymin / GRID_Y; int h = ymax_i - ymin_i; struct polygon *polygon = converter->polygon; struct cell_list *coverages = converter->coverages; struct active_list *active = converter->active;
/* Render each pixel row. */ for (i = 0; i < h; i = j) { int do_full_step = 0;
j = i + 1;
/* Determine if we can ignore this row or use the full pixel
* stepper. */ if (GRID_Y == EDGE_Y_BUCKET_HEIGHT && ! polygon->y_buckets[i]) { if (! active->head) { for (; j < h && ! polygon->y_buckets[j]; j++)
; continue;
}
if (do_full_step) { /* Step by a full pixel row's worth. */ if (nonzero_fill)
apply_nonzero_fill_rule_and_step_edges (active, coverages); else
apply_evenodd_fill_rule_and_step_edges (active, coverages);
if (active_list_is_vertical (active)) { while (j < h &&
polygon->y_buckets[j] == NULL &&
active->min_height >= 2*GRID_Y)
{
active->min_height -= GRID_Y;
j++;
} if (j != i + 1)
step_edges (active, j - (i + 1));
}
} else {
grid_scaled_y_t suby;
/* Subsample this row. */ for (suby = 0; suby < GRID_Y; suby++) {
grid_scaled_y_t y = (i+ymin_i)*GRID_Y + suby;
if (polygon->y_buckets[i]) {
active_list_merge_edges_from_polygon (active,
&polygon->y_buckets[i], y,
polygon);
}
if (nonzero_fill)
apply_nonzero_fill_rule_for_subrow (active, coverages); else
apply_evenodd_fill_rule_for_subrow (active, coverages);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.