cairo-pattern.c

来自「按照官方的说法:Cairo is a vector graphics libra」· C语言 代码 · 共 1,467 行 · 第 1/3 页

C
1,467
字号
    if (image->base.status) {	pixman_image_destroy (pixman_image);	return CAIRO_STATUS_NO_MEMORY;    }    pixman_image_set_filter (pixman_image, PIXMAN_FILTER_BILINEAR);    _cairo_matrix_to_pixman_matrix (&pattern->base.matrix, &pixman_transform);    pixman_image_set_transform (pixman_image, &pixman_transform);    switch (pattern->base.extend) {    case CAIRO_EXTEND_NONE:	pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_NONE);	break;    case CAIRO_EXTEND_REPEAT:	pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_NORMAL);	break;    case CAIRO_EXTEND_REFLECT:	pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_REFLECT);	break;    case CAIRO_EXTEND_PAD:	pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_PAD);	break;    }    pixman_composite (PIXMAN_OPERATOR_SRC,		      pixman_image,		      NULL,		      image->pixman_image,		      x, y,		      0, 0,		      0, 0,		      width, height);    pixman_image_destroy (pixman_image);    status = _cairo_surface_clone_similar (dst, &image->base, out);    cairo_surface_destroy (&image->base);    attr->x_offset = -x;    attr->y_offset = -y;    cairo_matrix_init_identity (&attr->matrix);    attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE;    attr->filter = CAIRO_FILTER_NEAREST;    attr->acquired = FALSE;    return status;}static cairo_int_status_t_cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t	     *pattern,					  cairo_surface_t	     *dst,					  int			     x,					  int			     y,					  unsigned int		     width,					  unsigned int		     height,					  cairo_surface_t	     **out,					  cairo_surface_attributes_t *attribs){    *out = _cairo_surface_create_similar_solid (dst,						CAIRO_CONTENT_COLOR_ALPHA,						1, 1,						&pattern->color);    if ((*out)->status)	return CAIRO_STATUS_NO_MEMORY;    attribs->x_offset = attribs->y_offset = 0;    cairo_matrix_init_identity (&attribs->matrix);    attribs->extend = CAIRO_EXTEND_REPEAT;    attribs->filter = CAIRO_FILTER_NEAREST;    attribs->acquired = FALSE;    return CAIRO_STATUS_SUCCESS;}/** * _cairo_pattern_is_opaque_solid * * Convenience function to determine whether a pattern is an opaque * (alpha==1.0) solid color pattern. This is done by testing whether * the pattern's alpha value when converted to a byte is 255, so if a * backend actually supported deep alpha channels this function might * not do the right thing. * * Return value: %TRUE if the pattern is an opaque, solid color. **/cairo_bool_t_cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern){    cairo_solid_pattern_t *solid;    if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)	return FALSE;    solid = (cairo_solid_pattern_t *) pattern;    return CAIRO_ALPHA_IS_OPAQUE (solid->color.alpha);}static cairo_bool_t_gradient_is_opaque (const cairo_gradient_pattern_t *gradient){    int i;    for (i = 0; i < gradient->n_stops; i++)	if (! CAIRO_ALPHA_IS_OPAQUE (gradient->stops[i].color.alpha))	    return FALSE;    return TRUE;}/** * _cairo_pattern_is_opaque * * Convenience function to determine whether a pattern is an opaque * pattern (of any type). The same caveats that apply to * _cairo_pattern_is_opaque_solid apply here as well. * * Return value: %TRUE if the pattern is a opaque. **/cairo_bool_t_cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern){    const cairo_pattern_union_t *pattern;    pattern = (cairo_pattern_union_t *) abstract_pattern;    switch (pattern->base.type) {    case CAIRO_PATTERN_TYPE_SOLID:	return _cairo_pattern_is_opaque_solid (abstract_pattern);    case CAIRO_PATTERN_TYPE_SURFACE:	return cairo_surface_get_content (pattern->surface.surface) == CAIRO_CONTENT_COLOR;    case CAIRO_PATTERN_TYPE_LINEAR:    case CAIRO_PATTERN_TYPE_RADIAL:	return _gradient_is_opaque (&pattern->gradient.base);    }    ASSERT_NOT_REACHED;    return FALSE;}static cairo_int_status_t_cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t   *pattern,					    cairo_surface_t	       *dst,					    int			       x,					    int			       y,					    unsigned int	       width,					    unsigned int	       height,					    cairo_surface_t	       **out,					    cairo_surface_attributes_t *attr){    cairo_int_status_t status;    int tx, ty;    attr->acquired = FALSE;    if (_cairo_surface_is_image (dst))    {	cairo_image_surface_t *image;	status = _cairo_surface_acquire_source_image (pattern->surface,						      &image,						      &attr->extra);	if (status)	    return status;	*out = &image->base;	attr->acquired = TRUE;    }    else    {	status = _cairo_surface_clone_similar (dst, pattern->surface, out);    }    attr->extend = pattern->base.extend;    attr->filter = pattern->base.filter;    if (_cairo_matrix_is_integer_translation (&pattern->base.matrix,					      &tx, &ty))    {	cairo_matrix_init_identity (&attr->matrix);	attr->x_offset = tx;	attr->y_offset = ty;	attr->filter = CAIRO_FILTER_NEAREST;    }    else    {	attr->matrix = pattern->base.matrix;	attr->x_offset = attr->y_offset = 0;    }    return status;}/** * _cairo_pattern_acquire_surface: * @pattern: a #cairo_pattern_t * @dst: destination surface * @x: X coordinate in source corresponding to left side of destination area * @y: Y coordinate in source corresponding to top side of destination area * @width: width of destination area * @height: height of destination area * @surface_out: location to store a pointer to a surface * @attributes: surface attributes that destination backend should apply to * the returned surface * * A convenience function to obtain a surface to use as the source for * drawing on @dst. * * Return value: %CAIRO_STATUS_SUCCESS if a surface was stored in @surface_out. **/cairo_int_status_t_cairo_pattern_acquire_surface (cairo_pattern_t		   *pattern,				cairo_surface_t		   *dst,				int			   x,				int			   y,				unsigned int		   width,				unsigned int		   height,				cairo_surface_t		   **surface_out,				cairo_surface_attributes_t *attributes){    cairo_status_t status;    if (pattern->status) {	*surface_out = NULL;	attributes->acquired = FALSE;	return pattern->status;    }    switch (pattern->type) {    case CAIRO_PATTERN_TYPE_SOLID: {	cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) pattern;	status = _cairo_pattern_acquire_surface_for_solid (src, dst,							   x, y, width, height,							   surface_out,							   attributes);	} break;    case CAIRO_PATTERN_TYPE_LINEAR:    case CAIRO_PATTERN_TYPE_RADIAL: {	cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) pattern;	/* fast path for gradients with less than 2 color stops */	if (src->n_stops < 2)	{	    cairo_solid_pattern_t solid;	    if (src->n_stops)	    {		cairo_color_t color;		_cairo_color_init_rgba (&color,					src->stops->color.red / 65536.0,					src->stops->color.green / 65536.0,					src->stops->color.blue / 65536.0,					src->stops->color.alpha / 65536.0);		_cairo_pattern_init_solid (&solid, &color);	    }	    else	    {		const cairo_color_t *color;		color =	_cairo_stock_color (CAIRO_STOCK_TRANSPARENT);		_cairo_pattern_init_solid (&solid, color);	    }	    status = _cairo_pattern_acquire_surface_for_solid (&solid, dst,							       x, y,							       width, height,							       surface_out,							       attributes);	}	else	{	    status = _cairo_pattern_acquire_surface_for_gradient (src, dst,								  x, y,								  width, height,								  surface_out,								  attributes);	}    } break;    case CAIRO_PATTERN_TYPE_SURFACE: {	cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) pattern;	status = _cairo_pattern_acquire_surface_for_surface (src, dst,							     x, y, width, height,							     surface_out,							     attributes);    } break;    default:	status = CAIRO_INT_STATUS_UNSUPPORTED;    }    return status;}/** * _cairo_pattern_release_surface: * @pattern: a #cairo_pattern_t * @surface: a surface obtained by _cairo_pattern_acquire_surface * @attributes: attributes obtained by _cairo_pattern_acquire_surface * * Releases resources obtained by _cairo_pattern_acquire_surface. **/void_cairo_pattern_release_surface (cairo_pattern_t		   *pattern,				cairo_surface_t		   *surface,				cairo_surface_attributes_t *attributes){    if (attributes->acquired)    {	cairo_surface_pattern_t *surface_pattern;	assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);	surface_pattern = (cairo_surface_pattern_t *) pattern;	_cairo_surface_release_source_image (surface_pattern->surface,					     (cairo_image_surface_t *) surface,					     attributes->extra);    }    else    {	cairo_surface_destroy (surface);    }}cairo_int_status_t_cairo_pattern_acquire_surfaces (cairo_pattern_t	    *src,				 cairo_pattern_t	    *mask,				 cairo_surface_t	    *dst,				 int			    src_x,				 int			    src_y,				 int			    mask_x,				 int			    mask_y,				 unsigned int		    width,				 unsigned int		    height,				 cairo_surface_t	    **src_out,				 cairo_surface_t	    **mask_out,				 cairo_surface_attributes_t *src_attributes,				 cairo_surface_attributes_t *mask_attributes){    cairo_int_status_t	  status;    cairo_pattern_union_t src_tmp, mask_tmp;    if (src->status)	return src->status;    if (mask && mask->status)	return mask->status;    /* If src and mask are both solid, then the mask alpha can be     * combined into src and mask can be ignored. */    /* XXX: This optimization assumes that there is no color     * information in mask, so this will need to change when we     * support RENDER-style 4-channel masks. */    if (src->type == CAIRO_PATTERN_TYPE_SOLID &&	mask && mask->type == CAIRO_PATTERN_TYPE_SOLID)    {	cairo_color_t combined;	cairo_solid_pattern_t *src_solid = (cairo_solid_pattern_t *) src;	cairo_solid_pattern_t *mask_solid = (cairo_solid_pattern_t *) mask;	combined = src_solid->color;	_cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);	_cairo_pattern_init_solid (&src_tmp.solid, &combined);	mask = NULL;    }    else    {	_cairo_pattern_init_copy (&src_tmp.base, src);    }    status = _cairo_pattern_acquire_surface (&src_tmp.base, dst,					     src_x, src_y,					     width, height,					     src_out, src_attributes);    if (status) {	_cairo_pattern_fini (&src_tmp.base);	return status;    }    if (mask == NULL)    {	_cairo_pattern_fini (&src_tmp.base);	*mask_out = NULL;	return CAIRO_STATUS_SUCCESS;    }    _cairo_pattern_init_copy (&mask_tmp.base, mask);    status = _cairo_pattern_acquire_surface (&mask_tmp.base, dst,					     mask_x, mask_y,					     width, height,					     mask_out, mask_attributes);    if (status)	_cairo_pattern_release_surface (&src_tmp.base,					*src_out, src_attributes);    _cairo_pattern_fini (&src_tmp.base);    _cairo_pattern_fini (&mask_tmp.base);    return status;}/** * _cairo_pattern_get_extents: * * Return the "target-space" extents of @pattern in @extents. * * For unbounded patterns, the @extents will be initialized with * "infinite" extents, (minimum and maximum fixed-point values). * * XXX: Currently, bounded gradient patterns will also return * "infinite" extents, though it would be possible to optimize these * with a little more work. **/cairo_status_t_cairo_pattern_get_extents (cairo_pattern_t         *pattern,			    cairo_rectangle_int16_t *extents){    if (pattern->extend == CAIRO_EXTEND_NONE &&	pattern->type == CAIRO_PATTERN_TYPE_SURFACE)    {	cairo_status_t status;	cairo_rectangle_int16_t surface_extents;	cairo_surface_pattern_t *surface_pattern =	    (cairo_surface_pattern_t *) pattern;	cairo_surface_t *surface = surface_pattern->surface;	cairo_matrix_t imatrix;	double x, y;	/* Initialize to keep the compiler quiet. */	int left=0, right=0, top=0, bottom=0;	int lx, rx, ty, by;	int sx, sy;	cairo_bool_t set = FALSE;	status = _cairo_surface_get_extents (surface, &surface_extents);	if (status)	    return status;	imatrix = pattern->matrix;	cairo_matrix_invert (&imatrix);	for (sy = 0; sy <= 1; sy++) {	    for (sx = 0; sx <= 1; sx++) {		x = surface_extents.x + sx * surface_extents.width;		y = surface_extents.y + sy * surface_extents.height;		cairo_matrix_transform_point (&imatrix, &x, &y);		if (x < 0) x = 0;		if (x > INT16_MAX) x = INT16_MAX;		if (y < 0) y = 0;		if (y > INT16_MAX) y = INT16_MAX;		lx = floor (x); rx = ceil (x);		ty = floor (y); by = ceil (y);		if (!set) {		    left = lx;		    right = rx;		    top = ty;		    bottom = by;		    set = TRUE;		} else {		    if (lx < left) left = lx;		    if (rx > right) right = rx;		    if (ty < top) top = ty;		    if (by > bottom) bottom = by;		}	    }	}	extents->x = left; extents->width = right - left;	extents->y = top; extents->height = bottom - top;	return CAIRO_STATUS_SUCCESS;    }    /* XXX: We could optimize gradients with pattern->extend of NONE     * here in some cases, (eg. radial gradients and 1 axis of     * horizontal/vertical linear gradients).     */    extents->x = 0;    extents->y = 0;    extents->width = INT16_MAX;    extents->height = INT16_MAX;    return CAIRO_STATUS_SUCCESS;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?