summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorM Joonas Pihlaja <jpihlaja@cc.helsinki.fi>2010-02-23 15:35:18 +0200
committerM Joonas Pihlaja <jpihlaja@cc.helsinki.fi>2010-02-23 15:35:18 +0200
commit8b63bed3692369d7a5d62a1a6e973d5301c39e1a (patch)
tree2a32a9c39da34b4f0bc5f1d790c622e4220bf899
parent7735b39a664c5ca0817a216bc9f1119407fb08d0 (diff)
spans: Clip invariant rasterisation: clipped edges.tor-clip-fix
-rw-r--r--src/cairo-tor-scan-converter.c77
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;