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 + -
显示快捷键?