diff options
author | M Joonas Pihlaja <jpihlaja@cc.helsinki.fi> | 2010-02-23 15:35:18 +0200 |
---|---|---|
committer | M Joonas Pihlaja <jpihlaja@cc.helsinki.fi> | 2010-02-23 15:35:18 +0200 |
commit | 8b63bed3692369d7a5d62a1a6e973d5301c39e1a (patch) | |
tree | 2a32a9c39da34b4f0bc5f1d790c622e4220bf899 | |
parent | 7735b39a664c5ca0817a216bc9f1119407fb08d0 (diff) |
spans: Clip invariant rasterisation: clipped edges.tor-clip-fix
-rw-r--r-- | src/cairo-tor-scan-converter.c | 77 |
1 files changed, 53 insertions, 24 deletions
diff --git a/src/cairo-tor-scan-converter.c b/src/cairo-tor-scan-converter.c index 7cea78d3..5a5b8534 100644 --- a/src/cairo-tor-scan-converter.c +++ b/src/cairo-tor-scan-converter.c @@ -406,7 +406,8 @@ struct bucket { * Edges are moved from the polygon to an active list while scan * converting. */ struct polygon { - /* The vertical clip extents. */ + /* The clip extents. */ + grid_scaled_x_t xmin, xmax; grid_scaled_y_t ymin, ymax; /* Array of edges all starting in the same bucket. An edge is put @@ -1049,6 +1050,7 @@ static void polygon_init (struct polygon *polygon) { polygon->ymin = polygon->ymax = 0; + polygon->xmin = polygon->xmax = 0; polygon->y_buckets = polygon->y_buckets_embedded; pool_init (polygon->edge_pool.base, 8192 - sizeof (struct _pool_chunk), @@ -1069,6 +1071,8 @@ polygon_fini (struct polygon *polygon) * [ymin,ymax). */ static glitter_status_t polygon_reset (struct polygon *polygon, + grid_scaled_x_t xmin, + grid_scaled_x_t xmax, grid_scaled_y_t ymin, grid_scaled_y_t ymax) { @@ -1095,6 +1099,8 @@ polygon_reset (struct polygon *polygon, polygon->ymin = ymin; polygon->ymax = ymax; + polygon->xmin = xmin; + polygon->xmax = xmax; return GLITTER_STATUS_SUCCESS; bail_no_mem: @@ -1155,6 +1161,18 @@ polygon_add_edge (struct polygon *polygon, e->dxdy.rem = 0; e->dxdy_full.quo = 0; e->dxdy_full.rem = 0; + + /* Drop edges to the right of the clip extents. */ + if (e->x.quo >= polygon->xmax) + return GLITTER_STATUS_SUCCESS; + + /* Offset vertical edges at the left side of the clip extents + * to just shy of the left side. We depend on this when + * checking for possible intersections within the clip + * rectangle. */ + if (e->x.quo <= polygon->xmin) { + e->x.quo = polygon->xmin - 1; + } } else { e->vertical = FALSE; e->dxdy = floored_divrem (dx, dy); @@ -1166,6 +1184,9 @@ polygon_add_edge (struct polygon *polygon, e->x.quo += edge->line.p1.x; } + if (e->x.quo >= polygon->xmax && e->dxdy.quo >= 0) + return GLITTER_STATUS_SUCCESS; + if (e->height_left >= GRID_Y) { e->dxdy_full = floored_muldivrem (GRID_Y, dx, dy); } else { @@ -1239,10 +1260,11 @@ merge_unsorted_edges(struct edge *sorted_head, struct edge *unsorted_head) /* Test if the edges on the active list can be safely advanced by a * full row without intersections or any edges ending. */ inline static int -active_list_can_step_full_row (struct active_list *active) +active_list_can_step_full_row (struct active_list *active, + grid_scaled_x_t xmin) { const struct edge *e; - int prev_x = INT_MIN; + grid_scaled_x_t prev_x = INT_MIN; /* Recomputes the minimum height of all edges on the active * list if we have been dropping edges. */ @@ -1274,10 +1296,19 @@ active_list_can_step_full_row (struct active_list *active) ++x.quo; } - if (x.quo <= prev_x) - return 0; - - prev_x = x.quo; + /* There's may be an intersection if the edge sort order might + * change. */ + if (x.quo <= prev_x) { + /* Ignore intersections to the left of the clip extents. + * This assumes that all vertical edges on or at the left + * side of the clip rectangle have been shifted slightly + * to the left in polygon_add_edge(). */ + if (x.quo >= xmin || e->x.quo >= xmin) + return 0; + } + else { + prev_x = x.quo; + } e = e->next; } @@ -1688,7 +1719,7 @@ glitter_scan_converter_reset( active_list_reset(converter->active); cell_list_reset(converter->coverages); - status = polygon_reset(converter->polygon, ymin, ymax); + status = polygon_reset(converter->polygon, xmin, xmax, ymin, ymax); if (status) return status; @@ -1799,6 +1830,7 @@ glitter_scan_converter_render( int ymax_i = converter->ymax / GRID_Y; int ymin_i = converter->ymin / GRID_Y; int xmin_i, xmax_i; + grid_scaled_x_t xmin = converter->xmin; int h = ymax_i - ymin_i; struct polygon *polygon = converter->polygon; struct cell_list *coverages = converter->coverages; @@ -1821,21 +1853,19 @@ glitter_scan_converter_render( /* Determine if we can ignore this row or use the full pixel * stepper. */ - if (GRID_Y == EDGE_Y_BUCKET_HEIGHT) { - if (polygon->y_buckets[i].edges == NULL) { - if (! active->head) { - for (; j < h && ! polygon->y_buckets[j].edges; j++) - ; - GLITTER_BLIT_COVERAGES_EMPTY (i+ymin_i, j-i, xmin_i, xmax_i); - continue; - } - do_full_step = active_list_can_step_full_row (active); - } - else if (! polygon->y_buckets[i].have_inside_edges) { - grid_scaled_y_t y = (i+ymin_i)*GRID_Y; - active_list_merge_edges_from_polygon (active, y, polygon); - do_full_step = active_list_can_step_full_row (active); + if (polygon->y_buckets[i].edges == NULL) { + if (! active->head) { + for (; j < h && ! polygon->y_buckets[j].edges; j++) + ; + GLITTER_BLIT_COVERAGES_EMPTY (i+ymin_i, j-i, xmin_i, xmax_i); + continue; } + do_full_step = active_list_can_step_full_row (active, xmin); + } + else if (! polygon->y_buckets[i].have_inside_edges) { + grid_scaled_y_t y = (i+ymin_i)*GRID_Y; + active_list_merge_edges_from_polygon (active, y, polygon); + do_full_step = active_list_can_step_full_row (active, xmin); } if (do_full_step) { @@ -1860,9 +1890,8 @@ glitter_scan_converter_render( step_edges (active, j - (i + 1)); } } else { + /* Supersample this row. */ 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; |