diff options
Diffstat (limited to 'src/cairo-glitz-surface.c')
-rw-r--r-- | src/cairo-glitz-surface.c | 1484 |
1 files changed, 893 insertions, 591 deletions
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c index 69fc82f2e..ee664e1cc 100644 --- a/src/cairo-glitz-surface.c +++ b/src/cairo-glitz-surface.c @@ -21,30 +21,12 @@ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * Author: David Reveman <c99drn@cs.umu.se> + * Author: David Reveman <davidr@novell.com> */ #include "cairoint.h" #include "cairo-glitz.h" -#define GLITZ_FIXED_TO_FLOAT(f) \ - (((glitz_float_t) (f)) / 65536) - -#define GLITZ_FIXED_LINE_X_TO_FLOAT(line, v) \ - (((glitz_float_t) \ - ((line).p1.x + (cairo_fixed_16_16_t) \ - (((cairo_fixed_32_32_t) ((v) - (line).p1.y) * \ - ((line).p2.x - (line).p1.x)) / \ - ((line).p2.y - (line).p1.y)))) / 65536) - -#define GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT(line, v) \ - (((glitz_float_t) \ - ((line).p1.x + (cairo_fixed_16_16_t) \ - (((((line).p2.y - (line).p1.y) - 1) + \ - ((cairo_fixed_32_32_t) ((v) - (line).p1.y) * \ - ((line).p2.x - (line).p1.x))) / \ - ((line).p2.y - (line).p1.y)))) / 65536) - void cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface) { @@ -65,13 +47,11 @@ cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface) } typedef struct _cairo_glitz_surface { - cairo_surface_t base; - - glitz_surface_t *surface; - glitz_format_t *format; + cairo_surface_t base; - cairo_pattern_t pattern; - cairo_box_t pattern_box; + glitz_surface_t *surface; + glitz_format_t *format; + pixman_region16_t *clip; } cairo_glitz_surface_t; static void @@ -79,11 +59,60 @@ _cairo_glitz_surface_destroy (void *abstract_surface) { cairo_glitz_surface_t *surface = abstract_surface; + if (surface->clip) + { + glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0); + pixman_region_destroy (surface->clip); + } + glitz_surface_destroy (surface->surface); + free (surface); +} - _cairo_pattern_fini (&surface->pattern); +static glitz_format_name_t +_glitz_format (cairo_format_t format) +{ + switch (format) { + default: + case CAIRO_FORMAT_ARGB32: + return GLITZ_STANDARD_ARGB32; + case CAIRO_FORMAT_RGB24: + return GLITZ_STANDARD_RGB24; + case CAIRO_FORMAT_A8: + return GLITZ_STANDARD_A8; + case CAIRO_FORMAT_A1: + return GLITZ_STANDARD_A1; + } +} - free (surface); +static cairo_surface_t * +_cairo_glitz_surface_create_similar (void *abstract_src, + cairo_format_t format, + int draw, + int width, + int height) +{ + cairo_glitz_surface_t *src = abstract_src; + cairo_surface_t *crsurface; + glitz_drawable_t *drawable; + glitz_surface_t *surface; + glitz_format_t *gformat; + + drawable = glitz_surface_get_drawable (src->surface); + + gformat = glitz_find_standard_format (drawable, _glitz_format (format)); + if (!gformat) + return NULL; + + surface = glitz_surface_create (drawable, gformat, width, height, 0, NULL); + if (!surface) + return NULL; + + crsurface = cairo_glitz_surface_create (surface); + + glitz_surface_destroy (surface); + + return crsurface; } static double @@ -92,31 +121,54 @@ _cairo_glitz_surface_pixels_per_inch (void *abstract_surface) return 96.0; } -static cairo_image_surface_t * -_cairo_glitz_surface_get_image (void *abstract_surface) +static cairo_status_t +_cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, + cairo_rectangle_t *interest, + cairo_image_surface_t **image_out, + cairo_rectangle_t *rect_out) { - cairo_glitz_surface_t *surface = abstract_surface; cairo_image_surface_t *image; - char *pixels; - int width, height; - cairo_format_masks_t format; - glitz_buffer_t *buffer; - glitz_pixel_format_t pf; - - if (surface->pattern.type != CAIRO_PATTERN_SURFACE) { - cairo_box_t box; - - box.p1.x = box.p1.y = 0; - box.p2.x = surface->pattern_box.p2.x; - box.p2.y = surface->pattern_box.p2.y; - - return _cairo_pattern_get_image (&surface->pattern, &box); + int x1, y1, x2, y2; + int width, height; + char *pixels; + cairo_format_masks_t format; + glitz_buffer_t *buffer; + glitz_pixel_format_t pf; + + x1 = 0; + y1 = 0; + x2 = glitz_surface_get_width (surface->surface); + y2 = glitz_surface_get_height (surface->surface); + + if (interest) + { + if (interest->x > x1) + x1 = interest->x; + if (interest->y > y1) + y1 = interest->y; + if (interest->x + interest->width < x2) + x2 = interest->x + interest->width; + if (interest->y + interest->height < y2) + y2 = interest->y + interest->height; + + if (x1 >= x2 || y1 >= y2) + { + *image_out = NULL; + return CAIRO_STATUS_SUCCESS; + } } + width = x2 - x1; + height = y2 - y1; - width = glitz_surface_get_width (surface->surface); - height = glitz_surface_get_height (surface->surface); - + if (rect_out) + { + rect_out->x = x1; + rect_out->y = y1; + rect_out->width = width; + rect_out->height = height; + } + if (surface->format->type == GLITZ_FORMAT_TYPE_COLOR) { if (surface->format->color.red_size > 0) { format.bpp = 32; @@ -149,21 +201,24 @@ _cairo_glitz_surface_get_image (void *abstract_surface) pf.masks.blue_mask = format.blue_mask; pf.xoffset = 0; pf.skip_lines = 0; + + /* XXX: we should eventually return images with negative stride, + need to verify that libpixman have no problem with this first. */ pf.bytes_per_line = (((width * format.bpp) / 8) + 3) & -4; pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; pixels = malloc (height * pf.bytes_per_line); if (!pixels) - return NULL; + return CAIRO_STATUS_NO_MEMORY; buffer = glitz_buffer_create_for_data (pixels); if (!buffer) { free (pixels); - return NULL; + return CAIRO_STATUS_NO_MEMORY; } glitz_get_pixels (surface->surface, - 0, 0, + x1, y1, width, height, &pf, buffer); @@ -175,27 +230,38 @@ _cairo_glitz_surface_get_image (void *abstract_surface) &format, width, height, pf.bytes_per_line); - + + if (!image) + { + free (pixels); + return CAIRO_STATUS_NO_MEMORY; + } + _cairo_image_surface_assume_ownership_of_data (image); _cairo_image_surface_set_repeat (image, surface->base.repeat); _cairo_image_surface_set_matrix (image, &(surface->base.matrix)); - return image; + *image_out = image; + + return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_glitz_surface_set_image (void *abstract_surface, - cairo_image_surface_t *image) +_cairo_glitz_surface_set_image (void *abstract_surface, + cairo_image_surface_t *image, + int x_dst, + int y_dst) { cairo_glitz_surface_t *surface = abstract_surface; - glitz_buffer_t *buffer; - glitz_pixel_format_t pf; - pixman_format_t *format; - int am, rm, gm, bm; + glitz_buffer_t *buffer; + glitz_pixel_format_t pf; + pixman_format_t *format; + int am, rm, gm, bm; + char *data; format = pixman_image_get_format (image->pixman_image); - if (format == NULL) + if (!format) return CAIRO_STATUS_NO_MEMORY; pixman_format_get_masks (format, &pf.masks.bpp, &am, &rm, &gm, &bm); @@ -206,15 +272,27 @@ _cairo_glitz_surface_set_image (void *abstract_surface, pf.masks.blue_mask = bm; pf.xoffset = 0; pf.skip_lines = 0; - pf.bytes_per_line = image->stride; - pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; - buffer = glitz_buffer_create_for_data (image->data); + /* check for negative stride */ + if (image->stride < 0) + { + pf.bytes_per_line = -image->stride; + pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP; + data = (char *) image->data + image->stride * (image->height - 1); + } + else + { + pf.bytes_per_line = image->stride; + pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; + data = (char *) image->data; + } + + buffer = glitz_buffer_create_for_data (data); if (!buffer) return CAIRO_STATUS_NO_MEMORY; glitz_set_pixels (surface->surface, - 0, 0, + x_dst, y_dst, image->width, image->height, &pf, buffer); @@ -225,63 +303,118 @@ _cairo_glitz_surface_set_image (void *abstract_surface, } static cairo_status_t -_cairo_glitz_surface_set_matrix (void *abstract_surface, - cairo_matrix_t *matrix) +_cairo_glitz_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) { cairo_glitz_surface_t *surface = abstract_surface; - glitz_transform_t transform; - transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]); - transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]); - transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]); + *image_extra = NULL; + + return _cairo_glitz_surface_get_image (surface, NULL, image_out, NULL); +} - transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]); - transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]); - transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]); +static void +_cairo_glitz_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_surface_destroy (&image->base); +} - transform.matrix[2][0] = 0; - transform.matrix[2][1] = 0; - transform.matrix[2][2] = 1 << 16; +static cairo_status_t +_cairo_glitz_surface_acquire_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect_out, + void **image_extra) +{ + cairo_glitz_surface_t *surface = abstract_surface; + cairo_image_surface_t *image; + cairo_status_t status; - glitz_surface_set_transform (surface->surface, &transform); + status = _cairo_glitz_surface_get_image (surface, interest_rect, &image, + image_rect_out); + if (status) + return status; - return CAIRO_STATUS_SUCCESS; + *image_out = image; + *image_extra = NULL; + + return status; } +static void +_cairo_glitz_surface_release_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_t *image_rect, + void *image_extra) +{ + cairo_glitz_surface_t *surface = abstract_surface; + + _cairo_glitz_surface_set_image (surface, image, + image_rect->x, image_rect->y); + + cairo_surface_destroy (&image->base); +} + + static cairo_status_t -_cairo_glitz_surface_set_filter (void *abstract_surface, cairo_filter_t filter) +_cairo_glitz_surface_clone_similar (void *abstract_surface, + cairo_surface_t *src, + cairo_surface_t **clone_out) { cairo_glitz_surface_t *surface = abstract_surface; - glitz_filter_t glitz_filter; + cairo_glitz_surface_t *clone; - switch (filter) { - case CAIRO_FILTER_FAST: - case CAIRO_FILTER_NEAREST: - glitz_filter = GLITZ_FILTER_NEAREST; - break; - case CAIRO_FILTER_GOOD: - case CAIRO_FILTER_BEST: - case CAIRO_FILTER_BILINEAR: - default: - glitz_filter = GLITZ_FILTER_BILINEAR; - break; + if (src->backend == surface->base.backend) + { + *clone_out = src; + cairo_surface_reference (src); + + return CAIRO_STATUS_SUCCESS; } + else if (_cairo_surface_is_image (src)) + { + cairo_image_surface_t *image_src = (cairo_image_surface_t *) src; + + clone = (cairo_glitz_surface_t *) + _cairo_glitz_surface_create_similar (surface, image_src->format, 0, + image_src->width, + image_src->height); + if (!clone) + return CAIRO_STATUS_NO_MEMORY; - glitz_surface_set_filter (surface->surface, glitz_filter, NULL, 0); + _cairo_glitz_surface_set_image (clone, image_src, 0, 0); + + *clone_out = &clone->base; - return CAIRO_STATUS_SUCCESS; + return CAIRO_STATUS_SUCCESS; + } + + return CAIRO_INT_STATUS_UNSUPPORTED; } -static cairo_status_t -_cairo_glitz_surface_set_repeat (void *abstract_surface, int repeat) +static void +_cairo_glitz_surface_set_matrix (cairo_glitz_surface_t *surface, + cairo_matrix_t *matrix) { - cairo_glitz_surface_t *surface = abstract_surface; + glitz_transform_t transform; + + transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]); + transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]); + transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]); - glitz_surface_set_fill (surface->surface, - (repeat)? GLITZ_FILL_REPEAT: - GLITZ_FILL_TRANSPARENT); + transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]); + transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]); + transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]); - return CAIRO_STATUS_SUCCESS; + transform.matrix[2][0] = 0; + transform.matrix[2][1] = 0; + transform.matrix[2][2] = 1 << 16; + + glitz_surface_set_transform (surface->surface, &transform); } static glitz_operator_t @@ -318,32 +451,6 @@ _glitz_operator (cairo_operator_t op) } } -static glitz_surface_t * -_glitz_surface_create_solid (glitz_surface_t *other, - glitz_format_name_t format_name, - glitz_color_t *color) -{ - glitz_drawable_t *drawable; - glitz_format_t *format; - glitz_surface_t *surface; - - drawable = glitz_surface_get_drawable (other); - - format = glitz_find_standard_format (drawable, format_name); - if (format == NULL) - return NULL; - - surface = glitz_surface_create (drawable, format, 1, 1); - if (surface == NULL) - return NULL; - - glitz_set_rectangle (surface, color, 0, 0, 1, 1); - - glitz_surface_set_fill (surface, GLITZ_FILL_REPEAT); - - return surface; -} - static glitz_status_t _glitz_ensure_target (glitz_surface_t *surface) { @@ -355,7 +462,6 @@ _glitz_ensure_target (glitz_surface_t *surface) glitz_drawable_format_t templ; glitz_format_t *format; glitz_drawable_t *pbuffer; - glitz_pbuffer_attributes_t attributes; unsigned long mask; int i; @@ -397,21 +503,13 @@ _glitz_ensure_target (glitz_surface_t *surface) if (!dformat) return CAIRO_INT_STATUS_UNSUPPORTED; - attributes.width = glitz_surface_get_width (surface); - attributes.height = glitz_surface_get_height (surface); - mask = GLITZ_PBUFFER_WIDTH_MASK | GLITZ_PBUFFER_HEIGHT_MASK; - - pbuffer = glitz_create_pbuffer_drawable (drawable, dformat, - &attributes, mask); + pbuffer = + glitz_create_pbuffer_drawable (drawable, dformat, + glitz_surface_get_width (surface), + glitz_surface_get_height (surface)); if (!pbuffer) return CAIRO_INT_STATUS_UNSUPPORTED; - if (glitz_drawable_get_width (pbuffer) < attributes.width || - glitz_drawable_get_height (pbuffer) < attributes.height) { - glitz_drawable_destroy (pbuffer); - return CAIRO_INT_STATUS_UNSUPPORTED; - } - glitz_surface_attach (surface, pbuffer, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR, 0, 0); @@ -422,388 +520,711 @@ _glitz_ensure_target (glitz_surface_t *surface) return CAIRO_STATUS_SUCCESS; } -static glitz_format_name_t -_glitz_format (cairo_format_t format) +typedef struct _cairo_glitz_surface_attributes { + cairo_surface_attributes_t base; + + glitz_fill_t fill; + glitz_filter_t filter; + glitz_fixed16_16_t *params; + int n_params; + cairo_bool_t acquired; +} cairo_glitz_surface_attributes_t; + +static cairo_int_status_t +_cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern, + cairo_glitz_surface_t *dst, + int x, + int y, + unsigned int width, + unsigned int height, + cairo_glitz_surface_t **surface_out, + cairo_glitz_surface_attributes_t *attr) { - switch (format) { + cairo_glitz_surface_t *src = NULL; + + attr->acquired = FALSE; + + switch (pattern->type) { + case CAIRO_PATTERN_LINEAR: + case CAIRO_PATTERN_RADIAL: { + cairo_gradient_pattern_t *gradient = + (cairo_gradient_pattern_t *) pattern; + glitz_drawable_t *drawable; + glitz_fixed16_16_t *params; + int n_params; + int i; + unsigned short alpha; + + /* XXX: the current color gradient acceleration provided by glitz is + * experimental, it's been proven inappropriate in a number of ways, + * most importantly, it's currently implemented as filters and + * gradients are not filters. eventually, it will be replaced with + * something more appropriate. + */ + + if (gradient->n_stops < 2) + break; + + /* glitz doesn't support inner and outer circle with different + center points. */ + if (pattern->type == CAIRO_PATTERN_RADIAL) + { + cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern; + + if (grad->center0.x != grad->center1.x || + grad->center0.y != grad->center1.y) + break; + } + + drawable = glitz_surface_get_drawable (dst->surface); + if (!(glitz_drawable_get_features (drawable) & + GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK)) + break; + + if (pattern->filter != CAIRO_FILTER_BILINEAR && + pattern->filter != CAIRO_FILTER_GOOD && + pattern->filter != CAIRO_FILTER_BEST) + break; + + alpha = (gradient->stops[0].color.alpha * pattern->alpha) * 0xffff; + for (i = 1; i < gradient->n_stops; i++) + { + unsigned short a; + + a = (gradient->stops[i].color.alpha * pattern->alpha) * 0xffff; + if (a != alpha) + break; + } + + /* we can't have color stops with different alpha as gradient color + interpolation should be done to unpremultiplied colors. */ + if (i < gradient->n_stops) + break; + + n_params = gradient->n_stops * 3 + 4; + + params = malloc (sizeof (glitz_fixed16_16_t) * n_params); + if (!params) + return CAIRO_STATUS_NO_MEMORY; + + src = (cairo_glitz_surface_t *) + _cairo_surface_create_similar_scratch (&dst->base, + CAIRO_FORMAT_ARGB32, 0, + gradient->n_stops, 1); + if (!src) + { + free (params); + return CAIRO_STATUS_NO_MEMORY; + } + + for (i = 0; i < gradient->n_stops; i++) { + glitz_color_t color; + + color.red = gradient->stops[i].color.red * alpha; + color.green = gradient->stops[i].color.green * alpha; + color.blue = gradient->stops[i].color.blue * alpha; + color.alpha = alpha; + + glitz_set_rectangle (src->surface, &color, i, 0, 1, 1); + + params[4 + 3 * i] = gradient->stops[i].offset; + params[5 + 3 * i] = i << 16; + params[6 + 3 * i] = 0; + } + + if (pattern->type == CAIRO_PATTERN_LINEAR) + { + cairo_linear_pattern_t *grad = (cairo_linear_pattern_t *) pattern; + + params[0] = _cairo_fixed_from_double (grad->point0.x); + params[1] = _cairo_fixed_from_double (grad->point0.y); + params[2] = _cairo_fixed_from_double (grad->point1.x); + params[3] = _cairo_fixed_from_double (grad->point1.y); + attr->filter = GLITZ_FILTER_LINEAR_GRADIENT; + } + else + { + cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern; + + params[0] = _cairo_fixed_from_double (grad->center0.x); + params[1] = _cairo_fixed_from_double (grad->center0.y); + params[2] = _cairo_fixed_from_double (grad->radius0); + params[3] = _cairo_fixed_from_double (grad->radius1); + attr->filter = GLITZ_FILTER_RADIAL_GRADIENT; + } + + switch (pattern->extend) { + case CAIRO_EXTEND_NONE: + attr->fill = GLITZ_FILL_NEAREST; + break; + case CAIRO_EXTEND_REPEAT: + attr->fill = GLITZ_FILL_REPEAT; + break; + case CAIRO_EXTEND_REFLECT: + attr->fill = GLITZ_FILL_REFLECT; + break; + } + + attr->params = params; + attr->n_params = n_params; + attr->base.matrix = pattern->matrix; + attr->base.x_offset = 0; + attr->base.y_offset = 0; + } break; default: - case CAIRO_FORMAT_ARGB32: - return GLITZ_STANDARD_ARGB32; - case CAIRO_FORMAT_RGB24: - return GLITZ_STANDARD_RGB24; - case CAIRO_FORMAT_A8: - return GLITZ_STANDARD_A8; - case CAIRO_FORMAT_A1: - return GLITZ_STANDARD_A1; + break; } -} -static cairo_surface_t * -_cairo_glitz_surface_create_similar (void *abstract_src, - cairo_format_t format, - int draw, - int width, - int height) -{ - cairo_glitz_surface_t *src = abstract_src; - cairo_surface_t *crsurface; - glitz_drawable_t *drawable; - glitz_surface_t *surface; - glitz_format_t *gformat; + if (!src) + { + cairo_int_status_t status; - drawable = glitz_surface_get_drawable (src->surface); - - gformat = glitz_find_standard_format (drawable, _glitz_format (format)); - if (gformat == NULL) - return NULL; - - surface = glitz_surface_create (drawable, gformat, width, height); - if (surface == NULL) - return NULL; + status = _cairo_pattern_acquire_surface (pattern, &dst->base, + x, y, width, height, + (cairo_surface_t **) &src, + &attr->base); + if (status) + return status; + + if (src) + { + switch (attr->base.extend) { + case CAIRO_EXTEND_NONE: + attr->fill = GLITZ_FILL_TRANSPARENT; + break; + case CAIRO_EXTEND_REPEAT: + attr->fill = GLITZ_FILL_REPEAT; + break; + case CAIRO_EXTEND_REFLECT: + attr->fill = GLITZ_FILL_REFLECT; + break; + } - crsurface = cairo_glitz_surface_create (surface); - - glitz_surface_destroy (surface); + switch (attr->base.filter) { + case CAIRO_FILTER_FAST: + case CAIRO_FILTER_NEAREST: + attr->filter = GLITZ_FILTER_NEAREST; + break; + case CAIRO_FILTER_GOOD: + case CAIRO_FILTER_BEST: + case CAIRO_FILTER_BILINEAR: + default: + attr->filter = GLITZ_FILTER_BILINEAR; + break; + } + + attr->params = NULL; + attr->n_params = 0; + attr->acquired = TRUE; + } + } - return crsurface; + *surface_out = src; + + return CAIRO_STATUS_SUCCESS; } -static cairo_glitz_surface_t * -_cairo_glitz_surface_clone_similar (cairo_glitz_surface_t *templ, - cairo_surface_t *src, - cairo_format_t format) +static void +_cairo_glitz_pattern_release_surface (cairo_glitz_surface_t *dst, + cairo_glitz_surface_t *surface, + cairo_glitz_surface_attributes_t *attr) { - cairo_glitz_surface_t *clone; - cairo_image_surface_t *src_image; + if (attr->acquired) + _cairo_pattern_release_surface (&dst->base, &surface->base, + &attr->base); + else + _cairo_glitz_surface_destroy (surface); +} - src_image = _cairo_surface_get_image (src); +static cairo_int_status_t +_cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t *src, + cairo_pattern_t *mask, + cairo_glitz_surface_t *dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + unsigned int width, + unsigned int height, + cairo_glitz_surface_t **src_out, + cairo_glitz_surface_t **mask_out, + cairo_glitz_surface_attributes_t *sattr, + cairo_glitz_surface_attributes_t *mattr) +{ + cairo_int_status_t status; + cairo_pattern_union_t tmp; + cairo_bool_t src_opaque, mask_opaque; + double src_alpha, mask_alpha; - clone = (cairo_glitz_surface_t *) - _cairo_glitz_surface_create_similar (templ, format, 0, - src_image->width, - src_image->height); - if (clone == NULL) - return NULL; - - _cairo_glitz_surface_set_filter (clone, cairo_surface_get_filter (src)); + src_opaque = _cairo_pattern_is_opaque (src); + mask_opaque = !mask || _cairo_pattern_is_opaque (mask); - _cairo_glitz_surface_set_image (clone, src_image); - - _cairo_glitz_surface_set_matrix (clone, &(src_image->base.matrix)); + /* For surface patterns, we move any translucency from src->alpha + * to mask->alpha so we can use the source unchanged. Otherwise we + * move the translucency from mask->alpha to src->alpha so that + * we can drop the mask if possible. + */ + if (src->type == CAIRO_PATTERN_SURFACE) + { + if (mask) { + mask_opaque = mask_opaque && src_opaque; + mask_alpha = mask->alpha * src->alpha; + } else { + mask_opaque = src_opaque; + mask_alpha = src->alpha; + } + + src_alpha = 1.0; + src_opaque = TRUE; + } + else + { + if (mask) + { + src_opaque = mask_opaque && src_opaque; + src_alpha = mask->alpha * src->alpha; + /* FIXME: This needs changing when we support RENDER + * style 4-channel masks. + */ + if (mask->type == CAIRO_PATTERN_SOLID) + mask = NULL; + } else + src_alpha = src->alpha; + + mask_alpha = 1.0; + mask_opaque = TRUE; + } + + _cairo_pattern_init_copy (&tmp.base, src); + _cairo_pattern_set_alpha (&tmp.base, src_alpha); + + status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst, + src_x, src_y, + width, height, + src_out, sattr); - cairo_surface_destroy (&src_image->base); + _cairo_pattern_fini (&tmp.base); - return clone; -} + if (status) + return status; -static cairo_int_status_t -_glitz_composite (glitz_operator_t op, - glitz_surface_t *src, - glitz_surface_t *mask, - glitz_surface_t *dst, - int src_x, - int src_y, - int mask_x, - int mask_y, - int dst_x, - int dst_y, - int width, - int height, - glitz_buffer_t *geometry, - glitz_geometry_format_t *format) -{ - if (_glitz_ensure_target (dst)) - return CAIRO_INT_STATUS_UNSUPPORTED; + if (mask || !mask_opaque) + { + if (mask) + _cairo_pattern_init_copy (&tmp.base, mask); + else + _cairo_pattern_init_solid (&tmp.solid, 0.0, 0.0, 0.0); - if (glitz_surface_get_status (dst)) - return CAIRO_STATUS_NO_TARGET_SURFACE; - - glitz_set_geometry (dst, - 0, 0, - format, geometry); - - glitz_composite (op, - src, - mask, - dst, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, - width, height); - - glitz_set_geometry (dst, 0, 0, NULL, NULL); + _cairo_pattern_set_alpha (&tmp.base, mask_alpha); + + status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst, + mask_x, mask_y, + width, height, + mask_out, mattr); + + _cairo_pattern_fini (&tmp.base); - if (glitz_surface_get_status (dst) == GLITZ_STATUS_NOT_SUPPORTED) - return CAIRO_INT_STATUS_UNSUPPORTED; + if (status) + { + _cairo_glitz_pattern_release_surface (dst, *src_out, sattr); + return status; + } + } + else + { + *mask_out = NULL; + } return CAIRO_STATUS_SUCCESS; } +static void +_cairo_glitz_surface_set_attributes (cairo_glitz_surface_t *surface, + cairo_glitz_surface_attributes_t *a) +{ + _cairo_glitz_surface_set_matrix (surface, &a->base.matrix); + glitz_surface_set_fill (surface->surface, a->fill); + glitz_surface_set_filter (surface->surface, a->filter, + a->params, a->n_params); +} + static cairo_int_status_t _cairo_glitz_surface_composite (cairo_operator_t op, - cairo_surface_t *generic_src, - cairo_surface_t *generic_mask, - void *abstract_dst, - int src_x, - int src_y, - int mask_x, - int mask_y, - int dst_x, - int dst_y, - unsigned int width, - unsigned int height) + cairo_pattern_t *src_pattern, + cairo_pattern_t *mask_pattern, + void *abstract_dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) { - cairo_glitz_surface_t *dst = abstract_dst; - cairo_glitz_surface_t *src = (cairo_glitz_surface_t *) generic_src; - cairo_glitz_surface_t *mask = (cairo_glitz_surface_t *) generic_mask; - cairo_glitz_surface_t *src_clone = NULL; - cairo_glitz_surface_t *mask_clone = NULL; - cairo_int_status_t status; + cairo_glitz_surface_attributes_t src_attr, mask_attr; + cairo_glitz_surface_t *dst = abstract_dst; + cairo_glitz_surface_t *src; + cairo_glitz_surface_t *mask; + cairo_int_status_t status; if (op == CAIRO_OPERATOR_SATURATE) return CAIRO_INT_STATUS_UNSUPPORTED; - if (generic_src->backend != dst->base.backend) { - src_clone = _cairo_glitz_surface_clone_similar (dst, generic_src, - CAIRO_FORMAT_ARGB32); - if (!src_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; + if (_glitz_ensure_target (dst->surface)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_glitz_pattern_acquire_surfaces (src_pattern, mask_pattern, + dst, + src_x, src_y, + mask_x, mask_y, + width, height, + &src, &mask, + &src_attr, &mask_attr); + if (status) + return status; + + _cairo_glitz_surface_set_attributes (src, &src_attr); + if (mask) + { + _cairo_glitz_surface_set_attributes (mask, &mask_attr); + glitz_composite (_glitz_operator (op), + src->surface, + mask->surface, + dst->surface, + src_x + src_attr.base.x_offset, + src_y + src_attr.base.y_offset, + mask_x + mask_attr.base.x_offset, + mask_y + mask_attr.base.y_offset, + dst_x, dst_y, + width, height); - src = src_clone; - } - - if (generic_mask && (generic_mask->backend != dst->base.backend)) { - mask_clone = _cairo_glitz_surface_clone_similar (dst, generic_mask, - CAIRO_FORMAT_A8); - if (!mask_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; + if (mask_attr.n_params) + free (mask_attr.params); - mask = mask_clone; + _cairo_glitz_pattern_release_surface (dst, mask, &mask_attr); + } + else + { + glitz_composite (_glitz_operator (op), + src->surface, + NULL, + dst->surface, + src_x + src_attr.base.x_offset, + src_y + src_attr.base.y_offset, + 0, 0, + dst_x, dst_y, + width, height); } - status = _glitz_composite (_glitz_operator (op), - src->surface, - (mask)? mask->surface: NULL, - dst->surface, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, - width, height, - NULL, NULL); - - if (src_clone) - cairo_surface_destroy (&src_clone->base); - - if (mask_clone) - cairo_surface_destroy (&mask_clone->base); + if (src_attr.n_params) + free (src_attr.params); - return status; + _cairo_glitz_pattern_release_surface (dst, src, &src_attr); + + if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) + return CAIRO_INT_STATUS_UNSUPPORTED; + + return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t -_cairo_glitz_surface_fill_rectangles (void *abstract_dst, - cairo_operator_t op, +_cairo_glitz_surface_fill_rectangles (void *abstract_dst, + cairo_operator_t op, const cairo_color_t *color, - cairo_rectangle_t *rects, - int n_rects) + cairo_rectangle_t *rects, + int n_rects) { cairo_glitz_surface_t *dst = abstract_dst; - glitz_color_t glitz_color; - if (op == CAIRO_OPERATOR_SATURATE) - return CAIRO_INT_STATUS_UNSUPPORTED; - - glitz_color.red = color->red_short; - glitz_color.green = color->green_short; - glitz_color.blue = color->blue_short; - glitz_color.alpha = color->alpha_short; + if (op == CAIRO_OPERATOR_SRC) + { + glitz_color_t glitz_color; + + glitz_color.red = color->red_short; + glitz_color.green = color->green_short; + glitz_color.blue = color->blue_short; + glitz_color.alpha = color->alpha_short; + + if (glitz_surface_get_width (dst->surface) != 1 || + glitz_surface_get_height (dst->surface) != 1) + _glitz_ensure_target (dst->surface); - if (op != CAIRO_OPERATOR_SRC) { - glitz_surface_t *solid; - glitz_float_t *vertices; - glitz_buffer_t *buffer; - glitz_geometry_format_t gf; - cairo_int_status_t status; - int width, height; - void *data; + glitz_set_rectangles (dst->surface, &glitz_color, + (glitz_rectangle_t *) rects, n_rects); + } + else + { + cairo_glitz_surface_t *src; - gf.mode = GLITZ_GEOMETRY_MODE_DIRECT; - gf.edge_hint = GLITZ_GEOMETRY_EDGE_HINT_SHARP; - gf.primitive = GLITZ_GEOMETRY_PRIMITIVE_QUADS; - gf.type = GLITZ_DATA_TYPE_FLOAT; - gf.first = 0; - gf.count = n_rects * 4; - - data = malloc (n_rects * 8 * sizeof (glitz_float_t)); - if (!data) - return CAIRO_STATUS_NO_MEMORY; - - buffer = glitz_buffer_create_for_data (data); - if (buffer == NULL) { - free (data); - return CAIRO_STATUS_NO_MEMORY; - } + if (op == CAIRO_OPERATOR_SATURATE) + return CAIRO_INT_STATUS_UNSUPPORTED; - width = height = 0; - vertices = glitz_buffer_map (buffer, GLITZ_BUFFER_ACCESS_WRITE_ONLY); - for (; n_rects; rects++, n_rects--) { - *vertices++ = (glitz_float_t) rects->x; - *vertices++ = (glitz_float_t) rects->y; - *vertices++ = (glitz_float_t) (rects->x + rects->width); - *vertices++ = (glitz_float_t) rects->y; - *vertices++ = (glitz_float_t) (rects->x + rects->width); - *vertices++ = (glitz_float_t) (rects->y + rects->height); - *vertices++ = (glitz_float_t) rects->x; - *vertices++ = (glitz_float_t) (rects->y + rects->height); - - if ((rects->x + rects->width) > width) - width = rects->x + rects->width; - - if ((rects->y + rects->height) > height) - height = rects->y + rects->height; - } - glitz_buffer_unmap (buffer); + if (_glitz_ensure_target (dst->surface)) + return CAIRO_INT_STATUS_UNSUPPORTED; - solid = _glitz_surface_create_solid (dst->surface, - GLITZ_STANDARD_ARGB32, - &glitz_color); - if (solid == NULL) + src = (cairo_glitz_surface_t *) + _cairo_surface_create_similar_solid (&dst->base, + CAIRO_FORMAT_ARGB32, 1, 1, + (cairo_color_t *) color); + if (!src) return CAIRO_STATUS_NO_MEMORY; - - status = _glitz_composite (_glitz_operator (op), - solid, - NULL, - dst->surface, - 0, 0, - 0, 0, - 0, 0, - width, height, - buffer, &gf); - - glitz_surface_destroy (solid); - glitz_buffer_destroy (buffer); - free (data); - - return status; - } else { - if (glitz_surface_get_width (dst->surface) != 1 || - glitz_surface_get_height (dst->surface) != 1) { - if (_glitz_ensure_target (dst->surface)) - return CAIRO_INT_STATUS_UNSUPPORTED; + + while (n_rects--) + { + glitz_composite (_glitz_operator (op), + src->surface, + NULL, + dst->surface, + 0, 0, + 0, 0, + rects->x, rects->y, + rects->width, rects->height); + rects++; } - glitz_set_rectangles (dst->surface, &glitz_color, - (glitz_rectangle_t *) rects, n_rects); + cairo_surface_destroy (&src->base); } + if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) + return CAIRO_INT_STATUS_UNSUPPORTED; + return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t -_cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, - cairo_surface_t *generic_src, - void *abstract_dst, - int x_src, - int y_src, +_cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, + cairo_pattern_t *pattern, + void *abstract_dst, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, cairo_trapezoid_t *traps, - int n_traps) + int n_traps) { - cairo_glitz_surface_t *dst = abstract_dst; - cairo_glitz_surface_t *src = (cairo_glitz_surface_t *) generic_src; - glitz_surface_t *mask = NULL; - glitz_float_t *vertices; - glitz_buffer_t *buffer; - glitz_geometry_format_t gf; - cairo_int_status_t status; - int x_dst, y_dst, x_rel, y_rel, width, height; - void *data; + cairo_glitz_surface_attributes_t attributes; + cairo_glitz_surface_t *dst = abstract_dst; + cairo_glitz_surface_t *src; + cairo_glitz_surface_t *mask = NULL; + glitz_buffer_t *buffer = NULL; + void *data = NULL; + cairo_int_status_t status; + unsigned short alpha; if (op == CAIRO_OPERATOR_SATURATE) return CAIRO_INT_STATUS_UNSUPPORTED; - if (generic_src->backend != dst->base.backend) + if (_glitz_ensure_target (dst->surface)) return CAIRO_INT_STATUS_UNSUPPORTED; - gf.mode = GLITZ_GEOMETRY_MODE_DIRECT; - gf.edge_hint = GLITZ_GEOMETRY_EDGE_HINT_GOOD_SMOOTH; - gf.primitive = GLITZ_GEOMETRY_PRIMITIVE_QUADS; - gf.type = GLITZ_DATA_TYPE_FLOAT; - gf.first = 0; - gf.count = n_traps * 4; + if (pattern->type == CAIRO_PATTERN_SURFACE) + { + cairo_pattern_union_t tmp; - data = malloc (n_traps * 8 * sizeof (glitz_float_t)); - if (!data) - return CAIRO_STATUS_NO_MEMORY; - - buffer = glitz_buffer_create_for_data (data); - if (buffer == NULL) { - free (data); - return CAIRO_STATUS_NO_MEMORY; - } - - x_dst = traps[0].left.p1.x >> 16; - y_dst = traps[0].left.p1.y >> 16; + _cairo_pattern_init_copy (&tmp.base, pattern); + _cairo_pattern_set_alpha (&tmp.base, 1.0); - vertices = glitz_buffer_map (buffer, GLITZ_BUFFER_ACCESS_WRITE_ONLY); - for (; n_traps; traps++, n_traps--) { - glitz_float_t top, bottom; + status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst, + src_x, src_y, + width, height, + &src, &attributes); - top = GLITZ_FIXED_TO_FLOAT (traps->top); - bottom = GLITZ_FIXED_TO_FLOAT (traps->bottom); + _cairo_pattern_fini (&tmp.base); - *vertices++ = GLITZ_FIXED_LINE_X_TO_FLOAT (traps->left, traps->top); - *vertices++ = top; - *vertices++ = - GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT (traps->right, traps->top); - *vertices++ = top; - *vertices++ = - GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT (traps->right, traps->bottom); - *vertices++ = bottom; - *vertices++ = GLITZ_FIXED_LINE_X_TO_FLOAT (traps->left, traps->bottom); - *vertices++ = bottom; + alpha = pattern->alpha * 0xffff; } - glitz_buffer_unmap (buffer); + else + { + status = _cairo_glitz_pattern_acquire_surface (pattern, dst, + src_x, src_y, + width, height, + &src, &attributes); + alpha = 0xffff; + } + + if (status) + return status; + + if (op == CAIRO_OPERATOR_ADD || n_traps <= 1) + { + static glitz_color_t clear_black = { 0, 0, 0, 0 }; + glitz_color_t color; + glitz_geometry_format_t format; + int n_trap_added; + int offset = 0; + int data_size = 0; + int size = 30 * n_traps; /* just a guess */ + + format.vertex.primitive = GLITZ_PRIMITIVE_QUADS; + format.vertex.type = GLITZ_DATA_TYPE_FLOAT; + format.vertex.bytes_per_vertex = 3 * sizeof (glitz_float_t); + format.vertex.attributes = GLITZ_VERTEX_ATTRIBUTE_MASK_COORD_MASK; + format.vertex.mask.type = GLITZ_DATA_TYPE_FLOAT; + format.vertex.mask.size = GLITZ_COORDINATE_SIZE_X; + format.vertex.mask.offset = 2 * sizeof (glitz_float_t); + + mask = (cairo_glitz_surface_t *) + _cairo_glitz_surface_create_similar (&dst->base, + CAIRO_FORMAT_A8, 0, + 2, 1); + if (!mask) + { + _cairo_glitz_pattern_release_surface (dst, src, &attributes); + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + color.red = color.green = color.blue = color.alpha = alpha; - if ((src->pattern.type == CAIRO_PATTERN_SURFACE) && - (src->pattern.color.alpha != 1.0)) { - glitz_color_t color; + glitz_set_rectangle (mask->surface, &clear_black, 0, 0, 1, 1); + glitz_set_rectangle (mask->surface, &color, 1, 0, 1, 1); + + glitz_surface_set_fill (mask->surface, GLITZ_FILL_NEAREST); + glitz_surface_set_filter (mask->surface, + GLITZ_FILTER_BILINEAR, + NULL, 0); + + size *= format.vertex.bytes_per_vertex; - color.red = color.green = color.blue = 0; - color.alpha = src->pattern.color.alpha_short; + while (n_traps) + { + if (data_size < size) + { + data_size = size; + data = realloc (data, data_size); + if (!data) + { + _cairo_glitz_pattern_release_surface (dst, src, + &attributes); + return CAIRO_STATUS_NO_MEMORY; + } + + if (buffer) + glitz_buffer_destroy (buffer); + + buffer = glitz_buffer_create_for_data (data); + if (!buffer) { + free (data); + _cairo_glitz_pattern_release_surface (dst, src, + &attributes); + return CAIRO_STATUS_NO_MEMORY; + } + } - mask = _glitz_surface_create_solid (dst->surface, - GLITZ_STANDARD_A8, - &color); + offset += + glitz_add_trapezoids (buffer, + offset, size - offset, + format.vertex.type, mask->surface, + (glitz_trapezoid_t *) traps, n_traps, + &n_trap_added); + + n_traps -= n_trap_added; + traps += n_trap_added; + size *= 2; + } + + glitz_set_geometry (dst->surface, + GLITZ_GEOMETRY_TYPE_VERTEX, + &format, buffer); + glitz_set_array (dst->surface, 0, 3, + offset / format.vertex.bytes_per_vertex, + 0, 0); } + else + { + cairo_image_surface_t *image; + char *ptr; + int stride; + + stride = (width + 3) & -4; + data = malloc (stride * height); + if (!data) + { + _cairo_glitz_pattern_release_surface (dst, src, &attributes); + return CAIRO_STATUS_NO_MEMORY; + } + + memset (data, 0, stride * height); - x_rel = (src->pattern_box.p1.x >> 16) + x_src - x_dst; - y_rel = (src->pattern_box.p1.y >> 16) + y_src - y_dst; + /* using negative stride */ + ptr = (char *) data + stride * (height - 1); + + image = (cairo_image_surface_t *) + cairo_image_surface_create_for_data (ptr, + CAIRO_FORMAT_A8, + width, height, + -stride); + if (!image) + { + cairo_surface_destroy (&src->base); + free (data); + return CAIRO_STATUS_NO_MEMORY; + } - x_dst = src->pattern_box.p1.x >> 16; - y_dst = src->pattern_box.p1.y >> 16; + pixman_add_trapezoids (image->pixman_image, -dst_x, -dst_y, + (pixman_trapezoid_t *) traps, n_traps); + + if (alpha != 0xffff) + { + pixman_color_t color; + + color.red = color.green = color.blue = color.alpha = alpha; + + pixman_fill_rectangle (PIXMAN_OPERATOR_IN, + image->pixman_image, + &color, + 0, 0, width, height); + } + + mask = (cairo_glitz_surface_t *) + _cairo_surface_create_similar_scratch (&dst->base, + CAIRO_FORMAT_A8, 0, + width, height); + if (!mask) + { + _cairo_glitz_pattern_release_surface (dst, src, &attributes); + free (data); + cairo_surface_destroy (&image->base); + return CAIRO_STATUS_NO_MEMORY; + } + + _cairo_glitz_surface_set_image (mask, image, 0, 0); + } + + _cairo_glitz_surface_set_attributes (src, &attributes); - width = ((src->pattern_box.p2.x + 65535) >> 16) - - (src->pattern_box.p1.x >> 16); - height = ((src->pattern_box.p2.y + 65535) >> 16) - - (src->pattern_box.p1.y >> 16); + glitz_composite (_glitz_operator (op), + src->surface, + mask->surface, + dst->surface, + src_x + attributes.base.x_offset, + src_y + attributes.base.y_offset, + 0, 0, + dst_x, dst_y, + width, height); + + if (attributes.n_params) + free (attributes.params); + + glitz_set_geometry (dst->surface, + GLITZ_GEOMETRY_TYPE_NONE, + NULL, NULL); + + if (buffer) + glitz_buffer_destroy (buffer); - status = _glitz_composite (_glitz_operator (op), - src->surface, - mask, - dst->surface, - x_rel, y_rel, - 0, 0, - x_dst, y_dst, - width, height, - buffer, &gf); + free (data); + _cairo_glitz_pattern_release_surface (dst, src, &attributes); if (mask) - glitz_surface_destroy (mask); + cairo_surface_destroy (&mask->base); - glitz_buffer_destroy (buffer); - free (data); + if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) + return CAIRO_INT_STATUS_UNSUPPORTED; - return status; + return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t @@ -819,173 +1240,56 @@ _cairo_glitz_surface_show_page (void *abstract_surface) } static cairo_int_status_t -_cairo_glitz_surface_create_pattern (void *abstract_dst, - cairo_pattern_t *pattern, - cairo_box_t *box) +_cairo_glitz_surface_set_clip_region (void *abstract_surface, + pixman_region16_t *region) { - cairo_glitz_surface_t *dst = abstract_dst; - cairo_surface_t *generic_src = NULL; - cairo_image_surface_t *image = NULL; - cairo_glitz_surface_t *src; - - switch (pattern->type) { - case CAIRO_PATTERN_SOLID: - generic_src = - _cairo_surface_create_similar_solid (abstract_dst, - CAIRO_FORMAT_ARGB32, - 1, 1, - &pattern->color); - if (generic_src) - cairo_surface_set_repeat (generic_src, 1); - break; - case CAIRO_PATTERN_RADIAL: - /* glitz doesn't support inner and outer circle with different - center points. */ - if (pattern->u.radial.center0.x != pattern->u.radial.center1.x || - pattern->u.radial.center0.y != pattern->u.radial.center1.y) - break; - /* fall-through */ - case CAIRO_PATTERN_LINEAR: { - glitz_drawable_t *drawable; - glitz_fixed16_16_t *params; - int i, n_params; - - drawable = glitz_surface_get_drawable (dst->surface); - if (!(glitz_drawable_get_features (drawable) & - GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK)) - break; - - if (pattern->filter != CAIRO_FILTER_BILINEAR) - break; - - n_params = pattern->n_stops * 3 + 4; - - params = malloc (sizeof (glitz_fixed16_16_t) * n_params); - if (params == NULL) - return CAIRO_STATUS_NO_MEMORY; - - generic_src = - _cairo_glitz_surface_create_similar (abstract_dst, - CAIRO_FORMAT_ARGB32, 0, - pattern->n_stops, 1); - if (generic_src == NULL) { - free (params); - return CAIRO_STATUS_NO_MEMORY; - } - - src = (cairo_glitz_surface_t *) generic_src; - - for (i = 0; i < pattern->n_stops; i++) { - glitz_color_t color; + cairo_glitz_surface_t *surface = abstract_surface; - color.alpha = pattern->stops[i].color_char[3]; - color.red = pattern->stops[i].color_char[0] * color.alpha; - color.green = pattern->stops[i].color_char[1] * color.alpha; - color.blue = pattern->stops[i].color_char[2] * color.alpha; - color.alpha *= 256; + if (region) + { + glitz_box_t *box; + int n; - glitz_set_rectangle (src->surface, &color, i, 0, 1, 1); - - params[4 + 3 * i] = pattern->stops[i].offset; - params[5 + 3 * i] = i << 16; - params[6 + 3 * i] = 0; - } - - if (pattern->type == CAIRO_PATTERN_LINEAR) { - params[0] = _cairo_fixed_from_double (pattern->u.linear.point0.x); - params[1] = _cairo_fixed_from_double (pattern->u.linear.point0.y); - params[2] = _cairo_fixed_from_double (pattern->u.linear.point1.x); - params[3] = _cairo_fixed_from_double (pattern->u.linear.point1.y); - - glitz_surface_set_filter (src->surface, - GLITZ_FILTER_LINEAR_GRADIENT, - params, n_params); - } else { - params[0] = _cairo_fixed_from_double (pattern->u.radial.center0.x); - params[1] = _cairo_fixed_from_double (pattern->u.radial.center0.y); - params[2] = _cairo_fixed_from_double (pattern->u.radial.radius0); - params[3] = _cairo_fixed_from_double (pattern->u.radial.radius1); - - glitz_surface_set_filter (src->surface, - GLITZ_FILTER_RADIAL_GRADIENT, - params, n_params); - } - - switch (pattern->extend) { - case CAIRO_EXTEND_REPEAT: - glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT); - break; - case CAIRO_EXTEND_REFLECT: - glitz_surface_set_fill (src->surface, GLITZ_FILL_REFLECT); - break; - case CAIRO_EXTEND_NONE: - default: - glitz_surface_set_fill (src->surface, GLITZ_FILL_NEAREST); - break; + if (!surface->clip) + { + surface->clip = pixman_region_create (); + if (!surface->clip) + return CAIRO_STATUS_NO_MEMORY; } + pixman_region_copy (surface->clip, region); - cairo_surface_set_matrix (&src->base, &pattern->matrix); - - free (params); - } break; - case CAIRO_PATTERN_SURFACE: - generic_src = pattern->u.surface.surface; - cairo_surface_reference (generic_src); - break; - } - - if (generic_src == NULL) { - image = _cairo_pattern_get_image (pattern, box); - if (image == NULL) - return CAIRO_STATUS_NO_MEMORY; - - generic_src = &image->base; + box = (glitz_box_t *) pixman_region_rects (surface->clip); + n = pixman_region_num_rects (surface->clip); + glitz_surface_set_clip_region (surface->surface, 0, 0, box, n); } + else + { + glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0); - if (generic_src->backend != dst->base.backend) { - src = _cairo_glitz_surface_clone_similar (dst, generic_src, - CAIRO_FORMAT_ARGB32); - if (src == NULL) - return CAIRO_STATUS_NO_MEMORY; - - cairo_surface_set_repeat (&src->base, generic_src->repeat); - } else - src = (cairo_glitz_surface_t *) generic_src; + if (surface->clip) + pixman_region_destroy (surface->clip); - if (image) - cairo_surface_destroy (&image->base); - - _cairo_pattern_init_copy (&src->pattern, pattern); - src->pattern_box = *box; - - pattern->source = &src->base; + surface->clip = NULL; + } return CAIRO_STATUS_SUCCESS; } -static cairo_int_status_t -_cairo_glitz_surface_set_clip_region (void *abstract_surface, - pixman_region16_t *region) -{ - return CAIRO_INT_STATUS_UNSUPPORTED; -} - static const cairo_surface_backend_t cairo_glitz_surface_backend = { _cairo_glitz_surface_create_similar, _cairo_glitz_surface_destroy, _cairo_glitz_surface_pixels_per_inch, - _cairo_glitz_surface_get_image, - _cairo_glitz_surface_set_image, - _cairo_glitz_surface_set_matrix, - _cairo_glitz_surface_set_filter, - _cairo_glitz_surface_set_repeat, + _cairo_glitz_surface_acquire_source_image, + _cairo_glitz_surface_release_source_image, + _cairo_glitz_surface_acquire_dest_image, + _cairo_glitz_surface_release_dest_image, + _cairo_glitz_surface_clone_similar, _cairo_glitz_surface_composite, _cairo_glitz_surface_fill_rectangles, _cairo_glitz_surface_composite_trapezoids, _cairo_glitz_surface_copy_page, _cairo_glitz_surface_show_page, _cairo_glitz_surface_set_clip_region, - _cairo_glitz_surface_create_pattern, NULL /* show_glyphs */ }; @@ -1004,12 +1308,10 @@ cairo_glitz_surface_create (glitz_surface_t *surface) _cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend); glitz_surface_reference (surface); - crsurface->surface = surface; - crsurface->format = glitz_surface_get_format (surface); - _cairo_pattern_init (&crsurface->pattern); - crsurface->pattern.type = CAIRO_PATTERN_SURFACE; - crsurface->pattern.u.surface.surface = NULL; + crsurface->surface = surface; + crsurface->format = glitz_surface_get_format (surface); + crsurface->clip = NULL; return (cairo_surface_t *) crsurface; } |