diff options
Diffstat (limited to 'gfx/cairo/clip-invariant.patch')
-rw-r--r-- | gfx/cairo/clip-invariant.patch | 1255 |
1 files changed, 0 insertions, 1255 deletions
diff --git a/gfx/cairo/clip-invariant.patch b/gfx/cairo/clip-invariant.patch deleted file mode 100644 index 08ba4d4dea..0000000000 --- a/gfx/cairo/clip-invariant.patch +++ /dev/null @@ -1,1255 +0,0 @@ -diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c -index 2acc8b5..019249e 100644 ---- a/src/cairo-gl-surface.c -+++ b/src/cairo-gl-surface.c -@@ -2012,13 +2012,14 @@ typedef struct _cairo_gl_surface_span_renderer { - - cairo_gl_composite_setup_t setup; - -+ int xmin, xmax; -+ - cairo_operator_t op; - cairo_antialias_t antialias; - - cairo_gl_surface_t *dst; - cairo_region_t *clip; - -- cairo_composite_rectangles_t composite_rectangles; - GLuint vbo; - void *vbo_base; - unsigned int vbo_size; -@@ -2049,11 +2050,11 @@ _cairo_gl_span_renderer_flush (cairo_gl_surface_span_renderer_t *renderer) - cairo_region_get_rectangle (renderer->clip, i, &rect); - - glScissor (rect.x, rect.y, rect.width, rect.height); -- glDrawArrays (GL_LINES, 0, count); -+ glDrawArrays (GL_QUADS, 0, count); - } - glDisable (GL_SCISSOR_TEST); - } else { -- glDrawArrays (GL_LINES, 0, count); -+ glDrawArrays (GL_QUADS, 0, count); - } - } - -@@ -2134,72 +2135,87 @@ _cairo_gl_emit_span_vertex (cairo_gl_surface_span_renderer_t *renderer, - - static void - _cairo_gl_emit_span (cairo_gl_surface_span_renderer_t *renderer, -- int x1, int x2, int y, uint8_t alpha) -+ int x, int y1, int y2, -+ uint8_t alpha) - { - float *vertices = _cairo_gl_span_renderer_get_vbo (renderer, 2); - -- _cairo_gl_emit_span_vertex (renderer, x1, y, alpha, vertices); -- _cairo_gl_emit_span_vertex (renderer, x2, y, alpha, -+ _cairo_gl_emit_span_vertex (renderer, x, y1, alpha, vertices); -+ _cairo_gl_emit_span_vertex (renderer, x, y2, alpha, - vertices + renderer->vertex_size / 4); - } - --/* Emits the contents of the span renderer rows as GL_LINES with the span's -- * alpha. -- * -- * Unlike the image surface, which is compositing into a temporary, we emit -- * coverage even for alpha == 0, in case we're using an unbounded operator. -- * But it means we avoid having to do the fixup. -- */ -+static void -+_cairo_gl_emit_rectangle (cairo_gl_surface_span_renderer_t *renderer, -+ int x1, int y1, -+ int x2, int y2, -+ int coverage) -+{ -+ _cairo_gl_emit_span (renderer, x1, y1, y2, coverage); -+ _cairo_gl_emit_span (renderer, x2, y2, y1, coverage); -+} -+ - static cairo_status_t --_cairo_gl_surface_span_renderer_render_row ( -- void *abstract_renderer, -- int y, -- const cairo_half_open_span_t *spans, -- unsigned num_spans) -+_cairo_gl_render_bounded_spans (void *abstract_renderer, -+ int y, int height, -+ const cairo_half_open_span_t *spans, -+ unsigned num_spans) - { - cairo_gl_surface_span_renderer_t *renderer = abstract_renderer; -- int xmin = renderer->composite_rectangles.mask.x; -- int xmax = xmin + renderer->composite_rectangles.width; -- int prev_x = xmin; -- int prev_alpha = 0; -- unsigned i; -- int x_translate; -- -- /* Make sure we're within y-range. */ -- if (y < renderer->composite_rectangles.mask.y || -- y >= renderer->composite_rectangles.mask.y + -- renderer->composite_rectangles.height) -+ -+ if (num_spans == 0) - return CAIRO_STATUS_SUCCESS; - -- x_translate = renderer->composite_rectangles.dst.x - -- renderer->composite_rectangles.mask.x; -- y += renderer->composite_rectangles.dst.y - -- renderer->composite_rectangles.mask.y; -+ do { -+ if (spans[0].coverage) { -+ _cairo_gl_emit_rectangle (renderer, -+ spans[0].x, y, -+ spans[1].x, y + height, -+ spans[0].coverage); -+ } - -- /* Find the first span within x-range. */ -- for (i=0; i < num_spans && spans[i].x < xmin; i++) {} -- if (i>0) -- prev_alpha = spans[i-1].coverage; -+ spans++; -+ } while (--num_spans > 1); - -- /* Set the intermediate spans. */ -- for (; i < num_spans; i++) { -- int x = spans[i].x; -+ return CAIRO_STATUS_SUCCESS; -+} - -- if (x >= xmax) -- break; -+static cairo_status_t -+_cairo_gl_render_unbounded_spans (void *abstract_renderer, -+ int y, int height, -+ const cairo_half_open_span_t *spans, -+ unsigned num_spans) -+{ -+ cairo_gl_surface_span_renderer_t *renderer = abstract_renderer; - -- _cairo_gl_emit_span (renderer, -- prev_x + x_translate, x + x_translate, y, -- prev_alpha); -+ if (num_spans == 0) { -+ _cairo_gl_emit_rectangle (renderer, -+ renderer->xmin, y, -+ renderer->xmax, y + height, -+ 0); -+ return CAIRO_STATUS_SUCCESS; -+ } - -- prev_x = x; -- prev_alpha = spans[i].coverage; -+ if (spans[0].x != renderer->xmin) { -+ _cairo_gl_emit_rectangle (renderer, -+ renderer->xmin, y, -+ spans[0].x, y + height, -+ 0); - } - -- if (prev_x < xmax) { -- _cairo_gl_emit_span (renderer, -- prev_x + x_translate, xmax + x_translate, y, -- prev_alpha); -+ do { -+ _cairo_gl_emit_rectangle (renderer, -+ spans[0].x, y, -+ spans[1].x, y + height, -+ spans[0].coverage); -+ spans++; -+ } while (--num_spans > 1); -+ -+ if (spans[0].x != renderer->xmax) { -+ _cairo_gl_emit_rectangle (renderer, -+ spans[0].x, y, -+ renderer->xmax, y + height, -+ 0); - } - - return CAIRO_STATUS_SUCCESS; -@@ -2274,8 +2290,6 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t op, - cairo_gl_surface_t *dst = abstract_dst; - cairo_gl_surface_span_renderer_t *renderer; - cairo_status_t status; -- int width = rects->width; -- int height = rects->height; - cairo_surface_attributes_t *src_attributes; - GLenum err; - -diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c -index 48d8013..d52979d 100644 ---- a/src/cairo-image-surface.c -+++ b/src/cairo-image-surface.c -@@ -1390,11 +1390,13 @@ typedef struct _cairo_image_surface_span_renderer { - const cairo_pattern_t *pattern; - cairo_antialias_t antialias; - -+ uint8_t *mask_data; -+ uint32_t mask_stride; -+ - cairo_image_surface_t *src; - cairo_surface_attributes_t src_attributes; - cairo_image_surface_t *mask; - cairo_image_surface_t *dst; -- - cairo_composite_rectangles_t composite_rectangles; - } cairo_image_surface_span_renderer_t; - -@@ -1403,66 +1405,46 @@ _cairo_image_surface_span_render_row ( - int y, - const cairo_half_open_span_t *spans, - unsigned num_spans, -- cairo_image_surface_t *mask, -- const cairo_composite_rectangles_t *rects) -+ uint8_t *data, -+ uint32_t stride) - { -- int xmin = rects->mask.x; -- int xmax = xmin + rects->width; - uint8_t *row; -- int prev_x = xmin; -- int prev_alpha = 0; - unsigned i; - -- /* Make sure we're within y-range. */ -- y -= rects->mask.y; -- if (y < 0 || y >= rects->height) -+ if (num_spans == 0) - return; - -- row = (uint8_t*)(mask->data) + y*(size_t)mask->stride - xmin; -- -- /* Find the first span within x-range. */ -- for (i=0; i < num_spans && spans[i].x < xmin; i++) {} -- if (i>0) -- prev_alpha = spans[i-1].coverage; -- -- /* Set the intermediate spans. */ -- for (; i < num_spans; i++) { -- int x = spans[i].x; -- -- if (x >= xmax) -- break; -- -- if (prev_alpha != 0) { -- /* We implement setting rendering the most common single -- * pixel wide span case to avoid the overhead of a memset -- * call. Open coding setting longer spans didn't show a -- * noticeable improvement over memset. */ -- if (x == prev_x + 1) { -- row[prev_x] = prev_alpha; -- } -- else { -- memset(row + prev_x, prev_alpha, x - prev_x); -- } -+ row = data + y * stride; -+ for (i = 0; i < num_spans - 1; i++) { -+ if (! spans[i].coverage) -+ continue; -+ -+ /* We implement setting the most common single pixel wide -+ * span case to avoid the overhead of a memset call. -+ * Open coding setting longer spans didn't show a -+ * noticeable improvement over memset. -+ */ -+ if (spans[i+1].x == spans[i].x + 1) { -+ row[spans[i].x] = spans[i].coverage; -+ } else { -+ memset (row + spans[i].x, -+ spans[i].coverage, -+ spans[i+1].x - spans[i].x); - } -- -- prev_x = x; -- prev_alpha = spans[i].coverage; -- } -- -- if (prev_alpha != 0 && prev_x < xmax) { -- memset(row + prev_x, prev_alpha, xmax - prev_x); - } - } - - static cairo_status_t --_cairo_image_surface_span_renderer_render_row ( -+_cairo_image_surface_span_renderer_render_rows ( - void *abstract_renderer, - int y, -+ int height, - const cairo_half_open_span_t *spans, - unsigned num_spans) - { - cairo_image_surface_span_renderer_t *renderer = abstract_renderer; -- _cairo_image_surface_span_render_row (y, spans, num_spans, renderer->mask, &renderer->composite_rectangles); -+ while (height--) -+ _cairo_image_surface_span_render_row (y++, spans, num_spans, renderer->mask_data, renderer->mask_stride); - return CAIRO_STATUS_SUCCESS; - } - -@@ -1517,11 +1499,11 @@ _cairo_image_surface_span_renderer_finish (void *abstract_renderer) - &dst->base, - src_attributes, - src->width, src->height, -- rects->width, rects->height, -+ width, height, - rects->src.x, rects->src.y, - 0, 0, /* mask.x, mask.y */ - rects->dst.x, rects->dst.y, -- rects->width, rects->height, -+ width, height, - dst->clip_region); - } - } -@@ -1567,7 +1549,7 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op, - - renderer->base.destroy = _cairo_image_surface_span_renderer_destroy; - renderer->base.finish = _cairo_image_surface_span_renderer_finish; -- renderer->base.render_row = _cairo_image_surface_span_renderer_render_row; -+ renderer->base.render_rows = _cairo_image_surface_span_renderer_render_rows; - renderer->op = op; - renderer->pattern = pattern; - renderer->antialias = antialias; -@@ -1604,6 +1586,9 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op, - _cairo_image_surface_span_renderer_destroy (renderer); - return _cairo_span_renderer_create_in_error (status); - } -+ -+ renderer->mask_data = renderer->mask->data - rects->mask.x - rects->mask.y * renderer->mask->stride; -+ renderer->mask_stride = renderer->mask->stride; - return &renderer->base; - } - -diff --git a/src/cairo-spans-private.h b/src/cairo-spans-private.h -index e29a567..af3b38c 100644 ---- a/src/cairo-spans-private.h -+++ b/src/cairo-spans-private.h -@@ -47,26 +47,24 @@ typedef struct _cairo_half_open_span { - * surfaces if they want to composite spans instead of trapezoids. */ - typedef struct _cairo_span_renderer cairo_span_renderer_t; - struct _cairo_span_renderer { -+ /* Private status variable. */ -+ cairo_status_t status; -+ - /* Called to destroy the renderer. */ - cairo_destroy_func_t destroy; - -- /* Render the spans on row y of the source by whatever compositing -- * method is required. The function should ignore spans outside -- * the bounding box set by the init() function. */ -- cairo_status_t (*render_row)( -- void *abstract_renderer, -- int y, -- const cairo_half_open_span_t *coverages, -- unsigned num_coverages); -+ /* Render the spans on row y of the destination by whatever compositing -+ * method is required. */ -+ cairo_warn cairo_status_t -+ (*render_rows) (void *abstract_renderer, -+ int y, int height, -+ const cairo_half_open_span_t *coverages, -+ unsigned num_coverages); - - /* Called after all rows have been rendered to perform whatever - * final rendering step is required. This function is called just - * once before the renderer is destroyed. */ -- cairo_status_t (*finish)( -- void *abstract_renderer); -- -- /* Private status variable. */ -- cairo_status_t status; -+ cairo_status_t (*finish) (void *abstract_renderer); - }; - - /* Scan converter interface. */ -diff --git a/src/cairo-spans.c b/src/cairo-spans.c -index af3b85f..69894c1 100644 ---- a/src/cairo-spans.c -+++ b/src/cairo-spans.c -@@ -275,13 +275,15 @@ _cairo_scan_converter_create_in_error (cairo_status_t status) - } - - static cairo_status_t --_cairo_nil_span_renderer_render_row ( -+_cairo_nil_span_renderer_render_rows ( - void *abstract_renderer, - int y, -+ int height, - const cairo_half_open_span_t *coverages, - unsigned num_coverages) - { - (void) y; -+ (void) height; - (void) coverages; - (void) num_coverages; - return _cairo_span_renderer_status (abstract_renderer); -@@ -310,7 +312,7 @@ _cairo_span_renderer_set_error ( - ASSERT_NOT_REACHED; - } - if (renderer->status == CAIRO_STATUS_SUCCESS) { -- renderer->render_row = _cairo_nil_span_renderer_render_row; -+ renderer->render_rows = _cairo_nil_span_renderer_render_rows; - renderer->finish = _cairo_nil_span_renderer_finish; - renderer->status = error; - } -diff --git a/src/cairo-tor-scan-converter.c b/src/cairo-tor-scan-converter.c -index 29262c2..2b9fb1b 100644 ---- a/src/cairo-tor-scan-converter.c -+++ b/src/cairo-tor-scan-converter.c -@@ -128,27 +128,29 @@ blit_with_span_renderer( - cairo_span_renderer_t *span_renderer, - struct pool *span_pool, - int y, -+ int height, - int xmin, - int xmax); - - static glitter_status_t --blit_empty_with_span_renderer (cairo_span_renderer_t *renderer, int y); -+blit_empty_with_span_renderer (cairo_span_renderer_t *renderer, int y, int height); - - #define GLITTER_BLIT_COVERAGES_ARGS \ - cairo_span_renderer_t *span_renderer, \ - struct pool *span_pool - --#define GLITTER_BLIT_COVERAGES(cells, y, xmin, xmax) do { \ -+#define GLITTER_BLIT_COVERAGES(cells, y, height,xmin, xmax) do { \ - cairo_status_t status = blit_with_span_renderer (cells, \ - span_renderer, \ - span_pool, \ -- y, xmin, xmax); \ -+ y, height, \ -+ xmin, xmax); \ - if (unlikely (status)) \ - return status; \ - } while (0) - --#define GLITTER_BLIT_COVERAGES_EMPTY(y, xmin, xmax) do { \ -- cairo_status_t status = blit_empty_with_span_renderer (span_renderer, y); \ -+#define GLITTER_BLIT_COVERAGES_EMPTY(y, height, xmin, xmax) do { \ -+ cairo_status_t status = blit_empty_with_span_renderer (span_renderer, y, height); \ - if (unlikely (status)) \ - return status; \ - } while (0) -@@ -309,8 +311,8 @@ typedef int grid_area_t; - #define UNROLL3(x) x x x - - struct quorem { -- int quo; -- int rem; -+ int32_t quo; -+ int32_t rem; - }; - - /* Header for a chunk of memory in a memory pool. */ -@@ -382,6 +384,7 @@ struct edge { - /* Original sign of the edge: +1 for downwards, -1 for upwards - * edges. */ - int dir; -+ int vertical; - }; - - /* Number of subsample rows per y-bucket. Must be GRID_Y. */ -@@ -389,18 +392,28 @@ struct edge { - - #define EDGE_Y_BUCKET_INDEX(y, ymin) (((y) - (ymin))/EDGE_Y_BUCKET_HEIGHT) - -+struct bucket { -+ /* Unsorted list of edges starting within this bucket. */ -+ struct edge *edges; -+ -+ /* Set to non-zero if there are edges starting strictly within the -+ * bucket. */ -+ unsigned have_inside_edges; -+}; -+ - /* A collection of sorted and vertically clipped edges of the polygon. - * 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 - * into bucket EDGE_BUCKET_INDEX(edge->ytop, polygon->ymin) when - * it is added to the polygon. */ -- struct edge **y_buckets; -- struct edge *y_buckets_embedded[64]; -+ struct bucket *y_buckets; -+ struct bucket y_buckets_embedded[64]; - - struct { - struct pool base[1]; -@@ -702,7 +715,6 @@ static void - cell_list_fini(struct cell_list *cells) - { - pool_fini (cells->cell_pool.base); -- cell_list_init (cells); - } - - /* Empty the cell list. This is called at the start of every pixel -@@ -715,6 +727,26 @@ cell_list_reset (struct cell_list *cells) - pool_reset (cells->cell_pool.base); - } - -+static struct cell * -+cell_list_alloc (struct cell_list *cells, -+ struct cell **cursor, -+ struct cell *tail, -+ int x) -+{ -+ struct cell *cell; -+ -+ cell = pool_alloc (cells->cell_pool.base, sizeof (struct cell)); -+ if (unlikely (NULL == cell)) -+ return NULL; -+ -+ *cursor = cell; -+ cell->next = tail; -+ cell->x = x; -+ cell->uncovered_area = 0; -+ cell->covered_height = 0; -+ return cell; -+} -+ - /* Find a cell at the given x-coordinate. Returns %NULL if a new cell - * needed to be allocated but couldn't be. Cells must be found with - * non-decreasing x-coordinate until the cell list is rewound using -@@ -737,22 +769,10 @@ cell_list_find (struct cell_list *cells, int x) - } - cells->cursor = cursor; - -- if (tail->x == x) { -+ if (tail->x == x) - return tail; -- } else { -- struct cell *cell; -- -- cell = pool_alloc (cells->cell_pool.base, sizeof (struct cell)); -- if (unlikely (NULL == cell)) -- return NULL; - -- *cursor = cell; -- cell->next = tail; -- cell->x = x; -- cell->uncovered_area = 0; -- cell->covered_height = 0; -- return cell; -- } -+ return cell_list_alloc (cells, cursor, tail, x); - } - - /* Find two cells at x1 and x2. This is exactly equivalent -@@ -832,9 +852,8 @@ cell_list_find_pair(struct cell_list *cells, int x1, int x2) - /* Add an unbounded subpixel span covering subpixels >= x to the - * coverage cells. */ - static glitter_status_t --cell_list_add_unbounded_subspan( -- struct cell_list *cells, -- grid_scaled_x_t x) -+cell_list_add_unbounded_subspan (struct cell_list *cells, -+ grid_scaled_x_t x) - { - struct cell *cell; - int ix, fx; -@@ -907,20 +926,24 @@ cell_list_render_edge( - struct edge *edge, - int sign) - { -- struct quorem x1 = edge->x; -- struct quorem x2 = x1; - grid_scaled_y_t y1, y2, dy; - grid_scaled_x_t dx; - int ix1, ix2; - grid_scaled_x_t fx1, fx2; - -- x2.quo += edge->dxdy_full.quo; -- x2.rem += edge->dxdy_full.rem; -- if (x2.rem >= 0) { -- ++x2.quo; -- x2.rem -= edge->dy; -+ struct quorem x1 = edge->x; -+ struct quorem x2 = x1; -+ -+ if (! edge->vertical) { -+ x2.quo += edge->dxdy_full.quo; -+ x2.rem += edge->dxdy_full.rem; -+ if (x2.rem >= 0) { -+ ++x2.quo; -+ x2.rem -= edge->dy; -+ } -+ -+ edge->x = x2; - } -- edge->x = x2; - - GRID_X_TO_INT_FRAC(x1.quo, ix1, fx1); - GRID_X_TO_INT_FRAC(x2.quo, ix2, fx2); -@@ -1026,6 +1049,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), -@@ -1045,10 +1069,11 @@ polygon_fini (struct polygon *polygon) - * receive new edges and clip them to the vertical range - * [ymin,ymax). */ - static glitter_status_t --polygon_reset( -- struct polygon *polygon, -- grid_scaled_y_t ymin, -- grid_scaled_y_t ymax) -+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) - { - unsigned h = ymax - ymin; - unsigned num_buckets = EDGE_Y_BUCKET_INDEX(ymax + EDGE_Y_BUCKET_HEIGHT-1, -@@ -1065,14 +1090,16 @@ polygon_reset( - polygon->y_buckets = polygon->y_buckets_embedded; - if (num_buckets > ARRAY_LENGTH (polygon->y_buckets_embedded)) { - polygon->y_buckets = _cairo_malloc_ab (num_buckets, -- sizeof (struct edge *)); -+ sizeof (struct bucket)); - if (unlikely (NULL == polygon->y_buckets)) - goto bail_no_mem; - } -- memset (polygon->y_buckets, 0, num_buckets * sizeof (struct edge *)); -+ memset (polygon->y_buckets, 0, num_buckets * sizeof (struct bucket)); - - polygon->ymin = ymin; - polygon->ymax = ymax; -+ polygon->xmin = xmin; -+ polygon->xmax = xmax; - return GLITTER_STATUS_SUCCESS; - - bail_no_mem: -@@ -1086,10 +1113,13 @@ _polygon_insert_edge_into_its_y_bucket( - struct polygon *polygon, - struct edge *e) - { -- unsigned ix = EDGE_Y_BUCKET_INDEX(e->ytop, polygon->ymin); -- struct edge **ptail = &polygon->y_buckets[ix]; -+ unsigned j = e->ytop - polygon->ymin; -+ unsigned ix = j / EDGE_Y_BUCKET_HEIGHT; -+ unsigned offset = j % EDGE_Y_BUCKET_HEIGHT; -+ struct edge **ptail = &polygon->y_buckets[ix].edges; - e->next = *ptail; - *ptail = e; -+ polygon->y_buckets[ix].have_inside_edges |= offset; - } - - inline static glitter_status_t -@@ -1115,30 +1145,53 @@ polygon_add_edge (struct polygon *polygon, - dx = edge->line.p2.x - edge->line.p1.x; - dy = edge->line.p2.y - edge->line.p1.y; - e->dy = dy; -- e->dxdy = floored_divrem (dx, dy); -- -- if (ymin <= edge->top) -- ytop = edge->top; -- else -- ytop = ymin; -- if (ytop == edge->line.p1.y) { -- e->x.quo = edge->line.p1.x; -- e->x.rem = 0; -- } else { -- e->x = floored_muldivrem (ytop - edge->line.p1.y, dx, dy); -- e->x.quo += edge->line.p1.x; -- } -- - e->dir = edge->dir; -+ -+ ytop = edge->top >= ymin ? edge->top : ymin; -+ ybot = edge->bottom <= ymax ? edge->bottom : ymax; - e->ytop = ytop; -- ybot = edge->bottom < ymax ? edge->bottom : ymax; - e->height_left = ybot - ytop; - -- if (e->height_left >= GRID_Y) { -- e->dxdy_full = floored_muldivrem (GRID_Y, dx, dy); -- } else { -+ if (dx == 0) { -+ e->vertical = TRUE; -+ e->x.quo = edge->line.p1.x; -+ e->x.rem = 0; -+ e->dxdy.quo = 0; -+ 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); -+ if (ytop == edge->line.p1.y) { -+ e->x.quo = edge->line.p1.x; -+ e->x.rem = 0; -+ } else { -+ e->x = floored_muldivrem (ytop - edge->line.p1.y, dx, dy); -+ 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 { -+ e->dxdy_full.quo = 0; -+ e->dxdy_full.rem = 0; -+ } - } - - _polygon_insert_edge_into_its_y_bucket (polygon, e); -@@ -1161,31 +1214,30 @@ active_list_init(struct active_list *active) - active_list_reset(active); - } - --static void --active_list_fini( -- struct active_list *active) --{ -- active_list_reset(active); --} -- - /* Merge the edges in an unsorted list of edges into a sorted - * list. The sort order is edges ascending by edge->x.quo. Returns - * the new head of the sorted list. */ - static struct edge * - merge_unsorted_edges(struct edge *sorted_head, struct edge *unsorted_head) - { -- struct edge *head = unsorted_head; - struct edge **cursor = &sorted_head; - int x; - -- while (NULL != head) { -+ if (sorted_head == NULL) { -+ sorted_head = unsorted_head; -+ unsorted_head = unsorted_head->next; -+ sorted_head->next = NULL; -+ if (unsorted_head == NULL) -+ return sorted_head; -+ } -+ -+ do { -+ struct edge *next = unsorted_head->next; - struct edge *prev = *cursor; -- struct edge *next = head->next; -- x = head->x.quo; - -- if (NULL == prev || x < prev->x.quo) { -+ x = unsorted_head->x.quo; -+ if (x < prev->x.quo) - cursor = &sorted_head; -- } - - while (1) { - UNROLL3({ -@@ -1196,26 +1248,29 @@ merge_unsorted_edges(struct edge *sorted_head, struct edge *unsorted_head) - }); - } - -- head->next = *cursor; -- *cursor = head; -+ unsorted_head->next = *cursor; -+ *cursor = unsorted_head; -+ unsorted_head = next; -+ } while (unsorted_head != NULL); - -- head = next; -- } - return sorted_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; -+ 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. */ - if (active->min_height <= 0) { -- struct edge *e = active->head; - int min_height = INT_MAX; - -+ e = active->head; - while (NULL != e) { - if (e->height_left < min_height) - min_height = e->height_left; -@@ -1225,27 +1280,38 @@ active_list_can_step_full_row( - active->min_height = min_height; - } - -- /* Check for intersections only if no edges end during the next -- * row. */ -- if (active->min_height >= GRID_Y) { -- grid_scaled_x_t prev_x = INT_MIN; -- struct edge *e = active->head; -- while (NULL != e) { -- struct quorem x = e->x; -+ if (active->min_height < GRID_Y) -+ return 0; - -+ /* 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) -+ /* 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 (prev_x >= xmin || x.quo >= xmin || e->x.quo >= xmin) - return 0; -+ } -+ else { - prev_x = x.quo; -- e = e->next; - } -- return 1; -+ e = e->next; - } -- return 0; -+ -+ return 1; - } - - /* Merges edges on the given subpixel row from the polygon to the -@@ -1261,7 +1327,7 @@ active_list_merge_edges_from_polygon( - unsigned ix = EDGE_Y_BUCKET_INDEX(y, polygon->ymin); - int min_height = active->min_height; - struct edge *subrow_edges = NULL; -- struct edge **ptail = &polygon->y_buckets[ix]; -+ struct edge **ptail = &polygon->y_buckets[ix].edges; - - while (1) { - struct edge *tail = *ptail; -@@ -1277,8 +1343,10 @@ active_list_merge_edges_from_polygon( - ptail = &tail->next; - } - } -- active->head = merge_unsorted_edges(active->head, subrow_edges); -- active->min_height = min_height; -+ if (subrow_edges) { -+ active->head = merge_unsorted_edges(active->head, subrow_edges); -+ active->min_height = min_height; -+ } - } - - /* Advance the edges on the active list by one subsample row by -@@ -1439,11 +1507,13 @@ apply_nonzero_fill_rule_and_step_edges (struct active_list *active, - } - } - -- right_edge->x.quo += right_edge->dxdy_full.quo; -- right_edge->x.rem += right_edge->dxdy_full.rem; -- if (right_edge->x.rem >= 0) { -- ++right_edge->x.quo; -- right_edge->x.rem -= right_edge->dy; -+ if (! right_edge->vertical) { -+ right_edge->x.quo += right_edge->dxdy_full.quo; -+ right_edge->x.rem += right_edge->dxdy_full.rem; -+ if (right_edge->x.rem >= 0) { -+ ++right_edge->x.quo; -+ right_edge->x.rem -= right_edge->dy; -+ } - } - } - -@@ -1472,6 +1542,7 @@ apply_evenodd_fill_rule_and_step_edges (struct active_list *active, - left_edge = *cursor; - while (NULL != left_edge) { - struct edge *right_edge; -+ int winding = left_edge->dir; - - left_edge->height_left -= GRID_Y; - if (left_edge->height_left) -@@ -1490,17 +1561,22 @@ apply_evenodd_fill_rule_and_step_edges (struct active_list *active, - else - *cursor = right_edge->next; - -+ winding += right_edge->dir; -+ if ((winding & 1) == 0) { - if (right_edge->next == NULL || - right_edge->next->x.quo != right_edge->x.quo) - { - break; - } -+ } - -- right_edge->x.quo += right_edge->dxdy_full.quo; -- right_edge->x.rem += right_edge->dxdy_full.rem; -- if (right_edge->x.rem >= 0) { -- ++right_edge->x.quo; -- right_edge->x.rem -= right_edge->dy; -+ if (! right_edge->vertical) { -+ right_edge->x.quo += right_edge->dxdy_full.quo; -+ right_edge->x.rem += right_edge->dxdy_full.rem; -+ if (right_edge->x.rem >= 0) { -+ ++right_edge->x.quo; -+ right_edge->x.rem -= right_edge->dy; -+ } - } - } - -@@ -1537,8 +1613,14 @@ blit_span( - } - } - --#define GLITTER_BLIT_COVERAGES(coverages, y, xmin, xmax) \ -- blit_cells(coverages, raster_pixels + (y)*raster_stride, xmin, xmax) -+#define GLITTER_BLIT_COVERAGES(coverages, y, height, xmin, xmax) \ -+ do { \ -+ int __y = y; \ -+ int __h = height; \ -+ do { \ -+ blit_cells(coverages, raster_pixels + (__y)*raster_stride, xmin, xmax); \ -+ } while (--__h); \ -+ } while (0) - - static void - blit_cells( -@@ -1597,7 +1679,6 @@ static void - _glitter_scan_converter_fini(glitter_scan_converter_t *converter) - { - polygon_fini(converter->polygon); -- active_list_fini(converter->active); - cell_list_fini(converter->coverages); - converter->xmin=0; - converter->ymin=0; -@@ -1641,7 +1722,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; - -@@ -1711,19 +1792,48 @@ glitter_scan_converter_add_edge (glitter_scan_converter_t *converter, - #endif - - #ifndef GLITTER_BLIT_COVERAGES_EMPTY --# define GLITTER_BLIT_COVERAGES_EMPTY(y, xmin, xmax) -+# define GLITTER_BLIT_COVERAGES_EMPTY(y0, y1, xmin, xmax) - #endif - -+static cairo_bool_t -+active_list_is_vertical (struct active_list *active) -+{ -+ struct edge *e; -+ -+ for (e = active->head; e != NULL; e = e->next) { -+ if (! e->vertical) -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ -+static void -+step_edges (struct active_list *active, int count) -+{ -+ struct edge **cursor = &active->head; -+ struct edge *edge; -+ -+ for (edge = *cursor; edge != NULL; edge = *cursor) { -+ edge->height_left -= GRID_Y * count; -+ if (edge->height_left) -+ cursor = &edge->next; -+ else -+ *cursor = edge->next; -+ } -+} -+ - I glitter_status_t - glitter_scan_converter_render( - glitter_scan_converter_t *converter, - int nonzero_fill, - GLITTER_BLIT_COVERAGES_ARGS) - { -- int i; -+ int i, j; - 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; -@@ -1738,22 +1848,28 @@ glitter_scan_converter_render( - GLITTER_BLIT_COVERAGES_BEGIN; - - /* Render each pixel row. */ -- for (i=0; i<h; i++) { -+ for (i = 0; i < h; i = j) { - int do_full_step = 0; - glitter_status_t status = 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 (polygon->y_buckets[i].edges == NULL) { - if (! active->head) { -- GLITTER_BLIT_COVERAGES_EMPTY (i+ymin_i, xmin_i, xmax_i); -+ 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); -+ 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); - } -- -- cell_list_reset (coverages); - - if (do_full_step) { - /* Step by a full pixel row's worth. */ -@@ -1764,8 +1880,20 @@ glitter_scan_converter_render( - status = apply_evenodd_fill_rule_and_step_edges (active, - coverages); - } -+ -+ if (active_list_is_vertical (active)) { -+ while (j < h && -+ polygon->y_buckets[j].edges == NULL && -+ active->min_height >= 2*GRID_Y) -+ { -+ active->min_height -= GRID_Y; -+ j++; -+ } -+ if (j != i + 1) -+ step_edges (active, j - (i + 1)); -+ } - } else { -- /* Subsample this row. */ -+ /* Supersample this row. */ - grid_scaled_y_t suby; - for (suby = 0; suby < GRID_Y; suby++) { - grid_scaled_y_t y = (i+ymin_i)*GRID_Y + suby; -@@ -1787,13 +1915,13 @@ glitter_scan_converter_render( - if (unlikely (status)) - return status; - -- GLITTER_BLIT_COVERAGES(coverages, i+ymin_i, xmin_i, xmax_i); -+ GLITTER_BLIT_COVERAGES(coverages, i+ymin_i, j-i, xmin_i, xmax_i); -+ cell_list_reset (coverages); - -- if (! active->head) { -+ if (! active->head) - active->min_height = INT_MAX; -- } else { -+ else - active->min_height -= GRID_Y; -- } - } - - /* Clean up the coverage blitter. */ -@@ -1807,21 +1935,20 @@ glitter_scan_converter_render( - * scan converter subclass. */ - - static glitter_status_t --blit_with_span_renderer( -- struct cell_list *cells, -- cairo_span_renderer_t *renderer, -- struct pool *span_pool, -- int y, -- int xmin, -- int xmax) -+blit_with_span_renderer (struct cell_list *cells, -+ cairo_span_renderer_t *renderer, -+ struct pool *span_pool, -+ int y, int height, -+ int xmin, int xmax) - { - struct cell *cell = cells->head; - int prev_x = xmin; - int cover = 0; - cairo_half_open_span_t *spans; - unsigned num_spans; -+ - if (cell == NULL) -- return CAIRO_STATUS_SUCCESS; -+ return blit_empty_with_span_renderer (renderer, y, height); - - /* Skip cells to the left of the clip region. */ - while (cell != NULL && cell->x < xmin) { -@@ -1833,12 +1960,12 @@ blit_with_span_renderer( - /* Count number of cells remaining. */ - { - struct cell *next = cell; -- num_spans = 0; -- while (next) { -+ num_spans = 1; -+ while (next != NULL) { - next = next->next; - ++num_spans; - } -- num_spans = 2*num_spans + 1; -+ num_spans = 2*num_spans; - } - - /* Allocate enough spans for the row. */ -@@ -1853,6 +1980,7 @@ blit_with_span_renderer( - for (; cell != NULL; cell = cell->next) { - int x = cell->x; - int area; -+ - if (x >= xmax) - break; - -@@ -1872,20 +2000,26 @@ blit_with_span_renderer( - prev_x = x+1; - } - -- if (prev_x < xmax) { -+ if (prev_x <= xmax) { - spans[num_spans].x = prev_x; - spans[num_spans].coverage = GRID_AREA_TO_ALPHA (cover); - ++num_spans; - } - -+ if (prev_x < xmax && cover) { -+ spans[num_spans].x = xmax; -+ spans[num_spans].coverage = 0; -+ ++num_spans; -+ } -+ - /* Dump them into the renderer. */ -- return renderer->render_row (renderer, y, spans, num_spans); -+ return renderer->render_rows (renderer, y, height, spans, num_spans); - } - - static glitter_status_t --blit_empty_with_span_renderer (cairo_span_renderer_t *renderer, int y) -+blit_empty_with_span_renderer (cairo_span_renderer_t *renderer, int y, int height) - { -- return renderer->render_row (renderer, y, NULL, 0); -+ return renderer->render_rows (renderer, y, height, NULL, 0); - } - - struct _cairo_tor_scan_converter { -diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c -index 82d1cf5..d4575a3 100644 ---- a/src/cairo-win32-surface.c -+++ b/src/cairo-win32-surface.c -@@ -1954,6 +1954,9 @@ typedef struct _cairo_win32_surface_span_renderer { - const cairo_pattern_t *pattern; - cairo_antialias_t antialias; - -+ uint8_t *mask_data; -+ uint32_t mask_stride; -+ - cairo_image_surface_t *mask; - cairo_win32_surface_t *dst; - cairo_region_t *clip_region; -@@ -1962,14 +1965,16 @@ typedef struct _cairo_win32_surface_span_renderer { - } cairo_win32_surface_span_renderer_t; - - static cairo_status_t --_cairo_win32_surface_span_renderer_render_row ( -+_cairo_win32_surface_span_renderer_render_rows ( - void *abstract_renderer, - int y, -+ int height, - const cairo_half_open_span_t *spans, - unsigned num_spans) - { - cairo_win32_surface_span_renderer_t *renderer = abstract_renderer; -- _cairo_image_surface_span_render_row (y, spans, num_spans, renderer->mask, &renderer->composite_rectangles); -+ while (height--) -+ _cairo_image_surface_span_render_row (y++, spans, num_spans, renderer->mask_data, renderer->mask_stride); - return CAIRO_STATUS_SUCCESS; - } - -@@ -2066,8 +2071,7 @@ _cairo_win32_surface_create_span_renderer (cairo_operator_t op, - - renderer->base.destroy = _cairo_win32_surface_span_renderer_destroy; - renderer->base.finish = _cairo_win32_surface_span_renderer_finish; -- renderer->base.render_row = -- _cairo_win32_surface_span_renderer_render_row; -+ renderer->base.render_rows = _cairo_win32_surface_span_renderer_render_rows; - renderer->op = op; - renderer->pattern = pattern; - renderer->antialias = antialias; -@@ -2088,6 +2092,9 @@ _cairo_win32_surface_create_span_renderer (cairo_operator_t op, - _cairo_win32_surface_span_renderer_destroy (renderer); - return _cairo_span_renderer_create_in_error (status); - } -+ -+ renderer->mask_data = renderer->mask->data - rects->mask.x - rects->mask.y * renderer->mask->stride; -+ renderer->mask_stride = renderer->mask->stride; - return &renderer->base; - } - -diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c -index a7a40b8..566d9fb 100644 ---- a/src/cairo-xlib-display.c -+++ b/src/cairo-xlib-display.c -@@ -407,6 +407,10 @@ _cairo_xlib_display_get (Display *dpy, - display->buggy_pad_reflect = TRUE; - } - -+ /* gradients don't seem to work */ -+ display->buggy_gradients = TRUE; -+ -+ - /* XXX workaround; see https://bugzilla.mozilla.org/show_bug.cgi?id=413583 */ - /* If buggy_repeat_force == -1, then initialize. - * - set to -2, meaning "nothing was specified", and we trust the above detection. -diff --git a/src/cairoint.h b/src/cairoint.h -index 58850ab..1cdf6ff 100644 ---- a/src/cairoint.h -+++ b/src/cairoint.h -@@ -2257,8 +2257,8 @@ cairo_private void - _cairo_image_surface_span_render_row (int y, - const cairo_half_open_span_t *spans, - unsigned num_spans, -- cairo_image_surface_t *mask, -- const cairo_composite_rectangles_t *rects); -+ uint8_t *data, -+ uint32_t stride); - - cairo_private cairo_image_transparency_t - _cairo_image_analyze_transparency (cairo_image_surface_t *image); |