gfx/cairo/clip-invariant.patch

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/cairo/clip-invariant.patch	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1255 @@
     1.4 +diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
     1.5 +index 2acc8b5..019249e 100644
     1.6 +--- a/src/cairo-gl-surface.c
     1.7 ++++ b/src/cairo-gl-surface.c
     1.8 +@@ -2012,13 +2012,14 @@ typedef struct _cairo_gl_surface_span_renderer {
     1.9 + 
    1.10 +     cairo_gl_composite_setup_t setup;
    1.11 + 
    1.12 ++    int xmin, xmax;
    1.13 ++
    1.14 +     cairo_operator_t op;
    1.15 +     cairo_antialias_t antialias;
    1.16 + 
    1.17 +     cairo_gl_surface_t *dst;
    1.18 +     cairo_region_t *clip;
    1.19 + 
    1.20 +-    cairo_composite_rectangles_t composite_rectangles;
    1.21 +     GLuint vbo;
    1.22 +     void *vbo_base;
    1.23 +     unsigned int vbo_size;
    1.24 +@@ -2049,11 +2050,11 @@ _cairo_gl_span_renderer_flush (cairo_gl_surface_span_renderer_t *renderer)
    1.25 + 	    cairo_region_get_rectangle (renderer->clip, i, &rect);
    1.26 + 
    1.27 + 	    glScissor (rect.x, rect.y, rect.width, rect.height);
    1.28 +-	    glDrawArrays (GL_LINES, 0, count);
    1.29 ++	    glDrawArrays (GL_QUADS, 0, count);
    1.30 + 	}
    1.31 + 	glDisable (GL_SCISSOR_TEST);
    1.32 +     } else {
    1.33 +-	glDrawArrays (GL_LINES, 0, count);
    1.34 ++	glDrawArrays (GL_QUADS, 0, count);
    1.35 +     }
    1.36 + }
    1.37 + 
    1.38 +@@ -2134,72 +2135,87 @@ _cairo_gl_emit_span_vertex (cairo_gl_surface_span_renderer_t *renderer,
    1.39 + 
    1.40 + static void
    1.41 + _cairo_gl_emit_span (cairo_gl_surface_span_renderer_t *renderer,
    1.42 +-		     int x1, int x2, int y, uint8_t alpha)
    1.43 ++		     int x, int y1, int y2,
    1.44 ++		     uint8_t alpha)
    1.45 + {
    1.46 +     float *vertices = _cairo_gl_span_renderer_get_vbo (renderer, 2);
    1.47 + 
    1.48 +-    _cairo_gl_emit_span_vertex (renderer, x1, y, alpha, vertices);
    1.49 +-    _cairo_gl_emit_span_vertex (renderer, x2, y, alpha,
    1.50 ++    _cairo_gl_emit_span_vertex (renderer, x, y1, alpha, vertices);
    1.51 ++    _cairo_gl_emit_span_vertex (renderer, x, y2, alpha,
    1.52 + 			       vertices + renderer->vertex_size / 4);
    1.53 + }
    1.54 + 
    1.55 +-/* Emits the contents of the span renderer rows as GL_LINES with the span's
    1.56 +- * alpha.
    1.57 +- *
    1.58 +- * Unlike the image surface, which is compositing into a temporary, we emit
    1.59 +- * coverage even for alpha == 0, in case we're using an unbounded operator.
    1.60 +- * But it means we avoid having to do the fixup.
    1.61 +- */
    1.62 ++static void
    1.63 ++_cairo_gl_emit_rectangle (cairo_gl_surface_span_renderer_t *renderer,
    1.64 ++			  int x1, int y1,
    1.65 ++			  int x2, int y2,
    1.66 ++			  int coverage)
    1.67 ++{
    1.68 ++    _cairo_gl_emit_span (renderer, x1, y1, y2, coverage);
    1.69 ++    _cairo_gl_emit_span (renderer, x2, y2, y1, coverage);
    1.70 ++}
    1.71 ++
    1.72 + static cairo_status_t
    1.73 +-_cairo_gl_surface_span_renderer_render_row (
    1.74 +-    void				*abstract_renderer,
    1.75 +-    int					 y,
    1.76 +-    const cairo_half_open_span_t	*spans,
    1.77 +-    unsigned				 num_spans)
    1.78 ++_cairo_gl_render_bounded_spans (void *abstract_renderer,
    1.79 ++				int y, int height,
    1.80 ++				const cairo_half_open_span_t *spans,
    1.81 ++				unsigned num_spans)
    1.82 + {
    1.83 +     cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
    1.84 +-    int xmin = renderer->composite_rectangles.mask.x;
    1.85 +-    int xmax = xmin + renderer->composite_rectangles.width;
    1.86 +-    int prev_x = xmin;
    1.87 +-    int prev_alpha = 0;
    1.88 +-    unsigned i;
    1.89 +-    int x_translate;
    1.90 +-
    1.91 +-    /* Make sure we're within y-range. */
    1.92 +-    if (y < renderer->composite_rectangles.mask.y ||
    1.93 +-	y >= renderer->composite_rectangles.mask.y +
    1.94 +-	renderer->composite_rectangles.height)
    1.95 ++
    1.96 ++    if (num_spans == 0)
    1.97 + 	return CAIRO_STATUS_SUCCESS;
    1.98 + 
    1.99 +-    x_translate = renderer->composite_rectangles.dst.x -
   1.100 +-	renderer->composite_rectangles.mask.x;
   1.101 +-    y += renderer->composite_rectangles.dst.y -
   1.102 +-	renderer->composite_rectangles.mask.y;
   1.103 ++    do {
   1.104 ++	if (spans[0].coverage) {
   1.105 ++	    _cairo_gl_emit_rectangle (renderer,
   1.106 ++				      spans[0].x, y,
   1.107 ++				      spans[1].x, y + height,
   1.108 ++				      spans[0].coverage);
   1.109 ++	}
   1.110 + 
   1.111 +-    /* Find the first span within x-range. */
   1.112 +-    for (i=0; i < num_spans && spans[i].x < xmin; i++) {}
   1.113 +-    if (i>0)
   1.114 +-	prev_alpha = spans[i-1].coverage;
   1.115 ++	spans++;
   1.116 ++    } while (--num_spans > 1);
   1.117 + 
   1.118 +-    /* Set the intermediate spans. */
   1.119 +-    for (; i < num_spans; i++) {
   1.120 +-	int x = spans[i].x;
   1.121 ++    return CAIRO_STATUS_SUCCESS;
   1.122 ++}
   1.123 + 
   1.124 +-	if (x >= xmax)
   1.125 +-	    break;
   1.126 ++static cairo_status_t
   1.127 ++_cairo_gl_render_unbounded_spans (void *abstract_renderer,
   1.128 ++				  int y, int height,
   1.129 ++				  const cairo_half_open_span_t *spans,
   1.130 ++				  unsigned num_spans)
   1.131 ++{
   1.132 ++    cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
   1.133 + 
   1.134 +-	_cairo_gl_emit_span (renderer,
   1.135 +-			     prev_x + x_translate, x + x_translate, y,
   1.136 +-			     prev_alpha);
   1.137 ++    if (num_spans == 0) {
   1.138 ++	_cairo_gl_emit_rectangle (renderer,
   1.139 ++				  renderer->xmin, y,
   1.140 ++				  renderer->xmax, y + height,
   1.141 ++				  0);
   1.142 ++	return CAIRO_STATUS_SUCCESS;
   1.143 ++    }
   1.144 + 
   1.145 +-	prev_x = x;
   1.146 +-	prev_alpha = spans[i].coverage;
   1.147 ++    if (spans[0].x != renderer->xmin) {
   1.148 ++	_cairo_gl_emit_rectangle (renderer,
   1.149 ++				  renderer->xmin, y,
   1.150 ++				  spans[0].x, y + height,
   1.151 ++				  0);
   1.152 +     }
   1.153 + 
   1.154 +-    if (prev_x < xmax) {
   1.155 +-	_cairo_gl_emit_span (renderer,
   1.156 +-			     prev_x + x_translate, xmax + x_translate, y,
   1.157 +-			     prev_alpha);
   1.158 ++    do {
   1.159 ++	_cairo_gl_emit_rectangle (renderer,
   1.160 ++				  spans[0].x, y,
   1.161 ++				  spans[1].x, y + height,
   1.162 ++				  spans[0].coverage);
   1.163 ++	spans++;
   1.164 ++    } while (--num_spans > 1);
   1.165 ++
   1.166 ++    if (spans[0].x != renderer->xmax) {
   1.167 ++	_cairo_gl_emit_rectangle (renderer,
   1.168 ++				  spans[0].x, y,
   1.169 ++				  renderer->xmax, y + height,
   1.170 ++				  0);
   1.171 +     }
   1.172 + 
   1.173 +     return CAIRO_STATUS_SUCCESS;
   1.174 +@@ -2274,8 +2290,6 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
   1.175 +     cairo_gl_surface_t *dst = abstract_dst;
   1.176 +     cairo_gl_surface_span_renderer_t *renderer;
   1.177 +     cairo_status_t status;
   1.178 +-    int width = rects->width;
   1.179 +-    int height = rects->height;
   1.180 +     cairo_surface_attributes_t *src_attributes;
   1.181 +     GLenum err;
   1.182 + 
   1.183 +diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
   1.184 +index 48d8013..d52979d 100644
   1.185 +--- a/src/cairo-image-surface.c
   1.186 ++++ b/src/cairo-image-surface.c
   1.187 +@@ -1390,11 +1390,13 @@ typedef struct _cairo_image_surface_span_renderer {
   1.188 +     const cairo_pattern_t *pattern;
   1.189 +     cairo_antialias_t antialias;
   1.190 + 
   1.191 ++    uint8_t *mask_data;
   1.192 ++    uint32_t mask_stride;
   1.193 ++
   1.194 +     cairo_image_surface_t *src;
   1.195 +     cairo_surface_attributes_t src_attributes;
   1.196 +     cairo_image_surface_t *mask;
   1.197 +     cairo_image_surface_t *dst;
   1.198 +-
   1.199 +     cairo_composite_rectangles_t composite_rectangles;
   1.200 + } cairo_image_surface_span_renderer_t;
   1.201 + 
   1.202 +@@ -1403,66 +1405,46 @@ _cairo_image_surface_span_render_row (
   1.203 +     int                                  y,
   1.204 +     const cairo_half_open_span_t        *spans,
   1.205 +     unsigned                             num_spans,
   1.206 +-    cairo_image_surface_t               *mask,
   1.207 +-    const cairo_composite_rectangles_t  *rects)
   1.208 ++    uint8_t				*data,
   1.209 ++    uint32_t				 stride)
   1.210 + {
   1.211 +-    int xmin = rects->mask.x;
   1.212 +-    int xmax = xmin + rects->width;
   1.213 +     uint8_t *row;
   1.214 +-    int prev_x = xmin;
   1.215 +-    int prev_alpha = 0;
   1.216 +     unsigned i;
   1.217 + 
   1.218 +-    /* Make sure we're within y-range. */
   1.219 +-    y -= rects->mask.y;
   1.220 +-    if (y < 0 || y >= rects->height)
   1.221 ++    if (num_spans == 0)
   1.222 + 	return;
   1.223 + 
   1.224 +-    row = (uint8_t*)(mask->data) + y*(size_t)mask->stride - xmin;
   1.225 +-
   1.226 +-    /* Find the first span within x-range. */
   1.227 +-    for (i=0; i < num_spans && spans[i].x < xmin; i++) {}
   1.228 +-    if (i>0)
   1.229 +-	prev_alpha = spans[i-1].coverage;
   1.230 +-
   1.231 +-    /* Set the intermediate spans. */
   1.232 +-    for (; i < num_spans; i++) {
   1.233 +-	int x = spans[i].x;
   1.234 +-
   1.235 +-	if (x >= xmax)
   1.236 +-	    break;
   1.237 +-
   1.238 +-	if (prev_alpha != 0) {
   1.239 +-	    /* We implement setting rendering the most common single
   1.240 +-	     * pixel wide span case to avoid the overhead of a memset
   1.241 +-	     * call.  Open coding setting longer spans didn't show a
   1.242 +-	     * noticeable improvement over memset. */
   1.243 +-	    if (x == prev_x + 1) {
   1.244 +-		row[prev_x] = prev_alpha;
   1.245 +-	    }
   1.246 +-	    else {
   1.247 +-		memset(row + prev_x, prev_alpha, x - prev_x);
   1.248 +-	    }
   1.249 ++    row = data + y * stride;
   1.250 ++    for (i = 0; i < num_spans - 1; i++) {
   1.251 ++	if (! spans[i].coverage)
   1.252 ++	    continue;
   1.253 ++
   1.254 ++	/* We implement setting the most common single pixel wide
   1.255 ++	 * span case to avoid the overhead of a memset call.
   1.256 ++	 * Open coding setting longer spans didn't show a
   1.257 ++	 * noticeable improvement over memset.
   1.258 ++	 */
   1.259 ++	if (spans[i+1].x == spans[i].x + 1) {
   1.260 ++	    row[spans[i].x] = spans[i].coverage;
   1.261 ++	} else {
   1.262 ++	    memset (row + spans[i].x,
   1.263 ++		    spans[i].coverage,
   1.264 ++		    spans[i+1].x - spans[i].x);
   1.265 + 	}
   1.266 +-
   1.267 +-	prev_x = x;
   1.268 +-	prev_alpha = spans[i].coverage;
   1.269 +-    }
   1.270 +-
   1.271 +-    if (prev_alpha != 0 && prev_x < xmax) {
   1.272 +-	memset(row + prev_x, prev_alpha, xmax - prev_x);
   1.273 +     }
   1.274 + }
   1.275 + 
   1.276 + static cairo_status_t
   1.277 +-_cairo_image_surface_span_renderer_render_row (
   1.278 ++_cairo_image_surface_span_renderer_render_rows (
   1.279 +     void				*abstract_renderer,
   1.280 +     int					 y,
   1.281 ++    int					 height,
   1.282 +     const cairo_half_open_span_t	*spans,
   1.283 +     unsigned				 num_spans)
   1.284 + {
   1.285 +     cairo_image_surface_span_renderer_t *renderer = abstract_renderer;
   1.286 +-    _cairo_image_surface_span_render_row (y, spans, num_spans, renderer->mask, &renderer->composite_rectangles);
   1.287 ++    while (height--)
   1.288 ++	_cairo_image_surface_span_render_row (y++, spans, num_spans, renderer->mask_data, renderer->mask_stride);
   1.289 +     return CAIRO_STATUS_SUCCESS;
   1.290 + }
   1.291 + 
   1.292 +@@ -1517,11 +1499,11 @@ _cairo_image_surface_span_renderer_finish (void *abstract_renderer)
   1.293 + 		&dst->base,
   1.294 + 		src_attributes,
   1.295 + 		src->width, src->height,
   1.296 +-		rects->width, rects->height,
   1.297 ++		width, height,
   1.298 + 		rects->src.x, rects->src.y,
   1.299 + 		0, 0,		/* mask.x, mask.y */
   1.300 + 		rects->dst.x, rects->dst.y,
   1.301 +-		rects->width, rects->height,
   1.302 ++		width, height,
   1.303 + 		dst->clip_region);
   1.304 + 	}
   1.305 +     }
   1.306 +@@ -1567,7 +1549,7 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t	 op,
   1.307 + 
   1.308 +     renderer->base.destroy = _cairo_image_surface_span_renderer_destroy;
   1.309 +     renderer->base.finish = _cairo_image_surface_span_renderer_finish;
   1.310 +-    renderer->base.render_row = _cairo_image_surface_span_renderer_render_row;
   1.311 ++    renderer->base.render_rows = _cairo_image_surface_span_renderer_render_rows;
   1.312 +     renderer->op = op;
   1.313 +     renderer->pattern = pattern;
   1.314 +     renderer->antialias = antialias;
   1.315 +@@ -1604,6 +1586,9 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t	 op,
   1.316 + 	_cairo_image_surface_span_renderer_destroy (renderer);
   1.317 + 	return _cairo_span_renderer_create_in_error (status);
   1.318 +     }
   1.319 ++
   1.320 ++    renderer->mask_data = renderer->mask->data - rects->mask.x - rects->mask.y * renderer->mask->stride;
   1.321 ++    renderer->mask_stride = renderer->mask->stride;
   1.322 +     return &renderer->base;
   1.323 + }
   1.324 + 
   1.325 +diff --git a/src/cairo-spans-private.h b/src/cairo-spans-private.h
   1.326 +index e29a567..af3b38c 100644
   1.327 +--- a/src/cairo-spans-private.h
   1.328 ++++ b/src/cairo-spans-private.h
   1.329 +@@ -47,26 +47,24 @@ typedef struct _cairo_half_open_span {
   1.330 +  * surfaces if they want to composite spans instead of trapezoids. */
   1.331 + typedef struct _cairo_span_renderer cairo_span_renderer_t;
   1.332 + struct _cairo_span_renderer {
   1.333 ++    /* Private status variable. */
   1.334 ++    cairo_status_t status;
   1.335 ++
   1.336 +     /* Called to destroy the renderer. */
   1.337 +     cairo_destroy_func_t	destroy;
   1.338 + 
   1.339 +-    /* Render the spans on row y of the source by whatever compositing
   1.340 +-     * method is required.  The function should ignore spans outside
   1.341 +-     * the bounding box set by the init() function. */
   1.342 +-    cairo_status_t (*render_row)(
   1.343 +-	void				*abstract_renderer,
   1.344 +-	int				 y,
   1.345 +-	const cairo_half_open_span_t	*coverages,
   1.346 +-	unsigned			 num_coverages);
   1.347 ++    /* Render the spans on row y of the destination by whatever compositing
   1.348 ++     * method is required. */
   1.349 ++    cairo_warn cairo_status_t
   1.350 ++    (*render_rows) (void *abstract_renderer,
   1.351 ++		    int y, int height,
   1.352 ++		    const cairo_half_open_span_t	*coverages,
   1.353 ++		    unsigned num_coverages);
   1.354 + 
   1.355 +     /* Called after all rows have been rendered to perform whatever
   1.356 +      * final rendering step is required.  This function is called just
   1.357 +      * once before the renderer is destroyed. */
   1.358 +-    cairo_status_t (*finish)(
   1.359 +-	void		      *abstract_renderer);
   1.360 +-
   1.361 +-    /* Private status variable. */
   1.362 +-    cairo_status_t status;
   1.363 ++    cairo_status_t (*finish) (void *abstract_renderer);
   1.364 + };
   1.365 + 
   1.366 + /* Scan converter interface. */
   1.367 +diff --git a/src/cairo-spans.c b/src/cairo-spans.c
   1.368 +index af3b85f..69894c1 100644
   1.369 +--- a/src/cairo-spans.c
   1.370 ++++ b/src/cairo-spans.c
   1.371 +@@ -275,13 +275,15 @@ _cairo_scan_converter_create_in_error (cairo_status_t status)
   1.372 + }
   1.373 + 
   1.374 + static cairo_status_t
   1.375 +-_cairo_nil_span_renderer_render_row (
   1.376 ++_cairo_nil_span_renderer_render_rows (
   1.377 +     void				*abstract_renderer,
   1.378 +     int					 y,
   1.379 ++    int					 height,
   1.380 +     const cairo_half_open_span_t	*coverages,
   1.381 +     unsigned				 num_coverages)
   1.382 + {
   1.383 +     (void) y;
   1.384 ++    (void) height;
   1.385 +     (void) coverages;
   1.386 +     (void) num_coverages;
   1.387 +     return _cairo_span_renderer_status (abstract_renderer);
   1.388 +@@ -310,7 +312,7 @@ _cairo_span_renderer_set_error (
   1.389 + 	ASSERT_NOT_REACHED;
   1.390 +     }
   1.391 +     if (renderer->status == CAIRO_STATUS_SUCCESS) {
   1.392 +-	renderer->render_row = _cairo_nil_span_renderer_render_row;
   1.393 ++	renderer->render_rows = _cairo_nil_span_renderer_render_rows;
   1.394 + 	renderer->finish = _cairo_nil_span_renderer_finish;
   1.395 + 	renderer->status = error;
   1.396 +     }
   1.397 +diff --git a/src/cairo-tor-scan-converter.c b/src/cairo-tor-scan-converter.c
   1.398 +index 29262c2..2b9fb1b 100644
   1.399 +--- a/src/cairo-tor-scan-converter.c
   1.400 ++++ b/src/cairo-tor-scan-converter.c
   1.401 +@@ -128,27 +128,29 @@ blit_with_span_renderer(
   1.402 +     cairo_span_renderer_t	*span_renderer,
   1.403 +     struct pool			*span_pool,
   1.404 +     int				 y,
   1.405 ++    int				 height,
   1.406 +     int				 xmin,
   1.407 +     int				 xmax);
   1.408 + 
   1.409 + static glitter_status_t
   1.410 +-blit_empty_with_span_renderer (cairo_span_renderer_t *renderer, int y);
   1.411 ++blit_empty_with_span_renderer (cairo_span_renderer_t *renderer, int y, int height);
   1.412 + 
   1.413 + #define GLITTER_BLIT_COVERAGES_ARGS \
   1.414 + 	cairo_span_renderer_t *span_renderer, \
   1.415 + 	struct pool *span_pool
   1.416 + 
   1.417 +-#define GLITTER_BLIT_COVERAGES(cells, y, xmin, xmax) do {		\
   1.418 ++#define GLITTER_BLIT_COVERAGES(cells, y, height,xmin, xmax) do {	\
   1.419 +     cairo_status_t status = blit_with_span_renderer (cells,		\
   1.420 + 						     span_renderer,	\
   1.421 + 						     span_pool,		\
   1.422 +-						     y, xmin, xmax);	\
   1.423 ++						     y, height,		\
   1.424 ++						     xmin, xmax);	\
   1.425 +     if (unlikely (status))						\
   1.426 + 	return status;							\
   1.427 + } while (0)
   1.428 + 
   1.429 +-#define GLITTER_BLIT_COVERAGES_EMPTY(y, xmin, xmax) do {		\
   1.430 +-    cairo_status_t status = blit_empty_with_span_renderer (span_renderer, y); \
   1.431 ++#define GLITTER_BLIT_COVERAGES_EMPTY(y, height, xmin, xmax) do {		\
   1.432 ++    cairo_status_t status = blit_empty_with_span_renderer (span_renderer, y, height); \
   1.433 +     if (unlikely (status))						\
   1.434 + 	return status;							\
   1.435 + } while (0)
   1.436 +@@ -309,8 +311,8 @@ typedef int grid_area_t;
   1.437 + #define UNROLL3(x) x x x
   1.438 + 
   1.439 + struct quorem {
   1.440 +-    int quo;
   1.441 +-    int rem;
   1.442 ++    int32_t quo;
   1.443 ++    int32_t rem;
   1.444 + };
   1.445 + 
   1.446 + /* Header for a chunk of memory in a memory pool. */
   1.447 +@@ -382,6 +384,7 @@ struct edge {
   1.448 +     /* Original sign of the edge: +1 for downwards, -1 for upwards
   1.449 +      * edges.  */
   1.450 +     int dir;
   1.451 ++    int vertical;
   1.452 + };
   1.453 + 
   1.454 + /* Number of subsample rows per y-bucket. Must be GRID_Y. */
   1.455 +@@ -389,18 +392,28 @@ struct edge {
   1.456 + 
   1.457 + #define EDGE_Y_BUCKET_INDEX(y, ymin) (((y) - (ymin))/EDGE_Y_BUCKET_HEIGHT)
   1.458 + 
   1.459 ++struct bucket {
   1.460 ++    /* Unsorted list of edges starting within this bucket. */
   1.461 ++    struct edge *edges;
   1.462 ++
   1.463 ++    /* Set to non-zero if there are edges starting strictly within the
   1.464 ++     * bucket. */
   1.465 ++    unsigned     have_inside_edges;
   1.466 ++};
   1.467 ++
   1.468 + /* A collection of sorted and vertically clipped edges of the polygon.
   1.469 +  * Edges are moved from the polygon to an active list while scan
   1.470 +  * converting. */
   1.471 + struct polygon {
   1.472 +-    /* The vertical clip extents. */
   1.473 ++    /* The clip extents. */
   1.474 ++    grid_scaled_x_t xmin, xmax;
   1.475 +     grid_scaled_y_t ymin, ymax;
   1.476 + 
   1.477 +     /* Array of edges all starting in the same bucket.	An edge is put
   1.478 +      * into bucket EDGE_BUCKET_INDEX(edge->ytop, polygon->ymin) when
   1.479 +      * it is added to the polygon. */
   1.480 +-    struct edge **y_buckets;
   1.481 +-    struct edge *y_buckets_embedded[64];
   1.482 ++    struct bucket *y_buckets;
   1.483 ++    struct bucket  y_buckets_embedded[64];
   1.484 + 
   1.485 +     struct {
   1.486 + 	struct pool base[1];
   1.487 +@@ -702,7 +715,6 @@ static void
   1.488 + cell_list_fini(struct cell_list *cells)
   1.489 + {
   1.490 +     pool_fini (cells->cell_pool.base);
   1.491 +-    cell_list_init (cells);
   1.492 + }
   1.493 + 
   1.494 + /* Empty the cell list.  This is called at the start of every pixel
   1.495 +@@ -715,6 +727,26 @@ cell_list_reset (struct cell_list *cells)
   1.496 +     pool_reset (cells->cell_pool.base);
   1.497 + }
   1.498 + 
   1.499 ++static struct cell *
   1.500 ++cell_list_alloc (struct cell_list *cells,
   1.501 ++		 struct cell **cursor,
   1.502 ++		 struct cell *tail,
   1.503 ++		 int x)
   1.504 ++{
   1.505 ++    struct cell *cell;
   1.506 ++
   1.507 ++    cell = pool_alloc (cells->cell_pool.base, sizeof (struct cell));
   1.508 ++    if (unlikely (NULL == cell))
   1.509 ++	return NULL;
   1.510 ++
   1.511 ++    *cursor = cell;
   1.512 ++    cell->next = tail;
   1.513 ++    cell->x = x;
   1.514 ++    cell->uncovered_area = 0;
   1.515 ++    cell->covered_height = 0;
   1.516 ++    return cell;
   1.517 ++}
   1.518 ++
   1.519 + /* Find a cell at the given x-coordinate.  Returns %NULL if a new cell
   1.520 +  * needed to be allocated but couldn't be.  Cells must be found with
   1.521 +  * non-decreasing x-coordinate until the cell list is rewound using
   1.522 +@@ -737,22 +769,10 @@ cell_list_find (struct cell_list *cells, int x)
   1.523 +     }
   1.524 +     cells->cursor = cursor;
   1.525 + 
   1.526 +-    if (tail->x == x) {
   1.527 ++    if (tail->x == x)
   1.528 + 	return tail;
   1.529 +-    } else {
   1.530 +-	struct cell *cell;
   1.531 +-
   1.532 +-	cell = pool_alloc (cells->cell_pool.base, sizeof (struct cell));
   1.533 +-	if (unlikely (NULL == cell))
   1.534 +-	    return NULL;
   1.535 + 
   1.536 +-	*cursor = cell;
   1.537 +-	cell->next = tail;
   1.538 +-	cell->x = x;
   1.539 +-	cell->uncovered_area = 0;
   1.540 +-	cell->covered_height = 0;
   1.541 +-	return cell;
   1.542 +-    }
   1.543 ++    return cell_list_alloc (cells, cursor, tail, x);
   1.544 + }
   1.545 + 
   1.546 + /* Find two cells at x1 and x2.	 This is exactly equivalent
   1.547 +@@ -832,9 +852,8 @@ cell_list_find_pair(struct cell_list *cells, int x1, int x2)
   1.548 + /* Add an unbounded subpixel span covering subpixels >= x to the
   1.549 +  * coverage cells. */
   1.550 + static glitter_status_t
   1.551 +-cell_list_add_unbounded_subspan(
   1.552 +-    struct cell_list *cells,
   1.553 +-    grid_scaled_x_t x)
   1.554 ++cell_list_add_unbounded_subspan (struct cell_list *cells,
   1.555 ++				 grid_scaled_x_t x)
   1.556 + {
   1.557 +     struct cell *cell;
   1.558 +     int ix, fx;
   1.559 +@@ -907,20 +926,24 @@ cell_list_render_edge(
   1.560 +     struct edge *edge,
   1.561 +     int sign)
   1.562 + {
   1.563 +-    struct quorem x1 = edge->x;
   1.564 +-    struct quorem x2 = x1;
   1.565 +     grid_scaled_y_t y1, y2, dy;
   1.566 +     grid_scaled_x_t dx;
   1.567 +     int ix1, ix2;
   1.568 +     grid_scaled_x_t fx1, fx2;
   1.569 + 
   1.570 +-    x2.quo += edge->dxdy_full.quo;
   1.571 +-    x2.rem += edge->dxdy_full.rem;
   1.572 +-    if (x2.rem >= 0) {
   1.573 +-	++x2.quo;
   1.574 +-	x2.rem -= edge->dy;
   1.575 ++    struct quorem x1 = edge->x;
   1.576 ++    struct quorem x2 = x1;
   1.577 ++
   1.578 ++    if (! edge->vertical) {
   1.579 ++	x2.quo += edge->dxdy_full.quo;
   1.580 ++	x2.rem += edge->dxdy_full.rem;
   1.581 ++	if (x2.rem >= 0) {
   1.582 ++	    ++x2.quo;
   1.583 ++	    x2.rem -= edge->dy;
   1.584 ++	}
   1.585 ++
   1.586 ++	edge->x = x2;
   1.587 +     }
   1.588 +-    edge->x = x2;
   1.589 + 
   1.590 +     GRID_X_TO_INT_FRAC(x1.quo, ix1, fx1);
   1.591 +     GRID_X_TO_INT_FRAC(x2.quo, ix2, fx2);
   1.592 +@@ -1026,6 +1049,7 @@ static void
   1.593 + polygon_init (struct polygon *polygon)
   1.594 + {
   1.595 +     polygon->ymin = polygon->ymax = 0;
   1.596 ++    polygon->xmin = polygon->xmax = 0;
   1.597 +     polygon->y_buckets = polygon->y_buckets_embedded;
   1.598 +     pool_init (polygon->edge_pool.base,
   1.599 + 	       8192 - sizeof (struct _pool_chunk),
   1.600 +@@ -1045,10 +1069,11 @@ polygon_fini (struct polygon *polygon)
   1.601 +  * receive new edges and clip them to the vertical range
   1.602 +  * [ymin,ymax). */
   1.603 + static glitter_status_t
   1.604 +-polygon_reset(
   1.605 +-    struct polygon *polygon,
   1.606 +-    grid_scaled_y_t ymin,
   1.607 +-    grid_scaled_y_t ymax)
   1.608 ++polygon_reset (struct polygon *polygon,
   1.609 ++	       grid_scaled_x_t xmin,
   1.610 ++	       grid_scaled_x_t xmax,
   1.611 ++	       grid_scaled_y_t ymin,
   1.612 ++	       grid_scaled_y_t ymax)
   1.613 + {
   1.614 +     unsigned h = ymax - ymin;
   1.615 +     unsigned num_buckets = EDGE_Y_BUCKET_INDEX(ymax + EDGE_Y_BUCKET_HEIGHT-1,
   1.616 +@@ -1065,14 +1090,16 @@ polygon_reset(
   1.617 +     polygon->y_buckets =  polygon->y_buckets_embedded;
   1.618 +     if (num_buckets > ARRAY_LENGTH (polygon->y_buckets_embedded)) {
   1.619 + 	polygon->y_buckets = _cairo_malloc_ab (num_buckets,
   1.620 +-					       sizeof (struct edge *));
   1.621 ++					       sizeof (struct bucket));
   1.622 + 	if (unlikely (NULL == polygon->y_buckets))
   1.623 + 	    goto bail_no_mem;
   1.624 +     }
   1.625 +-    memset (polygon->y_buckets, 0, num_buckets * sizeof (struct edge *));
   1.626 ++    memset (polygon->y_buckets, 0, num_buckets * sizeof (struct bucket));
   1.627 + 
   1.628 +     polygon->ymin = ymin;
   1.629 +     polygon->ymax = ymax;
   1.630 ++    polygon->xmin = xmin;
   1.631 ++    polygon->xmax = xmax;
   1.632 +     return GLITTER_STATUS_SUCCESS;
   1.633 + 
   1.634 +  bail_no_mem:
   1.635 +@@ -1086,10 +1113,13 @@ _polygon_insert_edge_into_its_y_bucket(
   1.636 +     struct polygon *polygon,
   1.637 +     struct edge *e)
   1.638 + {
   1.639 +-    unsigned ix = EDGE_Y_BUCKET_INDEX(e->ytop, polygon->ymin);
   1.640 +-    struct edge **ptail = &polygon->y_buckets[ix];
   1.641 ++    unsigned j = e->ytop - polygon->ymin;
   1.642 ++    unsigned ix = j / EDGE_Y_BUCKET_HEIGHT;
   1.643 ++    unsigned offset = j % EDGE_Y_BUCKET_HEIGHT;
   1.644 ++    struct edge **ptail = &polygon->y_buckets[ix].edges;
   1.645 +     e->next = *ptail;
   1.646 +     *ptail = e;
   1.647 ++    polygon->y_buckets[ix].have_inside_edges |= offset;
   1.648 + }
   1.649 + 
   1.650 + inline static glitter_status_t
   1.651 +@@ -1115,30 +1145,53 @@ polygon_add_edge (struct polygon *polygon,
   1.652 +     dx = edge->line.p2.x - edge->line.p1.x;
   1.653 +     dy = edge->line.p2.y - edge->line.p1.y;
   1.654 +     e->dy = dy;
   1.655 +-    e->dxdy = floored_divrem (dx, dy);
   1.656 +-
   1.657 +-    if (ymin <= edge->top)
   1.658 +-	ytop = edge->top;
   1.659 +-    else
   1.660 +-	ytop = ymin;
   1.661 +-    if (ytop == edge->line.p1.y) {
   1.662 +-	e->x.quo = edge->line.p1.x;
   1.663 +-	e->x.rem = 0;
   1.664 +-    } else {
   1.665 +-	e->x = floored_muldivrem (ytop - edge->line.p1.y, dx, dy);
   1.666 +-	e->x.quo += edge->line.p1.x;
   1.667 +-    }
   1.668 +-
   1.669 +     e->dir = edge->dir;
   1.670 ++
   1.671 ++    ytop = edge->top >= ymin ? edge->top : ymin;
   1.672 ++    ybot = edge->bottom <= ymax ? edge->bottom : ymax;
   1.673 +     e->ytop = ytop;
   1.674 +-    ybot = edge->bottom < ymax ? edge->bottom : ymax;
   1.675 +     e->height_left = ybot - ytop;
   1.676 + 
   1.677 +-    if (e->height_left >= GRID_Y) {
   1.678 +-	e->dxdy_full = floored_muldivrem (GRID_Y, dx, dy);
   1.679 +-    } else {
   1.680 ++    if (dx == 0) {
   1.681 ++	e->vertical = TRUE;
   1.682 ++	e->x.quo = edge->line.p1.x;
   1.683 ++	e->x.rem = 0;
   1.684 ++	e->dxdy.quo = 0;
   1.685 ++	e->dxdy.rem = 0;
   1.686 + 	e->dxdy_full.quo = 0;
   1.687 + 	e->dxdy_full.rem = 0;
   1.688 ++
   1.689 ++	/* Drop edges to the right of the clip extents. */
   1.690 ++	if (e->x.quo >= polygon->xmax)
   1.691 ++	    return GLITTER_STATUS_SUCCESS;
   1.692 ++
   1.693 ++	/* Offset vertical edges at the left side of the clip extents
   1.694 ++	 * to just shy of the left side.  We depend on this when
   1.695 ++	 * checking for possible intersections within the clip
   1.696 ++	 * rectangle. */
   1.697 ++	if (e->x.quo <= polygon->xmin) {
   1.698 ++	    e->x.quo = polygon->xmin - 1;
   1.699 ++	}
   1.700 ++    } else {
   1.701 ++	e->vertical = FALSE;
   1.702 ++	e->dxdy = floored_divrem (dx, dy);
   1.703 ++	if (ytop == edge->line.p1.y) {
   1.704 ++	    e->x.quo = edge->line.p1.x;
   1.705 ++	    e->x.rem = 0;
   1.706 ++	} else {
   1.707 ++	    e->x = floored_muldivrem (ytop - edge->line.p1.y, dx, dy);
   1.708 ++	    e->x.quo += edge->line.p1.x;
   1.709 ++	}
   1.710 ++
   1.711 ++	if (e->x.quo >= polygon->xmax && e->dxdy.quo >= 0)
   1.712 ++	    return GLITTER_STATUS_SUCCESS;
   1.713 ++
   1.714 ++	if (e->height_left >= GRID_Y) {
   1.715 ++	    e->dxdy_full = floored_muldivrem (GRID_Y, dx, dy);
   1.716 ++	} else {
   1.717 ++	    e->dxdy_full.quo = 0;
   1.718 ++	    e->dxdy_full.rem = 0;
   1.719 ++	}
   1.720 +     }
   1.721 + 
   1.722 +     _polygon_insert_edge_into_its_y_bucket (polygon, e);
   1.723 +@@ -1161,31 +1214,30 @@ active_list_init(struct active_list *active)
   1.724 +     active_list_reset(active);
   1.725 + }
   1.726 + 
   1.727 +-static void
   1.728 +-active_list_fini(
   1.729 +-    struct active_list *active)
   1.730 +-{
   1.731 +-    active_list_reset(active);
   1.732 +-}
   1.733 +-
   1.734 + /* Merge the edges in an unsorted list of edges into a sorted
   1.735 +  * list. The sort order is edges ascending by edge->x.quo.  Returns
   1.736 +  * the new head of the sorted list. */
   1.737 + static struct edge *
   1.738 + merge_unsorted_edges(struct edge *sorted_head, struct edge *unsorted_head)
   1.739 + {
   1.740 +-    struct edge *head = unsorted_head;
   1.741 +     struct edge **cursor = &sorted_head;
   1.742 +     int x;
   1.743 + 
   1.744 +-    while (NULL != head) {
   1.745 ++    if (sorted_head == NULL) {
   1.746 ++	sorted_head = unsorted_head;
   1.747 ++	unsorted_head = unsorted_head->next;
   1.748 ++	sorted_head->next = NULL;
   1.749 ++	if (unsorted_head == NULL)
   1.750 ++	    return sorted_head;
   1.751 ++    }
   1.752 ++
   1.753 ++    do {
   1.754 ++	struct edge *next = unsorted_head->next;
   1.755 + 	struct edge *prev = *cursor;
   1.756 +-	struct edge *next = head->next;
   1.757 +-	x = head->x.quo;
   1.758 + 
   1.759 +-	if (NULL == prev || x < prev->x.quo) {
   1.760 ++	x = unsorted_head->x.quo;
   1.761 ++	if (x < prev->x.quo)
   1.762 + 	    cursor = &sorted_head;
   1.763 +-	}
   1.764 + 
   1.765 + 	while (1) {
   1.766 + 	    UNROLL3({
   1.767 +@@ -1196,26 +1248,29 @@ merge_unsorted_edges(struct edge *sorted_head, struct edge *unsorted_head)
   1.768 + 	    });
   1.769 + 	}
   1.770 + 
   1.771 +-	head->next = *cursor;
   1.772 +-	*cursor = head;
   1.773 ++	unsorted_head->next = *cursor;
   1.774 ++	*cursor = unsorted_head;
   1.775 ++	unsorted_head = next;
   1.776 ++    } while (unsorted_head != NULL);
   1.777 + 
   1.778 +-	head = next;
   1.779 +-    }
   1.780 +     return sorted_head;
   1.781 + }
   1.782 + 
   1.783 + /* Test if the edges on the active list can be safely advanced by a
   1.784 +  * full row without intersections or any edges ending. */
   1.785 + inline static int
   1.786 +-active_list_can_step_full_row(
   1.787 +-    struct active_list *active)
   1.788 ++active_list_can_step_full_row (struct active_list *active,
   1.789 ++			       grid_scaled_x_t     xmin)
   1.790 + {
   1.791 ++    const struct edge *e;
   1.792 ++    grid_scaled_x_t prev_x = INT_MIN;
   1.793 ++
   1.794 +     /* Recomputes the minimum height of all edges on the active
   1.795 +      * list if we have been dropping edges. */
   1.796 +     if (active->min_height <= 0) {
   1.797 +-	struct edge *e = active->head;
   1.798 + 	int min_height = INT_MAX;
   1.799 + 
   1.800 ++	e = active->head;
   1.801 + 	while (NULL != e) {
   1.802 + 	    if (e->height_left < min_height)
   1.803 + 		min_height = e->height_left;
   1.804 +@@ -1225,27 +1280,38 @@ active_list_can_step_full_row(
   1.805 + 	active->min_height = min_height;
   1.806 +     }
   1.807 + 
   1.808 +-    /* Check for intersections only if no edges end during the next
   1.809 +-     * row. */
   1.810 +-    if (active->min_height >= GRID_Y) {
   1.811 +-	grid_scaled_x_t prev_x = INT_MIN;
   1.812 +-	struct edge *e = active->head;
   1.813 +-	while (NULL != e) {
   1.814 +-	    struct quorem x = e->x;
   1.815 ++    if (active->min_height < GRID_Y)
   1.816 ++	return 0;
   1.817 + 
   1.818 ++    /* Check for intersections as no edges end during the next row. */
   1.819 ++    e = active->head;
   1.820 ++    while (NULL != e) {
   1.821 ++	struct quorem x = e->x;
   1.822 ++
   1.823 ++	if (! e->vertical) {
   1.824 + 	    x.quo += e->dxdy_full.quo;
   1.825 + 	    x.rem += e->dxdy_full.rem;
   1.826 + 	    if (x.rem >= 0)
   1.827 + 		++x.quo;
   1.828 ++	}
   1.829 + 
   1.830 +-	    if (x.quo <= prev_x)
   1.831 ++	/* There's may be an intersection if the edge sort order might
   1.832 ++	 * change. */
   1.833 ++	if (x.quo <= prev_x) {
   1.834 ++	    /* Ignore intersections to the left of the clip extents.
   1.835 ++	     * This assumes that all vertical edges on or at the left
   1.836 ++	     * side of the clip rectangle have been shifted slightly
   1.837 ++	     * to the left in polygon_add_edge(). */
   1.838 ++	    if (prev_x >= xmin || x.quo >= xmin || e->x.quo >= xmin)
   1.839 + 		return 0;
   1.840 ++	}
   1.841 ++	else {
   1.842 + 	    prev_x = x.quo;
   1.843 +-	    e = e->next;
   1.844 + 	}
   1.845 +-	return 1;
   1.846 ++	e = e->next;
   1.847 +     }
   1.848 +-    return 0;
   1.849 ++
   1.850 ++    return 1;
   1.851 + }
   1.852 + 
   1.853 + /* Merges edges on the given subpixel row from the polygon to the
   1.854 +@@ -1261,7 +1327,7 @@ active_list_merge_edges_from_polygon(
   1.855 +     unsigned ix = EDGE_Y_BUCKET_INDEX(y, polygon->ymin);
   1.856 +     int min_height = active->min_height;
   1.857 +     struct edge *subrow_edges = NULL;
   1.858 +-    struct edge **ptail = &polygon->y_buckets[ix];
   1.859 ++    struct edge **ptail = &polygon->y_buckets[ix].edges;
   1.860 + 
   1.861 +     while (1) {
   1.862 + 	struct edge *tail = *ptail;
   1.863 +@@ -1277,8 +1343,10 @@ active_list_merge_edges_from_polygon(
   1.864 + 	    ptail = &tail->next;
   1.865 + 	}
   1.866 +     }
   1.867 +-    active->head = merge_unsorted_edges(active->head, subrow_edges);
   1.868 +-    active->min_height = min_height;
   1.869 ++    if (subrow_edges) {
   1.870 ++	active->head = merge_unsorted_edges(active->head, subrow_edges);
   1.871 ++	active->min_height = min_height;
   1.872 ++    }
   1.873 + }
   1.874 + 
   1.875 + /* Advance the edges on the active list by one subsample row by
   1.876 +@@ -1439,11 +1507,13 @@ apply_nonzero_fill_rule_and_step_edges (struct active_list *active,
   1.877 + 		}
   1.878 + 	    }
   1.879 + 
   1.880 +-	    right_edge->x.quo += right_edge->dxdy_full.quo;
   1.881 +-	    right_edge->x.rem += right_edge->dxdy_full.rem;
   1.882 +-	    if (right_edge->x.rem >= 0) {
   1.883 +-		++right_edge->x.quo;
   1.884 +-		right_edge->x.rem -= right_edge->dy;
   1.885 ++	    if (! right_edge->vertical) {
   1.886 ++		right_edge->x.quo += right_edge->dxdy_full.quo;
   1.887 ++		right_edge->x.rem += right_edge->dxdy_full.rem;
   1.888 ++		if (right_edge->x.rem >= 0) {
   1.889 ++		    ++right_edge->x.quo;
   1.890 ++		    right_edge->x.rem -= right_edge->dy;
   1.891 ++		}
   1.892 + 	    }
   1.893 + 	}
   1.894 + 
   1.895 +@@ -1472,6 +1542,7 @@ apply_evenodd_fill_rule_and_step_edges (struct active_list *active,
   1.896 +     left_edge = *cursor;
   1.897 +     while (NULL != left_edge) {
   1.898 + 	struct edge *right_edge;
   1.899 ++	int winding = left_edge->dir;
   1.900 + 
   1.901 + 	left_edge->height_left -= GRID_Y;
   1.902 + 	if (left_edge->height_left)
   1.903 +@@ -1490,17 +1561,22 @@ apply_evenodd_fill_rule_and_step_edges (struct active_list *active,
   1.904 + 	    else
   1.905 + 		*cursor = right_edge->next;
   1.906 + 
   1.907 ++	    winding += right_edge->dir;
   1.908 ++	    if ((winding & 1) == 0) {
   1.909 + 	    if (right_edge->next == NULL ||
   1.910 + 		right_edge->next->x.quo != right_edge->x.quo)
   1.911 + 	    {
   1.912 + 		break;
   1.913 + 	    }
   1.914 ++	    }
   1.915 + 
   1.916 +-	    right_edge->x.quo += right_edge->dxdy_full.quo;
   1.917 +-	    right_edge->x.rem += right_edge->dxdy_full.rem;
   1.918 +-	    if (right_edge->x.rem >= 0) {
   1.919 +-		++right_edge->x.quo;
   1.920 +-		right_edge->x.rem -= right_edge->dy;
   1.921 ++	    if (! right_edge->vertical) {
   1.922 ++		right_edge->x.quo += right_edge->dxdy_full.quo;
   1.923 ++		right_edge->x.rem += right_edge->dxdy_full.rem;
   1.924 ++		if (right_edge->x.rem >= 0) {
   1.925 ++		    ++right_edge->x.quo;
   1.926 ++		    right_edge->x.rem -= right_edge->dy;
   1.927 ++		}
   1.928 + 	    }
   1.929 + 	}
   1.930 + 
   1.931 +@@ -1537,8 +1613,14 @@ blit_span(
   1.932 +     }
   1.933 + }
   1.934 + 
   1.935 +-#define GLITTER_BLIT_COVERAGES(coverages, y, xmin, xmax) \
   1.936 +-	blit_cells(coverages, raster_pixels + (y)*raster_stride, xmin, xmax)
   1.937 ++#define GLITTER_BLIT_COVERAGES(coverages, y, height, xmin, xmax) \
   1.938 ++    do { \
   1.939 ++	int __y = y; \
   1.940 ++	int __h = height; \
   1.941 ++	do { \
   1.942 ++	    blit_cells(coverages, raster_pixels + (__y)*raster_stride, xmin, xmax); \
   1.943 ++	} while (--__h); \
   1.944 ++    } while (0)
   1.945 + 
   1.946 + static void
   1.947 + blit_cells(
   1.948 +@@ -1597,7 +1679,6 @@ static void
   1.949 + _glitter_scan_converter_fini(glitter_scan_converter_t *converter)
   1.950 + {
   1.951 +     polygon_fini(converter->polygon);
   1.952 +-    active_list_fini(converter->active);
   1.953 +     cell_list_fini(converter->coverages);
   1.954 +     converter->xmin=0;
   1.955 +     converter->ymin=0;
   1.956 +@@ -1641,7 +1722,7 @@ glitter_scan_converter_reset(
   1.957 + 
   1.958 +     active_list_reset(converter->active);
   1.959 +     cell_list_reset(converter->coverages);
   1.960 +-    status = polygon_reset(converter->polygon, ymin, ymax);
   1.961 ++    status = polygon_reset(converter->polygon, xmin, xmax, ymin, ymax);
   1.962 +     if (status)
   1.963 + 	return status;
   1.964 + 
   1.965 +@@ -1711,19 +1792,48 @@ glitter_scan_converter_add_edge (glitter_scan_converter_t *converter,
   1.966 + #endif
   1.967 + 
   1.968 + #ifndef GLITTER_BLIT_COVERAGES_EMPTY
   1.969 +-# define GLITTER_BLIT_COVERAGES_EMPTY(y, xmin, xmax)
   1.970 ++# define GLITTER_BLIT_COVERAGES_EMPTY(y0, y1, xmin, xmax)
   1.971 + #endif
   1.972 + 
   1.973 ++static cairo_bool_t
   1.974 ++active_list_is_vertical (struct active_list *active)
   1.975 ++{
   1.976 ++    struct edge *e;
   1.977 ++
   1.978 ++    for (e = active->head; e != NULL; e = e->next) {
   1.979 ++	if (! e->vertical)
   1.980 ++	    return FALSE;
   1.981 ++    }
   1.982 ++
   1.983 ++    return TRUE;
   1.984 ++}
   1.985 ++
   1.986 ++static void
   1.987 ++step_edges (struct active_list *active, int count)
   1.988 ++{
   1.989 ++    struct edge **cursor = &active->head;
   1.990 ++    struct edge *edge;
   1.991 ++
   1.992 ++    for (edge = *cursor; edge != NULL; edge = *cursor) {
   1.993 ++	edge->height_left -= GRID_Y * count;
   1.994 ++	if (edge->height_left)
   1.995 ++	    cursor = &edge->next;
   1.996 ++	else
   1.997 ++	    *cursor = edge->next;
   1.998 ++    }
   1.999 ++}
  1.1000 ++
  1.1001 + I glitter_status_t
  1.1002 + glitter_scan_converter_render(
  1.1003 +     glitter_scan_converter_t *converter,
  1.1004 +     int nonzero_fill,
  1.1005 +     GLITTER_BLIT_COVERAGES_ARGS)
  1.1006 + {
  1.1007 +-    int i;
  1.1008 ++    int i, j;
  1.1009 +     int ymax_i = converter->ymax / GRID_Y;
  1.1010 +     int ymin_i = converter->ymin / GRID_Y;
  1.1011 +     int xmin_i, xmax_i;
  1.1012 ++    grid_scaled_x_t xmin = converter->xmin;
  1.1013 +     int h = ymax_i - ymin_i;
  1.1014 +     struct polygon *polygon = converter->polygon;
  1.1015 +     struct cell_list *coverages = converter->coverages;
  1.1016 +@@ -1738,22 +1848,28 @@ glitter_scan_converter_render(
  1.1017 +     GLITTER_BLIT_COVERAGES_BEGIN;
  1.1018 + 
  1.1019 +     /* Render each pixel row. */
  1.1020 +-    for (i=0; i<h; i++) {
  1.1021 ++    for (i = 0; i < h; i = j) {
  1.1022 + 	int do_full_step = 0;
  1.1023 + 	glitter_status_t status = 0;
  1.1024 + 
  1.1025 ++	j = i + 1;
  1.1026 ++
  1.1027 + 	/* Determine if we can ignore this row or use the full pixel
  1.1028 + 	 * stepper. */
  1.1029 +-	if (GRID_Y == EDGE_Y_BUCKET_HEIGHT && ! polygon->y_buckets[i]) {
  1.1030 ++	if (polygon->y_buckets[i].edges == NULL) {
  1.1031 + 	    if (! active->head) {
  1.1032 +-		GLITTER_BLIT_COVERAGES_EMPTY (i+ymin_i, xmin_i, xmax_i);
  1.1033 ++		for (; j < h && ! polygon->y_buckets[j].edges; j++)
  1.1034 ++		    ;
  1.1035 ++		GLITTER_BLIT_COVERAGES_EMPTY (i+ymin_i, j-i, xmin_i, xmax_i);
  1.1036 + 		continue;
  1.1037 + 	    }
  1.1038 +-
  1.1039 +-	    do_full_step = active_list_can_step_full_row (active);
  1.1040 ++	    do_full_step = active_list_can_step_full_row (active, xmin);
  1.1041 ++	}
  1.1042 ++	else if (! polygon->y_buckets[i].have_inside_edges) {
  1.1043 ++	    grid_scaled_y_t y = (i+ymin_i)*GRID_Y;
  1.1044 ++	    active_list_merge_edges_from_polygon (active, y, polygon);
  1.1045 ++	    do_full_step = active_list_can_step_full_row (active, xmin);
  1.1046 + 	}
  1.1047 +-
  1.1048 +-	cell_list_reset (coverages);
  1.1049 + 
  1.1050 + 	if (do_full_step) {
  1.1051 + 	    /* Step by a full pixel row's worth. */
  1.1052 +@@ -1764,8 +1880,20 @@ glitter_scan_converter_render(
  1.1053 + 		status = apply_evenodd_fill_rule_and_step_edges (active,
  1.1054 + 								 coverages);
  1.1055 + 	    }
  1.1056 ++
  1.1057 ++	    if (active_list_is_vertical (active)) {
  1.1058 ++		while (j < h &&
  1.1059 ++		       polygon->y_buckets[j].edges == NULL &&
  1.1060 ++		       active->min_height >= 2*GRID_Y)
  1.1061 ++		{
  1.1062 ++		    active->min_height -= GRID_Y;
  1.1063 ++		    j++;
  1.1064 ++		}
  1.1065 ++		if (j != i + 1)
  1.1066 ++		    step_edges (active, j - (i + 1));
  1.1067 ++	    }
  1.1068 + 	} else {
  1.1069 +-	    /* Subsample this row. */
  1.1070 ++	    /* Supersample this row. */
  1.1071 + 	    grid_scaled_y_t suby;
  1.1072 + 	    for (suby = 0; suby < GRID_Y; suby++) {
  1.1073 + 		grid_scaled_y_t y = (i+ymin_i)*GRID_Y + suby;
  1.1074 +@@ -1787,13 +1915,13 @@ glitter_scan_converter_render(
  1.1075 + 	if (unlikely (status))
  1.1076 + 	    return status;
  1.1077 + 
  1.1078 +-	GLITTER_BLIT_COVERAGES(coverages, i+ymin_i, xmin_i, xmax_i);
  1.1079 ++	GLITTER_BLIT_COVERAGES(coverages, i+ymin_i, j-i, xmin_i, xmax_i);
  1.1080 ++	cell_list_reset (coverages);
  1.1081 + 
  1.1082 +-	if (! active->head) {
  1.1083 ++	if (! active->head)
  1.1084 + 	    active->min_height = INT_MAX;
  1.1085 +-	} else {
  1.1086 ++	else
  1.1087 + 	    active->min_height -= GRID_Y;
  1.1088 +-	}
  1.1089 +     }
  1.1090 + 
  1.1091 +     /* Clean up the coverage blitter. */
  1.1092 +@@ -1807,21 +1935,20 @@ glitter_scan_converter_render(
  1.1093 +  * scan converter subclass. */
  1.1094 + 
  1.1095 + static glitter_status_t
  1.1096 +-blit_with_span_renderer(
  1.1097 +-    struct cell_list *cells,
  1.1098 +-    cairo_span_renderer_t *renderer,
  1.1099 +-    struct pool *span_pool,
  1.1100 +-    int y,
  1.1101 +-    int xmin,
  1.1102 +-    int xmax)
  1.1103 ++blit_with_span_renderer (struct cell_list *cells,
  1.1104 ++			 cairo_span_renderer_t *renderer,
  1.1105 ++			 struct pool *span_pool,
  1.1106 ++			 int y, int height,
  1.1107 ++			 int xmin, int xmax)
  1.1108 + {
  1.1109 +     struct cell *cell = cells->head;
  1.1110 +     int prev_x = xmin;
  1.1111 +     int cover = 0;
  1.1112 +     cairo_half_open_span_t *spans;
  1.1113 +     unsigned num_spans;
  1.1114 ++
  1.1115 +     if (cell == NULL)
  1.1116 +-	return CAIRO_STATUS_SUCCESS;
  1.1117 ++	return blit_empty_with_span_renderer (renderer, y, height);
  1.1118 + 
  1.1119 +     /* Skip cells to the left of the clip region. */
  1.1120 +     while (cell != NULL && cell->x < xmin) {
  1.1121 +@@ -1833,12 +1960,12 @@ blit_with_span_renderer(
  1.1122 +     /* Count number of cells remaining. */
  1.1123 +     {
  1.1124 + 	struct cell *next = cell;
  1.1125 +-	num_spans = 0;
  1.1126 +-	while (next) {
  1.1127 ++	num_spans = 1;
  1.1128 ++	while (next != NULL) {
  1.1129 + 	    next = next->next;
  1.1130 + 	    ++num_spans;
  1.1131 + 	}
  1.1132 +-	num_spans = 2*num_spans + 1;
  1.1133 ++	num_spans = 2*num_spans;
  1.1134 +     }
  1.1135 + 
  1.1136 +     /* Allocate enough spans for the row. */
  1.1137 +@@ -1853,6 +1980,7 @@ blit_with_span_renderer(
  1.1138 +     for (; cell != NULL; cell = cell->next) {
  1.1139 + 	int x = cell->x;
  1.1140 + 	int area;
  1.1141 ++
  1.1142 + 	if (x >= xmax)
  1.1143 + 	    break;
  1.1144 + 
  1.1145 +@@ -1872,20 +2000,26 @@ blit_with_span_renderer(
  1.1146 + 	prev_x = x+1;
  1.1147 +     }
  1.1148 + 
  1.1149 +-    if (prev_x < xmax) {
  1.1150 ++    if (prev_x <= xmax) {
  1.1151 + 	spans[num_spans].x = prev_x;
  1.1152 + 	spans[num_spans].coverage = GRID_AREA_TO_ALPHA (cover);
  1.1153 + 	++num_spans;
  1.1154 +     }
  1.1155 + 
  1.1156 ++    if (prev_x < xmax && cover) {
  1.1157 ++	spans[num_spans].x = xmax;
  1.1158 ++	spans[num_spans].coverage = 0;
  1.1159 ++	++num_spans;
  1.1160 ++    }
  1.1161 ++
  1.1162 +     /* Dump them into the renderer. */
  1.1163 +-    return renderer->render_row (renderer, y, spans, num_spans);
  1.1164 ++    return renderer->render_rows (renderer, y, height, spans, num_spans);
  1.1165 + }
  1.1166 + 
  1.1167 + static glitter_status_t
  1.1168 +-blit_empty_with_span_renderer (cairo_span_renderer_t *renderer, int y)
  1.1169 ++blit_empty_with_span_renderer (cairo_span_renderer_t *renderer, int y, int height)
  1.1170 + {
  1.1171 +-    return renderer->render_row (renderer, y, NULL, 0);
  1.1172 ++    return renderer->render_rows (renderer, y, height, NULL, 0);
  1.1173 + }
  1.1174 + 
  1.1175 + struct _cairo_tor_scan_converter {
  1.1176 +diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
  1.1177 +index 82d1cf5..d4575a3 100644
  1.1178 +--- a/src/cairo-win32-surface.c
  1.1179 ++++ b/src/cairo-win32-surface.c
  1.1180 +@@ -1954,6 +1954,9 @@ typedef struct _cairo_win32_surface_span_renderer {
  1.1181 +     const cairo_pattern_t *pattern;
  1.1182 +     cairo_antialias_t antialias;
  1.1183 + 
  1.1184 ++    uint8_t *mask_data;
  1.1185 ++    uint32_t mask_stride;
  1.1186 ++
  1.1187 +     cairo_image_surface_t *mask;
  1.1188 +     cairo_win32_surface_t *dst;
  1.1189 +     cairo_region_t *clip_region;
  1.1190 +@@ -1962,14 +1965,16 @@ typedef struct _cairo_win32_surface_span_renderer {
  1.1191 + } cairo_win32_surface_span_renderer_t;
  1.1192 + 
  1.1193 + static cairo_status_t
  1.1194 +-_cairo_win32_surface_span_renderer_render_row (
  1.1195 ++_cairo_win32_surface_span_renderer_render_rows (
  1.1196 +     void				*abstract_renderer,
  1.1197 +     int					 y,
  1.1198 ++    int					 height,
  1.1199 +     const cairo_half_open_span_t	*spans,
  1.1200 +     unsigned				 num_spans)
  1.1201 + {
  1.1202 +     cairo_win32_surface_span_renderer_t *renderer = abstract_renderer;
  1.1203 +-    _cairo_image_surface_span_render_row (y, spans, num_spans, renderer->mask, &renderer->composite_rectangles);
  1.1204 ++    while (height--)
  1.1205 ++	_cairo_image_surface_span_render_row (y++, spans, num_spans, renderer->mask_data, renderer->mask_stride);
  1.1206 +     return CAIRO_STATUS_SUCCESS;
  1.1207 + }
  1.1208 + 
  1.1209 +@@ -2066,8 +2071,7 @@ _cairo_win32_surface_create_span_renderer (cairo_operator_t	 op,
  1.1210 + 
  1.1211 +     renderer->base.destroy = _cairo_win32_surface_span_renderer_destroy;
  1.1212 +     renderer->base.finish = _cairo_win32_surface_span_renderer_finish;
  1.1213 +-    renderer->base.render_row =
  1.1214 +-	_cairo_win32_surface_span_renderer_render_row;
  1.1215 ++    renderer->base.render_rows = _cairo_win32_surface_span_renderer_render_rows;
  1.1216 +     renderer->op = op;
  1.1217 +     renderer->pattern = pattern;
  1.1218 +     renderer->antialias = antialias;
  1.1219 +@@ -2088,6 +2092,9 @@ _cairo_win32_surface_create_span_renderer (cairo_operator_t	 op,
  1.1220 + 	_cairo_win32_surface_span_renderer_destroy (renderer);
  1.1221 + 	return _cairo_span_renderer_create_in_error (status);
  1.1222 +     }
  1.1223 ++
  1.1224 ++    renderer->mask_data = renderer->mask->data - rects->mask.x - rects->mask.y * renderer->mask->stride;
  1.1225 ++    renderer->mask_stride = renderer->mask->stride;
  1.1226 +     return &renderer->base;
  1.1227 + }
  1.1228 + 
  1.1229 +diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c
  1.1230 +index a7a40b8..566d9fb 100644
  1.1231 +--- a/src/cairo-xlib-display.c
  1.1232 ++++ b/src/cairo-xlib-display.c
  1.1233 +@@ -407,6 +407,10 @@ _cairo_xlib_display_get (Display *dpy,
  1.1234 + 	display->buggy_pad_reflect = TRUE;
  1.1235 +     }
  1.1236 + 
  1.1237 ++    /* gradients don't seem to work */
  1.1238 ++    display->buggy_gradients = TRUE;
  1.1239 ++
  1.1240 ++
  1.1241 +     /* XXX workaround; see https://bugzilla.mozilla.org/show_bug.cgi?id=413583 */
  1.1242 +     /* If buggy_repeat_force == -1, then initialize.
  1.1243 +      *    - set to -2, meaning "nothing was specified", and we trust the above detection.
  1.1244 +diff --git a/src/cairoint.h b/src/cairoint.h
  1.1245 +index 58850ab..1cdf6ff 100644
  1.1246 +--- a/src/cairoint.h
  1.1247 ++++ b/src/cairoint.h
  1.1248 +@@ -2257,8 +2257,8 @@ cairo_private void
  1.1249 + _cairo_image_surface_span_render_row (int				 y,
  1.1250 + 				      const cairo_half_open_span_t	 *spans,
  1.1251 + 				      unsigned				 num_spans,
  1.1252 +-				      cairo_image_surface_t              *mask,
  1.1253 +-				      const cairo_composite_rectangles_t *rects);
  1.1254 ++				      uint8_t				*data,
  1.1255 ++				      uint32_t				 stride);
  1.1256 + 
  1.1257 + cairo_private cairo_image_transparency_t
  1.1258 + _cairo_image_analyze_transparency (cairo_image_surface_t      *image);

mercurial