static cairo_surface_t *
_cairo_surface_subsurface_snapshot (void *abstract_surface)
{
    cairo_surface_subsurface_t *surface = abstract_surface;
    cairo_surface_pattern_t pattern;
    cairo_surface_t *clone;
    cairo_status_t status;

    TRACE ((stderr, "%s: target=%d\n", __FUNCTION__, surface->target->unique_id));

    clone = _cairo_surface_create_scratch (surface->target,
					   surface->target->content,
					   surface->extents.width,
					   surface->extents.height,
					   NULL);
    if (unlikely (clone->status))
	return clone;

    _cairo_pattern_init_for_surface (&pattern, surface->target);
    cairo_matrix_init_translate (&pattern.base.matrix,
				 surface->extents.x, surface->extents.y);
    pattern.base.filter = CAIRO_FILTER_NEAREST;
    status = _cairo_surface_paint (clone,
				   CAIRO_OPERATOR_SOURCE,
				   &pattern.base, NULL);
    _cairo_pattern_fini (&pattern.base);

    if (unlikely (status)) {
	cairo_surface_destroy (clone);
	clone = _cairo_surface_create_in_error (status);
    }

    return clone;
}
示例#2
0
cairo_surface_t *
_cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper,
				       cairo_content_t	content,
				       int		width,
				       int		height)
{
    return _cairo_surface_create_scratch (wrapper->target,
					  content, width, height, NULL);
}
示例#3
0
static cairo_gl_surface_t *
tristrip_to_surface (void *_dst,
		  const cairo_rectangle_int_t *extents,
		  cairo_antialias_t	antialias,
		  cairo_tristrip_t	*strip)
{
    pixman_format_code_t pixman_format;
    pixman_image_t *pixman_image;
    cairo_surface_t *image, *mask;
    cairo_status_t status;

    pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1,
    pixman_image = pixman_image_create_bits (pixman_format,
					     extents->width,
					     extents->height,
					     NULL, 0);
    if (unlikely (pixman_image == NULL))
	return (cairo_gl_surface_t *)_cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));

    _pixman_image_add_tristrip (pixman_image, extents->x, extents->y, strip);
    image = _cairo_image_surface_create_for_pixman_image (pixman_image,
							  pixman_format);
    if (unlikely (image->status)) {
	pixman_image_unref (pixman_image);
	return (cairo_gl_surface_t *)image;
    }

    mask = _cairo_surface_create_scratch (_dst,
					  CAIRO_CONTENT_COLOR_ALPHA,
					  extents->width,
					  extents->height,
					  NULL);
    if (unlikely (mask->status)) {
	cairo_surface_destroy (image);
	return (cairo_gl_surface_t *)mask;
    }

    status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *)mask,
					   (cairo_image_surface_t *)image,
					   0, 0,
					   extents->width, extents->height,
					   0, 0,
					   TRUE);
    cairo_surface_destroy (image);
    if (unlikely (status)) {
	cairo_surface_destroy (mask);
	return (cairo_gl_surface_t*)_cairo_surface_create_in_error (status);
    }

    return (cairo_gl_surface_t*)mask;
}
示例#4
0
cairo_surface_t *
_cairo_clip_get_surface (const cairo_clip_t *clip,
			 cairo_surface_t *target,
			 int *tx, int *ty)
{
    cairo_surface_t *surface;
    cairo_status_t status;
    cairo_clip_t *copy, *region;
    cairo_clip_path_t *copy_path, *clip_path;

    if (clip->num_boxes) {
	cairo_path_fixed_t path;
	int i;

	surface = _cairo_surface_create_scratch (target,
						 CAIRO_CONTENT_ALPHA,
						 clip->extents.width,
						 clip->extents.height,
						 CAIRO_COLOR_TRANSPARENT);
	if (unlikely (surface->status))
	    return surface;

	_cairo_path_fixed_init (&path);
	status = CAIRO_STATUS_SUCCESS;
	for (i = 0; status == CAIRO_STATUS_SUCCESS && i < clip->num_boxes; i++) {
	    status = _cairo_path_fixed_add_box (&path, &clip->boxes[i],
						-_cairo_fixed_from_int (clip->extents.x),
						-_cairo_fixed_from_int (clip->extents.y));
	}
	if (status == CAIRO_STATUS_SUCCESS)
	    status = _cairo_surface_fill (surface,
					  CAIRO_OPERATOR_ADD,
					  &_cairo_pattern_white.base,
					  &path,
					  CAIRO_FILL_RULE_WINDING,
					  1.,
					  CAIRO_ANTIALIAS_DEFAULT,
					  NULL);
	_cairo_path_fixed_fini (&path);
	if (unlikely (status)) {
	    cairo_surface_destroy (surface);
	    return _cairo_surface_create_in_error (status);
	}
    } else {
	surface = _cairo_surface_create_scratch (target,
						 CAIRO_CONTENT_ALPHA,
						 clip->extents.width,
						 clip->extents.height,
						 CAIRO_COLOR_WHITE);
	if (unlikely (surface->status))
	    return surface;
    }

    copy = _cairo_clip_copy_with_translation (clip,
					      -clip->extents.x,
					      -clip->extents.y);
    copy_path = copy->path;
    copy->path = NULL;

    region = copy;
    if (! _cairo_clip_is_region (copy))
	region = _cairo_clip_copy_region (copy);

    status = CAIRO_STATUS_SUCCESS;
    clip_path = copy_path;
    while (status == CAIRO_STATUS_SUCCESS && clip_path) {
	status = _cairo_surface_fill (surface,
				      CAIRO_OPERATOR_IN,
				      &_cairo_pattern_white.base,
				      &clip_path->path,
				      clip_path->fill_rule,
				      clip_path->tolerance,
				      clip_path->antialias,
				      region);
	clip_path = clip_path->prev;
    }

    copy->path = copy_path;
    _cairo_clip_destroy (copy);
    if (region != copy)
	_cairo_clip_destroy (region);

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

    *tx = clip->extents.x;
    *ty = clip->extents.y;
    return surface;
}
示例#5
0
static cairo_int_status_t
_cairo_shape_mask_compositor_stroke (const cairo_compositor_t *_compositor,
				     cairo_composite_rectangles_t *extents,
				     const cairo_path_fixed_t	*path,
				     const cairo_stroke_style_t	*style,
				     const cairo_matrix_t	*ctm,
				     const cairo_matrix_t	*ctm_inverse,
				     double		 tolerance,
				     cairo_antialias_t	 antialias)
{
    cairo_surface_t *mask;
    cairo_surface_pattern_t pattern;
    cairo_int_status_t status;
    cairo_clip_t *clip;

    if (! extents->is_bounded)
	return CAIRO_INT_STATUS_UNSUPPORTED;

    TRACE ((stderr, "%s\n", __FUNCTION__));
    mask = _cairo_surface_create_scratch (extents->surface,
					  CAIRO_CONTENT_ALPHA,
					  extents->bounded.width,
					  extents->bounded.height,
					  NULL);
    if (unlikely (mask->status))
	return mask->status;

    clip = extents->clip;
    if (! _cairo_clip_is_region (clip))
	clip = _cairo_clip_copy_region (clip);

    if (! mask->is_clear) {
	status = _cairo_surface_offset_paint (mask,
					      extents->bounded.x,
					      extents->bounded.y,
					      CAIRO_OPERATOR_CLEAR,
					      &_cairo_pattern_clear.base,
					      clip);
	if (unlikely (status))
	    goto error;
    }

    status = _cairo_surface_offset_stroke (mask,
					   extents->bounded.x,
					   extents->bounded.y,
					   CAIRO_OPERATOR_ADD,
					   &_cairo_pattern_white.base,
					   path, style, ctm, ctm_inverse,
					   tolerance, antialias,
					   clip);
    if (unlikely (status))
	goto error;

    if (clip != extents->clip) {
	status = _cairo_clip_combine_with_surface (extents->clip, mask,
						   extents->bounded.x,
						   extents->bounded.y);
	if (unlikely (status))
	    goto error;
    }

    _cairo_pattern_init_for_surface (&pattern, mask);
    cairo_matrix_init_translate (&pattern.base.matrix,
				 -extents->bounded.x,
				 -extents->bounded.y);
    pattern.base.filter = CAIRO_FILTER_NEAREST;
    pattern.base.extend = CAIRO_EXTEND_NONE;
    if (extents->op == CAIRO_OPERATOR_SOURCE) {
	status = _cairo_surface_mask (extents->surface,
				      CAIRO_OPERATOR_DEST_OUT,
				      &_cairo_pattern_white.base,
				      &pattern.base,
				      clip);
	if ((status == CAIRO_INT_STATUS_SUCCESS)) {
	    status = _cairo_surface_mask (extents->surface,
					  CAIRO_OPERATOR_ADD,
					  &extents->source_pattern.base,
					  &pattern.base,
					  clip);
	}
    } else {
	status = _cairo_surface_mask (extents->surface,
				      extents->op,
				      &extents->source_pattern.base,
				      &pattern.base,
				      clip);
    }
    _cairo_pattern_fini (&pattern.base);

error:
    cairo_surface_destroy (mask);
    if (clip != extents->clip)
	_cairo_clip_destroy (clip);
    return status;
}
示例#6
0
static cairo_status_t
_cairo_default_context_push_group (void *abstract_cr, cairo_content_t content)
{
    cairo_default_context_t *cr = abstract_cr;
    cairo_surface_t *group_surface;
    cairo_clip_t *clip;
    cairo_status_t status;

    clip = _cairo_gstate_get_clip (cr->gstate);
    if (_cairo_clip_is_all_clipped (clip)) {
	group_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
	status = group_surface->status;
	if (unlikely (status))
	    goto bail;
    } else {
	cairo_surface_t *parent_surface;
	cairo_rectangle_int_t extents;
	cairo_bool_t bounded, is_empty;

	parent_surface = _cairo_gstate_get_target (cr->gstate);

	if (unlikely (parent_surface->status))
	    return parent_surface->status;
	if (unlikely (parent_surface->finished))
	    return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);

	/* Get the extents that we'll use in creating our new group surface */
	bounded = _cairo_surface_get_extents (parent_surface, &extents);
	if (clip)
	    /* XXX: This assignment just fixes a compiler warning? */
	    is_empty = _cairo_rectangle_intersect (&extents,
						   _cairo_clip_get_extents (clip));

	if (!bounded) {
	    /* XXX: Generic solution? */
	    group_surface = cairo_recording_surface_create (content, NULL);
	    extents.x = extents.y = 0;
	} else {
	    group_surface = _cairo_surface_create_scratch (parent_surface,
							   content,
							   extents.width,
							   extents.height,
							   CAIRO_COLOR_TRANSPARENT);
	}
	status = group_surface->status;
	if (unlikely (status))
	    goto bail;

	/* Set device offsets on the new surface so that logically it appears at
	 * the same location on the parent surface -- when we pop_group this,
	 * the source pattern will get fixed up for the appropriate target surface
	 * device offsets, so we want to set our own surface offsets from /that/,
	 * and not from the device origin. */
	cairo_surface_set_device_offset (group_surface,
					 parent_surface->device_transform.x0 - extents.x,
					 parent_surface->device_transform.y0 - extents.y);

	cairo_surface_set_device_scale (group_surface,
					parent_surface->device_transform.xx,
					parent_surface->device_transform.yy);

	/* If we have a current path, we need to adjust it to compensate for
	 * the device offset just applied. */
	_cairo_path_fixed_translate (cr->path,
				     _cairo_fixed_from_int (-extents.x),
				     _cairo_fixed_from_int (-extents.y));
    }

    /* create a new gstate for the redirect */
    status = _cairo_gstate_save (&cr->gstate, &cr->gstate_freelist);
    if (unlikely (status))
	goto bail;

    status = _cairo_gstate_redirect_target (cr->gstate, group_surface);

bail:
    cairo_surface_destroy (group_surface);
    return status;
}
static cairo_surface_t *
get_clip_surface (const cairo_spans_compositor_t *compositor,
		  cairo_surface_t *dst,
		  const cairo_clip_t *clip,
		  const cairo_rectangle_int_t *extents)
{
    cairo_composite_rectangles_t composite;
    cairo_surface_t *surface;
    cairo_box_t box;
    cairo_polygon_t polygon;
    const cairo_clip_path_t *clip_path;
    cairo_antialias_t antialias;
    cairo_fill_rule_t fill_rule;
    cairo_int_status_t status;

    assert (clip->path);

    surface = _cairo_surface_create_scratch (dst,
					     CAIRO_CONTENT_ALPHA,
					     extents->width,
					     extents->height,
					     CAIRO_COLOR_TRANSPARENT);
#ifdef WKC_CAIRO_CUSTOMIZE
    if (unlikely (surface->status))
        return surface;
#endif

    _cairo_box_from_rectangle (&box, extents);
    _cairo_polygon_init (&polygon, &box, 1);

    clip_path = clip->path;
    status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
						clip_path->tolerance,
						&polygon);
    if (unlikely (status))
	goto cleanup_polygon;

    polygon.num_limits = 0;

    antialias = clip_path->antialias;
    fill_rule = clip_path->fill_rule;

    if (clip->boxes) {
	cairo_polygon_t intersect;
	cairo_boxes_t tmp;

	_cairo_boxes_init_for_array (&tmp, clip->boxes, clip->num_boxes);
	status= _cairo_polygon_init_boxes (&intersect, &tmp);
	if (unlikely (status))
	    goto cleanup_polygon;

	status = _cairo_polygon_intersect (&polygon, fill_rule,
					   &intersect, CAIRO_FILL_RULE_WINDING);
	_cairo_polygon_fini (&intersect);

	if (unlikely (status))
	    goto cleanup_polygon;

	fill_rule = CAIRO_FILL_RULE_WINDING;
    }

    polygon.limits = NULL;
    polygon.num_limits = 0;

    clip_path = clip_path->prev;
    while (clip_path) {
	if (clip_path->antialias == antialias) {
	    cairo_polygon_t next;

	    _cairo_polygon_init (&next, NULL, 0);
	    status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
							clip_path->tolerance,
							&next);
	    if (likely (status == CAIRO_INT_STATUS_SUCCESS))
		status = _cairo_polygon_intersect (&polygon, fill_rule,
						   &next, clip_path->fill_rule);
	    _cairo_polygon_fini (&next);
	    if (unlikely (status))
		goto cleanup_polygon;

	    fill_rule = CAIRO_FILL_RULE_WINDING;
	}

	clip_path = clip_path->prev;
    }

    _cairo_polygon_translate (&polygon, -extents->x, -extents->y);
    status = _cairo_composite_rectangles_init_for_polygon (&composite, surface,
							   CAIRO_OPERATOR_ADD,
							   &_cairo_pattern_white.base,
							   &polygon,
							   NULL);
    if (unlikely (status))
	goto cleanup_polygon;

    status = composite_polygon (compositor, &composite,
				&polygon, fill_rule, antialias);
    _cairo_composite_rectangles_fini (&composite);
    _cairo_polygon_fini (&polygon);
    if (unlikely (status))
	goto error;

    _cairo_polygon_init (&polygon, &box, 1);

    clip_path = clip->path;
    antialias = clip_path->antialias == CAIRO_ANTIALIAS_DEFAULT ? CAIRO_ANTIALIAS_NONE : CAIRO_ANTIALIAS_DEFAULT;
    clip_path = clip_path->prev;
    while (clip_path) {
	if (clip_path->antialias == antialias) {
	    if (polygon.num_edges == 0) {
		status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
							    clip_path->tolerance,
							    &polygon);

		fill_rule = clip_path->fill_rule;
		polygon.limits = NULL;
		polygon.num_limits = 0;
	    } else {
		cairo_polygon_t next;

		_cairo_polygon_init (&next, NULL, 0);
		status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
							    clip_path->tolerance,
							    &next);
		if (likely (status == CAIRO_INT_STATUS_SUCCESS))
		    status = _cairo_polygon_intersect (&polygon, fill_rule,
						       &next, clip_path->fill_rule);
		_cairo_polygon_fini (&next);
		fill_rule = CAIRO_FILL_RULE_WINDING;
	    }
	    if (unlikely (status))
		goto error;
	}

	clip_path = clip_path->prev;
    }

    if (polygon.num_edges) {
	_cairo_polygon_translate (&polygon, -extents->x, -extents->y);
	status = _cairo_composite_rectangles_init_for_polygon (&composite, surface,
							       CAIRO_OPERATOR_IN,
							       &_cairo_pattern_white.base,
							       &polygon,
							       NULL);
	if (unlikely (status))
	    goto cleanup_polygon;

	status = composite_polygon (compositor, &composite,
				    &polygon, fill_rule, antialias);
	_cairo_composite_rectangles_fini (&composite);
	_cairo_polygon_fini (&polygon);
	if (unlikely (status))
	    goto error;
    }

    return surface;

cleanup_polygon:
    _cairo_polygon_fini (&polygon);
error:
    cairo_surface_destroy (surface);
    return _cairo_int_surface_create_in_error (status);
}
示例#8
0
static cairo_int_status_t
traps_to_operand (void *_dst,
		  const cairo_rectangle_int_t *extents,
		  cairo_antialias_t	antialias,
		  cairo_traps_t		*traps,
		  cairo_gl_operand_t	*operand,
		  int dst_x, int dst_y)
{
    pixman_format_code_t pixman_format;
    pixman_image_t *pixman_image;
    cairo_surface_t *image, *mask;
    cairo_surface_pattern_t pattern;
    cairo_status_t status;

    pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1;
    pixman_image = pixman_image_create_bits (pixman_format,
					     extents->width,
					     extents->height,
					     NULL, 0);
    if (unlikely (pixman_image == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    _pixman_image_add_traps (pixman_image, extents->x, extents->y, traps);
    image = _cairo_image_surface_create_for_pixman_image (pixman_image,
							  pixman_format);
    if (unlikely (image->status)) {
	pixman_image_unref (pixman_image);
	return image->status;
    }

    /* GLES2 only supports RGB/RGBA when uploading */
    if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES) {
	cairo_surface_pattern_t pattern;
	cairo_surface_t *rgba_image;

	/* XXX perform this fixup inside _cairo_gl_draw_image() */

	rgba_image =
	    _cairo_image_surface_create_with_pixman_format (NULL,
							    _cairo_is_little_endian () ?  PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8,
							    extents->width,
							    extents->height,
							    0);
	if (unlikely (rgba_image->status))
	    return rgba_image->status;

	_cairo_pattern_init_for_surface (&pattern, image);
	status = _cairo_surface_paint (rgba_image, CAIRO_OPERATOR_SOURCE,
				       &pattern.base, NULL);
	_cairo_pattern_fini (&pattern.base);

	cairo_surface_destroy (image);
	image = rgba_image;

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

    mask = _cairo_surface_create_scratch (_dst,
					  CAIRO_CONTENT_COLOR_ALPHA,
					  extents->width,
					  extents->height,
					  NULL);
    if (unlikely (mask->status)) {
	cairo_surface_destroy (image);
	return mask->status;
    }

    status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *)mask,
					   (cairo_image_surface_t *)image,
					   0, 0,
					   extents->width, extents->height,
					   0, 0,
					   TRUE);
    cairo_surface_destroy (image);

    if (unlikely (status))
	goto error;

    _cairo_pattern_init_for_surface (&pattern, mask);
    cairo_matrix_init_translate (&pattern.base.matrix,
				 -extents->x+dst_x, -extents->y+dst_y);
    pattern.base.filter = CAIRO_FILTER_NEAREST;
    pattern.base.extend = CAIRO_EXTEND_NONE;
    status = _cairo_gl_operand_init (operand, &pattern.base, _dst,
				     &_cairo_unbounded_rectangle,
				     &_cairo_unbounded_rectangle,
				     FALSE);
    _cairo_pattern_fini (&pattern.base);

    if (unlikely (status))
	goto error;

    operand->texture.owns_surface = (cairo_gl_surface_t *)mask;
    return CAIRO_STATUS_SUCCESS;

error:
    cairo_surface_destroy (mask);
    return status;
}