diff --git a/src/cairo-ps-surface-private.h b/src/cairo-ps-surface-private.h index a5a8cd0da..1d5d27d49 100644 --- a/src/cairo-ps-surface-private.h +++ b/src/cairo-ps-surface-private.h @@ -70,11 +70,6 @@ typedef struct cairo_ps_surface { int bbox_x1, bbox_y1, bbox_x2, bbox_y2; cairo_matrix_t cairo_to_ps; - /* XXX These 3 are used as temporary storage whilst emitting patterns */ - cairo_image_surface_t *image; - cairo_image_surface_t *acquired_image; - void *image_extra; - cairo_bool_t use_string_datasource; cairo_bool_t current_pattern_is_solid_color; diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index f71b079f3..fe7e9602d 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -126,10 +126,6 @@ static cairo_bool_t _cairo_ps_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle); -static void -_cairo_ps_surface_release_surface (cairo_ps_surface_t *surface, - cairo_surface_pattern_t *pattern); - static const cairo_ps_level_t _cairo_ps_levels[] = { CAIRO_PS_LEVEL_2, @@ -1670,21 +1666,229 @@ color_is_gray (double red, double green, double blue) fabs (red - blue) < epsilon); } -static cairo_int_status_t -_cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t *surface, - cairo_surface_pattern_t *pattern) +/** + * _cairo_ps_surface_acquire_source_surface_from_pattern: + * @surface: the ps surface + * @pattern: A #cairo_pattern_t of type SURFACE or RASTER_SOURCE to use as the source + * @extents: extents of the operation that is using this source + * @width: returns width of surface + * @height: returns height of surface + * @x_offset: returns x offset of surface + * @y_offset: returns y offset of surface + * @surface: returns surface of type image surface or recording surface + * @image_extra: returns image extra for image type surface + * + * Acquire source surface surface or raster source pattern. + */ +static cairo_status_t +_cairo_ps_surface_acquire_source_surface_from_pattern (cairo_ps_surface_t *surface, + const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents, + int *width, + int *height, + double *x_offset, + double *y_offset, + cairo_surface_t **source_surface, + void **image_extra) { + cairo_status_t status; cairo_image_surface_t *image; - void *image_extra; + + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SURFACE: { + cairo_surface_t *surf = ((cairo_surface_pattern_t *) pattern)->surface; + + if (surf->type == CAIRO_SURFACE_TYPE_RECORDING) { + if (surf->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { + cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) surf; + + *width = sub->extents.width; + *height = sub->extents.height; + } else { + cairo_recording_surface_t *recording_surface; + cairo_box_t bbox; + cairo_rectangle_int_t extents; + + recording_surface = (cairo_recording_surface_t *) surf; + if (_cairo_surface_is_snapshot (&recording_surface->base)) + recording_surface = (cairo_recording_surface_t *) + _cairo_surface_snapshot_get_target (&recording_surface->base); + + status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL); + if (unlikely (status)) + return status; + + _cairo_box_round_to_rectangle (&bbox, &extents); + *width = extents.width; + *height = extents.height; + } + cairo_surface_get_device_offset (surf, x_offset, y_offset); + *source_surface = surf; + + return CAIRO_STATUS_SUCCESS; + } else { + status = _cairo_surface_acquire_source_image (surf, &image, image_extra); + if (unlikely (status)) + return status; + } + } break; + + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: { + cairo_surface_t *surf; + cairo_box_t box; + cairo_rectangle_int_t rect; + + /* get the operation extents in pattern space */ + _cairo_box_from_rectangle (&box, extents); + _cairo_matrix_transform_bounding_box_fixed (&pattern->matrix, &box, NULL); + _cairo_box_round_to_rectangle (&box, &rect); + surf = _cairo_raster_source_pattern_acquire (pattern, &surface->base, &rect); + if (!surf) + return CAIRO_INT_STATUS_UNSUPPORTED; + assert (cairo_surface_get_type (surf) == CAIRO_SURFACE_TYPE_IMAGE); + image = (cairo_image_surface_t *) surf; + } break; + + case CAIRO_PATTERN_TYPE_SOLID: + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + case CAIRO_PATTERN_TYPE_MESH: + default: + ASSERT_NOT_REACHED; + break; + } + + *width = image->width; + *height = image->height; + cairo_surface_get_device_offset (&image->base, x_offset, y_offset); + *source_surface = &image->base; + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_ps_surface_release_source_surface_from_pattern (cairo_ps_surface_t *surface, + const cairo_pattern_t *pattern, + cairo_surface_t *source, + void *image_extra) +{ + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SURFACE: { + cairo_surface_pattern_t *surf_pat = (cairo_surface_pattern_t *) pattern; + if (surf_pat->surface->type != CAIRO_SURFACE_TYPE_RECORDING) { + cairo_image_surface_t *image = (cairo_image_surface_t *) source; + _cairo_surface_release_source_image (surf_pat->surface, image, image_extra); + } + } break; + + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + _cairo_raster_source_pattern_release (pattern, source); + break; + + case CAIRO_PATTERN_TYPE_SOLID: + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + case CAIRO_PATTERN_TYPE_MESH: + default: + + ASSERT_NOT_REACHED; + break; + } +} + +/** + * _cairo_ps_surface_create_padded_image_from_image + * @surface: the ps surface + * @source: The source image + * @extents: extents of the operation that is using this source + * @width: returns width of padded image + * @height: returns height of padded image + * @x_offset: returns x offset of padded image + * @y_offset: returns y offset of padded image + * @image: returns the padded image + */ +static cairo_status_t +_cairo_ps_surface_create_padded_image_from_image (cairo_ps_surface_t *surface, + cairo_image_surface_t *source, + const cairo_matrix_t *source_matrix, + const cairo_rectangle_int_t *extents, + int *width, + int *height, + double *x_offset, + double *y_offset, + cairo_image_surface_t **image) +{ + cairo_box_t box; + cairo_rectangle_int_t rect; + cairo_surface_t *pad_image; + cairo_surface_pattern_t pad_pattern; + int w, h; + cairo_int_status_t status; + + /* get the operation extents in pattern space */ + _cairo_box_from_rectangle (&box, extents); + _cairo_matrix_transform_bounding_box_fixed (source_matrix, &box, NULL); + _cairo_box_round_to_rectangle (&box, &rect); + + /* Check if image needs padding to fill extents. */ + w = source->width; + h = source->height; + if (_cairo_fixed_integer_ceil(box.p1.x) < 0 || + _cairo_fixed_integer_ceil(box.p1.y) < 0 || + _cairo_fixed_integer_floor(box.p2.y) > w || + _cairo_fixed_integer_floor(box.p2.y) > h) + { + pad_image = + _cairo_image_surface_create_with_pixman_format (NULL, + source->pixman_format, + rect.width, rect.height, + 0); + if (pad_image->status) + return pad_image->status; + + _cairo_pattern_init_for_surface (&pad_pattern, &source->base); + cairo_matrix_init_translate (&pad_pattern.base.matrix, rect.x, rect.y); + pad_pattern.base.extend = CAIRO_EXTEND_PAD; + status = _cairo_surface_paint (pad_image, + CAIRO_OPERATOR_SOURCE, + &pad_pattern.base, + NULL); + _cairo_pattern_fini (&pad_pattern.base); + } + *image = (cairo_image_surface_t *) pad_image; + *width = rect.width; + *height = rect.height; + *x_offset = rect.x; + *y_offset = rect.y; + + return status; +} + +static cairo_int_status_t +_cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t *surface, + const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents) +{ + int width, height; + double x_offset, y_offset; + cairo_surface_t *source; + cairo_image_surface_t *image; + void *image_extra; cairo_int_status_t status; cairo_image_transparency_t transparency; - status = _cairo_surface_acquire_source_image (pattern->surface, - &image, - &image_extra); + status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface, + pattern, + extents, + &width, + &height, + &x_offset, + &y_offset, + &source, + &image_extra); if (unlikely (status)) return status; + image = (cairo_image_surface_t *) source; if (image->base.status) return image->base.status; @@ -1711,7 +1915,7 @@ _cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t ASSERT_NOT_REACHED; } - _cairo_surface_release_source_image (pattern->surface, image, image_extra); + _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source, image_extra); return status; } @@ -1771,8 +1975,9 @@ pattern_supported (cairo_ps_surface_t *surface, const cairo_pattern_t *pattern) case CAIRO_PATTERN_TYPE_SURFACE: return surface_pattern_supported ((cairo_surface_pattern_t *) pattern); + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: - return FALSE; + return TRUE; default: ASSERT_NOT_REACHED; @@ -1781,7 +1986,9 @@ pattern_supported (cairo_ps_surface_t *surface, const cairo_pattern_t *pattern) } static cairo_bool_t -mask_supported (cairo_ps_surface_t *surface, const cairo_pattern_t *mask) +mask_supported (cairo_ps_surface_t *surface, + const cairo_pattern_t *mask, + const cairo_rectangle_int_t *extents) { if (surface->ps_level == CAIRO_PS_LEVEL_2) return FALSE; @@ -1790,7 +1997,7 @@ mask_supported (cairo_ps_surface_t *surface, const cairo_pattern_t *mask) cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) mask; if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE) { /* check if mask if opaque or bilevel alpha */ - if (_cairo_ps_surface_analyze_surface_pattern_transparency (surface, surface_pattern) == CAIRO_INT_STATUS_SUCCESS) { + if (_cairo_ps_surface_analyze_surface_pattern_transparency (surface, mask, extents) == CAIRO_INT_STATUS_SUCCESS) { surface->ps_level_used = CAIRO_PS_LEVEL_3; return TRUE; } @@ -1822,7 +2029,7 @@ _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface, return CAIRO_INT_STATUS_UNSUPPORTED; /* Mask is only supported when the mask is an image with opaque or bilevel alpha. */ - if (mask && !mask_supported (surface, mask)) + if (mask && !mask_supported (surface, mask, extents)) return CAIRO_INT_STATUS_UNSUPPORTED; if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { @@ -1852,12 +2059,8 @@ _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface, * render stage and we blend the transparency into the white * background to convert the pattern to opaque. */ - if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { - cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; - - return _cairo_ps_surface_analyze_surface_pattern_transparency (surface, - surface_pattern); - } + if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE || pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) + return _cairo_ps_surface_analyze_surface_pattern_transparency (surface, pattern, extents); /* Patterns whose drawn part is opaque are directly supported; those whose drawn part is partially transparent can be @@ -2825,121 +3028,10 @@ _cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface, red, green, blue); } -static cairo_status_t -_cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface, - cairo_surface_pattern_t *pattern, - cairo_rectangle_int_t *extents, - int *width, - int *height, - int *origin_x, - int *origin_y) -{ - cairo_status_t status; - cairo_surface_t *pad_image; - int x = 0; - int y = 0; - int w, h; - - surface->acquired_image = NULL; - surface->image = NULL; - - if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) { - if (pattern->surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { - cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) pattern->surface; - - *width = sub->extents.width; - *height = sub->extents.height; - } else { - cairo_recording_surface_t *recording_surface; - cairo_box_t bbox; - cairo_rectangle_int_t extents; - - recording_surface = (cairo_recording_surface_t *) pattern->surface; - if (_cairo_surface_is_snapshot (&recording_surface->base)) - recording_surface = (cairo_recording_surface_t *) - _cairo_surface_snapshot_get_target (&recording_surface->base); - - status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL); - if (unlikely (status)) - return status; - - _cairo_box_round_to_rectangle (&bbox, &extents); - *width = extents.width; - *height = extents.height; - } - return CAIRO_STATUS_SUCCESS; - } else { - status = _cairo_surface_acquire_source_image (pattern->surface, - &surface->acquired_image, - &surface->image_extra); - if (unlikely (status)) - return status; - - pad_image = &surface->acquired_image->base; - if (cairo_pattern_get_extend (&pattern->base) == CAIRO_EXTEND_PAD) { - cairo_box_t box; - cairo_rectangle_int_t rect; - cairo_surface_pattern_t pad_pattern; - - /* get the operation extents in pattern space */ - _cairo_box_from_rectangle (&box, extents); - _cairo_matrix_transform_bounding_box_fixed (&pattern->base.matrix, &box, NULL); - _cairo_box_round_to_rectangle (&box, &rect); - - /* Check if image needs padding to fill extents. */ - w = surface->acquired_image->width; - h = surface->acquired_image->height; - if (_cairo_fixed_integer_ceil(box.p1.x) < 0 || - _cairo_fixed_integer_ceil(box.p1.y) < 0 || - _cairo_fixed_integer_floor(box.p2.y) > w || - _cairo_fixed_integer_floor(box.p2.y) > h) - { - x = -rect.x; - y = -rect.y; - - pad_image = - _cairo_image_surface_create_with_pixman_format (NULL, - surface->acquired_image->pixman_format, - rect.width, rect.height, - 0); - if (pad_image->status) { - status = pad_image->status; - goto BAIL; - } - - _cairo_pattern_init_for_surface (&pad_pattern, &surface->acquired_image->base); - cairo_matrix_init_translate (&pad_pattern.base.matrix, -x, -y); - pad_pattern.base.extend = CAIRO_EXTEND_PAD; - status = _cairo_surface_paint (pad_image, - CAIRO_OPERATOR_SOURCE, - &pad_pattern.base, - NULL); - _cairo_pattern_fini (&pad_pattern.base); - if (unlikely (status)) { - if (pad_image != &surface->acquired_image->base) - cairo_surface_destroy (pad_image); - - goto BAIL; - } - } - } - - surface->image = (cairo_image_surface_t *) pad_image; - *width = surface->image->width; - *height = surface->image->height; - *origin_x = x; - *origin_y = y; - return CAIRO_STATUS_SUCCESS; - } - -BAIL: - _cairo_ps_surface_release_surface (surface, pattern); - return status; -} - static cairo_status_t _cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface, - cairo_surface_pattern_t *pattern, + cairo_pattern_t *source_pattern, + cairo_surface_t *source_surface, cairo_operator_t op, int width, int height, @@ -2947,46 +3039,29 @@ _cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface, { cairo_int_status_t status; - if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) { - cairo_surface_t *source = pattern->surface; - - if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { - cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source; + if (source_surface->type == CAIRO_SURFACE_TYPE_RECORDING) { + if (source_surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { + cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source_surface; status = _cairo_ps_surface_emit_recording_subsurface (surface, sub->target, &sub->extents); } else { - status = _cairo_ps_surface_emit_recording_surface (surface, source); + status = _cairo_ps_surface_emit_recording_surface (surface, source_surface); } } else { - if (pattern->base.extend != CAIRO_EXTEND_PAD) { - status = _cairo_ps_surface_emit_jpeg_image (surface, pattern->surface, + cairo_image_surface_t *image = (cairo_image_surface_t *) source_surface; + if (source_pattern->extend != CAIRO_EXTEND_PAD) { + status = _cairo_ps_surface_emit_jpeg_image (surface, source_surface, width, height); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; } - status = _cairo_ps_surface_emit_image (surface, surface->image, - op, pattern->base.filter, stencil_mask); + status = _cairo_ps_surface_emit_image (surface, image, + op, source_pattern->filter, stencil_mask); } return status; } -static void -_cairo_ps_surface_release_surface (cairo_ps_surface_t *surface, - cairo_surface_pattern_t *pattern) -{ - if (surface->image != surface->acquired_image) - cairo_surface_destroy (&surface->image->base); - - if (pattern->surface->type != CAIRO_SURFACE_TYPE_RECORDING) { - _cairo_surface_release_source_image (pattern->surface, - surface->acquired_image, - surface->image_extra); - } - - surface->acquired_image = NULL; - surface->image = NULL; -} static void _path_fixed_init_rectangle (cairo_path_fixed_t *path, @@ -3018,40 +3093,60 @@ _path_fixed_init_rectangle (cairo_path_fixed_t *path, } static cairo_status_t -_cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface, - cairo_surface_pattern_t *pattern, - cairo_rectangle_int_t *extents, - cairo_operator_t op, - cairo_bool_t stencil_mask) +_cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface, + cairo_pattern_t *pattern, + cairo_rectangle_int_t *extents, + cairo_operator_t op, + cairo_bool_t stencil_mask) { cairo_status_t status; int width, height; cairo_matrix_t cairo_p2d, ps_p2d; cairo_path_fixed_t path; - int origin_x = 0; - int origin_y = 0; + double x_offset, y_offset; + cairo_surface_t *source; + cairo_image_surface_t *image = NULL; + void *image_extra; status = _cairo_pdf_operators_flush (&surface->pdf_operators); if (unlikely (status)) return status; - status = _cairo_ps_surface_acquire_surface (surface, - pattern, - extents, - &width, &height, - &origin_x, &origin_y); + status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface, + pattern, + extents, + &width, &height, + &x_offset, &y_offset, + &source, + &image_extra); if (unlikely (status)) return status; + if (pattern->extend == CAIRO_EXTEND_PAD) { + cairo_image_surface_t *img; + + assert (source->type == CAIRO_SURFACE_TYPE_IMAGE); + img = (cairo_image_surface_t *) source; + status = _cairo_ps_surface_create_padded_image_from_image (surface, + img, + &pattern->matrix, + extents, + &width, &height, + &x_offset, &y_offset, + &image); + if (unlikely (status)) + goto release_source; + } + _path_fixed_init_rectangle (&path, extents); status = _cairo_pdf_operators_clip (&surface->pdf_operators, &path, CAIRO_FILL_RULE_WINDING); _cairo_path_fixed_fini (&path); if (unlikely (status)) - return status; + goto release_source; - cairo_p2d = pattern->base.matrix; + cairo_p2d = pattern->matrix; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) { double x_scale = cairo_p2d.xx; @@ -3092,7 +3187,7 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface, ps_p2d = surface->cairo_to_ps; cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d); - cairo_matrix_translate (&ps_p2d, -origin_x, -origin_y); + cairo_matrix_translate (&ps_p2d, x_offset, y_offset); cairo_matrix_translate (&ps_p2d, 0.0, height); cairo_matrix_scale (&ps_p2d, 1.0, -1.0); @@ -3104,15 +3199,74 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface, ps_p2d.x0, ps_p2d.y0); } - status = _cairo_ps_surface_emit_surface (surface, pattern, op, width, height, stencil_mask); - _cairo_ps_surface_release_surface (surface, pattern); + status = _cairo_ps_surface_emit_surface (surface, + pattern, + image ? &image->base : source, + op, + width, height, + stencil_mask); + + release_source: + if (image) + cairo_surface_destroy (&image->base); + + _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source, image_extra); return status; } +static cairo_status_t +_cairo_ps_surface_paint_pattern (cairo_ps_surface_t *surface, + const cairo_pattern_t *source, + cairo_rectangle_int_t *extents, + cairo_operator_t op, + cairo_bool_t stencil_mask) +{ + switch (source->type) { + case CAIRO_PATTERN_TYPE_SURFACE: + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + return _cairo_ps_surface_paint_surface (surface, + (cairo_pattern_t *)source, + extents, + op, + stencil_mask); + + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + case CAIRO_PATTERN_TYPE_MESH: + case CAIRO_PATTERN_TYPE_SOLID: + default: + ASSERT_NOT_REACHED; + return CAIRO_STATUS_SUCCESS; + } +} + +static cairo_bool_t +_can_paint_pattern (const cairo_pattern_t *pattern) +{ + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: + return FALSE; + + case CAIRO_PATTERN_TYPE_SURFACE: + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + return (pattern->extend == CAIRO_EXTEND_NONE || + pattern->extend == CAIRO_EXTEND_PAD); + + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + case CAIRO_PATTERN_TYPE_MESH: + return FALSE; + + default: + ASSERT_NOT_REACHED; + return FALSE; + } +} + static cairo_status_t _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, - cairo_surface_pattern_t *pattern, + cairo_pattern_t *pattern, cairo_rectangle_int_t *extents, cairo_operator_t op) { @@ -3122,23 +3276,45 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, double xstep, ystep; cairo_matrix_t cairo_p2d, ps_p2d; cairo_bool_t old_use_string_datasource; - int origin_x = 0; - int origin_y = 0; + double x_offset, y_offset; + cairo_surface_t *source; + cairo_image_surface_t *image = NULL; + void *image_extra; - cairo_p2d = pattern->base.matrix; + cairo_p2d = pattern->matrix; status = cairo_matrix_invert (&cairo_p2d); /* cairo_pattern_set_matrix ensures the matrix is invertible */ assert (status == CAIRO_STATUS_SUCCESS); - status = _cairo_ps_surface_acquire_surface (surface, - pattern, - extents, - &pattern_width, &pattern_height, - &origin_x, &origin_y); + status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface, + pattern, + extents, + &pattern_width, &pattern_height, + &x_offset, &y_offset, + &source, + &image_extra); if (unlikely (status)) return status; - switch (pattern->base.extend) { + if (pattern->extend == CAIRO_EXTEND_PAD) { + cairo_image_surface_t *img; + + assert (source->type == CAIRO_SURFACE_TYPE_IMAGE); + img = (cairo_image_surface_t *) source; + status = _cairo_ps_surface_create_padded_image_from_image (surface, + img, + &pattern->matrix, + extents, + &pattern_width, &pattern_height, + &x_offset, &y_offset, + &image); + if (unlikely (status)) + goto release_source; + } + if (unlikely (status)) + goto release_source; + + switch (pattern->extend) { case CAIRO_EXTEND_PAD: case CAIRO_EXTEND_NONE: { @@ -3156,7 +3332,7 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, */ double x1 = 0.0, y1 = 0.0; double x2 = surface->width, y2 = surface->height; - _cairo_matrix_transform_bounding_box (&pattern->base.matrix, + _cairo_matrix_transform_bounding_box (&pattern->matrix, &x1, &y1, &x2, &y2, NULL); @@ -3195,10 +3371,13 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, surface->content == CAIRO_CONTENT_COLOR ? 0 : 1, xstep, ystep); } - status = _cairo_ps_surface_emit_surface (surface, pattern, op, + status = _cairo_ps_surface_emit_surface (surface, + pattern, + image ? &image->base : source, + op, pattern_width, pattern_height, FALSE); if (unlikely (status)) - return status; + goto release_source; surface->use_string_datasource = old_use_string_datasource; _cairo_output_stream_printf (surface->stream, @@ -3212,7 +3391,7 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, " /XStep %f /YStep %f\n", xstep, ystep); - if (pattern->base.extend == CAIRO_EXTEND_REFLECT) { + if (pattern->extend == CAIRO_EXTEND_REFLECT) { _cairo_output_stream_printf (surface->stream, " /BBox [0 0 %d %d]\n" " /PaintProc {\n" @@ -3243,7 +3422,7 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, _cairo_output_stream_printf (surface->stream, ">>\n"); - cairo_p2d = pattern->base.matrix; + cairo_p2d = pattern->matrix; status = cairo_matrix_invert (&cairo_p2d); /* cairo_pattern_set_matrix ensures the matrix is invertible */ assert (status == CAIRO_STATUS_SUCCESS); @@ -3263,7 +3442,13 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, _cairo_output_stream_printf (surface->stream, "makepattern setpattern\n"); - return CAIRO_STATUS_SUCCESS; + release_source: + if (image) + cairo_surface_destroy (&image->base); + + _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source, image_extra); + + return status; } typedef struct _cairo_ps_color_stop { @@ -3735,8 +3920,9 @@ _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface, break; case CAIRO_PATTERN_TYPE_SURFACE: + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: status = _cairo_ps_surface_emit_surface_pattern (surface, - (cairo_surface_pattern_t *) pattern, + (cairo_pattern_t *)pattern, extents, op); if (unlikely (status)) @@ -3757,9 +3943,6 @@ _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface, if (unlikely (status)) return status; break; - - case CAIRO_PATTERN_TYPE_RASTER_SOURCE: /* XXX */ - break; } return CAIRO_STATUS_SUCCESS; @@ -3847,17 +4030,14 @@ _cairo_ps_surface_paint (void *abstract_surface, if (unlikely (status)) goto cleanup_composite; - if (source->type == CAIRO_PATTERN_TYPE_SURFACE && - (source->extend == CAIRO_EXTEND_NONE || - source->extend == CAIRO_EXTEND_PAD)) - { + if (_can_paint_pattern (source)) { status = _cairo_pdf_operators_flush (&surface->pdf_operators); if (unlikely (status)) goto cleanup_composite; _cairo_output_stream_printf (stream, "q\n"); - status = _cairo_ps_surface_paint_surface (surface, - (cairo_surface_pattern_t *) source, + status = _cairo_ps_surface_paint_pattern (surface, + source, &extents.bounded, op, FALSE); if (unlikely (status)) goto cleanup_composite; @@ -3916,8 +4096,8 @@ _cairo_ps_surface_mask (void *abstract_surface, goto cleanup_composite; _cairo_output_stream_printf (stream, "q\n"); - status = _cairo_ps_surface_paint_surface (surface, - (cairo_surface_pattern_t *) mask, + status = _cairo_ps_surface_paint_pattern (surface, + mask, &extents.bounded, op, TRUE); if (unlikely (status)) goto cleanup_composite; @@ -4059,10 +4239,7 @@ _cairo_ps_surface_fill (void *abstract_surface, if (unlikely (status)) goto cleanup_composite; - if (source->type == CAIRO_PATTERN_TYPE_SURFACE && - (source->extend == CAIRO_EXTEND_NONE || - source->extend == CAIRO_EXTEND_PAD)) - { + if (_can_paint_pattern (source)) { _cairo_output_stream_printf (surface->stream, "q\n"); status = _cairo_pdf_operators_clip (&surface->pdf_operators, @@ -4071,8 +4248,8 @@ _cairo_ps_surface_fill (void *abstract_surface, if (unlikely (status)) goto cleanup_composite; - status = _cairo_ps_surface_paint_surface (surface, - (cairo_surface_pattern_t *) source, + status = _cairo_ps_surface_paint_pattern (surface, + source, &extents.bounded, op, FALSE); if (unlikely (status)) goto cleanup_composite; diff --git a/test/reference/raster-source.ps.ref.png b/test/reference/raster-source.ps.ref.png new file mode 100644 index 000000000..2ffc11412 Binary files /dev/null and b/test/reference/raster-source.ps.ref.png differ