From 19ee13ca2b5b1e08a7fc965516be514d2fe40232 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Wed, 1 Oct 2008 21:01:17 +0930 Subject: [PATCH] PS: Implement EXTEND_PAD for image patterns Images with EXTEND_PAD are painted into a new image the size of the operation extents. The new image is then embedded in the PS file with the pattern matrix adjusted to ensure the image origin is in the correct location. --- src/cairo-ps-surface-private.h | 1 + src/cairo-ps-surface.c | 99 ++++++++++++++++++++++++++++------ 2 files changed, 83 insertions(+), 17 deletions(-) diff --git a/src/cairo-ps-surface-private.h b/src/cairo-ps-surface-private.h index e78833d05..98d2750a8 100644 --- a/src/cairo-ps-surface-private.h +++ b/src/cairo-ps-surface-private.h @@ -68,6 +68,7 @@ typedef struct cairo_ps_surface { int bbox_x1, bbox_y1, bbox_x2, bbox_y2; cairo_matrix_t cairo_to_ps; cairo_image_surface_t *image; + cairo_image_surface_t *acquired_image; void *image_extra; cairo_bool_t use_string_datasource; diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index 624214383..ea8a2b778 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -79,6 +79,10 @@ static const cairo_surface_backend_t cairo_ps_surface_backend; static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend; +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, @@ -2224,11 +2228,16 @@ _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, - cairo_operator_t op) + int *origin_x, + int *origin_y) { cairo_status_t status; + cairo_surface_t *pad_image; + int x = 0; + int y = 0; if (_cairo_surface_is_meta (pattern->surface)) { cairo_surface_t *meta_surface = pattern->surface; @@ -2242,16 +2251,62 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface, *height = pattern_extents.height; } else { status = _cairo_surface_acquire_source_image (pattern->surface, - &surface->image, + &surface->acquired_image, &surface->image_extra); if (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); + x = -rect.x; + y = -rect.y; + + pad_image = _cairo_image_surface_create_with_content (pattern->surface->content, + rect.width, + rect.height); + 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_composite (CAIRO_OPERATOR_SOURCE, + &pad_pattern.base, + NULL, + pad_image, + 0, 0, + 0, 0, + 0, 0, + rect.width, + rect.height); + _cairo_pattern_fini (&pad_pattern.base); + if (status) + 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 @@ -2279,24 +2334,28 @@ _cairo_ps_surface_release_surface (cairo_ps_surface_t *surface, cairo_surface_pattern_t *pattern) { if (!_cairo_surface_is_meta (pattern->surface)) - _cairo_surface_release_source_image (pattern->surface, surface->image, + _cairo_surface_release_source_image (pattern->surface, + surface->acquired_image, surface->image_extra); } 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_status_t status; int width, height; cairo_matrix_t cairo_p2d, ps_p2d; + int origin_x = 0; + int origin_y = 0; status = _cairo_ps_surface_acquire_surface (surface, pattern, - &width, - &height, - op); + extents, + &width, &height, + &origin_x, &origin_y); if (status) return status; @@ -2329,6 +2388,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, 0.0, height); cairo_matrix_scale (&ps_p2d, 1.0, -1.0); @@ -2349,6 +2409,7 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface, static cairo_status_t _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, cairo_surface_pattern_t *pattern, + cairo_rectangle_int_t *extents, cairo_operator_t op) { cairo_status_t status; @@ -2358,6 +2419,8 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, cairo_matrix_t cairo_p2d, ps_p2d; cairo_rectangle_int_t surface_extents; cairo_bool_t old_use_string_datasource; + int origin_x = 0; + int origin_y = 0; cairo_p2d = pattern->base.matrix; status = cairo_matrix_invert (&cairo_p2d); @@ -2366,19 +2429,19 @@ _cairo_ps_surface_emit_surface_pattern (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, 0.0, pattern_height); cairo_matrix_scale (&ps_p2d, 1.0, -1.0); status = _cairo_ps_surface_acquire_surface (surface, pattern, - &pattern_width, - &pattern_height, - op); + extents, + &pattern_width, &pattern_height, + &origin_x, &origin_y); if (status) return status; switch (pattern->base.extend) { - /* We implement EXTEND_PAD like EXTEND_NONE for now */ case CAIRO_EXTEND_PAD: case CAIRO_EXTEND_NONE: { @@ -2914,7 +2977,8 @@ _cairo_ps_surface_emit_radial_pattern (cairo_ps_surface_t *surface, static cairo_status_t _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface, const cairo_pattern_t *pattern, - cairo_operator_t op) + cairo_rectangle_int_t *extents, + cairo_operator_t op) { cairo_status_t status; @@ -2951,6 +3015,7 @@ _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface, case CAIRO_PATTERN_TYPE_SURFACE: status = _cairo_ps_surface_emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern, + extents, op); if (status) return status; @@ -3079,13 +3144,13 @@ _cairo_ps_surface_paint (void *abstract_surface, status = _cairo_ps_surface_paint_surface (surface, (cairo_surface_pattern_t *) source, - op); + paint_extents, op); if (status) return status; _cairo_output_stream_printf (stream, "Q\n"); } else { - status = _cairo_ps_surface_emit_pattern (surface, source, op); + status = _cairo_ps_surface_emit_pattern (surface, source, paint_extents, op); if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; @@ -3125,7 +3190,7 @@ _cairo_ps_surface_stroke (void *abstract_surface, "%% _cairo_ps_surface_stroke\n"); #endif - status = _cairo_ps_surface_emit_pattern (surface, source, op); + status = _cairo_ps_surface_emit_pattern (surface, source, extents, op); if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; @@ -3177,14 +3242,14 @@ _cairo_ps_surface_fill (void *abstract_surface, status = _cairo_ps_surface_paint_surface (surface, (cairo_surface_pattern_t *) source, - op); + extents, op); if (status) return status; _cairo_output_stream_printf (surface->stream, "Q\n"); _cairo_pdf_operators_reset (&surface->pdf_operators); } else { - status = _cairo_ps_surface_emit_pattern (surface, source, op); + status = _cairo_ps_surface_emit_pattern (surface, source, extents, op); if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; @@ -3225,7 +3290,7 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface, if (num_glyphs <= 0) return CAIRO_STATUS_SUCCESS; - status = _cairo_ps_surface_emit_pattern (surface, source, op); + status = _cairo_ps_surface_emit_pattern (surface, source, extents, op); if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS;