📄 cairo-pattern.c
字号:
pattern = malloc (sizeof (cairo_radial_pattern_t)); if (pattern == NULL) { _cairo_error (CAIRO_STATUS_NO_MEMORY); return (cairo_pattern_t *) &cairo_pattern_nil.base; } _cairo_pattern_init_radial (pattern, cx0, cy0, radius0, cx1, cy1, radius1); return &pattern->base.base;}/** * cairo_pattern_reference: * @pattern: a #cairo_pattern_t * * Increases the reference count on @pattern by one. This prevents * @pattern from being destroyed until a matching call to * cairo_pattern_destroy() is made. * * Return value: the referenced #cairo_pattern_t. **/cairo_pattern_t *cairo_pattern_reference (cairo_pattern_t *pattern){ if (pattern == NULL) return NULL; if (pattern->ref_count == (unsigned int)-1) return pattern; assert (pattern->ref_count > 0); pattern->ref_count++; return pattern;}/** * cairo_pattern_get_type: * @pattern: a #cairo_pattern_t * * Return value: The type of @pattern. See #cairo_pattern_type_t. * * Since: 1.2 **/cairo_pattern_type_tcairo_pattern_get_type (cairo_pattern_t *pattern){ return pattern->type;}/** * cairo_pattern_status: * @pattern: a #cairo_pattern_t * * Checks whether an error has previously occurred for this * pattern. * * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_STATUS_NO_MEMORY, or * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. **/cairo_status_tcairo_pattern_status (cairo_pattern_t *pattern){ return pattern->status;}/** * cairo_pattern_destroy: * @pattern: a #cairo_pattern_t * * Decreases the reference count on @pattern by one. If the result is * zero, then @pattern and all associated resources are freed. See * cairo_pattern_reference(). **/voidcairo_pattern_destroy (cairo_pattern_t *pattern){ if (pattern == NULL) return; if (pattern->ref_count == (unsigned int)-1) return; assert (pattern->ref_count > 0); pattern->ref_count--; if (pattern->ref_count) return; _cairo_pattern_fini (pattern); free (pattern);}static void_cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern, double offset, double red, double green, double blue, double alpha){ pixman_gradient_stop_t *new_stops; cairo_fixed_t x; int i; new_stops = realloc (pattern->stops, (pattern->n_stops + 1) * sizeof (pixman_gradient_stop_t)); if (new_stops == NULL) { _cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY); return; } pattern->stops = new_stops; x = _cairo_fixed_from_double (offset); for (i = 0; i < pattern->n_stops; i++) { if (x < new_stops[i].x) { memmove (&new_stops[i + 1], &new_stops[i], sizeof (pixman_gradient_stop_t) * (pattern->n_stops - i)); break; } } new_stops[i].x = x; new_stops[i].color.red = red * 65535.0; new_stops[i].color.green = green * 65535.0; new_stops[i].color.blue = blue * 65535.0; new_stops[i].color.alpha = alpha * 65535.0; pattern->n_stops++;}/** * cairo_pattern_add_color_stop_rgb: * @pattern: a #cairo_pattern_t * @offset: an offset in the range [0.0 .. 1.0] * @red: red component of color * @green: green component of color * @blue: blue component of color * * Adds an opaque color stop to a gradient pattern. The offset * specifies the location along the gradient's control vector. For * example, a linear gradient's control vector is from (x0,y0) to * (x1,y1) while a radial gradient's control vector is from any point * on the start circle to the corresponding point on the end circle. * * The color is specified in the same way as in cairo_set_source_rgb(). * * Note: If the pattern is not a gradient pattern, (eg. a linear or * radial pattern), then the pattern will be put into an error status * with a status of %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. **/voidcairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern, double offset, double red, double green, double blue){ if (pattern->status) return; if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR && pattern->type != CAIRO_PATTERN_TYPE_RADIAL) { _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH); return; } _cairo_restrict_value (&offset, 0.0, 1.0); _cairo_restrict_value (&red, 0.0, 1.0); _cairo_restrict_value (&green, 0.0, 1.0); _cairo_restrict_value (&blue, 0.0, 1.0); _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern, offset, red, green, blue, 1.0);}/** * cairo_pattern_add_color_stop_rgba: * @pattern: a #cairo_pattern_t * @offset: an offset in the range [0.0 .. 1.0] * @red: red component of color * @green: green component of color * @blue: blue component of color * @alpha: alpha component of color * * Adds a translucent color stop to a gradient pattern. The offset * specifies the location along the gradient's control vector. For * example, a linear gradient's control vector is from (x0,y0) to * (x1,y1) while a radial gradient's control vector is from any point * on the start circle to the corresponding point on the end circle. * * The color is specified in the same way as in cairo_set_source_rgba(). * * Note: If the pattern is not a gradient pattern, (eg. a linear or * radial pattern), then the pattern will be put into an error status * with a status of %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. */voidcairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern, double offset, double red, double green, double blue, double alpha){ if (pattern->status) return; if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR && pattern->type != CAIRO_PATTERN_TYPE_RADIAL) { _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH); return; } _cairo_restrict_value (&offset, 0.0, 1.0); _cairo_restrict_value (&red, 0.0, 1.0); _cairo_restrict_value (&green, 0.0, 1.0); _cairo_restrict_value (&blue, 0.0, 1.0); _cairo_restrict_value (&alpha, 0.0, 1.0); _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern, offset, red, green, blue, alpha);}/** * cairo_pattern_set_matrix: * @pattern: a #cairo_pattern_t * @matrix: a #cairo_matrix_t * * Sets the pattern's transformation matrix to @matrix. This matrix is * a transformation from user space to pattern space. * * When a pattern is first created it always has the identity matrix * for its transformation matrix, which means that pattern space is * initially identical to user space. * * Important: Please note that the direction of this transformation * matrix is from user space to pattern space. This means that if you * imagine the flow from a pattern to user space (and on to device * space), then coordinates in that flow will be transformed by the * inverse of the pattern matrix. * * For example, if you want to make a pattern appear twice as large as * it does by default the correct code to use is: * * <informalexample><programlisting> * cairo_matrix_init_scale (&matrix, 0.5, 0.5); * cairo_pattern_set_matrix (pattern, &matrix); * </programlisting></informalexample> * * Meanwhile, using values of 2.0 rather than 0.5 in the code above * would cause the pattern to appear at half of its default size. * * Also, please note the discussion of the user-space locking * semantics of cairo_set_source(). **/voidcairo_pattern_set_matrix (cairo_pattern_t *pattern, const cairo_matrix_t *matrix){ if (pattern->status) return; pattern->matrix = *matrix;}/** * cairo_pattern_get_matrix: * @pattern: a #cairo_pattern_t * @matrix: return value for the matrix * * Stores the pattern's transformation matrix into @matrix. **/voidcairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix){ *matrix = pattern->matrix;}voidcairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter){ if (pattern->status) return; pattern->filter = filter;}cairo_filter_tcairo_pattern_get_filter (cairo_pattern_t *pattern){ return pattern->filter;}/** * cairo_pattern_set_extend: * @pattern: a #cairo_pattern_t * @extend: a #cairo_extend_t describing how the area outside of the * pattern will be drawn * * Sets the mode to be used for drawing outside the area of a pattern. * See #cairo_extend_t for details on the semantics of each extend * strategy. **/voidcairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend){ if (pattern->status) return; pattern->extend = extend;}/** * cairo_pattern_get_extend: * @pattern: a #cairo_pattern_t * * Gets the current extend mode for a pattern. See #cairo_extend_t * for details on the semantics of each extend strategy. * * Return value: the current extend strategy used for drawing the * pattern. **/cairo_extend_tcairo_pattern_get_extend (cairo_pattern_t *pattern){ return pattern->extend;}void_cairo_pattern_transform (cairo_pattern_t *pattern, const cairo_matrix_t *ctm_inverse){ assert (pattern->status == CAIRO_STATUS_SUCCESS); cairo_matrix_multiply (&pattern->matrix, ctm_inverse, &pattern->matrix);}static void_cairo_linear_pattern_classify (cairo_linear_pattern_t *pattern, double offset_x, double offset_y, int width, int height, cairo_bool_t *is_horizontal, cairo_bool_t *is_vertical){ cairo_point_double_t point0, point1; double a, b, c, d, tx, ty; double scale, start, dx, dy; cairo_fixed_t factors[3]; int i; /* To classidy a pattern as horizontal or vertical, we first * compute the (fixed point) factors at the corners of the * pattern. We actually only need 3/4 corners, so we skip the * fourth. */ point0.x = _cairo_fixed_to_double (pattern->gradient.p1.x); point0.y = _cairo_fixed_to_double (pattern->gradient.p1.y); point1.x = _cairo_fixed_to_double (pattern->gradient.p2.x); point1.y = _cairo_fixed_to_double (pattern->gradient.p2.y); _cairo_matrix_get_affine (&pattern->base.base.matrix, &a, &b, &c, &d, &tx, &ty); dx = point1.x - point0.x; dy = point1.y - point0.y; scale = dx * dx + dy * dy; scale = (scale) ? 1.0 / scale : 1.0; start = dx * point0.x + dy * point0.y; for (i = 0; i < 3; i++) { double qx_device = (i % 2) * (width - 1) + offset_x; double qy_device = (i / 2) * (height - 1) + offset_y; /* transform fragment into pattern space */ double qx = a * qx_device + c * qy_device + tx; double qy = b * qx_device + d * qy_device + ty; factors[i] = _cairo_fixed_from_double (((dx * qx + dy * qy) - start) * scale); } /* We consider a pattern to be vertical if the fixed point factor * at the two upper corners is the same. We could accept a small * change, but determining what change is acceptable would require * sorting the stops in the pattern and looking at the differences. * * Horizontal works the same way with the two left corners. */ *is_vertical = factors[1] == factors[0]; *is_horizontal = factors[2] == factors[0];}static cairo_int_status_t_cairo_pattern_acquire_surface_for_gradient (cairo_gradient_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_image_surface_t *image; pixman_image_t *pixman_image; pixman_transform_t pixman_transform; cairo_status_t status; cairo_bool_t repeat = FALSE; if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) { cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern; pixman_image = pixman_image_create_linear_gradient (&linear->gradient, pattern->stops, pattern->n_stops); } else { cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern; pixman_image = pixman_image_create_radial_gradient (&radial->gradient, pattern->stops, pattern->n_stops); } if (pixman_image == NULL) return CAIRO_STATUS_NO_MEMORY; if (_cairo_surface_is_image (dst)) { image = (cairo_image_surface_t *) _cairo_image_surface_create_for_pixman_image (pixman_image, CAIRO_FORMAT_ARGB32); if (image->base.status) { pixman_image_destroy (pixman_image); return CAIRO_STATUS_NO_MEMORY; } attr->x_offset = attr->y_offset = 0; attr->matrix = pattern->base.matrix; attr->extend = pattern->base.extend; attr->filter = CAIRO_FILTER_NEAREST; attr->acquired = FALSE; *out = &image->base; return CAIRO_STATUS_SUCCESS; } if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) { cairo_bool_t is_horizontal; cairo_bool_t is_vertical; _cairo_linear_pattern_classify ((cairo_linear_pattern_t *)pattern, x, y, width, height, &is_horizontal, &is_vertical); if (is_horizontal) { height = 1; repeat = TRUE; } /* width-1 repeating patterns are quite slow with scan-line based * compositing code, so we use a wider strip and spend some extra * expense in computing the gradient. It's possible that for narrow * gradients we'd be better off using a 2 or 4 pixel strip; the * wider the gradient, the more it's worth spending extra time * computing a sample. */ if (is_vertical && width > 8) { width = 8; repeat = TRUE; } } image = (cairo_image_surface_t *) cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -