summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSøren Sandmann Pedersen <ssp@redhat.com>2012-09-29 15:41:26 -0400
committerSøren Sandmann Pedersen <ssp@redhat.com>2012-09-29 15:41:26 -0400
commit1f65b69c145d641c0ebd188d944ab1be6f3a67b6 (patch)
treefb27cd378072ff570c9ebda17975d43cd99f4ae1
parent0bfe6b819b569501052a6ebe1cbf64cdaf669d38 (diff)
Some compositing
-rw-r--r--src/cairo-pixman-surface.c620
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