diff options
author | Adrian Johnson <ajohnson@redneon.com> | 2016-06-04 14:43:43 +0930 |
---|---|---|
committer | Adrian Johnson <ajohnson@redneon.com> | 2016-06-05 20:43:36 +0930 |
commit | a736fd8699e0ebcdd98392acb8383ea414688caf (patch) | |
tree | 6504e48c57df95103f89d2f40ce4821500e07942 | |
parent | 1e07ced66d26475e6631df9ffa2a15709104bd8f (diff) |
Fix PDF record-neg-extents test failure
Modify PDF surface to allow surface extents to have negative x, y.
When emitting recording surfaces, set the surface extents to the
recording extents.
-rw-r--r-- | src/cairo-analysis-surface.c | 16 | ||||
-rw-r--r-- | src/cairo-debug.c | 11 | ||||
-rw-r--r-- | src/cairo-pattern.c | 31 | ||||
-rw-r--r-- | src/cairo-pdf-surface-private.h | 10 | ||||
-rw-r--r-- | src/cairo-pdf-surface.c | 417 | ||||
-rw-r--r-- | src/cairoint.h | 5 | ||||
-rw-r--r-- | test/reference/record-neg-extents-bounded.pdf.argb32.ref.png | bin | 0 -> 520 bytes | |||
-rw-r--r-- | test/reference/record-neg-extents-bounded.pdf.rgb24.ref.png | bin | 0 -> 520 bytes | |||
-rw-r--r-- | test/reference/record-neg-extents-unbounded.pdf.argb32.ref.png | bin | 0 -> 520 bytes | |||
-rw-r--r-- | test/reference/record-neg-extents-unbounded.pdf.rgb24.ref.png | bin | 0 -> 520 bytes |
10 files changed, 284 insertions, 206 deletions
diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c index fb5ef0ed2..b2a4416aa 100644 --- a/src/cairo-analysis-surface.c +++ b/src/cairo-analysis-surface.c @@ -146,6 +146,7 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface, cairo_surface_t *source, *proxy; cairo_matrix_t p2d, surface_transform; cairo_status_t status, analysis_status; + cairo_bool_t unused; assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE); surface_pattern = (const cairo_surface_pattern_t *) pattern; @@ -176,7 +177,22 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface, source = _cairo_surface_get_source (source, NULL); status = _cairo_recording_surface_replay_and_create_regions (source, &surface_transform, &tmp->base); + + if (!tmp->first_op) + _cairo_box_add_box (&surface->page_bbox, &tmp->page_bbox); + + if (tmp->has_supported) { + surface->has_supported = TRUE; + unused = cairo_region_union (&surface->supported_region, &tmp->supported_region); + } + + if (tmp->has_unsupported) { + surface->has_unsupported = TRUE; + unused = cairo_region_union (&surface->fallback_region, &tmp->fallback_region); + } + analysis_status = tmp->has_unsupported ? CAIRO_INT_STATUS_IMAGE_FALLBACK : CAIRO_INT_STATUS_SUCCESS; + detach_proxy (proxy); cairo_surface_destroy (&tmp->base); diff --git a/src/cairo-debug.c b/src/cairo-debug.c index 33d46aa3f..dbc9e2f2c 100644 --- a/src/cairo-debug.c +++ b/src/cairo-debug.c @@ -237,7 +237,7 @@ _print_close (void *closure) } void -_cairo_debug_print_path (FILE *stream, cairo_path_fixed_t *path) +_cairo_debug_print_path (FILE *stream, const cairo_path_fixed_t *path) { cairo_status_t status; cairo_box_t box; @@ -302,3 +302,12 @@ _cairo_debug_print_polygon (FILE *stream, cairo_polygon_t *polygon) } } + +void +_cairo_debug_print_matrix (FILE *file, const cairo_matrix_t *matrix) +{ + fprintf (file, "[%g %g %g %g %g %g]\n", + matrix->xx, matrix->yx, + matrix->xy, matrix->yy, + matrix->x0, matrix->y0); +} diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index b4bc83c0e..9cb89e99f 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -4607,7 +4607,36 @@ static void _cairo_debug_print_surface_pattern (FILE *file, const cairo_surface_pattern_t *pattern) { - printf (" surface type: %d\n", pattern->surface->type); + const char *s; + switch (pattern->surface->type) { + case CAIRO_SURFACE_TYPE_IMAGE: s = "image"; break; + case CAIRO_SURFACE_TYPE_PDF: s = "pdf"; break; + case CAIRO_SURFACE_TYPE_PS: s = "ps"; break; + case CAIRO_SURFACE_TYPE_XLIB: s = "xlib"; break; + case CAIRO_SURFACE_TYPE_XCB: s = "xcb"; break; + case CAIRO_SURFACE_TYPE_GLITZ: s = "glitz"; break; + case CAIRO_SURFACE_TYPE_QUARTZ: s = "quartz"; break; + case CAIRO_SURFACE_TYPE_WIN32: s = "win32"; break; + case CAIRO_SURFACE_TYPE_BEOS: s = "beos"; break; + case CAIRO_SURFACE_TYPE_DIRECTFB: s = "directfb"; break; + case CAIRO_SURFACE_TYPE_SVG: s = "svg"; break; + case CAIRO_SURFACE_TYPE_OS2: s = "os2"; break; + case CAIRO_SURFACE_TYPE_WIN32_PRINTING: s = "win32_printing"; break; + case CAIRO_SURFACE_TYPE_QUARTZ_IMAGE: s = "quartz_image"; break; + case CAIRO_SURFACE_TYPE_SCRIPT: s = "script"; break; + case CAIRO_SURFACE_TYPE_QT: s = "qt"; break; + case CAIRO_SURFACE_TYPE_RECORDING: s = "recording"; break; + case CAIRO_SURFACE_TYPE_VG: s = "vg"; break; + case CAIRO_SURFACE_TYPE_GL: s = "gl"; break; + case CAIRO_SURFACE_TYPE_DRM: s = "drm"; break; + case CAIRO_SURFACE_TYPE_TEE: s = "tee"; break; + case CAIRO_SURFACE_TYPE_XML: s = "xml"; break; + case CAIRO_SURFACE_TYPE_SKIA: s = "skia"; break; + case CAIRO_SURFACE_TYPE_SUBSURFACE: s = "subsurface"; break; + case CAIRO_SURFACE_TYPE_COGL: s = "cogl"; break; + default: s = "invalid"; ASSERT_NOT_REACHED; break; + } + fprintf (file, " surface type: %s\n", s); } static void diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h index 66ebf609d..cf1a60881 100644 --- a/src/cairo-pdf-surface-private.h +++ b/src/cairo-pdf-surface-private.h @@ -76,9 +76,14 @@ typedef struct _cairo_pdf_source_surface_entry { cairo_bool_t smask; cairo_pdf_resource_t surface_res; cairo_pdf_resource_t smask_res; - int width; - int height; + + /* Extents of the source surface. If bounded is false, + * extents is the ink extents. */ + cairo_bool_t bounded; cairo_rectangle_int_t extents; + + /* Union of source extents requried for all operations using this source */ + cairo_rectangle_int_t required_extents; } cairo_pdf_source_surface_entry_t; typedef struct _cairo_pdf_source_surface { @@ -160,6 +165,7 @@ struct _cairo_pdf_surface { double width; double height; + cairo_rectangle_int_t surface_extents; cairo_matrix_t cairo_to_pdf; cairo_bool_t in_xobject; diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index db75bc6f8..af3e56c6f 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -300,6 +300,10 @@ _cairo_pdf_surface_set_size_internal (cairo_pdf_surface_t *surface, { surface->width = width; surface->height = height; + surface->surface_extents.x = 0; + surface->surface_extents.y = 0; + surface->surface_extents.width = ceil (surface->width); + surface->surface_extents.height = ceil (surface->height); } static cairo_bool_t @@ -372,6 +376,10 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output, surface->height = height; cairo_matrix_init (&surface->cairo_to_pdf, 1, 0, 0, 1, 0, 0); surface->in_xobject = FALSE; + surface->surface_extents.x = 0; + surface->surface_extents.y = 0; + surface->surface_extents.width = ceil (surface->width); + surface->surface_extents.height = ceil (surface->height); _cairo_array_init (&surface->objects, sizeof (cairo_pdf_object_t)); _cairo_array_init (&surface->pages, sizeof (cairo_pdf_resource_t)); @@ -1237,16 +1245,18 @@ _get_jpeg_image_info (cairo_surface_t *source, } static cairo_int_status_t -_get_source_surface_size (cairo_surface_t *source, - int *width, - int *height, - cairo_rectangle_int_t *extents) +_get_source_surface_extents (cairo_surface_t *source, + cairo_rectangle_int_t *extents, + cairo_bool_t *bounded, + cairo_bool_t *subsurface) { cairo_int_status_t status; cairo_image_info_t info; const unsigned char *mime_data; unsigned long mime_data_length; + *bounded = TRUE; + *subsurface = FALSE; if (source->type == CAIRO_SURFACE_TYPE_RECORDING) { cairo_surface_t *free_me = NULL; @@ -1257,28 +1267,20 @@ _get_source_surface_size (cairo_surface_t *source, cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source; *extents = sub->extents; - extents->x = 0; - extents->y = 0; - *width = extents->width; - *height = extents->height; + *subsurface = TRUE; } else { cairo_rectangle_int_t surf_extents; cairo_box_t box; - cairo_bool_t bounded; - status = _cairo_recording_surface_get_ink_bbox ((cairo_recording_surface_t *)source, - &box, NULL); - if (unlikely (status)) { - cairo_surface_destroy (free_me); - return status; + if (! _cairo_surface_get_extents (source, extents)) { + status = _cairo_recording_surface_get_ink_bbox ((cairo_recording_surface_t *)source, + &box, NULL); + if (unlikely (status)) { + cairo_surface_destroy (free_me); + return status; + } + _cairo_box_round_to_rectangle (&box, extents); } - - bounded = _cairo_surface_get_extents (source, &surf_extents); - - *width = surf_extents.width; - *height = surf_extents.height; - - _cairo_box_round_to_rectangle (&box, extents); } cairo_surface_destroy (free_me); @@ -1290,8 +1292,6 @@ _get_source_surface_size (cairo_surface_t *source, status = _get_jbig2_image_info (source, &info, &mime_data, &mime_data_length); if (status != CAIRO_INT_STATUS_UNSUPPORTED) { - *width = info.width; - *height = info.height; extents->width = info.width; extents->height = info.height; return status; @@ -1299,8 +1299,6 @@ _get_source_surface_size (cairo_surface_t *source, status = _get_jpx_image_info (source, &info, &mime_data, &mime_data_length); if (status != CAIRO_INT_STATUS_UNSUPPORTED) { - *width = info.width; - *height = info.height; extents->width = info.width; extents->height = info.height; return status; @@ -1308,8 +1306,6 @@ _get_source_surface_size (cairo_surface_t *source, status = _get_jpeg_image_info (source, &info, &mime_data, &mime_data_length); if (status != CAIRO_INT_STATUS_UNSUPPORTED) { - *width = info.width; - *height = info.height; extents->width = info.width; extents->height = info.height; return status; @@ -1318,9 +1314,6 @@ _get_source_surface_size (cairo_surface_t *source, if (! _cairo_surface_get_extents (source, extents)) return CAIRO_INT_STATUS_UNSUPPORTED; - *width = extents->width; - *height = extents->height; - return CAIRO_STATUS_SUCCESS; } @@ -1333,51 +1326,52 @@ _get_source_surface_size (cairo_surface_t *source, * @filter: filter type of the source pattern * @stencil_mask: if true, the surface will be written to the PDF as an /ImageMask * @smask: if true, only the alpha channel will be written (images only) + * @smask_res: if not NULL, the image written will specify this resource as the smask for + the image (images only) * @extents: extents of the operation that is using this source - * @smask_res: if not NULL, the image written will specify this resource as the smask for the image (images only) - * @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) + * @pdf_source: return pdf_source_surface entry in hash table + * @x_offset: if not NULL return x offset of surface + * @y_offset: if not NULL return y offset of surface + * @source_extents: if not NULL return operation extents in source space * * 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. + * a PDF resource to reference the surface. A hash table of all + * surfaces in the PDF file (keyed by CAIRO_MIME_TYPE_UNIQUE_ID or + * surface unique_id) is used 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_int_status_t -_cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface, - cairo_surface_t *source_surface, - const cairo_pattern_t *source_pattern, - cairo_operator_t op, - cairo_filter_t filter, - cairo_bool_t stencil_mask, - cairo_bool_t smask, - const cairo_rectangle_int_t *extents, - cairo_pdf_resource_t *smask_res, - cairo_pdf_resource_t *surface_res, - int *width, - int *height, - double *x_offset, - double *y_offset, - cairo_rectangle_int_t *source_extents) +_cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface, + cairo_surface_t *source_surface, + const cairo_pattern_t *source_pattern, + cairo_operator_t op, + cairo_filter_t filter, + cairo_bool_t stencil_mask, + cairo_bool_t smask, + cairo_pdf_resource_t *smask_res, + const cairo_rectangle_int_t *extents, + cairo_pdf_source_surface_entry_t **pdf_source, + 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_int_status_t status; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; cairo_bool_t interpolate; unsigned char *unique_id = NULL; unsigned long unique_id_length = 0; cairo_image_surface_t *image; void *image_extra; + cairo_box_t box; + cairo_rectangle_int_t op_extents; + double x, y; + cairo_bool_t subsurface; switch (filter) { default: @@ -1393,8 +1387,8 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface, break; } - *x_offset = 0; - *y_offset = 0; + x = 0; + y = 0; if (source_pattern) { if (source_pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) { status = _cairo_pdf_surface_acquire_source_image_from_pattern (surface, source_pattern, @@ -1402,12 +1396,27 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface, if (unlikely (status)) return status; source_surface = &image->base; - cairo_surface_get_device_offset (source_surface, x_offset, y_offset); + cairo_surface_get_device_offset (source_surface, &x, &y); } else { cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source_pattern; source_surface = surface_pattern->surface; } } + if (x_offset) + *x_offset = x; + if (y_offset) + *y_offset = y; + + /* transform operation extents to pattern space */ + op_extents = *extents; + if (source_pattern) + { + _cairo_box_from_rectangle (&box, extents); + _cairo_matrix_transform_bounding_box_fixed (&source_pattern->matrix, &box, NULL); + _cairo_box_round_to_rectangle (&box, &op_extents); + } + if (source_extents) + *source_extents = op_extents; surface_key.id = source_surface->unique_id; surface_key.interpolate = interpolate; @@ -1417,40 +1426,36 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface, _cairo_pdf_source_surface_init_key (&surface_key); surface_entry = _cairo_hash_table_lookup (surface->all_surfaces, &surface_key.base); if (surface_entry) { - *surface_res = surface_entry->surface_res; - *width = surface_entry->width; - *height = surface_entry->height; - *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; + if (pdf_source) + *pdf_source = surface_entry; - if (surface_key.unique_id && surface_key.unique_id_length > 0) { - unique_id = _cairo_malloc (surface_key.unique_id_length); - if (unique_id == NULL) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto release_source; - } + if (source_pattern && source_pattern->extend != CAIRO_EXTEND_NONE) + _cairo_unbounded_rectangle_init (&op_extents); - 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; - } + _cairo_rectangle_intersect (&op_extents, &surface_entry->extents); + _cairo_rectangle_union (&surface_entry->required_extents, &op_extents); + status = CAIRO_STATUS_SUCCESS; } -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) + if (status || surface_entry) { + 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); return status; + } + + if (surface_key.unique_id && surface_key.unique_id_length > 0) { + unique_id = _cairo_malloc (surface_key.unique_id_length); + if (unique_id == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail1; + } + + 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; + } surface_entry = malloc (sizeof (cairo_pdf_source_surface_entry_t)); if (surface_entry == NULL) { @@ -1458,6 +1463,8 @@ release_source: goto fail1; } + if (pdf_source) + *pdf_source = surface_entry; surface_entry->id = surface_key.id; surface_entry->operator = op; surface_entry->interpolate = interpolate; @@ -1465,13 +1472,29 @@ release_source: surface_entry->smask = smask; surface_entry->unique_id_length = unique_id_length; surface_entry->unique_id = unique_id; - surface_entry->width = *width; - surface_entry->height = *height; - surface_entry->extents = *source_extents; if (smask_res) surface_entry->smask_res = *smask_res; else surface_entry->smask_res.id = 0; + + status = _get_source_surface_extents (source_surface, + &surface_entry->extents, + &surface_entry->bounded, + &subsurface); + if (unlikely (status)) + goto fail2; + + if (subsurface) { + *x_offset = -surface_entry->extents.x; + *y_offset = -surface_entry->extents.y; + } + + if (source_pattern && source_pattern->extend != CAIRO_EXTEND_NONE) + _cairo_unbounded_rectangle_init (&op_extents); + + _cairo_rectangle_intersect (&op_extents, &surface_entry->extents); + surface_entry->required_extents = op_extents; + _cairo_pdf_source_surface_init_key (surface_entry); src_surface.hash_entry = surface_entry; @@ -1503,9 +1526,10 @@ release_source: if (unlikely(status)) goto fail3; - *surface_res = surface_entry->surface_res; + 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); - return status; + return CAIRO_STATUS_SUCCESS; fail3: if (source_pattern && source_pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) @@ -1517,7 +1541,11 @@ fail2: free (surface_entry); fail1: - free (unique_id); + if (unique_id) + free (unique_id); + + 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); return status; } @@ -2166,6 +2194,7 @@ _cairo_pdf_surface_start_page (void *abstract_surface) } _cairo_pdf_group_resources_clear (&surface->resources); + surface->in_xobject = FALSE; return CAIRO_STATUS_SUCCESS; } @@ -2179,6 +2208,7 @@ _cairo_pdf_surface_has_fallback_images (void *abstract_surface, cairo_box_double_t bbox; surface->has_fallback_images = has_fallbacks; + surface->in_xobject = has_fallbacks; bbox.p1.x = 0; bbox.p1.y = 0; bbox.p2.x = surface->width; @@ -2200,18 +2230,16 @@ static cairo_int_status_t _cairo_pdf_surface_add_padded_image_surface (cairo_pdf_surface_t *surface, const cairo_pattern_t *source, const cairo_rectangle_int_t *extents, - cairo_pdf_resource_t *surface_res, - int *width, - int *height, + cairo_pdf_source_surface_entry_t **pdf_source, double *x_offset, - double *y_offset) + double *y_offset, + cairo_rectangle_int_t *source_extents) { cairo_image_surface_t *image; cairo_surface_t *pad_image; void *image_extra; cairo_int_status_t status; int w, h; - cairo_rectangle_int_t extents2; cairo_box_t box; cairo_rectangle_int_t rect; cairo_surface_pattern_t pad_pattern; @@ -2258,18 +2286,16 @@ _cairo_pdf_surface_add_padded_image_surface (cairo_pdf_surface_t *surfa status = _cairo_pdf_surface_add_source_surface (surface, pad_image, NULL, - FALSE, + CAIRO_OPERATOR_OVER, /* not used for images */ source->filter, - FALSE, - FALSE, + FALSE, /* stencil mask */ + FALSE, /* smask */ + NULL, /* smask_res */ extents, - NULL, - surface_res, - width, - height, + pdf_source, x_offset, y_offset, - &extents2); + source_extents); if (unlikely (status)) goto BAIL; @@ -3001,6 +3027,7 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface, cairo_pdf_source_surface_t *pdf_source) { double old_width, old_height; + cairo_rectangle_int_t old_surface_extents; cairo_paginated_mode_t old_paginated_mode; cairo_surface_clipper_t old_clipper; cairo_bool_t old_in_xobject; @@ -3017,9 +3044,9 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface, cairo_recording_surface_t *recording; assert (pdf_source->type == CAIRO_PATTERN_TYPE_SURFACE); - extents = &pdf_source->hash_entry->extents; - width = pdf_source->hash_entry->width; - height = pdf_source->hash_entry->height; + extents = &pdf_source->hash_entry->required_extents; + width = pdf_source->hash_entry->extents.width; + height = pdf_source->hash_entry->extents.height; is_subsurface = FALSE; source = pdf_source->surface; if (_cairo_surface_is_snapshot (source)) @@ -3041,15 +3068,17 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface, old_width = surface->width; old_height = surface->height; old_in_xobject = surface->in_xobject; - + old_surface_extents = surface->surface_extents; old_paginated_mode = surface->paginated_mode; old_clipper = surface->clipper; + surface->surface_extents = *extents; _cairo_surface_clipper_init (&surface->clipper, _cairo_pdf_surface_clipper_intersect_clip_path); _cairo_pdf_surface_set_size_internal (surface, width, height); _cairo_pdf_operators_reset (&surface->pdf_operators); surface->in_xobject = TRUE; + surface->surface_extents = *extents; /* Patterns are emitted after fallback images. The paginated mode * needs to be set to _RENDER while the recording surface is replayed @@ -3058,10 +3087,10 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface, surface->paginated_mode = CAIRO_PAGINATED_MODE_RENDER; _cairo_pdf_group_resources_clear (&surface->resources); if (is_subsurface) { - bbox.p1.x = 0; - bbox.p1.y = 0; - bbox.p2.x = extents->width; - bbox.p2.y = extents->height; + bbox.p1.x = extents->x; + bbox.p1.y = extents->y; + bbox.p2.x = extents->x + extents->width; + bbox.p2.y = extents->y + extents->height; } else { _get_bbox_from_extents (height, extents, &bbox); } @@ -3108,6 +3137,7 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface, _cairo_pdf_operators_reset (&surface->pdf_operators); surface->in_xobject = old_in_xobject; surface->paginated_mode = old_paginated_mode; + surface->surface_extents = old_surface_extents; err: cairo_surface_destroy (free_me); @@ -3131,7 +3161,6 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, { cairo_pattern_t *pattern = pdf_pattern->pattern; cairo_int_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); double xstep, ystep; @@ -3141,42 +3170,46 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, double x_offset; double y_offset; char draw_surface[200]; - cairo_box_double_t bbox; + cairo_box_double_t bbox; cairo_matrix_t mat; + cairo_pdf_source_surface_entry_t *pdf_source; + cairo_rectangle_int_t op_extents; 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, + &pdf_source, &x_offset, - &y_offset); - pattern_extents.x = 0; - pattern_extents.y = 0; - pattern_extents.width = pattern_width; - pattern_extents.height = pattern_height; + &y_offset, + &op_extents); } else { status = _cairo_pdf_surface_add_source_surface (surface, NULL, pattern, pdf_pattern->operator, pattern->filter, - FALSE, - FALSE, + FALSE, /* stencil mask */ + FALSE, /* smask */ + NULL, /* smask_res */ &pdf_pattern->extents, - NULL, - &pattern_resource, - &pattern_width, - &pattern_height, + &pdf_source, &x_offset, &y_offset, - &pattern_extents); + &op_extents); } if (unlikely (status)) return status; + pattern_extents = pdf_source->extents; + pattern_width = pdf_source->extents.width; + pattern_height = pdf_source->extents.height; + if (!pdf_source->bounded) + { + extend = CAIRO_EXTEND_NONE; + _cairo_rectangle_intersect (&pattern_extents, &op_extents); + } + switch (extend) { case CAIRO_EXTEND_PAD: case CAIRO_EXTEND_NONE: @@ -3194,7 +3227,8 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, * repeat visibly. */ double x1 = 0.0, y1 = 0.0; - double x2 = surface->width, y2 = surface->height; + double x2 = surface->surface_extents.width; + double y2 = surface->surface_extents.height; _cairo_matrix_transform_bounding_box (&pattern->matrix, &x1, &y1, &x2, &y2, NULL); @@ -3207,20 +3241,21 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, pattern_width + pattern_height); } break; + case CAIRO_EXTEND_REPEAT: xstep = pattern_width; ystep = pattern_height; break; + case CAIRO_EXTEND_REFLECT: - pattern_extents.x = 0; - pattern_extents.y = 0; - pattern_extents.width = pattern_width*2; - pattern_extents.height = pattern_height*2; - xstep = pattern_width*2; - ystep = pattern_height*2; + pattern_extents.width *= 2; + pattern_extents.height *= 2; + xstep = pattern_extents.width; + ystep = pattern_extents.height; break; - /* All the rest (if any) should have been analyzed away, so this - * case should be unreachable. */ + + /* All the rest (if any) should have been analyzed away, so this + * case should be unreachable. */ default: ASSERT_NOT_REACHED; xstep = 0; @@ -3265,7 +3300,7 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, cairo_matrix_init (&mat, 1, 0, 0, -1, 0, surface->height); cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &mat); - cairo_matrix_translate (&pdf_p2d, -x_offset, -y_offset); + cairo_matrix_translate (&pdf_p2d, x_offset, y_offset); if (((cairo_surface_pattern_t *)pattern)->surface->type != CAIRO_SURFACE_TYPE_RECORDING) { cairo_matrix_translate (&pdf_p2d, 0.0, pattern_height); @@ -3290,8 +3325,8 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, pdf_p2d.xx, pdf_p2d.yx, pdf_p2d.xy, pdf_p2d.yy, pdf_p2d.x0, pdf_p2d.y0, - pattern_resource.id, - pattern_resource.id); + pdf_source->surface_res.id, + pdf_source->surface_res.id); if (unlikely (status)) return status; @@ -3300,14 +3335,14 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, snprintf(draw_surface, sizeof (draw_surface), "/x%d Do\n", - pattern_resource.id); + pdf_source->surface_res.id); } else { snprintf(draw_surface, sizeof (draw_surface), "q %d 0 0 %d 0 0 cm /x%d Do Q", pattern_width, pattern_height, - pattern_resource.id); + pdf_source->surface_res.id); } if (extend == CAIRO_EXTEND_REFLECT) { @@ -4245,16 +4280,8 @@ _cairo_pdf_surface_emit_mesh_pattern (cairo_pdf_surface_t *surface, static cairo_int_status_t _cairo_pdf_surface_emit_pattern (cairo_pdf_surface_t *surface, cairo_pdf_pattern_t *pdf_pattern) { - double old_width, old_height; cairo_int_status_t status; - old_width = surface->width; - old_height = surface->height; - _cairo_pdf_surface_set_size_internal (surface, - pdf_pattern->width, - pdf_pattern->height); - _cairo_pdf_operators_reset (&surface->pdf_operators); - switch (pdf_pattern->pattern->type) { case CAIRO_PATTERN_TYPE_SOLID: ASSERT_NOT_REACHED; @@ -4281,11 +4308,6 @@ _cairo_pdf_surface_emit_pattern (cairo_pdf_surface_t *surface, cairo_pdf_pattern break; } - _cairo_pdf_surface_set_size_internal (surface, - old_width, - old_height); - _cairo_pdf_operators_reset (&surface->pdf_operators); - return status; } @@ -4297,14 +4319,12 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface, cairo_pdf_resource_t *smask_res, cairo_bool_t stencil_mask) { - cairo_pdf_resource_t surface_res; - int width, height; cairo_matrix_t cairo_p2d, pdf_p2d; cairo_int_status_t status; int alpha; - cairo_rectangle_int_t extents2; double x_offset; double y_offset; + cairo_pdf_source_surface_entry_t *pdf_source; if (source->extend == CAIRO_EXTEND_PAD && !(source->type == CAIRO_PATTERN_TYPE_SURFACE && @@ -4313,11 +4333,10 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface, status = _cairo_pdf_surface_add_padded_image_surface (surface, source, extents, - &surface_res, - &width, - &height, + &pdf_source, &x_offset, - &y_offset); + &y_offset, + NULL); } else { status = _cairo_pdf_surface_add_source_surface (surface, NULL, @@ -4325,15 +4344,13 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface, op, source->filter, stencil_mask, - FALSE, - extents, + FALSE, /* smask */ smask_res, - &surface_res, - &width, - &height, + extents, + &pdf_source, &x_offset, &y_offset, - &extents2); + NULL); } if (unlikely (status)) return status; @@ -4349,9 +4366,9 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface, if (!(source->type == CAIRO_PATTERN_TYPE_SURFACE && ((cairo_surface_pattern_t *)source)->surface->type == CAIRO_SURFACE_TYPE_RECORDING)) { - cairo_matrix_translate (&pdf_p2d, 0.0, height); + cairo_matrix_translate (&pdf_p2d, 0.0, pdf_source->extents.height); cairo_matrix_scale (&pdf_p2d, 1.0, -1.0); - cairo_matrix_scale (&pdf_p2d, width, height); + cairo_matrix_scale (&pdf_p2d, pdf_source->extents.width, pdf_source->extents.height); } status = _cairo_pdf_operators_flush (&surface->pdf_operators); @@ -4370,15 +4387,15 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface, if (stencil_mask) { _cairo_output_stream_printf (surface->output, "/x%d Do\n", - surface_res.id); + pdf_source->surface_res.id); } else { _cairo_output_stream_printf (surface->output, "/a%d gs /x%d Do\n", alpha, - surface_res.id); + pdf_source->surface_res.id); } - return _cairo_pdf_surface_add_xobject (surface, surface_res); + return _cairo_pdf_surface_add_xobject (surface, pdf_source->surface_res); } static cairo_int_status_t @@ -4664,15 +4681,7 @@ _cairo_pdf_surface_get_extents (void *abstract_surface, { cairo_pdf_surface_t *surface = abstract_surface; - rectangle->x = 0; - rectangle->y = 0; - - /* XXX: The conversion to integers here is pretty bogus, (not to - * mention the arbitrary limitation of width to a short(!). We - * may need to come up with a better interface for get_size. - */ - rectangle->width = ceil (surface->width); - rectangle->height = ceil (surface->height); + *rectangle = surface->surface_extents; return TRUE; } @@ -6744,7 +6753,6 @@ _cairo_pdf_surface_emit_combined_smask (cairo_pdf_surface_t *surface, cairo_image_surface_t *image; void *image_extra; cairo_image_transparency_t transparency; - cairo_pdf_resource_t smask_res; int src_width, src_height; int mask_width, mask_height; double src_x_offset, src_y_offset; @@ -6753,8 +6761,8 @@ _cairo_pdf_surface_emit_combined_smask (cairo_pdf_surface_t *surface, double mask_x1, mask_y1, mask_x2, mask_y2; cairo_matrix_t p2u; double src_radius, mask_radius, e; - cairo_rectangle_int_t extents2; cairo_bool_t need_smask; + cairo_pdf_source_surface_entry_t *pdf_source; /* Check that source and mask are images */ @@ -6873,16 +6881,14 @@ _cairo_pdf_surface_emit_combined_smask (cairo_pdf_surface_t *surface, mask, op, source->filter, - FALSE, - TRUE, + FALSE, /* stencil mask */ + TRUE, /* smask */ + NULL, /* smask_res */ extents, + &pdf_source, + NULL, NULL, - &smask_res, - &mask_width, - &mask_height, - &mask_x_offset, - &mask_y_offset, - &extents2); + NULL); if (unlikely (status)) return status; } @@ -6893,7 +6899,7 @@ _cairo_pdf_surface_emit_combined_smask (cairo_pdf_surface_t *surface, _cairo_output_stream_printf (surface->output, "q\n"); status = _cairo_pdf_surface_paint_surface_pattern (surface, op, source, extents, - need_smask ? &smask_res : NULL, + need_smask ? &pdf_source->smask_res : NULL, FALSE); if (unlikely (status)) return status; @@ -7010,7 +7016,7 @@ _cairo_pdf_surface_paint (void *abstract_surface, status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded); goto cleanup; } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) { - status = _cairo_pdf_surface_start_fallback (surface); + status = _cairo_pdf_surface_start_fallback (surface); if (unlikely (status)) goto cleanup; } @@ -7091,8 +7097,11 @@ _cairo_pdf_surface_paint (void *abstract_surface, goto cleanup; _cairo_output_stream_printf (surface->output, - "0 0 %f %f re f\n", - surface->width, surface->height); + "%d %d %d %d re f\n", + surface->surface_extents.x, + surface->surface_extents.y, + surface->surface_extents.width, + surface->surface_extents.height); status = _cairo_pdf_surface_unselect_pattern (surface); if (unlikely (status)) @@ -7887,6 +7896,12 @@ _cairo_pdf_surface_set_paginated_mode (void *abstract_surface, cairo_pdf_surface_t *surface = abstract_surface; surface->paginated_mode = paginated_mode; + if (paginated_mode == CAIRO_PAGINATED_MODE_RENDER) { + surface->surface_extents.x = 0; + surface->surface_extents.y = 0; + surface->surface_extents.width = ceil (surface->width); + surface->surface_extents.height = ceil (surface->height); + } } static const cairo_surface_backend_t cairo_pdf_surface_backend = { diff --git a/src/cairoint.h b/src/cairoint.h index f7817484b..88b1bf739 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -1781,6 +1781,9 @@ _cairo_matrix_to_pixman_matrix_offset (const cairo_matrix_t *matrix, int *out_x_offset, int *out_y_offset); +cairo_private void +_cairo_debug_print_matrix (FILE *file, const cairo_matrix_t *matrix); + cairo_private cairo_status_t _cairo_bentley_ottmann_tessellate_rectilinear_polygon (cairo_traps_t *traps, const cairo_polygon_t *polygon, @@ -2062,7 +2065,7 @@ _cairo_debug_check_image_surface_is_defined (const cairo_surface_t *surface); #endif cairo_private void -_cairo_debug_print_path (FILE *stream, cairo_path_fixed_t *path); +_cairo_debug_print_path (FILE *stream, const cairo_path_fixed_t *path); cairo_private void _cairo_debug_print_polygon (FILE *stream, cairo_polygon_t *polygon); diff --git a/test/reference/record-neg-extents-bounded.pdf.argb32.ref.png b/test/reference/record-neg-extents-bounded.pdf.argb32.ref.png Binary files differnew file mode 100644 index 000000000..159283651 --- /dev/null +++ b/test/reference/record-neg-extents-bounded.pdf.argb32.ref.png diff --git a/test/reference/record-neg-extents-bounded.pdf.rgb24.ref.png b/test/reference/record-neg-extents-bounded.pdf.rgb24.ref.png Binary files differnew file mode 100644 index 000000000..159283651 --- /dev/null +++ b/test/reference/record-neg-extents-bounded.pdf.rgb24.ref.png diff --git a/test/reference/record-neg-extents-unbounded.pdf.argb32.ref.png b/test/reference/record-neg-extents-unbounded.pdf.argb32.ref.png Binary files differnew file mode 100644 index 000000000..159283651 --- /dev/null +++ b/test/reference/record-neg-extents-unbounded.pdf.argb32.ref.png diff --git a/test/reference/record-neg-extents-unbounded.pdf.rgb24.ref.png b/test/reference/record-neg-extents-unbounded.pdf.rgb24.ref.png Binary files differnew file mode 100644 index 000000000..159283651 --- /dev/null +++ b/test/reference/record-neg-extents-unbounded.pdf.rgb24.ref.png |