diff options
author | Søren Sandmann Pedersen <ssp@redhat.com> | 2012-09-29 15:41:26 -0400 |
---|---|---|
committer | Søren Sandmann Pedersen <ssp@redhat.com> | 2012-09-29 15:41:26 -0400 |
commit | 1f65b69c145d641c0ebd188d944ab1be6f3a67b6 (patch) | |
tree | fb27cd378072ff570c9ebda17975d43cd99f4ae1 | |
parent | 0bfe6b819b569501052a6ebe1cbf64cdaf669d38 (diff) |
Some compositing
-rw-r--r-- | src/cairo-pixman-surface.c | 620 |
1 files changed, 534 insertions, 86 deletions
diff --git a/src/cairo-pixman-surface.c b/src/cairo-pixman-surface.c index 61ba2d96..4c549a65 100644 --- a/src/cairo-pixman-surface.c +++ b/src/cairo-pixman-surface.c @@ -44,6 +44,8 @@ #include "cairo-image-surface-private.h" #include "cairo-pattern-private.h" #include "cairo-clip-inline.h" +#include "cairo-traps-private.h" +#include "cairoint.h" extern const cairo_surface_backend_t cairo_pixman_surface_backend; @@ -173,33 +175,33 @@ create_image_surface (cairo_pixman_surface_t *psurface) cairo_bool_t must_copy = FALSE; cairo_surface_t *image; cairo_format_t format; - + switch (pformat) { case PIXMAN_a8r8g8b8: format = CAIRO_FORMAT_ARGB32; break; - + case PIXMAN_x8r8g8b8: format = CAIRO_FORMAT_RGB24; break; - + case PIXMAN_a8: format = CAIRO_FORMAT_A8; break; - + case PIXMAN_a1: format = CAIRO_FORMAT_A1; break; - + case PIXMAN_r5g6b5: format = CAIRO_FORMAT_RGB16_565; break; - + case PIXMAN_x2r10g10b10: format = CAIRO_FORMAT_RGB30; break; - + case PIXMAN_a8b8g8r8: case PIXMAN_x8b8g8r8: case PIXMAN_b8g8r8a8: case PIXMAN_b8g8r8x8: case PIXMAN_r8g8b8a8: case PIXMAN_r8g8b8x8: case PIXMAN_x14r6g6b6: case PIXMAN_a2r10g10b10: case PIXMAN_x2b10g10r10: @@ -213,23 +215,23 @@ create_image_surface (cairo_pixman_surface_t *psurface) case PIXMAN_b1g2r1: case PIXMAN_a1r1g1b1: case PIXMAN_a1b1g1r1: case PIXMAN_c4: case PIXMAN_g4: case PIXMAN_g1: case PIXMAN_yuy2: case PIXMAN_yv12: - + default: format = CAIRO_FORMAT_ARGB32; must_copy = TRUE; break; } - + if (must_copy) { int width = pixman_image_get_width (pimage); int height = pixman_image_get_height (pimage); pixman_image_t *dest; - + image = cairo_image_surface_create (format, width, height); - + dest = ((cairo_image_surface_t *)image)->pixman_image; - + pixman_image_composite32 (PIXMAN_OP_SRC, pimage, NULL, dest, 0, 0, 0, 0, 0, 0, width, height); @@ -238,7 +240,7 @@ create_image_surface (cairo_pixman_surface_t *psurface) { image = _cairo_image_surface_create_for_pixman_image (pimage, pformat); } - + return image; } @@ -247,7 +249,7 @@ cairo_pixman_surface_map_to_image (void *abstract_other, const cairo_rectangle_int_t *extents) { cairo_pixman_surface_t *surface = abstract_other; - + /* FIXME: if we need to copy, we should only copy extents */ return create_image_surface (surface); } @@ -257,7 +259,7 @@ cairo_pixman_surface_unmap_image (void *abstract_surface, cairo_image_surface_t *image) { cairo_pixman_surface_t *surface = abstract_surface; - + if (image->pixman_image != surface->pimage) { pixman_image_composite32 (PIXMAN_OP_SRC, @@ -266,7 +268,7 @@ cairo_pixman_surface_unmap_image (void *abstract_surface, pixman_image_get_width (surface->pimage), pixman_image_get_height (surface->pimage)); } - + return CAIRO_STATUS_SUCCESS; } @@ -292,7 +294,7 @@ cairo_pixman_surface_acquire_source_image (void *abstract_sur *image_out = (cairo_image_surface_t *)create_image_surface (psurface); *image_extra = NULL; - + /* FIXME: create_image_surface can fail (or should be able to fail) */ return CAIRO_STATUS_SUCCESS; } @@ -318,12 +320,12 @@ cairo_pixman_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle) { cairo_pixman_surface_t *psurface = abstract_surface; - + rectangle->x = 0; rectangle->y = 0; rectangle->width = pixman_image_get_width (psurface->pimage); rectangle->height = pixman_image_get_height (psurface->pimage); - + return CAIRO_STATUS_SUCCESS; } @@ -344,7 +346,7 @@ set_properties (pixman_image_t *image, cairo_pattern_t *pattern) pixman_transform_t transform; pixman_filter_t filter; pixman_repeat_t repeat; - + /* Transform */ transform.matrix[0][0] = _cairo_fixed_16_16_from_double (matrix->xx); transform.matrix[0][1] = _cairo_fixed_16_16_from_double (matrix->xy); @@ -352,11 +354,11 @@ set_properties (pixman_image_t *image, cairo_pattern_t *pattern) transform.matrix[1][0] = _cairo_fixed_16_16_from_double (matrix->yx); transform.matrix[1][1] = _cairo_fixed_16_16_from_double (matrix->yy); transform.matrix[1][2] = _cairo_fixed_16_16_from_double (matrix->y0); - + transform.matrix[2][0] = 0; transform.matrix[2][1] = 0; transform.matrix[2][2] = pixman_fixed_1; - + pixman_image_set_transform (image, &transform); /* Filter */ @@ -380,9 +382,9 @@ set_properties (pixman_image_t *image, cairo_pattern_t *pattern) case CAIRO_FILTER_GAUSSIAN: break; } - + pixman_image_set_filter (image, filter, NULL, -1); - + /* Repeat mode */ switch (pattern->extend) { @@ -399,23 +401,27 @@ set_properties (pixman_image_t *image, cairo_pattern_t *pattern) repeat = PIXMAN_REPEAT_PAD; break; } - + pixman_image_set_repeat (image, repeat); - + pixman_image_set_component_alpha (image, pattern->has_component_alpha); } -static pixman_image_t * -pimage_from_solid_pattern (cairo_solid_pattern_t *solid) +static cairo_int_status_t +pimage_from_solid_pattern (cairo_solid_pattern_t *solid, + pixman_image_t **result) { pixman_color_t pcolor; - + pcolor.red = _cairo_color_double_to_short (solid->color.red); pcolor.green = _cairo_color_double_to_short (solid->color.green); pcolor.blue = _cairo_color_double_to_short (solid->color.blue); pcolor.alpha = _cairo_color_double_to_short (solid->color.alpha); - - return pixman_image_create_solid_fill (&pcolor); + + if (!(*result = pixman_image_create_solid_fill (&pcolor))) + return CAIRO_INT_STATUS_NO_MEMORY; + + return CAIRO_INT_STATUS_SUCCESS; } typedef struct acquire_source_cleanup_t @@ -429,17 +435,25 @@ static void clean_up_acquire (pixman_image_t *image, void *closure) { acquire_source_cleanup_t *info = closure; + + if (info) + { + if (info->image) + { + _cairo_surface_release_source_image ( + info->surface, info->image, info->extra); + } - _cairo_surface_release_source_image ( - info->surface, info->image, info->extra); + free (info); + } } -static pixman_image_t * -pimage_from_surface_pattern (cairo_surface_pattern_t *pattern) +static cairo_int_status_t +pimage_from_surface_pattern (cairo_surface_pattern_t *pattern, + pixman_image_t **result) { - pixman_image_t *simage, *result; - cairo_status_t status; - cairo_image_surface_t *image = NULL; + pixman_image_t *simage; + cairo_int_status_t status; acquire_source_cleanup_t *info = NULL; /* First, get a pixman image that has the right bits */ @@ -448,11 +462,11 @@ pimage_from_surface_pattern (cairo_surface_pattern_t *pattern) case CAIRO_SURFACE_TYPE_PIXMAN: simage = ((cairo_pixman_surface_t *)pattern->surface)->pimage; break; - + case CAIRO_SURFACE_TYPE_IMAGE: simage = ((cairo_image_surface_t *)pattern->surface)->pixman_image; break; - + case CAIRO_SURFACE_TYPE_PDF: case CAIRO_SURFACE_TYPE_PS: case CAIRO_SURFACE_TYPE_XLIB: @@ -479,56 +493,65 @@ pimage_from_surface_pattern (cairo_surface_pattern_t *pattern) case CAIRO_SURFACE_TYPE_COGL: default: if (!(info = malloc (sizeof (acquire_source_cleanup_t)))) - return NULL; - + { + status = CAIRO_INT_STATUS_NO_MEMORY; + goto out; + } + info->surface = pattern->surface; + info->image = NULL; + info->extra = NULL; + status = _cairo_surface_acquire_source_image ( pattern->surface, &info->image, &info->extra); - - if (unlikely (status)) - { - /* FIXME */; - } - simage = image->pixman_image; + if (status != CAIRO_INT_STATUS_SUCCESS) + goto out; + + simage = info->image->pixman_image; break; } - + /* Then create a clone of that image */ - result = pixman_image_create_bits ( - pixman_image_get_format (simage), - pixman_image_get_width (simage), - pixman_image_get_height (simage), - pixman_image_get_data (simage), - pixman_image_get_stride (simage)); - - if (unlikely (result == NULL)) + if (!(*result = pixman_image_create_bits ( + pixman_image_get_format (simage), + pixman_image_get_width (simage), + pixman_image_get_height (simage), + pixman_image_get_data (simage), + pixman_image_get_stride (simage)))) { - /* FIXME */; + status = CAIRO_INT_STATUS_NO_MEMORY; + goto out; } if (info) - pixman_image_set_destroy_function (result, clean_up_acquire, info); - + pixman_image_set_destroy_function (*result, clean_up_acquire, info); + /* Then set the right properties on the clone */ - set_properties (result, (cairo_pattern_t *)pattern); - - return result; + set_properties (*result, (cairo_pattern_t *)pattern); + +out: + if (status != CAIRO_INT_STATUS_SUCCESS) + clean_up_acquire (NULL, info); + + return status; } -static pixman_image_t * -pimage_from_pattern (const cairo_pattern_t *pattern) +static cairo_int_status_t +pimage_from_pattern (const cairo_pattern_t *pattern, pixman_image_t **image) { switch (pattern->type) { case CAIRO_PATTERN_TYPE_SOLID: - return pimage_from_solid_pattern ((cairo_solid_pattern_t *)pattern); + return pimage_from_solid_pattern ( + (cairo_solid_pattern_t *)pattern, image); break; case CAIRO_PATTERN_TYPE_SURFACE: - return pimage_from_surface_pattern ((cairo_surface_pattern_t *)pattern); + return pimage_from_surface_pattern ( + (cairo_surface_pattern_t *)pattern, image); break; - + case CAIRO_PATTERN_TYPE_LINEAR: case CAIRO_PATTERN_TYPE_RADIAL: case CAIRO_PATTERN_TYPE_MESH: @@ -537,45 +560,456 @@ pimage_from_pattern (const cairo_pattern_t *pattern) } } -static pixman_image_t * -clip_to_image (const cairo_clip_t *clip) +static const pixman_color_t white = { 0xffff, 0xffff, 0xffff, 0xffff }; + +#define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768) +#define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767) + +static cairo_bool_t +line_exceeds_16_16 (const cairo_line_t *line) { - pixman_image_t *image; + return + line->p1.x <= CAIRO_FIXED_16_16_MIN || + line->p1.x >= CAIRO_FIXED_16_16_MAX || + + line->p2.x <= CAIRO_FIXED_16_16_MIN || + line->p2.x >= CAIRO_FIXED_16_16_MAX || + + line->p1.y <= CAIRO_FIXED_16_16_MIN || + line->p1.y >= CAIRO_FIXED_16_16_MAX || + + line->p2.y <= CAIRO_FIXED_16_16_MIN || + line->p2.y >= CAIRO_FIXED_16_16_MAX; +} + +static void +project_line_x_onto_16_16 (const cairo_line_t *line, + cairo_fixed_t top, + cairo_fixed_t bottom, + pixman_line_fixed_t *out) +{ + /* XXX use fixed-point arithmetic? */ + cairo_point_double_t p1, p2; + double m; + + p1.x = _cairo_fixed_to_double (line->p1.x); + p1.y = _cairo_fixed_to_double (line->p1.y); + + p2.x = _cairo_fixed_to_double (line->p2.x); + p2.y = _cairo_fixed_to_double (line->p2.y); + + m = (p2.x - p1.x) / (p2.y - p1.y); + out->p1.x = _cairo_fixed_16_16_from_double ( + p1.x + m * _cairo_fixed_to_double (top - line->p1.y)); + out->p2.x = _cairo_fixed_16_16_from_double ( + p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y)); +} + +static void +ptrap_from_cairo_trap (pixman_trapezoid_t *ptrap, cairo_trapezoid_t *trap) +{ + /* top/bottom will be clamped to surface bounds */ + ptrap->top = _cairo_fixed_to_16_16 (trap->top); + ptrap->bottom = _cairo_fixed_to_16_16 (trap->bottom); + + /* However, all the other coordinates will have been left + * untouched so as not to introduce numerical error. Recompute + * them if they + * exceed the 16.16 limits. + */ + if (unlikely (line_exceeds_16_16 (&trap->left))) + { + project_line_x_onto_16_16 ( + &trap->left, trap->top, trap->bottom, &ptrap->left); + + ptrap->left.p1.y = ptrap->top; + ptrap->left.p2.y = ptrap->bottom; + } + else + { + ptrap->left.p1.x = _cairo_fixed_to_16_16 (trap->left.p1.x); + ptrap->left.p1.y = _cairo_fixed_to_16_16 (trap->left.p1.y); + ptrap->left.p2.x = _cairo_fixed_to_16_16 (trap->left.p2.x); + ptrap->left.p2.y = _cairo_fixed_to_16_16 (trap->left.p2.y); + } + + if (unlikely (line_exceeds_16_16 (&trap->right))) + { + project_line_x_onto_16_16 ( + &trap->right, trap->top, trap->bottom, &ptrap->right); + ptrap->right.p1.y = ptrap->top; + ptrap->right.p2.y = ptrap->bottom; + } + else + { + ptrap->right.p1.x = _cairo_fixed_to_16_16 (trap->right.p1.x); + ptrap->right.p1.y = _cairo_fixed_to_16_16 (trap->right.p1.y); + ptrap->right.p2.x = _cairo_fixed_to_16_16 (trap->right.p2.x); + ptrap->right.p2.y = _cairo_fixed_to_16_16 (trap->right.p2.y); + } +} + +static cairo_int_status_t +create_clip_image (const cairo_clip_t *clip, pixman_image_t **clip_image) +{ + cairo_int_status_t status; + pixman_trapezoid_t *traps; + pixman_image_t *white_img; + cairo_clip_path_t *clip_path; int i; - image = pixman_image_create_bits ( - PIXMAN_a8, clip->extents.width, clip->extents.height, NULL, -1); + status = CAIRO_INT_STATUS_SUCCESS; + + if (!clip) + { + *clip_image = NULL; + goto out; + } + else if (!(*clip_image = pixman_image_create_bits ( + PIXMAN_a8, clip->extents.width, clip->extents.height, + NULL, -1))) + { + status = CAIRO_INT_STATUS_NO_MEMORY; + goto out; + } + /* First add the boxes */ + if (!(traps = malloc (clip->num_boxes * sizeof (pixman_trapezoid_t)))) + { + status = CAIRO_INT_STATUS_NO_MEMORY; + goto out; + } + for (i = 0; i < clip->num_boxes; ++i) { cairo_box_t *box = &(clip->boxes[i]); + pixman_trapezoid_t *trap = &(traps[i]); + + trap->top = _cairo_fixed_to_16_16 (box->p1.y); + trap->bottom = _cairo_fixed_to_16_16 (box->p2.y); + + trap->left.p1.x = _cairo_fixed_to_16_16 (box->p1.x); + trap->left.p1.y = _cairo_fixed_to_16_16 (box->p1.y); + trap->left.p2.x = _cairo_fixed_to_16_16 (box->p1.x); + trap->left.p2.y = _cairo_fixed_to_16_16 (box->p2.y); + + trap->right.p1.x = _cairo_fixed_to_16_16 (box->p2.x); + trap->right.p1.y = _cairo_fixed_to_16_16 (box->p1.y); + trap->right.p2.x = _cairo_fixed_to_16_16 (box->p2.x); + trap->right.p2.y = _cairo_fixed_to_16_16 (box->p2.y); } - return image; + pixman_add_trapezoids (*clip_image, 0, 0, clip->num_boxes, traps); + + /* Then intersect with all the paths */ + if (!(white_img = pixman_image_create_solid_fill ((pixman_color_t *)&white))) + { + status = CAIRO_INT_STATUS_NO_MEMORY; + goto out; + } + + for (clip_path = clip->path; clip_path != NULL; clip_path = clip_path->prev) + { + cairo_polygon_t polygon; + cairo_traps_t traps; + pixman_trapezoid_t *ptraps; + int i; + + _cairo_polygon_init (&polygon, NULL, 0); + _cairo_traps_init (&traps); + + _cairo_path_fixed_fill_to_polygon ( + &clip_path->path, clip_path->tolerance, &polygon); + + status = _cairo_bentley_ottmann_tessellate_polygon ( + &traps, &polygon, clip_path->fill_rule); + + if (!(ptraps = malloc (traps.num_traps * sizeof (pixman_trapezoid_t)))) + status = CAIRO_INT_STATUS_NO_MEMORY; + + if (status == CAIRO_INT_STATUS_SUCCESS) + { + for (i = 0; i < traps.num_traps; ++i) + { + cairo_trapezoid_t *trap = &(traps.traps[i]); + pixman_trapezoid_t *ptrap = &ptraps[i]; + + ptrap_from_cairo_trap (ptrap, trap); + } + + pixman_composite_trapezoids ( + PIXMAN_OP_IN, white_img, *clip_image, PIXMAN_a8, 0, 0, 0, 0, + traps.num_traps, ptraps); + } + + free (ptraps); + _cairo_polygon_fini (&polygon); + _cairo_traps_fini (&traps); + } + +out: + if (status != CAIRO_INT_STATUS_SUCCESS && *clip_image) + pixman_image_unref (*clip_image); + + if (white_img) + pixman_image_unref (white_img); + + if (traps) + free (traps); + + return status; +} + +static pixman_op_t +_pixman_operator (cairo_operator_t op) +{ + switch ((int) op) { + case CAIRO_OPERATOR_CLEAR: + return PIXMAN_OP_CLEAR; + + case CAIRO_OPERATOR_SOURCE: + return PIXMAN_OP_SRC; + case CAIRO_OPERATOR_OVER: + return PIXMAN_OP_OVER; + case CAIRO_OPERATOR_IN: + return PIXMAN_OP_IN; + case CAIRO_OPERATOR_OUT: + return PIXMAN_OP_OUT; + case CAIRO_OPERATOR_ATOP: + return PIXMAN_OP_ATOP; + + case CAIRO_OPERATOR_DEST: + return PIXMAN_OP_DST; + case CAIRO_OPERATOR_DEST_OVER: + return PIXMAN_OP_OVER_REVERSE; + case CAIRO_OPERATOR_DEST_IN: + return PIXMAN_OP_IN_REVERSE; + case CAIRO_OPERATOR_DEST_OUT: + return PIXMAN_OP_OUT_REVERSE; + case CAIRO_OPERATOR_DEST_ATOP: + return PIXMAN_OP_ATOP_REVERSE; + + case CAIRO_OPERATOR_XOR: + return PIXMAN_OP_XOR; + case CAIRO_OPERATOR_ADD: + return PIXMAN_OP_ADD; + case CAIRO_OPERATOR_SATURATE: + return PIXMAN_OP_SATURATE; + + case CAIRO_OPERATOR_MULTIPLY: + return PIXMAN_OP_MULTIPLY; + case CAIRO_OPERATOR_SCREEN: + return PIXMAN_OP_SCREEN; + case CAIRO_OPERATOR_OVERLAY: + return PIXMAN_OP_OVERLAY; + case CAIRO_OPERATOR_DARKEN: + return PIXMAN_OP_DARKEN; + case CAIRO_OPERATOR_LIGHTEN: + return PIXMAN_OP_LIGHTEN; + case CAIRO_OPERATOR_COLOR_DODGE: + return PIXMAN_OP_COLOR_DODGE; + case CAIRO_OPERATOR_COLOR_BURN: + return PIXMAN_OP_COLOR_BURN; + case CAIRO_OPERATOR_HARD_LIGHT: + return PIXMAN_OP_HARD_LIGHT; + case CAIRO_OPERATOR_SOFT_LIGHT: + return PIXMAN_OP_SOFT_LIGHT; + case CAIRO_OPERATOR_DIFFERENCE: + return PIXMAN_OP_DIFFERENCE; + case CAIRO_OPERATOR_EXCLUSION: + return PIXMAN_OP_EXCLUSION; + case CAIRO_OPERATOR_HSL_HUE: + return PIXMAN_OP_HSL_HUE; + case CAIRO_OPERATOR_HSL_SATURATION: + return PIXMAN_OP_HSL_SATURATION; + case CAIRO_OPERATOR_HSL_COLOR: + return PIXMAN_OP_HSL_COLOR; + case CAIRO_OPERATOR_HSL_LUMINOSITY: + return PIXMAN_OP_HSL_LUMINOSITY; + + default: + ASSERT_NOT_REACHED; + return PIXMAN_OP_OVER; + } } static cairo_int_status_t -cairo_pixman_surface_paint (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_clip_t *clip) +combine_mask_and_clip (pixman_image_t *mask_image, pixman_image_t *clip_image, + pixman_image_t **combined) { - cairo_pixman_surface_t *psurface = abstract_surface; - pixman_image_t *image = pimage_from_pattern (source); + if (mask_image && clip_image) + { + int width = pixman_image_get_width (mask_image); + int height = pixman_image_get_height (mask_image); + + if (!(*combined = pixman_image_create_bits ( + pixman_image_get_format (mask_image), + width, height, NULL, -1))) + { + return CAIRO_INT_STATUS_NO_MEMORY; + } + + pixman_image_composite32 ( + PIXMAN_OP_SRC, + clip_image, mask_image, *combined, + 0, 0, 0, 0, 0, 0, width, height); + + pixman_image_set_component_alpha ( + *combined, pixman_image_get_component_alpha (mask_image)); + } + else if (mask_image) + { + *combined = pixman_image_ref (mask_image); + } + else if (clip_image) + { + *combined = pixman_image_ref (clip_image); + } + else + { + *combined = NULL; + } + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +clip_and_composite (cairo_pixman_surface_t *psurface, + cairo_operator_t operator, + const cairo_pattern_t *source, + pixman_image_t *mask_image, + const cairo_clip_t *clip) +{ + pixman_image_t *dest_image = psurface->pimage; + int width = pixman_image_get_width (dest_image); + int height = pixman_image_get_height (dest_image); + pixman_image_t *src_image = NULL; pixman_image_t *clip_image = NULL; + pixman_image_t *combined = NULL; + cairo_int_status_t status; + pixman_op_t pop; + + status = CAIRO_INT_STATUS_SUCCESS; + + if (clip && _cairo_clip_is_all_clipped (clip)) + goto out; + + status = create_clip_image (clip, &clip_image); + if (status != CAIRO_INT_STATUS_SUCCESS) + goto out; - clip_image = clip_to_image (clip); + status = pimage_from_pattern (source, &src_image); + if (status != CAIRO_INT_STATUS_SUCCESS) + goto out; + + if (!(status = pimage_from_pattern (source, &src_image))) + goto out; + + pop = _pixman_operator (operator); - if (clip) + if (pop == PIXMAN_OP_CLEAR) { - if (_cairo_clip_is_all_clipped (clip)) - return CAIRO_STATUS_SUCCESS; - - clip_image = clip_to_image (clip); + if (clip_image) + { + pixman_image_composite32 ( + PIXMAN_OP_OUT_REVERSE, + clip_image, mask_image, dest_image, + 0, 0, 0, 0, 0, 0, width, height); + } + else + { + pixman_image_composite32 ( + PIXMAN_OP_OUT_REVERSE, + mask_image, NULL, dest_image, + 0, 0, 0, 0, 0, 0, width, height); + } + } + else if (clip_image && + (pop == PIXMAN_OP_IN || + pop == PIXMAN_OP_OUT || + pop == PIXMAN_OP_IN_REVERSE || + pop == PIXMAN_OP_ATOP_REVERSE)) + { + /* First composite to a temporary surface */ + if (!(combined = pixman_image_create_bits ( + pixman_image_get_format (psurface->pimage), + width, height, NULL, -1))) + { + status = CAIRO_INT_STATUS_NO_MEMORY; + + goto out; + } + + pixman_image_composite32 ( + PIXMAN_OP_SRC, + dest_image, NULL, combined, + 0, 0, 0, 0, 0, 0, width, height); + + pixman_image_composite32 ( + pop, + src_image, mask_image, combined, + 0, 0, 0, 0, 0, 0, width, height); + + /* Then punch out the clip from the destination */ + pixman_image_composite32 ( + PIXMAN_OP_OUT_REVERSE, + clip_image, NULL, dest_image, + 0, 0, 0, 0, 0, 0, width, height); + + /* And add the pieces together */ + pixman_image_composite32 ( + PIXMAN_OP_ADD, + combined, clip_image, dest_image, + 0, 0, 0, 0, 0, 0, width, height); + } + else if (pop == PIXMAN_OP_SRC) + { + status = combine_mask_and_clip (mask_image, clip_image, &combined); + if (status != CAIRO_INT_STATUS_SUCCESS) + goto out; + + pixman_image_composite32 ( + PIXMAN_OP_OUT_REVERSE, + combined, NULL, dest_image, + 0, 0, 0, 0, 0, 0, width, height); + + pixman_image_composite32 ( + PIXMAN_OP_ADD, + src_image, combined, dest_image, + 0, 0, 0, 0, 0, 0, width, height); + } + else + { + status = combine_mask_and_clip (mask_image, clip_image, &combined); + if (status != CAIRO_INT_STATUS_SUCCESS) + goto out; + + pixman_image_composite32 ( + pop, + src_image, combined, dest_image, + 0, 0, 0, 0, 0, 0, width, height); } +out: + if (combined) + pixman_image_unref (combined); + if (clip_image) + pixman_image_unref (clip_image); + if (src_image) + pixman_image_unref (src_image); + return status; +} +static cairo_int_status_t +cairo_pixman_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + cairo_pixman_surface_t *psurface = abstract_surface; + + return clip_and_composite (psurface, op, source, NULL, clip); } static cairo_int_status_t @@ -585,6 +1019,19 @@ cairo_pixman_surface_mask (void *abstract_surface, const cairo_pattern_t *mask, const cairo_clip_t *clip) { + cairo_pixman_surface_t *psurface = abstract_surface; + pixman_image_t *mask_image; + cairo_int_status_t status; + + status = pimage_from_pattern (mask, &mask_image); + if (status == CAIRO_INT_STATUS_SUCCESS) + { + status = clip_and_composite (psurface, op, source, mask_image, clip); + + pixman_image_unref (mask_image); + } + + return status; } static cairo_int_status_t @@ -599,6 +1046,7 @@ cairo_pixman_surface_stroke (void *abstract_surface, cairo_antialias_t antialias, const cairo_clip_t *clip) { + } static cairo_int_status_t |