static cairo_status_t
_composite_traps_draw_func (void                          *closure,
			    cairo_operator_t               op,
			    cairo_pattern_t               *src,
			    cairo_surface_t               *dst,
			    int                            dst_x,
			    int                            dst_y,
			    const cairo_rectangle_int_t   *extents)
{
    cairo_composite_traps_info_t *info = closure;
    cairo_pattern_union_t pattern;
    cairo_status_t status;

    if (dst_x != 0 || dst_y != 0)
	_cairo_traps_translate (info->traps, - dst_x, - dst_y);

    _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
			       CAIRO_CONTENT_COLOR);
    if (!src)
	src = &pattern.base;

    status = _cairo_surface_composite_trapezoids (op,
						  src, dst, info->antialias,
						  extents->x,         extents->y,
						  extents->x - dst_x, extents->y - dst_y,
						  extents->width,     extents->height,
						  info->traps->traps,
						  info->traps->num_traps);
    _cairo_pattern_fini (&pattern.base);

    return status;
}
cairo_status_t
_cairo_surface_fallback_composite_trapezoids (cairo_operator_t		op,
					      cairo_pattern_t	       *pattern,
					      cairo_surface_t	       *dst,
					      cairo_antialias_t		antialias,
					      int			src_x,
					      int			src_y,
					      int			dst_x,
					      int			dst_y,
					      unsigned int		width,
					      unsigned int		height,
					      cairo_trapezoid_t	       *traps,
					      int			num_traps)
{
    fallback_state_t state;
    cairo_trapezoid_t *offset_traps = NULL;
    cairo_status_t status;

    status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
    if (status) {
	if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
	    return CAIRO_STATUS_SUCCESS;
	return status;
    }

    /* If the destination image isn't at 0,0, we need to offset the trapezoids */

    if (state.image_rect.x != 0 || state.image_rect.y != 0) {
	offset_traps = _cairo_malloc_ab (num_traps, sizeof (cairo_trapezoid_t));
	if (!offset_traps) {
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	    goto DONE;
	}

	_cairo_trapezoid_array_translate_and_scale (offset_traps, traps, num_traps,
                                                    - state.image_rect.x, - state.image_rect.y,
                                                    1.0, 1.0);
	traps = offset_traps;
    }

    status = _cairo_surface_composite_trapezoids (op, pattern,
					          &state.image->base,
						  antialias,
						  src_x, src_y,
						  dst_x - state.image_rect.x,
						  dst_y - state.image_rect.y,
						  width, height,
						  traps, num_traps);
    if (offset_traps)
	free (offset_traps);

 DONE:
    _fallback_fini (&state);

    return status;
}
Beispiel #3
0
static cairo_status_t
_cairo_clip_intersect_mask (cairo_clip_t      *clip,
			    cairo_traps_t     *traps,
			    cairo_antialias_t antialias,
			    cairo_surface_t   *target)
{
    cairo_pattern_union_t pattern;
    cairo_box_t extents;
    cairo_rectangle_int16_t surface_rect, target_rect;
    cairo_surface_t *surface;
    cairo_status_t status;

    /* Represent the clip as a mask surface.  We create a new surface
     * the size of the intersection of the old mask surface and the
     * extents of the new clip path. */

    _cairo_traps_extents (traps, &extents);
    _cairo_box_round_to_rectangle (&extents, &surface_rect);

    if (clip->surface != NULL)
	_cairo_rectangle_intersect (&surface_rect, &clip->surface_rect);

    /* Intersect with the target surface rectangle so we don't use
     * more memory and time than we need to. */

    status = _cairo_surface_get_extents (target, &target_rect);
    if (!status)
	_cairo_rectangle_intersect (&surface_rect, &target_rect);

    surface = _cairo_surface_create_similar_solid (target,
						   CAIRO_CONTENT_ALPHA,
						   surface_rect.width,
						   surface_rect.height,
						   CAIRO_COLOR_WHITE);
    if (surface->status)
	return CAIRO_STATUS_NO_MEMORY;

    /* Render the new clipping path into the new mask surface. */

    _cairo_traps_translate (traps, -surface_rect.x, -surface_rect.y);
    _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);

    status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN,
						  &pattern.base,
						  surface,
						  antialias,
						  0, 0,
						  0, 0,
						  surface_rect.width,
						  surface_rect.height,
						  traps->traps,
						  traps->num_traps);

    _cairo_pattern_fini (&pattern.base);

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

    /* If there was a clip surface already, combine it with the new
     * mask surface using the IN operator, so we get the intersection
     * of the old and new clipping paths. */

    if (clip->surface != NULL) {
	_cairo_pattern_init_for_surface (&pattern.surface, clip->surface);

	status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
					   &pattern.base,
					   NULL,
					   surface,
					   surface_rect.x - clip->surface_rect.x,
					   surface_rect.y - clip->surface_rect.y,
					   0, 0,
					   0, 0,
					   surface_rect.width,
					   surface_rect.height);

	_cairo_pattern_fini (&pattern.base);

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

	cairo_surface_destroy (clip->surface);
    }

    clip->surface = surface;
    clip->surface_rect = surface_rect;
    clip->serial = _cairo_surface_allocate_clip_serial (target);

    return status;
}
Beispiel #4
0
static cairo_status_t
_cairo_clip_intersect_mask (cairo_clip_t      *clip,
			    cairo_traps_t     *traps,
			    cairo_antialias_t antialias,
			    cairo_surface_t   *target)
{
    cairo_pattern_union_t pattern;
    cairo_box_t extents;
    cairo_rectangle_int_t surface_rect, target_rect;
    cairo_surface_t *surface;
    cairo_status_t status;

    if (clip->all_clipped)
	return CAIRO_STATUS_SUCCESS;

    /* Represent the clip as a mask surface.  We create a new surface
     * the size of the intersection of the old mask surface and the
     * extents of the new clip path. */

    _cairo_traps_extents (traps, &extents);
    _cairo_box_round_to_rectangle (&extents, &surface_rect);

    if (clip->surface != NULL)
	_cairo_rectangle_intersect (&surface_rect, &clip->surface_rect);

    /* Intersect with the target surface rectangle so we don't use
     * more memory and time than we need to. */

    status = _cairo_surface_get_extents (target, &target_rect);
    if (!status)
	_cairo_rectangle_intersect (&surface_rect, &target_rect);

    if (surface_rect.width == 0 || surface_rect.height == 0) {
	surface = NULL;
	status = CAIRO_STATUS_SUCCESS;
	if (clip->surface != NULL)
	    cairo_surface_destroy (clip->surface);
	goto DONE;
    }

    _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
			       CAIRO_CONTENT_COLOR);
    /* The clipping operation should ideally be something like the following to
     * avoid having to do as many passes over the data

	if (clip->surface != NULL) {
	    _cairo_pattern_init_for_surface (&pattern.surface, clip->surface);
	} else {
	    _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
			       CAIRO_CONTENT_COLOR);
	}
	status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN,
						  &pattern.base,
						  surface,
						  antialias,
						  0, 0,
						  0, 0,
						  surface_rect.width,
						  surface_rect.height,
						  traps->traps,
						  traps->num_traps);

	However this operation is not accelerated by pixman

	I believe the best possible operation would probably an unbounded SRC
	operator.  Using SRC we could potentially avoid having to initialize
	the surface which would be ideal from an efficiency point of view.
	However, _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_SOURCE) is
	bounded by the mask.

    */

    surface = _cairo_surface_create_similar_solid (target,
						   CAIRO_CONTENT_ALPHA,
						   surface_rect.width,
						   surface_rect.height,
						   CAIRO_COLOR_TRANSPARENT,
						   &pattern.base);
    if (surface->status) {
	_cairo_pattern_fini (&pattern.base);
	return surface->status;
    }

    /* Render the new clipping path into the new mask surface. */

    _cairo_traps_translate (traps, -surface_rect.x, -surface_rect.y);

    status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
						  &pattern.base,
						  surface,
						  antialias,
						  0, 0,
						  0, 0,
						  surface_rect.width,
						  surface_rect.height,
						  traps->traps,
						  traps->num_traps);

    _cairo_pattern_fini (&pattern.base);

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

    /* If there was a clip surface already, combine it with the new
     * mask surface using the IN operator, so we get the intersection
     * of the old and new clipping paths. */

    if (clip->surface != NULL) {
	_cairo_pattern_init_for_surface (&pattern.surface, clip->surface);

	status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
					   &pattern.base,
					   NULL,
					   surface,
					   surface_rect.x - clip->surface_rect.x,
					   surface_rect.y - clip->surface_rect.y,
					   0, 0,
					   0, 0,
					   surface_rect.width,
					   surface_rect.height);

	_cairo_pattern_fini (&pattern.base);

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

	cairo_surface_destroy (clip->surface);
    }

 DONE:
    clip->surface = surface;
    clip->surface_rect = surface_rect;
    clip->serial = _cairo_surface_allocate_clip_serial (target);

    if (surface_rect.width == 0 || surface_rect.height == 0)
	_cairo_clip_set_all_clipped (clip, target);

    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;
}