static cairo_int_status_t
base_compositor_fill (const cairo_compositor_t *_compositor,
		      cairo_composite_rectangles_t *extents,
		      const cairo_path_fixed_t	*path,
		      cairo_fill_rule_t		 fill_rule,
		      double			 tolerance,
		      cairo_antialias_t		 antialias)
{
    composite_traps_info_t info;
    cairo_int_status_t status;

    TRACE ((stderr, "%s\n", __FUNCTION__));

    info.antialias = antialias;
    _cairo_traps_init_with_clip (&info.traps, extents->clip);
    status = _cairo_path_fixed_fill_to_traps (path,
					      fill_rule, tolerance,
					      &info.traps);
    if (likely (status == CAIRO_INT_STATUS_SUCCESS))
	status = trim_extents_to_traps (extents, &info.traps);
    if (likely (status == CAIRO_INT_STATUS_SUCCESS))
	status = clip_and_composite (extents, composite_traps, &info);
    _cairo_traps_fini (&info.traps);

    return status;
}
cairo_status_t
_cairo_surface_fallback_fill (cairo_surface_t		*surface,
			      cairo_operator_t		 op,
			      cairo_pattern_t		*source,
			      cairo_path_fixed_t	*path,
			      cairo_fill_rule_t		 fill_rule,
			      double			 tolerance,
			      cairo_antialias_t		 antialias)
{
    cairo_status_t status;
    cairo_traps_t traps;
    cairo_box_t box;
    cairo_rectangle_int_t extents;

    status = _cairo_surface_get_extents (surface, &extents);
    if (status)
        return status;

    if (_cairo_operator_bounded_by_source (op)) {
	cairo_rectangle_int_t source_extents;
	status = _cairo_pattern_get_extents (source, &source_extents);
	if (status)
	    return status;

	_cairo_rectangle_intersect (&extents, &source_extents);
    }

    status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents);
    if (status)
        return status;

    box.p1.x = _cairo_fixed_from_int (extents.x);
    box.p1.y = _cairo_fixed_from_int (extents.y);
    box.p2.x = _cairo_fixed_from_int (extents.x + extents.width);
    box.p2.y = _cairo_fixed_from_int (extents.y + extents.height);

    _cairo_traps_init (&traps);

    _cairo_traps_limit (&traps, &box);

    status = _cairo_path_fixed_fill_to_traps (path,
					      fill_rule,
					      tolerance,
					      &traps);
    if (status) {
	_cairo_traps_fini (&traps);
	return status;
    }

    status = _clip_and_composite_trapezoids (source,
					     op,
					     surface,
					     &traps,
					     surface->clip,
					     antialias);

    _cairo_traps_fini (&traps);

    return status;
}
Beispiel #3
0
static cairo_status_t
_cairo_clip_path_intersect_to_rectangle (cairo_clip_path_t       *clip_path,
				         cairo_rectangle_int_t   *rectangle)
{
    while (clip_path) {
        cairo_status_t status;
        cairo_traps_t traps;
        cairo_box_t extents;
        cairo_rectangle_int_t extents_rect;

        _cairo_traps_init (&traps);

        status = _cairo_path_fixed_fill_to_traps (&clip_path->path,
                                                  clip_path->fill_rule,
                                                  clip_path->tolerance,
                                                  &traps);
        if (status) {
            _cairo_traps_fini (&traps);
            return status;
        }

        _cairo_traps_extents (&traps, &extents);
        _cairo_box_round_to_rectangle (&extents, &extents_rect);
        _cairo_rectangle_intersect (rectangle, &extents_rect);

        _cairo_traps_fini (&traps);

        clip_path = clip_path->prev;
    }

    return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_surface_fallback_fill (cairo_surface_t		*surface,
			      cairo_operator_t		 op,
			      cairo_pattern_t		*source,
			      cairo_path_fixed_t	*path,
			      cairo_fill_rule_t		 fill_rule,
			      double			 tolerance,
			      cairo_antialias_t		 antialias)
{
    cairo_status_t status;
    cairo_traps_t traps;

    _cairo_traps_init (&traps);

    status = _cairo_path_fixed_fill_to_traps (path,
					      fill_rule,
					      tolerance,
					      &traps);
    if (status) {
	_cairo_traps_fini (&traps);
	return status;
    }

    status = _clip_and_composite_trapezoids (source,
					     op,
					     surface,
					     &traps,
					     surface->clip,
					     antialias);

    _cairo_traps_fini (&traps);

    return status;
}
Beispiel #5
0
cairo_status_t
_cairo_clip_clip (cairo_clip_t       *clip,
		  cairo_path_fixed_t *path,
		  cairo_fill_rule_t   fill_rule,
		  double              tolerance,
		  cairo_antialias_t   antialias,
		  cairo_surface_t    *target)
{
    cairo_status_t status;
    cairo_traps_t traps;
    cairo_path_fixed_t path_transformed;

    if (_cairo_surface_has_device_offset_or_scale (target)) {
	_cairo_path_fixed_init_copy (&path_transformed, path);
	_cairo_path_fixed_offset (&path_transformed,
				  _cairo_fixed_from_double (target->device_x_offset),
				  _cairo_fixed_from_double (target->device_y_offset));
	path = &path_transformed;
    }
    
    status = _cairo_clip_intersect_path (clip,
					 path, fill_rule, tolerance,
					 antialias);
    if (status == CAIRO_STATUS_SUCCESS)
        clip->serial = _cairo_surface_allocate_clip_serial (target);

    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	return status;


    _cairo_traps_init (&traps);
    status = _cairo_path_fixed_fill_to_traps (path,
					      fill_rule,
					      tolerance,
					      &traps);
    if (status)
	goto bail;

    status = _cairo_clip_intersect_region (clip, &traps, target);
    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	goto bail;

    status = _cairo_clip_intersect_mask (clip, &traps, antialias, target);
	
 bail:
    _cairo_traps_fini (&traps);
    if (path == &path_transformed)
	_cairo_path_fixed_fini (&path_transformed);

    return status;
}
Beispiel #6
0
cairo_status_t
_cairo_clip_clip (cairo_clip_t       *clip,
		  cairo_path_fixed_t *path,
		  cairo_fill_rule_t   fill_rule,
		  double              tolerance,
		  cairo_antialias_t   antialias,
		  cairo_surface_t    *target)
{
    cairo_status_t status;
    cairo_traps_t traps;

    if (clip->all_clipped)
	return CAIRO_STATUS_SUCCESS;

    /* catch the empty clip path */
    if (! path->has_current_point) {
	_cairo_clip_set_all_clipped (clip, target);
	return CAIRO_STATUS_SUCCESS;
    }

    status = _cairo_clip_intersect_path (clip,
					 path, fill_rule, tolerance,
					 antialias);
    if (status == CAIRO_STATUS_SUCCESS)
        clip->serial = _cairo_surface_allocate_clip_serial (target);

    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	return status;

    _cairo_traps_init (&traps);
    status = _cairo_path_fixed_fill_to_traps (path,
					      fill_rule,
					      tolerance,
					      &traps);
    if (status)
	goto bail;

    status = _cairo_clip_intersect_region (clip, &traps, target);
    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	goto bail;

    status = _cairo_clip_intersect_mask (clip, &traps, antialias, target);

 bail:
    _cairo_traps_fini (&traps);

    return status;
}
static cairo_int_status_t
_cairo_gl_msaa_compositor_fill (const cairo_compositor_t	*compositor,
				cairo_composite_rectangles_t	*composite,
				const cairo_path_fixed_t	*path,
				cairo_fill_rule_t		 fill_rule,
				double				 tolerance,
				cairo_antialias_t		 antialias)
{
    cairo_gl_composite_t setup;
    cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
    cairo_gl_context_t *ctx = NULL;
    cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
    cairo_traps_t traps;
    cairo_bool_t use_color_attr = FALSE;

    if (! can_use_msaa_compositor (dst, antialias))
	return CAIRO_INT_STATUS_UNSUPPORTED;

    if (composite->is_bounded == FALSE) {
	cairo_surface_t* surface = _prepare_unbounded_surface (dst);

	if (unlikely (surface == NULL))
	    return CAIRO_INT_STATUS_UNSUPPORTED;


	status = _cairo_compositor_fill (compositor, surface,
					 CAIRO_OPERATOR_SOURCE,
					 &composite->source_pattern.base,
					 path, fill_rule, tolerance,
					 antialias, NULL);

	if (unlikely (status)) {
	    cairo_surface_destroy (surface);
	    return status;
	}

	return _paint_back_unbounded_surface (compositor, composite, surface);
    }

    if (_cairo_path_fixed_fill_is_rectilinear (path) &&
	composite->clip != NULL &&
	composite->clip->num_boxes == 1 &&
	composite->clip->path == NULL) {
	cairo_clip_t *clip = _cairo_clip_copy (composite->clip);
	clip = _cairo_clip_intersect_rectilinear_path (clip,
						       path,
						       fill_rule,
						       antialias);
	if (clip->num_boxes)
		status = _cairo_gl_msaa_compositor_fill_rectilinear (compositor,
								     composite,
								     path,
								     fill_rule,
								     tolerance,
								     antialias,
								     clip);
	_cairo_clip_destroy (clip);

	return status;
    }

    status = _cairo_gl_composite_init (&setup,
				       composite->op,
				       dst,
				       FALSE /* assume_component_alpha */);
    if (unlikely (status)) {
        _cairo_gl_composite_fini (&setup);
	return status;
    }

    _cairo_traps_init (&traps);

    if (_cairo_path_fixed_fill_is_rectilinear (path)) {
	status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
							      fill_rule,
							      antialias,
							      &traps);
	use_color_attr = TRUE;
    } else
	status = _cairo_path_fixed_fill_to_traps (path, fill_rule,
						  tolerance, &traps);
    if (unlikely (status))
	goto cleanup_traps;

    status = _cairo_gl_composite_set_source (&setup,
					     composite->original_source_pattern,
					     &composite->source_sample_area,
					     &composite->bounded,
					     use_color_attr);
    if (unlikely (status))
	goto cleanup_setup;

    _cairo_gl_msaa_compositor_set_clip (composite, &setup);

    status = _cairo_gl_composite_begin_multisample (&setup, &ctx,
	antialias != CAIRO_ANTIALIAS_NONE);
    if (unlikely (status))
	goto cleanup_setup;

    status = _draw_traps (ctx, &setup, &traps);
    if (unlikely (status))
        goto cleanup_setup;

cleanup_setup:
    _cairo_gl_composite_fini (&setup);

    if (ctx)
	status = _cairo_gl_context_release (ctx, status);

cleanup_traps:
    _cairo_traps_fini (&traps);

    return status;
}
Beispiel #8
0
cairo_status_t
_cairo_clip_clip (cairo_clip_t       *clip,
		  cairo_path_fixed_t *path,
		  cairo_fill_rule_t   fill_rule,
		  double              tolerance,
		  cairo_antialias_t   antialias,
		  cairo_surface_t    *target)
{
    cairo_status_t status;
    cairo_rectangle_int_t rectangle;
    cairo_traps_t traps;
    cairo_box_t ignored_box;

    if (clip->all_clipped)
	return CAIRO_STATUS_SUCCESS;

    /* catch the empty clip path */
    if (! path->has_current_point) {
	_cairo_clip_set_all_clipped (clip, target);
	return CAIRO_STATUS_SUCCESS;
    }

    status = _cairo_clip_intersect_path (clip,
					 path, fill_rule, tolerance,
					 antialias);
    if (status == CAIRO_STATUS_SUCCESS)
        clip->serial = _cairo_surface_allocate_clip_serial (target);

    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	return status;

    /* TODO: allow ANTIALIAS_NONE when we have a mono scan converter
     * again. */
    if (antialias != CAIRO_ANTIALIAS_NONE &&
	!_cairo_path_fixed_is_box (path, &ignored_box) &&
	!_cairo_path_fixed_is_region (path))
    {
	status = _cairo_clip_intersect_mask_using_spans (
	    clip, path, fill_rule, tolerance, antialias, target);
	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	    return status;
    }

    _cairo_traps_init (&traps);

    /* Limit the traps to the target surface
     * - so we don't add more traps than needed. */
    status = _cairo_surface_get_extents (target, &rectangle);
    if (status == CAIRO_STATUS_SUCCESS) {
	cairo_box_t box;

	_cairo_box_from_rectangle (&box, &rectangle);
	_cairo_traps_limit (&traps, &box);
    }

    status = _cairo_path_fixed_fill_to_traps (path,
					      fill_rule,
					      tolerance,
					      &traps);
    if (unlikely (status))
	goto bail;

    status = _cairo_clip_intersect_region (clip, &traps, target);
    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	goto bail;

    status = _cairo_clip_intersect_mask (clip, &traps, antialias, target);

 bail:
    _cairo_traps_fini (&traps);

    return status;
}
cairo_status_t
_cairo_surface_fallback_fill (cairo_surface_t		*surface,
			      cairo_operator_t		 op,
			      const cairo_pattern_t	*source,
			      cairo_path_fixed_t	*path,
			      cairo_fill_rule_t		 fill_rule,
			      double			 tolerance,
			      cairo_antialias_t		 antialias)
{
    cairo_status_t status;
    cairo_traps_t traps;
    cairo_box_t box;
    cairo_rectangle_int_t extents;

    status = _cairo_surface_get_extents (surface, &extents);
    if (unlikely (status))
        return status;

    if (_cairo_operator_bounded_by_source (op)) {
	cairo_rectangle_int_t source_extents;

	status = _cairo_pattern_get_extents (source, &source_extents);
	if (unlikely (status))
	    return status;

	if (! _cairo_rectangle_intersect (&extents, &source_extents))
	    return CAIRO_STATUS_SUCCESS;
    }

    status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents);
    if (unlikely (status))
        return status;

    if (extents.width == 0 || extents.height == 0)
	return CAIRO_STATUS_SUCCESS;

    /* Ask if the surface would like to render this combination of
     * op/source/dst/antialias with spans or not, but don't actually
     * make a renderer yet.  We'll try to hit the region optimisations
     * in _clip_and_composite_trapezoids() if it looks like the path
     * is a region. */
    /* TODO: Until we have a mono scan converter we won't even try
     * to use spans for CAIRO_ANTIALIAS_NONE. */
    /* TODO: The region filling code should be lifted from
     * _clip_and_composite_trapezoids() and given first priority
     * explicitly before deciding between spans and trapezoids. */
    if (antialias != CAIRO_ANTIALIAS_NONE &&
	!_cairo_path_fixed_is_box (path, &box) &&
	!_cairo_path_fixed_is_region (path) &&
	_cairo_surface_check_span_renderer (
	    op, source, surface, antialias, NULL))
    {
	cairo_composite_spans_fill_info_t info;
	info.path = path;
	info.fill_rule = fill_rule;
	info.tolerance = tolerance;
	info.antialias = antialias;

	if (_cairo_operator_bounded_by_mask (op)) {
	    cairo_rectangle_int_t path_extents;

	    _cairo_path_fixed_approximate_clip_extents (path,
							&path_extents);
	    if (! _cairo_rectangle_intersect (&extents, &path_extents))
		return CAIRO_STATUS_SUCCESS;
	}

	return _clip_and_composite (
	    surface->clip, op, source,
	    _composite_spans_fill_func,
	    &info,
	    surface,
	    &extents);
    }

    /* Fall back to trapezoid fills. */
    _cairo_box_from_rectangle (&box, &extents);
    _cairo_traps_init (&traps);
    _cairo_traps_limit (&traps, &box);

    status = _cairo_path_fixed_fill_to_traps (path,
					      fill_rule,
					      tolerance,
					      &traps);
    if (unlikely (status)) {
	_cairo_traps_fini (&traps);
	return status;
    }

    status = _clip_and_composite_trapezoids (source,
					     op,
					     surface,
					     &traps,
					     surface->clip,
					     antialias);

    _cairo_traps_fini (&traps);

    return status;
}
static cairo_int_status_t
_cairo_gl_msaa_compositor_fill (const cairo_compositor_t	*compositor,
				cairo_composite_rectangles_t	*composite,
				const cairo_path_fixed_t	*path,
				cairo_fill_rule_t		 fill_rule,
				double				 tolerance,
				cairo_antialias_t		 antialias)
{
    cairo_gl_composite_t setup;
    cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
    cairo_gl_context_t *ctx = NULL;
    cairo_int_status_t status;
    cairo_traps_t traps;
    cairo_bool_t used_stencil_buffer;

    if (antialias != CAIRO_ANTIALIAS_NONE)
	return CAIRO_INT_STATUS_UNSUPPORTED;

    _cairo_traps_init (&traps);
    status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps);
    if (unlikely (status))
	goto cleanup_traps;

    status = _cairo_gl_composite_init (&setup,
				       composite->op,
				       dst,
				       FALSE, /* assume_component_alpha */
				       &composite->bounded);
    if (unlikely (status))
	goto cleanup_traps;

    status = _cairo_gl_composite_set_source (&setup,
					     &composite->source_pattern.base,
					     &composite->source_sample_area,
					     &composite->bounded);
    if (unlikely (status))
	goto cleanup_setup;

    status = _cairo_gl_composite_begin_tristrip (&setup, &ctx);
    if (unlikely (status))
	goto cleanup_setup;

    status = _scissor_and_clip (ctx, &setup, composite,
				&used_stencil_buffer);
    if (unlikely (status))
	goto cleanup_setup;

    status = _draw_traps (ctx, &setup, &traps);
    if (unlikely (status))
        goto cleanup_setup;

    _cairo_gl_composite_flush (ctx);
cleanup_setup:
    _cairo_gl_composite_fini (&setup);

    if (ctx) {
	glDisable (GL_SCISSOR_TEST);
	_disable_stencil_buffer ();
	status = _cairo_gl_context_release (ctx, status);
    }
cleanup_traps:
    _cairo_traps_fini (&traps);

    return status;
}
static cairo_int_status_t
_cairo_analysis_surface_fill (void			*abstract_surface,
			      cairo_operator_t		 op,
			      cairo_pattern_t		*source,
			      cairo_path_fixed_t	*path,
			      cairo_fill_rule_t		 fill_rule,
			      double			 tolerance,
			      cairo_antialias_t		 antialias)
{
    cairo_analysis_surface_t *surface = abstract_surface;
    cairo_status_t	     status, backend_status;
    cairo_traps_t            traps;
    cairo_rectangle_int_t  extents;

    if (!surface->target->backend->fill)
	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
    else
	backend_status = (*surface->target->backend->fill) (surface->target, op,
						    source, path, fill_rule,
						    tolerance, antialias);

    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
	backend_status = _analyze_meta_surface_pattern (surface, source);

    status = _cairo_surface_get_extents (&surface->base, &extents);
    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
	return status;

    if (_cairo_operator_bounded_by_source (op)) {
	cairo_rectangle_int_t source_extents;
	status = _cairo_pattern_get_extents (source, &source_extents);
	if (status)
	    return status;

	_cairo_rectangle_intersect (&extents, &source_extents);
    }

    _cairo_rectangle_intersect (&extents, &surface->current_clip);

    if (_cairo_operator_bounded_by_mask (op)) {
	cairo_box_t box;

	_cairo_box_from_rectangle (&box, &extents);

	_cairo_traps_init (&traps);
	_cairo_traps_limit (&traps, &box);
	status = _cairo_path_fixed_fill_to_traps (path,
						  fill_rule,
						  tolerance,
						  &traps);
	if (status) {
	    _cairo_traps_fini (&traps);
	    return status;
	}

	_cairo_traps_extents (&traps, &box);
	_cairo_traps_fini (&traps);

        _cairo_box_round_to_rectangle (&box, &extents);
    }

    status = _add_operation (surface, &extents, backend_status);

    return status;
}
static cairo_int_status_t
_cairo_clip_path_to_region_geometric (cairo_clip_path_t *clip_path)
{
    cairo_traps_t traps;
    cairo_box_t stack_boxes[CAIRO_STACK_ARRAY_LENGTH (cairo_box_t)];
    cairo_box_t *boxes = stack_boxes;
    cairo_status_t status;
    int n;

    /* If we have nothing to intersect with this path, then it cannot
     * magically be reduced into a region.
     */
    if (clip_path->prev == NULL)
	goto UNSUPPORTED;

    /* Start simple... Intersect some boxes with an arbitrary path. */
    if (! clip_path->path.is_rectilinear)
	goto UNSUPPORTED;
    if (clip_path->prev->prev != NULL)
	goto UNSUPPORTED;

    _cairo_traps_init (&traps);
    _cairo_box_from_rectangle (&boxes[0], &clip_path->extents);
    _cairo_traps_limit (&traps, boxes, 1);

    status = _cairo_path_fixed_fill_rectilinear_to_traps (&clip_path->path,
							  clip_path->fill_rule,
							  &traps);
    if (unlikely (_cairo_status_is_error (status)))
	return status;
    if (status == CAIRO_INT_STATUS_UNSUPPORTED)
	goto UNSUPPORTED;

    if (traps.num_traps > ARRAY_LENGTH (stack_boxes)) {
	boxes = _cairo_malloc_ab (traps.num_traps, sizeof (cairo_box_t));
	if (unlikely (boxes == NULL))
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }

    for (n = 0; n < traps.num_traps; n++) {
	boxes[n].p1.x = traps.traps[n].left.p1.x;
	boxes[n].p1.y = traps.traps[n].top;
	boxes[n].p2.x = traps.traps[n].right.p1.x;
	boxes[n].p2.y = traps.traps[n].bottom;
    }

    _cairo_traps_clear (&traps);
    _cairo_traps_limit (&traps, boxes, n);
    status = _cairo_path_fixed_fill_to_traps (&clip_path->prev->path,
					      clip_path->prev->fill_rule,
					      clip_path->prev->tolerance,
					      &traps);
    if (boxes != stack_boxes)
	free (boxes);

    if (unlikely (status))
	return status;

    status = _cairo_traps_extract_region (&traps, &clip_path->region);
    _cairo_traps_fini (&traps);

    if (status == CAIRO_INT_STATUS_UNSUPPORTED)
	goto UNSUPPORTED;
    if (unlikely (status))
	return status;

    clip_path->flags |= CAIRO_CLIP_PATH_HAS_REGION;
    return CAIRO_STATUS_SUCCESS;

UNSUPPORTED:
    clip_path->flags |= CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED;
    return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_int_status_t
_cairo_gl_msaa_compositor_fill (const cairo_compositor_t	*compositor,
                                cairo_composite_rectangles_t	*composite,
                                const cairo_path_fixed_t	*path,
                                cairo_fill_rule_t		 fill_rule,
                                double				 tolerance,
                                cairo_antialias_t		 antialias)
{
    cairo_gl_composite_t setup;
    cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
    cairo_gl_context_t *ctx = NULL;
    cairo_int_status_t status;
    cairo_traps_t traps;
    cairo_bool_t draw_path_with_traps;

    if (! can_use_msaa_compositor (dst, antialias))
        return CAIRO_INT_STATUS_UNSUPPORTED;

    if (composite->is_bounded == FALSE) {
        cairo_surface_t* surface = _prepare_unbounded_surface (dst);

        if (unlikely (surface == NULL))
            return CAIRO_INT_STATUS_UNSUPPORTED;


        status = _cairo_compositor_fill (compositor, surface,
                                         CAIRO_OPERATOR_SOURCE,
                                         &composite->source_pattern.base,
                                         path, fill_rule, tolerance,
                                         antialias, NULL);

        if (unlikely (status)) {
            cairo_surface_destroy (surface);
            return status;
        }

        return _paint_back_unbounded_surface (compositor, composite, surface);
    }

    draw_path_with_traps = ! _cairo_path_fixed_is_simple_quad (path);

    if (draw_path_with_traps) {
        _cairo_traps_init (&traps);
        status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps);
        if (unlikely (status))
            goto cleanup_traps;
    }

    status = _cairo_gl_composite_init (&setup,
                                       composite->op,
                                       dst,
                                       FALSE /* assume_component_alpha */);
    if (unlikely (status))
        goto cleanup_traps;

    status = _cairo_gl_composite_set_source (&setup,
             &composite->source_pattern.base,
             &composite->source_sample_area,
             &composite->bounded,
             FALSE);
    if (unlikely (status))
        goto cleanup_setup;

    _cairo_gl_msaa_compositor_set_clip (composite, &setup);
    if (antialias != CAIRO_ANTIALIAS_NONE)
        _cairo_gl_composite_set_multisample (&setup);

    status = _cairo_gl_composite_begin (&setup, &ctx);
    if (unlikely (status))
        goto cleanup_setup;

    if (! draw_path_with_traps)
        status = _draw_simple_quad_path (ctx, &setup, path);
    else
        status = _draw_traps (ctx, &setup, &traps);
    if (unlikely (status))
        goto cleanup_setup;

cleanup_setup:
    _cairo_gl_composite_fini (&setup);

    if (ctx)
        status = _cairo_gl_context_release (ctx, status);

cleanup_traps:
    if (draw_path_with_traps)
        _cairo_traps_fini (&traps);

    return status;
}
cairo_int_status_t
_cairo_meta_surface_replay (cairo_surface_t *surface,
			    cairo_surface_t *target)
{
    cairo_meta_surface_t *meta;
    cairo_command_t *command, **elements;
    int i, num_elements;
    cairo_int_status_t status;
    cairo_traps_t traps;
    cairo_clip_t clip;

    meta = (cairo_meta_surface_t *) surface;
    status = CAIRO_STATUS_SUCCESS;

    _cairo_clip_init (&clip, target);    

    num_elements = meta->commands.num_elements;
    elements = (cairo_command_t **) meta->commands.elements;
    for (i = 0; i < num_elements; i++) {
	command = elements[i];
	switch (command->type) {
	case CAIRO_COMMAND_COMPOSITE:
	    status = _cairo_surface_set_clip (target, &clip);
	    if (status)
		break;

	    status = _cairo_surface_composite
		(command->composite.operator,
		 &command->composite.src_pattern.base,
		 command->composite.mask_pattern_pointer,
		 target,
		 command->composite.src_x,
		 command->composite.src_y,
		 command->composite.mask_x,
		 command->composite.mask_y,
		 command->composite.dst_x,
		 command->composite.dst_y,
		 command->composite.width,
		 command->composite.height);
	    break;

	case CAIRO_COMMAND_FILL_RECTANGLES:
	    status = _cairo_surface_set_clip (target, &clip);
	    if (status)
		break;

	    status = _cairo_surface_fill_rectangles
		(target,
		 command->fill_rectangles.operator,
		 &command->fill_rectangles.color,
		 command->fill_rectangles.rects,
		 command->fill_rectangles.num_rects);
	    break;

	case CAIRO_COMMAND_COMPOSITE_TRAPEZOIDS:
	    status = _cairo_surface_set_clip (target, &clip);
	    if (status)
		break;

	    status = _cairo_surface_composite_trapezoids
		(command->composite_trapezoids.operator,
		 &command->composite_trapezoids.pattern.base,
		 target,
		 command->composite_trapezoids.antialias,
		 command->composite_trapezoids.x_src,
		 command->composite_trapezoids.y_src,
		 command->composite_trapezoids.x_dst,
		 command->composite_trapezoids.y_dst,
		 command->composite_trapezoids.width,
		 command->composite_trapezoids.height,
		 command->composite_trapezoids.traps,
		 command->composite_trapezoids.num_traps);
	    break;

	case CAIRO_COMMAND_INTERSECT_CLIP_PATH:
	    /* XXX Meta surface clipping is broken and requires some
	     * cairo-gstate.c rewriting.  Work around it for now. */
	    if (command->intersect_clip_path.path_pointer == NULL)
		status = _cairo_clip_reset (&clip);
	    else
		status = _cairo_clip_clip (&clip,
					   command->intersect_clip_path.path_pointer,
					   command->intersect_clip_path.fill_rule,
					   command->intersect_clip_path.tolerance,
					   command->intersect_clip_path.antialias,
					   target);
	    break;

	case CAIRO_COMMAND_SHOW_GLYPHS:
	    status = _cairo_surface_set_clip (target, &clip);
	    if (status)
		break;

	    status = _cairo_surface_show_glyphs
		(command->show_glyphs.scaled_font,
		 command->show_glyphs.operator,
		 &command->show_glyphs.pattern.base,
		 target,
		 command->show_glyphs.source_x,
		 command->show_glyphs.source_y,
		 command->show_glyphs.dest_x,
		 command->show_glyphs.dest_y,
		 command->show_glyphs.width,
		 command->show_glyphs.height,
		 command->show_glyphs.glyphs,
		 command->show_glyphs.num_glyphs);
	    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
		break;
	    
	    status = (*command->show_glyphs.scaled_font->backend->
		      show_glyphs) (command->show_glyphs.scaled_font,
				    command->show_glyphs.operator,
				    &command->show_glyphs.pattern.base,
				    target,
				    command->show_glyphs.source_x,
				    command->show_glyphs.source_y,
				    command->show_glyphs.dest_x,
				    command->show_glyphs.dest_y,
				    command->show_glyphs.width,
				    command->show_glyphs.height,
				    command->show_glyphs.glyphs,
				    command->show_glyphs.num_glyphs);

	    break;

	case CAIRO_COMMAND_FILL_PATH:
	    status = _cairo_surface_set_clip (target, &clip);
	    if (status)
		break;

	    status = _cairo_surface_fill_path (command->fill_path.operator,
					       &command->fill_path.pattern.base,
					       target,
					       &command->fill_path.path,
					       command->fill_path.fill_rule,
					       command->fill_path.tolerance);
	    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
		break;

	    _cairo_traps_init (&traps);

	    status = _cairo_path_fixed_fill_to_traps (&command->fill_path.path,
						      command->fill_path.fill_rule,
						      command->fill_path.tolerance,
						      &traps);
	    if (status) {
		_cairo_traps_fini (&traps);
		break;
	    }

	    status = _cairo_surface_clip_and_composite_trapezoids (&command->fill_path.pattern.base,
								   command->fill_path.operator,
								   target,
								   &traps,
								   &clip,
								   command->fill_path.antialias);

	    _cairo_traps_fini (&traps);
	    break;

	default:
	    ASSERT_NOT_REACHED;
	}

	if (status)
	    break;
    }

    _cairo_clip_fini (&clip);

    return status;
}