diff options
author | Søren Sandmann Pedersen <ssp@redhat.com> | 2012-10-01 01:45:05 -0400 |
---|---|---|
committer | Søren Sandmann Pedersen <ssp@redhat.com> | 2012-10-01 01:45:05 -0400 |
commit | 53d119c357451e812b3d0b184ae2c5152540fadd (patch) | |
tree | b8576615d45a7ec9e36ef88a253714ccf32d3c55 | |
parent | 10fa14d84e365c7f4c951153bd67b54d8a8cf9e5 (diff) |
Beginning of command buffer
-rw-r--r-- | src/cairo-pixman-surface.c | 898 |
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 |