pdf: support RASTER_SOURCE patterns

This commit is contained in:
Adrian Johnson 2012-01-10 00:11:41 +10:30
parent fefc273c53
commit 0a10982f8c
2 changed files with 326 additions and 157 deletions

View file

@ -75,11 +75,15 @@ typedef struct _cairo_pdf_source_surface_entry {
cairo_pdf_resource_t surface_res;
int width;
int height;
double x_offset;
double y_offset;
cairo_rectangle_int_t extents;
} cairo_pdf_source_surface_entry_t;
typedef struct _cairo_pdf_source_surface {
cairo_pattern_type_t type;
cairo_surface_t *surface;
cairo_pattern_t *raster_pattern;
cairo_pdf_source_surface_entry_t *hash_entry;
} cairo_pdf_source_surface_t;

View file

@ -1103,6 +1103,67 @@ _cairo_pdf_source_surface_init_key (cairo_pdf_source_surface_entry_t *key)
}
}
static cairo_int_status_t
_cairo_pdf_surface_acquire_source_image_from_pattern (cairo_pdf_surface_t *surface,
const cairo_pattern_t *pattern,
const cairo_rectangle_int_t *extents,
cairo_image_surface_t **image,
void **image_extra)
{
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SURFACE: {
cairo_surface_pattern_t *surf_pat = (cairo_surface_pattern_t *) pattern;
return _cairo_surface_acquire_source_image (surf_pat->surface, image, image_extra);
} break;
case CAIRO_PATTERN_TYPE_RASTER_SOURCE: {
cairo_surface_t *surf;
surf = _cairo_raster_source_pattern_acquire (pattern, &surface->base, extents);
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;
}
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_pdf_surface_release_source_image_from_pattern (cairo_pdf_surface_t *surface,
const cairo_pattern_t *pattern,
cairo_image_surface_t *image,
void *image_extra)
{
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SURFACE: {
cairo_surface_pattern_t *surf_pat = (cairo_surface_pattern_t *) pattern;
_cairo_surface_release_source_image (surf_pat->surface, image, image_extra);
} break;
case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
_cairo_raster_source_pattern_release (pattern, &image->base);
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;
}
}
static cairo_int_status_t
_get_jpx_image_info (cairo_surface_t *source,
cairo_image_info_t *info,
@ -1202,23 +1263,56 @@ _get_source_surface_size (cairo_surface_t *source,
return CAIRO_STATUS_SUCCESS;
}
/**
* _cairo_pdf_surface_add_source_surface:
* @surface: the pdf surface
* @source_surface: A #cairo_surface_t to use as the source surface
* @source_pattern: A #cairo_pattern_t of type SURFACE or RASTER_SOURCE to use as the source
* @filter: filter type of the source pattern
* @stencil_mask: if true, the surface will be written to the PDF as an /ImageMask
* @extents: extents of the operation that is using this source
* @surface_res: return PDF resource number of the surface
* @width: returns width of surface
* @height: returns height of surface
* @x_offset: x offset of surface
* @t_offset: y offset of surface
* @source_extents: returns extents of source (either ink extents or extents needed to cover @extents)
*
* Add surface or raster_source pattern to list of surfaces to be
* written to the PDF file when the current page is finished. Returns
* a PDF resource to reference the image. A hash table of all images
* in the PDF files (keyed by CAIRO_MIME_TYPE_UNIQUE_ID or surface
* unique_id) to ensure surfaces with the same id are only written
* once to the PDF file.
*
* Only one of @source_pattern or @source_surface is to be
* specified. Set the other to NULL.
*/
static cairo_status_t
_cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
cairo_surface_t *source,
cairo_filter_t filter,
cairo_bool_t stencil_mask,
cairo_pdf_resource_t *surface_res,
int *width,
int *height,
cairo_rectangle_int_t *extents)
_cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
cairo_surface_t *source_surface,
const cairo_pattern_t *source_pattern,
cairo_filter_t filter,
cairo_bool_t stencil_mask,
const cairo_rectangle_int_t *extents,
cairo_pdf_resource_t *surface_res,
int *width,
int *height,
double *x_offset,
double *y_offset,
cairo_rectangle_int_t *source_extents)
{
cairo_pdf_source_surface_t src_surface;
cairo_pdf_source_surface_entry_t surface_key;
cairo_pdf_source_surface_entry_t *surface_entry;
cairo_status_t status;
cairo_bool_t interpolate;
const unsigned char *unique_id;
unsigned long unique_id_length;
unsigned char *unique_id;
unsigned long unique_id_length = 0;
cairo_box_t box;
cairo_rectangle_int_t rect;
cairo_image_surface_t *image;
void *image_extra;
switch (filter) {
default:
@ -1234,9 +1328,32 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
break;
}
surface_key.id = source->unique_id;
*x_offset = 0;
*y_offset = 0;
if (source_pattern) {
if (source_pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) {
/* get the operation extents in pattern space */
_cairo_box_from_rectangle (&box, extents);
_cairo_matrix_transform_bounding_box_fixed (&source_pattern->matrix, &box, NULL);
_cairo_box_round_to_rectangle (&box, &rect);
status = _cairo_pdf_surface_acquire_source_image_from_pattern (surface, source_pattern,
&rect, &image,
&image_extra);
if (unlikely (status))
return status;
source_surface = &image->base;
cairo_surface_get_device_offset (source_surface, x_offset, y_offset);
} else {
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source_pattern;
source_surface = surface_pattern->surface;
}
} else {
cairo_surface_get_device_offset (source_surface, x_offset, y_offset);
}
surface_key.id = source_surface->unique_id;
surface_key.interpolate = interpolate;
cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_UNIQUE_ID,
cairo_surface_get_mime_data (source_surface, CAIRO_MIME_TYPE_UNIQUE_ID,
(const unsigned char **) &surface_key.unique_id,
&surface_key.unique_id_length);
_cairo_pdf_source_surface_init_key (&surface_key);
@ -1245,64 +1362,100 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
*surface_res = surface_entry->surface_res;
*width = surface_entry->width;
*height = surface_entry->height;
*extents = surface_entry->extents;
*source_extents = surface_entry->extents;
status = CAIRO_STATUS_SUCCESS;
} else {
status = _get_source_surface_size (source_surface,
width,
height,
source_extents);
if (unlikely(status))
goto release_source;
return CAIRO_STATUS_SUCCESS;
if (surface_key.unique_id && surface_key.unique_id_length > 0) {
unique_id = malloc (unique_id_length);
if (unique_id == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto release_source;
}
unique_id_length = surface_key.unique_id_length;
memcpy (unique_id, surface_key.unique_id, unique_id_length);
} else {
unique_id = NULL;
unique_id_length = 0;
}
}
release_source:
if (source_pattern && source_pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE)
_cairo_pdf_surface_release_source_image_from_pattern (surface, source_pattern, image, image_extra);
if (status || surface_entry)
return status;
surface_entry = malloc (sizeof (cairo_pdf_source_surface_entry_t));
if (surface_entry == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (surface_entry == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail1;
}
surface_entry->id = surface_key.id;
surface_entry->interpolate = interpolate;
surface_entry->stencil_mask = stencil_mask;
cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_UNIQUE_ID,
&unique_id, &unique_id_length);
if (unique_id && unique_id_length > 0) {
surface_entry->unique_id = malloc (unique_id_length);
if (surface_entry->unique_id == NULL) {
cairo_surface_destroy (source);
free (surface_entry);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
surface_entry->unique_id_length = unique_id_length;
memcpy (surface_entry->unique_id, unique_id, unique_id_length);
} else {
surface_entry->unique_id = NULL;
surface_entry->unique_id_length = 0;
}
surface_entry->unique_id_length = unique_id_length;
surface_entry->unique_id = unique_id;
surface_entry->width = *width;
surface_entry->height = *height;
surface_entry->x_offset = *x_offset;
surface_entry->y_offset = *y_offset;
surface_entry->extents = *source_extents;
_cairo_pdf_source_surface_init_key (surface_entry);
src_surface.hash_entry = surface_entry;
src_surface.surface = cairo_surface_reference (source);
if (source_pattern && source_pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) {
src_surface.type = CAIRO_PATTERN_TYPE_RASTER_SOURCE;
src_surface.surface = NULL;
status = _cairo_pattern_create_copy (&src_surface.raster_pattern, source_pattern);
if (unlikely (status))
goto fail2;
} else {
src_surface.type = CAIRO_PATTERN_TYPE_SURFACE;
src_surface.surface = cairo_surface_reference (source_surface);
src_surface.raster_pattern = NULL;
}
surface_entry->surface_res = _cairo_pdf_surface_new_object (surface);
if (surface_entry->surface_res.id == 0) {
cairo_surface_destroy (source);
free (surface_entry);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3;
}
status = _get_source_surface_size (source,
&surface_entry->width,
&surface_entry->height,
&surface_entry->extents);
status = _cairo_array_append (&surface->page_surfaces, &src_surface);
if (unlikely (status)) {
cairo_surface_destroy (source);
free (surface_entry);
return status;
}
if (unlikely (status))
goto fail3;
status = _cairo_hash_table_insert (surface->all_surfaces,
&surface_entry->base);
if (unlikely(status))
goto fail3;
*surface_res = surface_entry->surface_res;
*width = surface_entry->width;
*height = surface_entry->height;
*extents = surface_entry->extents;
return status;
fail3:
if (source_pattern && source_pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE)
cairo_pattern_destroy (src_surface.raster_pattern);
else
cairo_surface_destroy (src_surface.surface);
fail2:
free (surface_entry);
fail1:
free (unique_id);
return status;
}
@ -1936,27 +2089,26 @@ _cairo_pdf_surface_supports_fine_grained_fallbacks (void *abstract_surface)
static cairo_status_t
_cairo_pdf_surface_add_padded_image_surface (cairo_pdf_surface_t *surface,
cairo_surface_pattern_t *source,
const cairo_pattern_t *source,
const cairo_rectangle_int_t *extents,
cairo_pdf_resource_t *surface_res,
int *width,
int *height,
int *origin_x,
int *origin_y)
double *x_offset,
double *y_offset)
{
cairo_image_surface_t *image;
cairo_surface_t *pad_image;
void *image_extra;
cairo_int_status_t status;
int x = 0;
int y = 0;
int w, h;
cairo_rectangle_int_t extents2;
cairo_box_t box;
cairo_rectangle_int_t rect;
cairo_surface_pattern_t pad_pattern;
status = _cairo_surface_acquire_source_image (source->surface, &image, &image_extra);
status = _cairo_pdf_surface_acquire_source_image_from_pattern (surface, source, extents,
&image, &image_extra);
if (unlikely (status))
return status;
@ -1964,7 +2116,7 @@ _cairo_pdf_surface_add_padded_image_surface (cairo_pdf_surface_t *surfa
/* get the operation extents in pattern space */
_cairo_box_from_rectangle (&box, extents);
_cairo_matrix_transform_bounding_box_fixed (&source->base.matrix, &box, NULL);
_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 */
@ -1975,9 +2127,7 @@ _cairo_pdf_surface_add_padded_image_surface (cairo_pdf_surface_t *surfa
_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_content (source->surface->content,
pad_image = _cairo_image_surface_create_with_content (cairo_surface_get_content (&image->base),
rect.width,
rect.height);
if (pad_image->status) {
@ -1986,7 +2136,7 @@ _cairo_pdf_surface_add_padded_image_surface (cairo_pdf_surface_t *surfa
}
_cairo_pattern_init_for_surface (&pad_pattern, &image->base);
cairo_matrix_init_translate (&pad_pattern.base.matrix, -x, -y);
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,
@ -1994,29 +2144,30 @@ _cairo_pdf_surface_add_padded_image_surface (cairo_pdf_surface_t *surfa
_cairo_pattern_fini (&pad_pattern.base);
if (unlikely (status))
goto BAIL;
cairo_surface_set_device_offset (pad_image, rect.x, rect.y);
}
status = _cairo_pdf_surface_add_source_surface (surface,
pad_image,
source->base.filter,
NULL,
source->filter,
FALSE,
extents,
surface_res,
&w,
&h,
width,
height,
x_offset,
y_offset,
&extents2);
if (unlikely (status))
goto BAIL;
*width = ((cairo_image_surface_t *)pad_image)->width;
*height = ((cairo_image_surface_t *)pad_image)->height;
*origin_x = x;
*origin_y = y;
BAIL:
if (pad_image != &image->base)
cairo_surface_destroy (pad_image);
_cairo_surface_release_source_image (source->surface, image, image_extra);
_cairo_pdf_surface_release_source_image_from_pattern (surface, source, image, image_extra);
return status;
}
@ -2440,37 +2591,44 @@ _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface,
}
static cairo_status_t
_cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface,
cairo_surface_t *source,
cairo_pdf_resource_t resource,
cairo_bool_t interpolate,
cairo_bool_t stencil_mask)
_cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface,
cairo_pdf_source_surface_t *source)
{
cairo_image_surface_t *image;
void *image_extra;
cairo_int_status_t status;
if (!stencil_mask) {
status = _cairo_pdf_surface_emit_jpx_image (surface, source, resource);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
status = _cairo_pdf_surface_emit_jpeg_image (surface, source, resource);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
status = _cairo_surface_acquire_source_image (source->surface, &image, &image_extra);
} else {
status = _cairo_pdf_surface_acquire_source_image_from_pattern (surface, source->raster_pattern,
&source->hash_entry->extents,
&image, &image_extra);
}
status = _cairo_surface_acquire_source_image (source, &image, &image_extra);
if (unlikely (status))
return status;
status = _cairo_pdf_surface_emit_image (surface, image,
&resource, interpolate, stencil_mask);
if (unlikely (status))
goto BAIL;
if (!source->hash_entry->stencil_mask) {
status = _cairo_pdf_surface_emit_jpx_image (surface, &image->base, source->hash_entry->surface_res);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto release_source;
BAIL:
_cairo_surface_release_source_image (source, image, image_extra);
status = _cairo_pdf_surface_emit_jpeg_image (surface, &image->base, source->hash_entry->surface_res);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto release_source;
}
status = _cairo_pdf_surface_emit_image (surface, image,
&source->hash_entry->surface_res,
source->hash_entry->interpolate,
source->hash_entry->stencil_mask);
release_source:
if (source->type == CAIRO_PATTERN_TYPE_SURFACE)
_cairo_surface_release_source_image (source->surface, image, image_extra);
else
_cairo_pdf_surface_release_source_image_from_pattern (surface, source->raster_pattern,
image, image_extra);
return status;
}
@ -2485,8 +2643,10 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface,
cairo_box_double_t bbox;
cairo_int_status_t status;
int alpha = 0;
cairo_surface_t *source = pdf_source->surface;
cairo_surface_t *source;
assert (pdf_source->type == CAIRO_PATTERN_TYPE_SURFACE);
source = pdf_source->surface;
if (_cairo_surface_is_snapshot (source))
source = _cairo_surface_snapshot_get_target (source);
@ -2613,69 +2773,66 @@ static cairo_status_t
_cairo_pdf_surface_emit_surface (cairo_pdf_surface_t *surface,
cairo_pdf_source_surface_t *src_surface)
{
if (src_surface->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
if (src_surface->surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) src_surface->surface;
return _cairo_pdf_surface_emit_recording_subsurface (surface,
sub->target,
&sub->extents,
src_surface->hash_entry->surface_res);
} else {
return _cairo_pdf_surface_emit_recording_surface (surface,
src_surface);
if (src_surface->type == CAIRO_PATTERN_TYPE_SURFACE) {
if (src_surface->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
if (src_surface->surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) src_surface->surface;
return _cairo_pdf_surface_emit_recording_subsurface (surface,
sub->target,
&sub->extents,
src_surface->hash_entry->surface_res);
} else {
return _cairo_pdf_surface_emit_recording_surface (surface,
src_surface);
}
}
} else {
return _cairo_pdf_surface_emit_image_surface (surface,
src_surface->surface,
src_surface->hash_entry->surface_res,
src_surface->hash_entry->interpolate,
src_surface->hash_entry->stencil_mask);
}
return _cairo_pdf_surface_emit_image_surface (surface, src_surface);
}
static cairo_status_t
_cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface,
cairo_pdf_pattern_t *pdf_pattern)
{
cairo_surface_pattern_t *pattern = (cairo_surface_pattern_t *) pdf_pattern->pattern;
cairo_pattern_t *pattern = pdf_pattern->pattern;
cairo_status_t status;
cairo_pdf_resource_t pattern_resource = {0};
cairo_matrix_t cairo_p2d, pdf_p2d;
cairo_extend_t extend = cairo_pattern_get_extend (&pattern->base);
cairo_extend_t extend = cairo_pattern_get_extend (pattern);
double xstep, ystep;
cairo_rectangle_int_t pattern_extents;
int pattern_width = 0; /* squelch bogus compiler warning */
int pattern_height = 0; /* squelch bogus compiler warning */
int origin_x = 0; /* squelch bogus compiler warning */
int origin_y = 0; /* squelch bogus compiler warning */
double x_offset;
double y_offset;
char draw_surface[200];
cairo_box_double_t bbox;
if (pattern->base.extend == CAIRO_EXTEND_PAD &&
pattern->surface->type != CAIRO_SURFACE_TYPE_RECORDING)
{
if (pattern->extend == CAIRO_EXTEND_PAD) {
status = _cairo_pdf_surface_add_padded_image_surface (surface,
pattern,
&pdf_pattern->extents,
&pattern_resource,
&pattern_width,
&pattern_height,
&origin_x,
&origin_y);
&x_offset,
&y_offset);
pattern_extents.x = 0;
pattern_extents.y = 0;
pattern_extents.width = pattern_width;
pattern_extents.height = pattern_height;
}
else
{
} else {
status = _cairo_pdf_surface_add_source_surface (surface,
pattern->surface,
pdf_pattern->pattern->filter,
NULL,
pattern,
pattern->filter,
FALSE,
&pdf_pattern->extents,
&pattern_resource,
&pattern_width,
&pattern_height,
&x_offset,
&y_offset,
&pattern_extents);
}
if (unlikely (status))
@ -2699,7 +2856,7 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_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);
@ -2758,13 +2915,13 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface,
* have to scale it up by the image width and height to fill our
* pattern cell.
*/
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);
cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &surface->cairo_to_pdf);
cairo_matrix_translate (&pdf_p2d, -origin_x, -origin_y);
cairo_matrix_translate (&pdf_p2d, -x_offset, -y_offset);
cairo_matrix_translate (&pdf_p2d, 0.0, pattern_height);
cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
@ -2791,7 +2948,8 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface,
if (unlikely (status))
return status;
if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE &&
((cairo_surface_pattern_t *) pattern)->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
snprintf(draw_surface,
sizeof (draw_surface),
"/x%d Do\n",
@ -3712,12 +3870,12 @@ _cairo_pdf_surface_emit_pattern (cairo_pdf_surface_t *surface, cairo_pdf_pattern
switch (pdf_pattern->pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
ASSERT_NOT_REACHED;
status = _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
break;
case CAIRO_PATTERN_TYPE_SURFACE:
case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
status = _cairo_pdf_surface_emit_surface_pattern (surface, pdf_pattern);
break;
@ -3745,7 +3903,7 @@ _cairo_pdf_surface_emit_pattern (cairo_pdf_surface_t *surface, cairo_pdf_pattern
static cairo_status_t
_cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface,
cairo_surface_pattern_t *source,
const cairo_pattern_t *source,
const cairo_rectangle_int_t *extents,
cairo_bool_t stencil_mask)
{
@ -3755,11 +3913,12 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface,
cairo_status_t status;
int alpha;
cairo_rectangle_int_t extents2;
int origin_x = 0;
int origin_y = 0;
double x_offset;
double y_offset;
if (source->base.extend == CAIRO_EXTEND_PAD &&
source->surface->type != CAIRO_SURFACE_TYPE_RECORDING)
if (source->extend == CAIRO_EXTEND_PAD &&
!(source->type == CAIRO_PATTERN_TYPE_SURFACE &&
((cairo_surface_pattern_t *)source)->surface->type == CAIRO_SURFACE_TYPE_RECORDING))
{
status = _cairo_pdf_surface_add_padded_image_surface (surface,
source,
@ -3767,33 +3926,40 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface,
&surface_res,
&width,
&height,
&origin_x,
&origin_y);
&x_offset,
&y_offset);
} else {
status = _cairo_pdf_surface_add_source_surface (surface,
source->surface,
source->base.filter,
NULL,
source,
source->filter,
stencil_mask,
extents,
&surface_res,
&width,
&height,
&x_offset,
&y_offset,
&extents2);
}
if (unlikely (status))
return status;
cairo_p2d = source->base.matrix;
cairo_p2d = source->matrix;
status = cairo_matrix_invert (&cairo_p2d);
/* cairo_pattern_set_matrix ensures the matrix is invertible */
assert (status == CAIRO_STATUS_SUCCESS);
pdf_p2d = surface->cairo_to_pdf;
cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &pdf_p2d);
cairo_matrix_translate (&pdf_p2d, -origin_x, -origin_y);
cairo_matrix_translate (&pdf_p2d, x_offset, y_offset);
cairo_matrix_translate (&pdf_p2d, 0.0, height);
cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
if (source->surface->type != CAIRO_SURFACE_TYPE_RECORDING)
if (!(source->type == CAIRO_PATTERN_TYPE_SURFACE &&
((cairo_surface_pattern_t *)source)->surface->type == CAIRO_SURFACE_TYPE_RECORDING))
{
cairo_matrix_scale (&pdf_p2d, width, height);
}
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (unlikely (status))
@ -3896,8 +4062,9 @@ _cairo_pdf_surface_paint_pattern (cairo_pdf_surface_t *surface,
{
switch (source->type) {
case CAIRO_PATTERN_TYPE_SURFACE:
case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
return _cairo_pdf_surface_paint_surface_pattern (surface,
(cairo_surface_pattern_t *)source,
source,
extents,
mask);
case CAIRO_PATTERN_TYPE_LINEAR:
@ -3922,6 +4089,7 @@ _can_paint_pattern (const cairo_pattern_t *pattern)
return FALSE;
case CAIRO_PATTERN_TYPE_SURFACE:
case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
return (pattern->extend == CAIRO_EXTEND_NONE ||
pattern->extend == CAIRO_EXTEND_PAD);
@ -5965,6 +6133,7 @@ _pattern_supported (const cairo_pattern_t *pattern)
case CAIRO_PATTERN_TYPE_LINEAR:
case CAIRO_PATTERN_TYPE_RADIAL:
case CAIRO_PATTERN_TYPE_MESH:
case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
return TRUE;
case CAIRO_PATTERN_TYPE_SURFACE:
@ -5972,7 +6141,6 @@ _pattern_supported (const cairo_pattern_t *pattern)
default:
ASSERT_NOT_REACHED;
case CAIRO_PATTERN_TYPE_RASTER_SOURCE: /* XXX */
return FALSE;
}
}
@ -6116,28 +6284,29 @@ _cairo_pdf_surface_start_fallback (cairo_pdf_surface_t *surface)
/* A PDF stencil mask is an A1 mask used with the current color */
static cairo_int_status_t
_cairo_pdf_surface_emit_stencil_mask (cairo_pdf_surface_t *surface,
const cairo_pattern_t *source,
const cairo_pattern_t *mask)
_cairo_pdf_surface_emit_stencil_mask (cairo_pdf_surface_t *surface,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
const cairo_rectangle_int_t *extents)
{
cairo_status_t status;
cairo_surface_pattern_t *surface_pattern;
cairo_image_surface_t *image;
void *image_extra;
cairo_image_transparency_t transparency;
cairo_pdf_resource_t pattern_res = {0};
if (! (source->type == CAIRO_PATTERN_TYPE_SOLID &&
mask->type == CAIRO_PATTERN_TYPE_SURFACE))
(mask->type == CAIRO_PATTERN_TYPE_SURFACE || mask->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE)))
return CAIRO_INT_STATUS_UNSUPPORTED;
surface_pattern = (cairo_surface_pattern_t *) mask;
if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
if (mask->type == CAIRO_PATTERN_TYPE_SURFACE &&
((cairo_surface_pattern_t *) mask)->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
status = _cairo_surface_acquire_source_image (surface_pattern->surface,
&image,
&image_extra);
status = _cairo_pdf_surface_acquire_source_image_from_pattern (surface, mask, extents,
&image, &image_extra);
if (unlikely (status))
return status;
@ -6162,20 +6331,16 @@ _cairo_pdf_surface_emit_stencil_mask (cairo_pdf_surface_t *surface,
return status;
_cairo_output_stream_printf (surface->output, "q\n");
status = _cairo_pdf_surface_paint_surface_pattern (surface,
(cairo_surface_pattern_t *) surface_pattern,
NULL,
TRUE);
status = _cairo_pdf_surface_paint_surface_pattern (surface, mask, NULL, TRUE);
if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output, "Q\n");
_cairo_surface_release_source_image (surface_pattern->surface, image, image_extra);
status = _cairo_output_stream_get_status (surface->output);
cleanup:
_cairo_surface_release_source_image (surface_pattern->surface, image, image_extra);
_cairo_pdf_surface_release_source_image_from_pattern (surface, mask, image, image_extra);
return status;
}
@ -6396,7 +6561,7 @@ _cairo_pdf_surface_mask (void *abstract_surface,
goto cleanup;
/* Check if we can use a stencil mask */
status = _cairo_pdf_surface_emit_stencil_mask (surface, source, mask);
status = _cairo_pdf_surface_emit_stencil_mask (surface, source, mask, &extents.bounded);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto cleanup;