[cairo-commit] src/cairo-ps-surface.c src/cairo-ps-surface-private.h test/reference
Adrian Johnson
ajohnson at kemper.freedesktop.org
Tue Jan 31 05:44:36 PST 2012
src/cairo-ps-surface-private.h | 5
src/cairo-ps-surface.c | 601 ++++++++++++++++++++------------
test/reference/raster-source.ps.ref.png |binary
3 files changed, 389 insertions(+), 217 deletions(-)
New commits:
commit 46ca65895fb84ab70f9506e02bca5e5bc915f750
Author: Adrian Johnson <ajohnson at redneon.com>
Date: Tue Jan 31 22:29:01 2012 +1030
ps: support RASTER_SOURCE patterns
diff --git a/src/cairo-ps-surface-private.h b/src/cairo-ps-surface-private.h
index a5a8cd0..1d5d27d 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 f71b079..fe7e960 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
@@ -2826,120 +3029,9 @@ _cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface,
}
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 0000000..2ffc114
Binary files /dev/null and b/test/reference/raster-source.ps.ref.png differ
More information about the cairo-commit
mailing list