summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSøren Sandmann Pedersen <ssp@redhat.com>2012-10-01 01:45:05 -0400
committerSøren Sandmann Pedersen <ssp@redhat.com>2012-10-01 01:45:05 -0400
commit53d119c357451e812b3d0b184ae2c5152540fadd (patch)
treeb8576615d45a7ec9e36ef88a253714ccf32d3c55
parent10fa14d84e365c7f4c951153bd67b54d8a8cf9e5 (diff)
Beginning of command buffer
-rw-r--r--src/cairo-pixman-surface.c898
1 files changed, 888 insertions, 10 deletions
diff --git a/src/cairo-pixman-surface.c b/src/cairo-pixman-surface.c
index 67350dad..b2502230 100644
--- a/src/cairo-pixman-surface.c
+++ b/src/cairo-pixman-surface.c
@@ -339,6 +339,415 @@ cairo_pixman_surface_get_font_options (void *abstract_surface,
_cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON);
}
+typedef enum
+{
+ NEW_BLANK,
+ NEW_BROKEN,
+ NEW_WHITE,
+ NEW_IMAGE,
+ NEW_REGION,
+ NEW_TRAPS,
+ NEW_GLYPHS,
+ COMPOSITE
+} command_type_t;
+
+typedef union
+{
+ command_type_t type;
+
+ /* Create a new image 'id' with the same
+ * format as "based on"
+ */
+ struct
+ {
+ command_type_t type;
+ int id;
+ int based_on;
+ } new_blank;
+
+ struct
+ {
+ command_type_t type;
+ int id;
+ } new_white;
+
+ struct
+ {
+ command_type_t type;
+ } new_broken;
+
+ struct
+ {
+ command_type_t type;
+ int id;
+ pixman_image_t * image;
+ } new_image;
+
+ struct
+ {
+ command_type_t type;
+ int id;
+ pixman_region32_t * region;
+ } new_region;
+
+ struct
+ {
+ command_type_t type;
+ int id;
+ int n_traps;
+ pixman_trapezoid_t * traps;
+ } new_traps;
+
+ struct
+ {
+ command_type_t type;
+ int id;
+ pixman_glyph_cache_t * glyph_cache;
+ int n_glyphs;
+ pixman_glyph_t * glyphs;
+ } new_glyphs;
+
+ struct
+ {
+ command_type_t type;
+ int dest;
+ pixman_op_t op;
+ int src;
+ int mask;
+ } composite;
+
+} command_t;
+
+typedef struct command_buffer_t command_buffer_t;
+
+struct command_buffer_t
+{
+ int oom;
+ int n_commands;
+ int n_allocated;
+ int id;
+
+ command_t commands[1];
+};
+
+static command_buffer_t *
+command_buffer_ensure (command_buffer_t *buffer, int n_more)
+{
+ int required;
+
+ if (buffer->oom)
+ return buffer;
+
+ required = buffer->n_commands + n_more;
+
+ if (required > buffer->n_allocated)
+ {
+ command_buffer_t *new_buffer;
+ int pot = 1;
+
+ while (pot < required)
+ pot *= 2;
+
+ new_buffer = realloc (
+ buffer, sizeof (command_buffer_t) + pot * sizeof (command_t));
+
+ if (!new_buffer)
+ {
+ buffer->oom = 1;
+ return buffer;
+ }
+
+ new_buffer->n_allocated = pot;
+ buffer = new_buffer;
+ }
+
+ return buffer;
+}
+
+static void
+command_buffer_clear (command_buffer_t *buffer)
+{
+ buffer->oom = 0;
+ buffer->n_commands = 0;
+ buffer->n_allocated = 1;
+ buffer->id = 0;
+}
+
+static command_buffer_t *
+command_buffer_new (void)
+{
+ command_buffer_t *buffer = malloc (sizeof (command_buffer_t));
+
+ if (!buffer)
+ return NULL;
+
+ command_buffer_clear (buffer);
+ return buffer;
+}
+
+static void
+command_buffer_free (command_buffer_t *buffer)
+{
+ free (buffer);
+}
+
+static command_buffer_t *
+command_buffer_append (command_buffer_t *buffer,
+ command_t **command, command_type_t type)
+{
+ if (buffer->oom)
+ {
+ /* Just overwrite the first command since
+ * the buffer is unusable anyway
+ */
+ *command = &(buffer->commands[0]);
+ return buffer;
+ }
+
+ buffer = command_buffer_ensure (buffer, 1);
+
+ *command = buffer->commands + buffer->n_commands++;
+ (*command)->type = type;
+
+ return buffer;
+}
+
+static int
+command_buffer_new_white (command_buffer_t **buffer)
+{
+ command_t *command;
+
+ *buffer = command_buffer_append (*buffer, &command, NEW_WHITE);
+
+ command->new_white.id = (*buffer)->id++;
+
+ return command->new_white.id;
+}
+
+static int
+command_buffer_new_blank (command_buffer_t **buffer, int based_on)
+{
+ command_t *command;
+
+ *buffer = command_buffer_append (*buffer, &command, NEW_BLANK);
+
+ command->new_blank.id = (*buffer)->id++;
+ command->new_blank.based_on = based_on;
+
+ return command->new_blank.id;
+}
+
+static int
+command_buffer_new_broken (command_buffer_t **buffer)
+{
+ command_t *command;
+
+ *buffer = command_buffer_append (*buffer, &command, NEW_BROKEN);
+
+ return -1;
+}
+
+static int
+command_buffer_new_image (command_buffer_t **buffer, pixman_image_t *image)
+{
+ command_t *command;
+
+ *buffer = command_buffer_append (*buffer, &command, NEW_IMAGE);
+
+ command->new_image.id = (*buffer)->id++;
+ command->new_image.image = image;
+
+ return command->new_image.id;
+}
+
+static int
+command_buffer_new_region (command_buffer_t **buffer, pixman_region32_t *region)
+{
+ command_t *command;
+
+ *buffer = command_buffer_append (*buffer, &command, NEW_REGION);
+
+ command->new_region.id = (*buffer)->id++;
+ command->new_region.region = region;
+
+ return command->new_region.id;
+}
+
+static int
+command_buffer_new_traps (command_buffer_t **buffer,
+ int n_traps, pixman_trapezoid_t *traps)
+{
+ command_t *command;
+
+ *buffer = command_buffer_append (*buffer, &command, NEW_TRAPS);
+
+ command->new_traps.id = (*buffer)->id++;
+ command->new_traps.n_traps = n_traps;
+ command->new_traps.traps = traps;
+
+ return command->new_traps.id;
+}
+
+static int
+command_buffer_new_glyphs (command_buffer_t **buffer,
+ pixman_glyph_cache_t *glyph_cache,
+ int n_glyphs,
+ pixman_glyph_t *glyphs)
+{
+ command_t *command;
+
+ *buffer = command_buffer_append (*buffer, &command, NEW_GLYPHS);
+
+ command->new_glyphs.id = (*buffer)->id++;
+ command->new_glyphs.glyph_cache = glyph_cache;
+ command->new_glyphs.n_glyphs = n_glyphs;
+ command->new_glyphs.glyphs = glyphs;
+
+ return command->new_glyphs.id;
+}
+
+static void
+command_buffer_composite (command_buffer_t **buffer,
+ int dest, pixman_op_t op,
+ int src, int mask)
+{
+ command_t *command;
+
+ *buffer = command_buffer_append (*buffer, &command, COMPOSITE);
+
+ command->composite.dest = dest;
+ command->composite.src = src;
+ command->composite.mask = mask;
+ command->composite.op = op;
+}
+
+static const pixman_color_t white = { 0xffff, 0xffff, 0xffff, 0xffff };
+
+static cairo_int_status_t
+command_buffer_process (command_buffer_t *buffer, int width, int height)
+{
+ pixman_image_t **images = NULL;
+ pixman_image_t *white_img = NULL;
+ cairo_int_status_t status;
+ int i;
+ int n_images;
+
+ status = CAIRO_INT_STATUS_NO_MEMORY;
+ if (buffer->oom)
+ goto out;
+
+ n_images = buffer->id;
+ if (!(images = calloc (sizeof (pixman_image_t *), n_images)))
+ goto out;
+
+ if (!(white_img = pixman_image_create_solid_fill (&white)))
+ goto out;
+
+ for (i = 0; i < buffer->n_commands; ++i)
+ {
+ command_t *command = &(buffer->commands[i]);
+ pixman_image_t *img;
+ pixman_format_code_t format;
+
+ switch (command->type)
+ {
+ case NEW_BLANK:
+ img = images[command->new_blank.based_on];
+ format = pixman_image_get_format (img);
+ if (format == 0)
+ format = PIXMAN_a8r8g8b8; /* FIXME: set to dest format */
+ img = pixman_image_create_bits (format, width, height, NULL, -1);
+ if (!img)
+ goto out;
+ images[command->new_blank.id] = img;
+ break;
+
+ case NEW_BROKEN:
+ goto out;
+ break;
+
+ case NEW_WHITE:
+ images[command->new_white.id] = pixman_image_ref (white_img);
+ break;
+
+ case NEW_IMAGE:
+ images[command->new_image.id] =
+ pixman_image_ref (command->new_image.image);
+ break;
+
+ case NEW_REGION:
+ if (!(img = pixman_image_create_bits (
+ PIXMAN_a8, width, height, NULL, -1)))
+ {
+ goto out;
+ }
+ pixman_image_set_clip_region32 (img, command->new_region.region);
+ pixman_image_composite32 (PIXMAN_OP_SRC, white_img, NULL, img,
+ 0, 0, 0, 0, 0, 0, width, height);
+ images[command->new_region.id] = img;
+ break;
+
+ case NEW_TRAPS:
+ if (!(img = pixman_image_create_bits (
+ PIXMAN_a8, width, height, NULL, -1)))
+ {
+ goto out;
+ }
+ pixman_add_trapezoids (
+ img, 0, 0,
+ command->new_traps.n_traps,
+ command->new_traps.traps);
+ images[command->new_traps.id] = img;
+ break;
+
+ case NEW_GLYPHS:
+ format = pixman_glyph_get_mask_format (
+ command->new_glyphs.glyph_cache,
+ command->new_glyphs.n_glyphs,
+ command->new_glyphs.glyphs);
+ img = pixman_image_create_bits (format, width, height, NULL, -1);
+ if (!img)
+ goto out;
+ pixman_composite_glyphs (
+ PIXMAN_OP_SRC,
+ white_img, img, format,
+ 0, 0, 0, 0, 0, 0, width, height,
+ command->new_glyphs.glyph_cache,
+ command->new_glyphs.n_glyphs,
+ command->new_glyphs.glyphs);
+ break;
+
+ case COMPOSITE:
+ pixman_image_composite32 (
+ command->composite.op,
+ images[command->composite.src],
+ images[command->composite.mask],
+ images[command->composite.dest],
+ 0, 0, 0, 0, 0, 0, width, height);
+ break;
+ }
+ }
+
+ status = CAIRO_INT_STATUS_SUCCESS;
+
+out:
+ if (images)
+ {
+ for (i = 0; i < n_images; ++i)
+ {
+ if (images[i])
+ pixman_image_unref (images[i]);
+ }
+ free (images);
+ }
+
+ if (white_img)
+ pixman_image_unref (white_img);
+
+ return status;
+}
+
+
static void
set_properties (pixman_image_t *image, cairo_pattern_t *pattern, cairo_matrix_t *matrix)
{
@@ -427,6 +836,24 @@ pimage_from_solid_pattern (cairo_solid_pattern_t *solid,
return CAIRO_INT_STATUS_SUCCESS;
}
+static int
+pimage_from_solid_pattern2 (command_buffer_t **buffer,
+ cairo_solid_pattern_t *solid)
+{
+ pixman_color_t pcolor;
+ pixman_image_t *image;
+
+ 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);
+
+ if (!(image = pixman_image_create_solid_fill (&pcolor)))
+ return command_buffer_new_broken (buffer);
+
+ return command_buffer_new_image (buffer, image);
+}
+
typedef struct acquire_source_cleanup_t
{
cairo_surface_t * surface;
@@ -542,6 +969,93 @@ out:
return status;
}
+static int
+pimage_from_surface_pattern2 (command_buffer_t **buffer,
+ cairo_surface_pattern_t *pattern)
+{
+ pixman_image_t *simage, *image;
+ acquire_source_cleanup_t *info = NULL;
+ cairo_int_status_t status;
+
+ /* First, get a pixman image that has the right bits */
+ switch (pattern->surface->type)
+ {
+ 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:
+ case CAIRO_SURFACE_TYPE_XCB:
+ case CAIRO_SURFACE_TYPE_GLITZ:
+ case CAIRO_SURFACE_TYPE_QUARTZ:
+ case CAIRO_SURFACE_TYPE_WIN32:
+ case CAIRO_SURFACE_TYPE_BEOS:
+ case CAIRO_SURFACE_TYPE_DIRECTFB:
+ case CAIRO_SURFACE_TYPE_SVG:
+ case CAIRO_SURFACE_TYPE_OS2:
+ case CAIRO_SURFACE_TYPE_WIN32_PRINTING:
+ case CAIRO_SURFACE_TYPE_QUARTZ_IMAGE:
+ case CAIRO_SURFACE_TYPE_SCRIPT:
+ case CAIRO_SURFACE_TYPE_QT:
+ case CAIRO_SURFACE_TYPE_RECORDING:
+ case CAIRO_SURFACE_TYPE_VG:
+ case CAIRO_SURFACE_TYPE_GL:
+ case CAIRO_SURFACE_TYPE_DRM:
+ case CAIRO_SURFACE_TYPE_TEE:
+ case CAIRO_SURFACE_TYPE_XML:
+ case CAIRO_SURFACE_TYPE_SKIA:
+ case CAIRO_SURFACE_TYPE_SUBSURFACE:
+ case CAIRO_SURFACE_TYPE_COGL:
+ default:
+ if (!(info = malloc (sizeof (acquire_source_cleanup_t))))
+ return command_buffer_new_broken (buffer);
+
+ info->surface = pattern->surface;
+ info->image = NULL;
+ info->extra = NULL;
+
+ status = _cairo_surface_acquire_source_image (
+ pattern->surface, &info->image, &info->extra);
+
+ if (status != CAIRO_INT_STATUS_SUCCESS)
+ {
+ clean_up_acquire (NULL, info);
+
+ return command_buffer_new_broken (buffer);
+ }
+
+ simage = info->image->pixman_image;
+ break;
+ }
+
+ /* Then create a clone of that image */
+ if (!(image = 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))))
+ {
+ clean_up_acquire (NULL, info);
+
+ return command_buffer_new_broken (buffer);
+ }
+
+ if (info)
+ pixman_image_set_destroy_function (image, clean_up_acquire, info);
+
+ /* Then set the right properties on the clone */
+ set_properties (image, (cairo_pattern_t *)pattern, NULL);
+
+ return command_buffer_new_image (buffer, image);
+}
+
#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
static cairo_int_status_t
@@ -604,6 +1118,66 @@ pimage_from_gradient_pattern (const cairo_gradient_pattern_t *pattern, pixman_im
return status;
}
+static int
+pimage_from_gradient_pattern2 (command_buffer_t **buffer,
+ const cairo_gradient_pattern_t *pattern)
+{
+ pixman_gradient_stop_t *pstops;
+ cairo_circle_double_t extremes[2];
+ pixman_point_fixed_t p1, p2;
+ cairo_int_status_t status;
+ cairo_matrix_t matrix;
+ pixman_image_t *image;
+ unsigned int i;
+
+ if (!(pstops = malloc (pattern->n_stops * sizeof (pixman_gradient_stop_t))))
+ return command_buffer_new_broken (buffer);
+
+ for (i = 0; i < pattern->n_stops; i++)
+ {
+ pstops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
+ pstops[i].color.red = pattern->stops[i].color.red_short;
+ pstops[i].color.green = pattern->stops[i].color.green_short;
+ pstops[i].color.blue = pattern->stops[i].color.blue_short;
+ pstops[i].color.alpha = pattern->stops[i].color.alpha_short;
+ }
+
+ _cairo_gradient_pattern_fit_to_range (
+ pattern, PIXMAN_MAX_INT >> 1, &matrix, extremes);
+
+ p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
+ p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
+ p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
+ p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
+
+ status = CAIRO_INT_STATUS_SUCCESS;
+
+ if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR)
+ {
+ image = pixman_image_create_linear_gradient (
+ &p1, &p2, pstops, pattern->n_stops);
+ }
+ else /* CAIRO_PATTERN_TYPE_RADIAL */
+ {
+ pixman_fixed_t r1, r2;
+
+ r1 = _cairo_fixed_16_16_from_double (extremes[0].radius);
+ r2 = _cairo_fixed_16_16_from_double (extremes[1].radius);
+
+ image = pixman_image_create_radial_gradient (
+ &p1, &p2, r1, r2, pstops, pattern->n_stops);
+ }
+
+ free (pstops);
+
+ if (!image)
+ return command_buffer_new_broken (buffer);
+
+ set_properties (image, (cairo_pattern_t *)pattern, &matrix);
+
+ return command_buffer_new_image (buffer, image);
+}
+
static cairo_int_status_t
pimage_from_mesh_pattern (cairo_pixman_surface_t *surface,
const cairo_mesh_pattern_t *pattern,
@@ -627,6 +1201,30 @@ pimage_from_mesh_pattern (cairo_pixman_surface_t *surface,
return CAIRO_INT_STATUS_SUCCESS;
}
+static int
+pimage_from_mesh_pattern2 (command_buffer_t **buffer,
+ cairo_pixman_surface_t *surface,
+ const cairo_mesh_pattern_t *pattern)
+{
+ int width, height;
+ pixman_image_t *image;
+
+ width = pixman_image_get_width (surface->pimage);
+ height = pixman_image_get_height (surface->pimage);
+
+ image = pixman_image_create_bits (PIXMAN_a8r8g8b8, width, height, NULL, 0);
+ if (!image)
+ return command_buffer_new_broken (buffer);
+
+ _cairo_mesh_pattern_rasterize (pattern,
+ pixman_image_get_data (image),
+ width, height,
+ pixman_image_get_stride (image),
+ 0, 0);
+
+ return command_buffer_new_image (buffer, image);
+}
+
typedef struct
{
const cairo_pattern_t *pattern;
@@ -714,6 +1312,68 @@ pimage_from_raster_source_pattern (cairo_pixman_surface_t *psurface
return CAIRO_INT_STATUS_SUCCESS;
}
+static int
+pimage_from_raster_source_pattern2 (command_buffer_t **buffer,
+ cairo_pixman_surface_t *psurface,
+ const cairo_raster_source_pattern_t *pattern)
+{
+ int width, height;
+ cairo_surface_t *surface;
+ cairo_image_surface_t *image;
+ raster_info_t *info;
+ cairo_int_status_t status;
+ pixman_image_t *result;
+ void *extra;
+
+ width = pixman_image_get_width (psurface->pimage);
+ height = pixman_image_get_height (psurface->pimage);
+
+ surface = _cairo_raster_source_pattern_acquire (
+ &pattern->base, &psurface->base, NULL);
+
+ if (surface == NULL || surface->status)
+ return command_buffer_new_broken (buffer);
+
+ status = _cairo_surface_acquire_source_image (surface, &image, &extra);
+ if (status != CAIRO_INT_STATUS_SUCCESS)
+ {
+ _cairo_raster_source_pattern_release (&pattern->base, surface);
+
+ return command_buffer_new_broken (buffer);
+ }
+
+ if (!(result = pixman_image_create_bits (
+ image->pixman_format, image->width, image->height,
+ (uint32_t *) image->data, image->stride)))
+ {
+ _cairo_surface_release_source_image (surface, image, extra);
+ _cairo_raster_source_pattern_release (&pattern->base, surface);
+
+ return command_buffer_new_broken (buffer);
+ }
+
+ if (!(info = malloc (sizeof (*info))))
+ {
+ pixman_image_unref (result);
+ _cairo_surface_release_source_image (surface, image, extra);
+ _cairo_raster_source_pattern_release (&pattern->base, surface);
+
+ return command_buffer_new_broken (buffer);
+ }
+
+ info->pattern = &pattern->base;
+ info->surface = surface;
+ info->image = image;
+ info->extra = extra;
+
+ pixman_image_set_destroy_function (
+ result, raster_source_clean_up, info);
+
+ set_properties (result, (cairo_pattern_t *)pattern, NULL);
+
+ return command_buffer_new_image (buffer, result);
+}
+
static cairo_int_status_t
pimage_from_pattern (cairo_pixman_surface_t *surface,
const cairo_pattern_t *pattern, pixman_image_t **image)
@@ -753,7 +1413,43 @@ pimage_from_pattern (cairo_pixman_surface_t *surface,
return CAIRO_INT_STATUS_DEGENERATE;
}
-static const pixman_color_t white = { 0xffff, 0xffff, 0xffff, 0xffff };
+static int
+pimage_from_pattern2 (command_buffer_t **buffer,
+ cairo_pixman_surface_t *surface,
+ const cairo_pattern_t *pattern)
+{
+ switch (pattern->type)
+ {
+ case CAIRO_PATTERN_TYPE_SOLID:
+ return pimage_from_solid_pattern2 (
+ buffer, (cairo_solid_pattern_t *)pattern);
+ break;
+
+ case CAIRO_PATTERN_TYPE_SURFACE:
+ return pimage_from_surface_pattern2 (
+ buffer, (cairo_surface_pattern_t *)pattern);
+ break;
+
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ return pimage_from_gradient_pattern2 (
+ buffer, (cairo_gradient_pattern_t *)pattern);
+ break;
+
+ case CAIRO_PATTERN_TYPE_MESH:
+ return pimage_from_mesh_pattern2 (
+ buffer, surface, (cairo_mesh_pattern_t *)pattern);
+ break;
+
+ case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
+ return pimage_from_raster_source_pattern2 (
+ buffer, surface, (cairo_raster_source_pattern_t *)pattern);
+ break;
+ }
+
+ ASSERT_NOT_REACHED;
+ return CAIRO_INT_STATUS_DEGENERATE;
+}
#define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768)
#define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767)
@@ -967,6 +1663,97 @@ out:
return status;
}
+static int
+create_clip_image2 (command_buffer_t **buffer,
+ const cairo_clip_t *clip, int width, int height)
+{
+ cairo_int_status_t status;
+ pixman_trapezoid_t *ptraps = NULL;
+ cairo_clip_path_t *clip_path;
+ int i;
+ int boxes, clip_id, wh;
+
+ status = CAIRO_INT_STATUS_SUCCESS;
+
+ if (!clip)
+ return command_buffer_new_white (buffer);
+
+ /* First add the boxes */
+ if (!(ptraps = malloc (clip->num_boxes * sizeof (pixman_trapezoid_t))))
+ return command_buffer_new_broken (buffer);
+
+ for (i = 0; i < clip->num_boxes; ++i)
+ {
+ cairo_box_t *box = &(clip->boxes[i]);
+ pixman_trapezoid_t *trap = &(ptraps[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);
+ }
+
+ boxes = command_buffer_new_traps (buffer, clip->num_boxes, ptraps);
+ clip_id = command_buffer_new_blank (buffer, boxes);
+ wh = command_buffer_new_white (buffer);
+
+ command_buffer_composite (buffer, clip_id, PIXMAN_OP_SRC, wh, boxes);
+
+ 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 = NULL;
+ int tmp;
+
+ _cairo_polygon_init (&polygon, NULL, 0);
+ _cairo_traps_init (&traps);
+
+ status = _cairo_path_fixed_fill_to_polygon (
+ &clip_path->path, clip_path->tolerance, &polygon);
+
+ if (status != CAIRO_INT_STATUS_SUCCESS)
+ goto exit_loop;
+
+ status = _cairo_bentley_ottmann_tessellate_polygon (
+ &traps, &polygon, clip_path->fill_rule);
+
+ if (status != CAIRO_INT_STATUS_SUCCESS)
+ goto exit_loop;
+
+ if (!(ptraps = traps_to_pixman_trapezoids (&traps)))
+ {
+ status = CAIRO_INT_STATUS_NO_MEMORY;
+ goto exit_loop;
+ }
+
+ tmp = command_buffer_new_traps (buffer, traps.num_traps, ptraps);
+
+ command_buffer_composite (buffer, clip_id, PIXMAN_OP_IN, wh, tmp);
+
+ exit_loop:
+ free (ptraps);
+ _cairo_polygon_fini (&polygon);
+ _cairo_traps_fini (&traps);
+
+ if (status != CAIRO_INT_STATUS_SUCCESS)
+ {
+ command_buffer_new_broken (buffer);
+ break;
+ }
+ }
+
+ return clip_id;
+}
+
static pixman_op_t
_pixman_operator (cairo_operator_t op)
{
@@ -1079,6 +1866,19 @@ combine_mask_and_clip (pixman_image_t *mask_image, pixman_image_t *clip_image,
return CAIRO_INT_STATUS_SUCCESS;
}
+static int
+combine_mask_and_clip2 (command_buffer_t **buffer, int mask_id, int clip_id)
+{
+ int combined_id;
+
+ combined_id = command_buffer_new_blank (buffer, mask_id);
+
+ command_buffer_composite (
+ buffer, combined_id, PIXMAN_OP_SRC, clip_id, mask_id);
+
+ return combined_id;
+}
+
static cairo_int_status_t
clip_and_composite (cairo_pixman_surface_t *psurface,
cairo_operator_t operator,
@@ -1218,6 +2018,76 @@ out:
return status;
}
+static void
+clip_and_composite2 (command_buffer_t **buffer,
+ cairo_pixman_surface_t *psurface,
+ cairo_operator_t operator,
+ const cairo_pattern_t *source,
+ int mask_id,
+ 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);
+ int src_id, clip_id, combined_id, dest_id, white_id;
+ pixman_op_t pop;
+
+ if (clip && _cairo_clip_is_all_clipped (clip))
+ return;
+
+ dest_id = command_buffer_new_image (buffer, psurface->pimage);
+ clip_id = create_clip_image2 (buffer, clip, width, height);
+ src_id = pimage_from_pattern2 (buffer, psurface, source);
+ white_id = command_buffer_new_white (buffer);
+ pop = _pixman_operator (operator);
+
+ if (pop == PIXMAN_OP_CLEAR)
+ {
+ /* clip in mask OUT_REVERSE dest */
+ command_buffer_composite (
+ buffer, dest_id, PIXMAN_OP_OUT_REVERSE, mask_id, clip_id);
+ }
+ else if (pop == PIXMAN_OP_IN ||
+ pop == PIXMAN_OP_OUT ||
+ pop == PIXMAN_OP_IN_REVERSE ||
+ pop == PIXMAN_OP_ATOP_REVERSE)
+ {
+ /* First composite to a temporary surface */
+ combined_id = command_buffer_new_blank (buffer, dest_id);
+
+ command_buffer_composite (
+ buffer, combined_id, PIXMAN_OP_SRC, dest_id, white_id);
+
+ command_buffer_composite (
+ buffer, combined_id, pop, src_id, mask_id);
+
+ /* Then punch out the clip from the destination */
+ command_buffer_composite (
+ buffer, dest_id, PIXMAN_OP_OUT_REVERSE, clip_id, white_id);
+
+ /* And add the pieces together */
+ command_buffer_composite (
+ buffer, dest_id, PIXMAN_OP_ADD, combined_id, clip_id);
+ }
+ else if (pop == PIXMAN_OP_SRC)
+ {
+ combined_id = combine_mask_and_clip2 (buffer, mask_id, clip_id);
+
+ command_buffer_composite (
+ buffer, dest_id, PIXMAN_OP_OUT_REVERSE, combined_id, white_id);
+
+ command_buffer_composite (
+ buffer, dest_id, PIXMAN_OP_ADD, src_id, combined_id);
+ }
+ else
+ {
+ combined_id = combine_mask_and_clip2 (buffer, mask_id, clip_id);
+
+ command_buffer_composite (
+ buffer, dest_id, pop, src_id, combined_id);
+ }
+}
+
static cairo_int_status_t
cairo_pixman_surface_paint (void *abstract_surface,
cairo_operator_t op,
@@ -1225,6 +2095,16 @@ cairo_pixman_surface_paint (void *abstract_surface,
const cairo_clip_t *clip)
{
cairo_pixman_surface_t *psurface = abstract_surface;
+ command_buffer_t *buffer = command_buffer_new ();
+ int width = pixman_image_get_width (psurface->pimage);
+ int height = pixman_image_get_height (psurface->pimage);
+ int mask_id;
+
+ mask_id = command_buffer_new_white (&buffer);
+
+ clip_and_composite2 (&buffer, psurface, op, source, mask_id, clip);
+
+ return command_buffer_process (buffer, width, height);
return clip_and_composite (psurface, op, source, NULL, clip);
}
@@ -1237,18 +2117,16 @@ cairo_pixman_surface_mask (void *abstract_surface,
const cairo_clip_t *clip)
{
cairo_pixman_surface_t *psurface = abstract_surface;
- pixman_image_t *mask_image;
- cairo_int_status_t status;
+ command_buffer_t *buffer = command_buffer_new ();
+ int width = pixman_image_get_width (psurface->pimage);
+ int height = pixman_image_get_height (psurface->pimage);
+ int mask_id;
- status = pimage_from_pattern (psurface, mask, &mask_image);
- if (status == CAIRO_INT_STATUS_SUCCESS)
- {
- status = clip_and_composite (psurface, op, source, mask_image, clip);
+ mask_id = pimage_from_pattern2 (&buffer, psurface, mask);
- pixman_image_unref (mask_image);
- }
+ clip_and_composite2 (&buffer, psurface, op, source, mask_id, clip);
- return status;
+ return command_buffer_process (buffer, width, height);
}
static cairo_int_status_t