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