summaryrefslogtreecommitdiff
path: root/Build/source/libs/cairo/cairo-src/src/cairo-ps-surface.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/cairo/cairo-src/src/cairo-ps-surface.c')
-rw-r--r--Build/source/libs/cairo/cairo-src/src/cairo-ps-surface.c1940
1 files changed, 1332 insertions, 608 deletions
diff --git a/Build/source/libs/cairo/cairo-src/src/cairo-ps-surface.c b/Build/source/libs/cairo/cairo-src/src/cairo-ps-surface.c
index 3b66b275d82..0a17b81afe3 100644
--- a/Build/source/libs/cairo/cairo-src/src/cairo-ps-surface.c
+++ b/Build/source/libs/cairo/cairo-src/src/cairo-ps-surface.c
@@ -77,6 +77,7 @@
#include "cairo-output-stream-private.h"
#include "cairo-type3-glyph-surface-private.h"
#include "cairo-image-info-private.h"
+#include "cairo-tag-attributes-private.h"
#include <stdio.h>
#include <ctype.h>
@@ -84,7 +85,14 @@
#include <zlib.h>
#include <errno.h>
-#define DEBUG_PS 0
+/* Forms are emitted at the start and stored in memory so we limit the
+ * total size of all forms to prevent running out of memory. If this
+ * limit is exceeded, surfaces that would be stored in forms are
+ * emitted each time the surface is used. */
+#define MAX_L2_FORM_DATA (256*1024)
+#define MAX_L3_FORM_DATA (2*1024*1024) /* Assume Level 3 printers have more memory */
+
+/* #define DEBUG_PS 1 */
#if DEBUG_PS
#define DEBUG_FALLBACK(s) \
@@ -105,11 +113,44 @@
*
* The PostScript surface is used to render cairo graphics to Adobe
* PostScript files and is a multi-page vector surface backend.
+ *
+ * The following mime types are supported: %CAIRO_MIME_TYPE_JPEG,
+ * %CAIRO_MIME_TYPE_UNIQUE_ID,
+ * %CAIRO_MIME_TYPE_CCITT_FAX, %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS,
+ * %CAIRO_MIME_TYPE_CCITT_FAX, %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS,
+ * %CAIRO_MIME_TYPE_EPS, %CAIRO_MIME_TYPE_EPS_PARAMS.
+ *
+ * Source surfaces used by the PostScript surface that have a
+ * %CAIRO_MIME_TYPE_UNIQUE_ID mime type will be stored in PostScript
+ * printer memory for the duration of the print
+ * job. %CAIRO_MIME_TYPE_UNIQUE_ID should only be used for small
+ * frequently used sources.
+ *
+ * The %CAIRO_MIME_TYPE_CCITT_FAX and %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS mime types
+ * are documented in [CCITT Fax Images][ccitt].
+ *
+ * # Embedding EPS files # {#eps}
+ *
+ * Encapsulated PostScript files can be embedded in the PS output by
+ * setting the CAIRO_MIME_TYPE_EPS mime data on a surface to the EPS
+ * data and painting the surface. The EPS will be scaled and
+ * translated to the extents of the surface the EPS data is attached
+ * to.
+ *
+ * The %CAIRO_MIME_TYPE_EPS mime type requires the
+ * %CAIRO_MIME_TYPE_EPS_PARAMS mime data to also be provided in order
+ * to specify the embeddding parameters. %CAIRO_MIME_TYPE_EPS_PARAMS
+ * mime data must contain a string of the form "bbox=[llx lly urx
+ * ury]" that specifies the bounding box (in PS coordinates) of the
+ * EPS graphics. The parameters are: lower left x, lower left y, upper
+ * right x, upper right y. Normally the bbox data is identical to the
+ * %%%BoundingBox data in the EPS file.
+ *
**/
/**
* CAIRO_HAS_PS_SURFACE:
- *
+ *
* Defined if the PostScript surface backend is available.
* This macro can be used to conditionally compile backend-specific code.
*
@@ -120,7 +161,30 @@ typedef enum {
CAIRO_PS_COMPRESS_NONE,
CAIRO_PS_COMPRESS_LZW,
CAIRO_PS_COMPRESS_DEFLATE
- } cairo_ps_compress_t;
+} cairo_ps_compress_t;
+
+typedef enum {
+ CAIRO_EMIT_SURFACE_ANALYZE,
+ CAIRO_EMIT_SURFACE_EMIT,
+ CAIRO_EMIT_SURFACE_EMIT_FORM
+} cairo_emit_surface_mode_t;
+
+typedef struct {
+ /* input params */
+ cairo_surface_t *src_surface;
+ cairo_operator_t op;
+ const cairo_rectangle_int_t *src_surface_extents;
+ cairo_bool_t src_surface_bounded;
+ const cairo_rectangle_int_t *src_op_extents; /* operation extents in src space */
+ cairo_filter_t filter;
+ cairo_bool_t stencil_mask; /* TRUE if source is to be used as a mask */
+
+ /* output params */
+ cairo_bool_t is_image; /* returns TRUE if PS image will be emitted */
+ /* FALSE if recording will be emitted */
+ long approx_size;
+ int eod_count;
+} cairo_emit_surface_params_t;
static const cairo_surface_backend_t cairo_ps_surface_backend;
static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend;
@@ -129,6 +193,9 @@ static cairo_bool_t
_cairo_ps_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle);
+static void
+_cairo_ps_form_emit (void *entry, void *closure);
+
static const cairo_ps_level_t _cairo_ps_levels[] =
{
CAIRO_PS_LEVEL_2,
@@ -146,6 +213,8 @@ static const char * _cairo_ps_level_strings[CAIRO_PS_LEVEL_LAST] =
static const char *_cairo_ps_supported_mime_types[] =
{
CAIRO_MIME_TYPE_JPEG,
+ CAIRO_MIME_TYPE_CCITT_FAX,
+ CAIRO_MIME_TYPE_CCITT_FAX_PARAMS,
NULL
};
@@ -184,6 +253,40 @@ typedef struct _cairo_page_media {
} cairo_page_media_t;
static void
+_cairo_ps_form_init_key (cairo_ps_form_t *key)
+{
+ key->base.hash = _cairo_hash_bytes (_CAIRO_HASH_INIT_VALUE,
+ key->unique_id, key->unique_id_length);
+}
+
+static cairo_bool_t
+_cairo_ps_form_equal (const void *key_a, const void *key_b)
+{
+ const cairo_ps_form_t *a = key_a;
+ const cairo_ps_form_t *b = key_b;
+
+ if (a->filter != b->filter)
+ return FALSE;
+
+ if (a->unique_id_length != b->unique_id_length)
+ return FALSE;
+
+ return memcmp (a->unique_id, b->unique_id, a->unique_id_length) == 0;
+}
+
+static void
+_cairo_ps_form_pluck (void *entry, void *closure)
+{
+ cairo_ps_form_t *surface_entry = entry;
+ cairo_hash_table_t *patterns = closure;
+
+ _cairo_hash_table_remove (patterns, &surface_entry->base);
+ free (surface_entry->unique_id);
+ cairo_surface_destroy (surface_entry->src_surface);
+ free (surface_entry);
+}
+
+static void
_cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
{
char ctime_buf[26];
@@ -209,7 +312,7 @@ _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
_cairo_output_stream_printf (surface->final_stream,
"%%!PS-Adobe-3.0%s\n"
- "%%%%Creator: cairo %s (http://cairographics.org)\n"
+ "%%%%Creator: cairo %s (https://cairographics.org)\n"
"%%%%CreationDate: %s"
"%%%%Pages: %d\n",
eps_header,
@@ -259,10 +362,10 @@ _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
if (!has_bbox) {
_cairo_output_stream_printf (surface->final_stream,
"%%%%BoundingBox: %d %d %d %d\n",
- surface->bbox_x1,
- surface->bbox_y1,
- surface->bbox_x2,
- surface->bbox_y2);
+ surface->document_bbox_p1.x,
+ surface->document_bbox_p1.y,
+ surface->document_bbox_p2.x,
+ surface->document_bbox_p2.y);
}
_cairo_output_stream_printf (surface->final_stream,
@@ -273,7 +376,6 @@ _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
if (surface->eps) {
_cairo_output_stream_printf (surface->final_stream,
- "save\n"
"50 dict begin\n");
} else {
_cairo_output_stream_printf (surface->final_stream,
@@ -309,9 +411,6 @@ _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
"/W* { eoclip } bind def\n"
"/BT { } bind def\n"
"/ET { } bind def\n"
- "/pdfmark where { pop globaldict /?pdfmark /exec load put }\n"
- " { globaldict begin /?pdfmark /pop load def /pdfmark\n"
- " /cleartomark load def end } ifelse\n"
"/BDC { mark 3 1 roll /BDC pdfmark } bind def\n"
"/EMC { mark /EMC pdfmark } bind def\n"
"/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def\n"
@@ -336,6 +435,11 @@ _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
"/g { setgray } bind def\n"
"/rg { setrgbcolor } bind def\n"
"/d1 { setcachedevice } bind def\n"
+ "/cairo_data_source {\n"
+ " CairoDataIndex CairoData length lt\n"
+ " { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def }\n"
+ " { () } ifelse\n"
+ "} def\n"
"/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def\n"
"/cairo_image { image cairo_flush_ascii85_file } def\n"
"/cairo_imagemask { imagemask cairo_flush_ascii85_file } def\n");
@@ -374,11 +478,25 @@ _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
" } ifelse\n"
"} def\n");
}
+ if (surface->contains_eps) {
+ _cairo_output_stream_printf (surface->final_stream,
+ "/cairo_eps_begin {\n"
+ " /cairo_save_state save def\n"
+ " /dict_count countdictstack def\n"
+ " /op_count count 1 sub def\n"
+ " userdict begin\n"
+ " /showpage { } def\n"
+ " 0 g 0 J 1 w 0 j 10 M [ ] 0 d n\n"
+ "} bind def\n"
+ "/cairo_eps_end {\n"
+ " count op_count sub { pop } repeat\n"
+ " countdictstack dict_count sub { end } repeat\n"
+ " cairo_save_state restore\n"
+ "} bind def\n");
+ }
_cairo_output_stream_printf (surface->final_stream,
"%%%%EndProlog\n");
- _cairo_output_stream_printf (surface->final_stream,
- "%%%%BeginSetup\n");
num_comments = _cairo_array_num_elements (&surface->dsc_setup_comments);
if (num_comments) {
@@ -673,7 +791,7 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface,
_cairo_output_stream_printf (surface->final_stream,
"8 dict begin\n"
"/FontType 3 def\n"
- "/FontMatrix [1 0 0 1 0 0] def\n"
+ "/FontMatrix [1 0 0 -1 0 0] def\n"
"/Encoding 256 array def\n"
"0 1 255 { Encoding exch /.notdef put } for\n");
@@ -836,6 +954,16 @@ _cairo_ps_surface_emit_font_subsets (cairo_ps_surface_t *surface)
surface);
}
+
+static cairo_int_status_t
+_cairo_ps_surface_emit_forms (cairo_ps_surface_t *surface)
+{
+ _cairo_hash_table_foreach (surface->forms,
+ _cairo_ps_form_emit,
+ surface);
+ return surface->base.status;
+}
+
static cairo_status_t
_cairo_ps_surface_emit_body (cairo_ps_surface_t *surface)
{
@@ -863,7 +991,7 @@ _cairo_ps_surface_emit_footer (cairo_ps_surface_t *surface)
if (surface->eps) {
_cairo_output_stream_printf (surface->final_stream,
- "end restore\n");
+ "end\n");
}
_cairo_output_stream_printf (surface->final_stream,
@@ -882,11 +1010,11 @@ _path_covers_bbox (cairo_ps_surface_t *surface,
_cairo_box_round_to_rectangle (&box, &rect);
/* skip trivial whole-page clips */
- if (_cairo_rectangle_intersect (&rect, &surface->page_bbox)) {
- if (rect.x == surface->page_bbox.x &&
- rect.width == surface->page_bbox.width &&
- rect.y == surface->page_bbox.y &&
- rect.height == surface->page_bbox.height)
+ if (_cairo_rectangle_intersect (&rect, &surface->surface_extents)) {
+ if (rect.x == surface->surface_extents.x &&
+ rect.width == surface->surface_extents.width &&
+ rect.y == surface->surface_extents.y &&
+ rect.height == surface->surface_extents.height)
{
return TRUE;
}
@@ -975,7 +1103,7 @@ _cairo_ps_surface_get_page_media (cairo_ps_surface_t *surface)
}
}
- page = malloc (sizeof (cairo_page_media_t));
+ page = _cairo_malloc (sizeof (cairo_page_media_t));
if (unlikely (page == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL;
@@ -1011,7 +1139,7 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
cairo_status_t status, status_ignored;
cairo_ps_surface_t *surface;
- surface = malloc (sizeof (cairo_ps_surface_t));
+ surface = _cairo_malloc (sizeof (cairo_ps_surface_t));
if (unlikely (surface == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP;
@@ -1020,7 +1148,8 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
_cairo_surface_init (&surface->base,
&cairo_ps_surface_backend,
NULL, /* device */
- CAIRO_CONTENT_COLOR_ALPHA);
+ CAIRO_CONTENT_COLOR_ALPHA,
+ TRUE); /* is_vector */
surface->final_stream = stream;
@@ -1055,17 +1184,23 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
surface->ps_level_used = CAIRO_PS_LEVEL_2;
surface->width = width;
surface->height = height;
- cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, height);
+ cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, 1, 0, 0);
+ surface->surface_extents.x = 0;
+ surface->surface_extents.y = 0;
+ surface->surface_extents.width = ceil (surface->width);
+ surface->surface_extents.height = ceil (surface->height);
+ surface->surface_bounded = TRUE;
surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
surface->force_fallbacks = FALSE;
surface->content = CAIRO_CONTENT_COLOR_ALPHA;
- surface->use_string_datasource = FALSE;
surface->current_pattern_is_solid_color = FALSE;
-
- surface->page_bbox.x = 0;
- surface->page_bbox.y = 0;
- surface->page_bbox.width = width;
- surface->page_bbox.height = height;
+ surface->document_bbox_p1.x = 0;
+ surface->document_bbox_p1.y = 0;
+ surface->document_bbox_p2.x = 0;
+ surface->document_bbox_p2.y = 0;
+ surface->total_form_size = 0;
+ surface->contains_eps = FALSE;
+ surface->paint_proc = FALSE;
_cairo_surface_clipper_init (&surface->clipper,
_cairo_ps_surface_clipper_intersect_clip_path);
@@ -1081,6 +1216,14 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
_cairo_array_init (&surface->dsc_header_comments, sizeof (char *));
_cairo_array_init (&surface->dsc_setup_comments, sizeof (char *));
_cairo_array_init (&surface->dsc_page_setup_comments, sizeof (char *));
+ _cairo_array_init (&surface->recording_surf_stack, sizeof (unsigned int));
+
+ surface->num_forms = 0;
+ surface->forms = _cairo_hash_table_create (_cairo_ps_form_equal);
+ if (unlikely (surface->forms == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto CLEANUP_FONT_SUBSETS;
+ }
surface->dsc_comment_target = &surface->dsc_header_comments;
@@ -1095,6 +1238,7 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
return surface->paginated_surface;
}
+ CLEANUP_FONT_SUBSETS:
_cairo_scaled_font_subsets_destroy (surface->font_subsets);
CLEANUP_OUTPUT_STREAM:
status_ignored = _cairo_output_stream_destroy (surface->stream);
@@ -1403,7 +1547,11 @@ cairo_ps_surface_set_size (cairo_surface_t *surface,
ps_surface->width = width_in_points;
ps_surface->height = height_in_points;
- cairo_matrix_init (&ps_surface->cairo_to_ps, 1, 0, 0, -1, 0, height_in_points);
+ cairo_matrix_init (&ps_surface->cairo_to_ps, 1, 0, 0, 1, 0, 0);
+ ps_surface->surface_extents.x = 0;
+ ps_surface->surface_extents.y = 0;
+ ps_surface->surface_extents.width = ceil (ps_surface->width);
+ ps_surface->surface_extents.height = ceil (ps_surface->height);
_cairo_pdf_operators_set_cairo_to_pdf_matrix (&ps_surface->pdf_operators,
&ps_surface->cairo_to_ps);
status = _cairo_paginated_surface_set_size (ps_surface->paginated_surface,
@@ -1613,10 +1761,17 @@ _cairo_ps_surface_finish (void *abstract_surface)
_cairo_ps_surface_emit_header (surface);
+ _cairo_output_stream_printf (surface->final_stream,
+ "%%%%BeginSetup\n");
+
status = _cairo_ps_surface_emit_font_subsets (surface);
if (unlikely (status))
goto CLEANUP;
+ status = _cairo_ps_surface_emit_forms (surface);
+ if (unlikely (status))
+ goto CLEANUP;
+
_cairo_output_stream_printf (surface->final_stream,
"%%%%EndSetup\n");
@@ -1627,6 +1782,10 @@ _cairo_ps_surface_finish (void *abstract_surface)
_cairo_ps_surface_emit_footer (surface);
CLEANUP:
+ _cairo_hash_table_foreach (surface->forms,
+ _cairo_ps_form_pluck,
+ surface->forms);
+ _cairo_hash_table_destroy (surface->forms);
_cairo_scaled_font_subsets_destroy (surface->font_subsets);
status2 = _cairo_output_stream_destroy (surface->stream);
@@ -1668,6 +1827,8 @@ CLEANUP:
free (comments[i]);
_cairo_array_fini (&surface->dsc_page_setup_comments);
+ _cairo_array_fini (&surface->recording_surf_stack);
+
_cairo_surface_clipper_reset (&surface->clipper);
return status;
@@ -1715,133 +1876,97 @@ color_is_gray (double red, double green, double blue)
/**
* _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
+ * @surface: [in] the ps surface
+ * @pattern: [in] A #cairo_pattern_t of type SURFACE or RASTER_SOURCE to use
+ * as the source
+ * @extents: [in] extents of the operation that is using this source
+ * @src_surface_extents: [out] return source surface extents
+ * @src_surface_bounded: [out] return TRUE if source surface is bounded
+ * @src_op_extents: [out] return operation extents in source space
+ * @source_surface: [out] returns surface of type image surface or recording surface
+ * @x_offset: [out] return x offset of surface
+ * @y_offset: [out] return y offset of surface
*
* Acquire source 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_ps_surface_acquire_source_surface_from_pattern (
+ cairo_ps_surface_t *surface,
+ const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents,
+ cairo_rectangle_int_t *src_surface_extents,
+ cairo_bool_t *src_surface_bounded,
+ cairo_rectangle_int_t *src_op_extents,
+ cairo_surface_t **source_surface,
+ double *x_offset,
+ double *y_offset)
{
- cairo_status_t status;
- cairo_image_surface_t *image;
+ cairo_status_t status;
+ cairo_box_t bbox;
- *x_offset = *y_offset = 0;
- switch (pattern->type) {
- case CAIRO_PATTERN_TYPE_SURFACE: {
- cairo_surface_t *surf = ((cairo_surface_pattern_t *) pattern)->surface;
+ *x_offset = 0;
+ *y_offset = 0;
+
+ /* get the operation extents in pattern space */
+ _cairo_box_from_rectangle (&bbox, extents);
+ _cairo_matrix_transform_bounding_box_fixed (&pattern->matrix, &bbox, NULL);
+ _cairo_box_round_to_rectangle (&bbox, src_op_extents);
+
+ if (pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) {
+ cairo_surface_t *surf;
+
+ surf = _cairo_raster_source_pattern_acquire (pattern, &surface->base, src_op_extents);
+ if (!surf)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ *src_surface_bounded = _cairo_surface_get_extents (surf, src_surface_extents);
+ cairo_surface_get_device_offset (surf, x_offset, y_offset);
+ *source_surface = surf;
+ } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_surface_t *surf = NULL;
+
+ *source_surface = ((cairo_surface_pattern_t *) pattern)->surface;
+ surf = *source_surface;
+ *src_surface_bounded = _cairo_surface_get_extents (surf, src_surface_extents);
if (surf->type == CAIRO_SURFACE_TYPE_RECORDING) {
+ if (_cairo_surface_is_snapshot (surf))
+ surf = _cairo_surface_snapshot_get_target (surf);
+
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_surface_t *free_me = NULL;
- 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)) {
- free_me = _cairo_surface_snapshot_get_target (&recording_surface->base);
- recording_surface = (cairo_recording_surface_t *) free_me;
- }
-
- status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL);
- cairo_surface_destroy (free_me);
- if (unlikely (status))
- return status;
-
- _cairo_box_round_to_rectangle (&bbox, &extents);
- *width = extents.width;
- *height = extents.height;
+ *src_surface_extents = sub->extents;
+ *src_surface_bounded = TRUE;
+ *x_offset = -sub->extents.x;
+ *y_offset = -sub->extents.y;
}
- *source_surface = surf;
- return CAIRO_STATUS_SUCCESS;
- } else {
- status = _cairo_surface_acquire_source_image (surf, &image, image_extra);
+ cairo_surface_destroy (surf);
+ } else if (surf->type != CAIRO_SURFACE_TYPE_IMAGE) {
+ cairo_image_surface_t *image;
+ void *image_extra;
+
+ 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_is_image (surf));
- 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:
+ *src_surface_bounded = _cairo_surface_get_extents (&image->base, src_surface_extents);
+ _cairo_surface_release_source_image (surf, image, image_extra);
+ }
+ } else {
ASSERT_NOT_REACHED;
- break;
}
- *width = image->width;
- *height = image->height;
- *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)
+ cairo_surface_t *source_surface)
{
- 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;
- }
+ if (pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE)
+ _cairo_raster_source_pattern_release (pattern, source_surface);
}
/**
@@ -1849,11 +1974,8 @@ _cairo_ps_surface_release_source_surface_from_pattern (cairo_ps_surface_t
* @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 or NULL if padding not required to fill @extents
+ * @image_extents: returns extents of padded image. These extents in are in source image space.
*
* Creates a padded image if the source image does not fill the extents.
**/
@@ -1862,11 +1984,8 @@ _cairo_ps_surface_create_padded_image_from_image (cairo_ps_surface_t *
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_image_surface_t **image,
+ cairo_rectangle_int_t *image_extents)
{
cairo_box_t box;
cairo_rectangle_int_t rect;
@@ -1888,11 +2007,9 @@ _cairo_ps_surface_create_padded_image_from_image (cairo_ps_surface_t *
_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);
+ pad_image = _cairo_image_surface_create_with_content (source->base.content,
+ rect.width,
+ rect.height);
if (pad_image->status)
return pad_image->status;
@@ -1905,10 +2022,10 @@ _cairo_ps_surface_create_padded_image_from_image (cairo_ps_surface_t *
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;
+ image_extents->x = rect.x;
+ image_extents->y = rect.y;
+ image_extents->width = rect.width;
+ image_extents->height = rect.height;
} else {
*image = NULL;
status = CAIRO_STATUS_SUCCESS;
@@ -1922,27 +2039,32 @@ _cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t
const cairo_pattern_t *pattern,
const cairo_rectangle_int_t *extents)
{
- int width, height;
+ cairo_rectangle_int_t src_surface_extents;
+ cairo_bool_t src_surface_bounded;
+ cairo_rectangle_int_t src_op_extents;
+ cairo_surface_t *source_surface;
double x_offset, y_offset;
- cairo_surface_t *source;
cairo_image_surface_t *image;
void *image_extra;
- cairo_int_status_t status;
+ cairo_int_status_t status;
cairo_image_transparency_t transparency;
status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface,
pattern,
extents,
- &width,
- &height,
+ &src_surface_extents,
+ &src_surface_bounded,
+ &src_op_extents,
+ &source_surface,
&x_offset,
- &y_offset,
- &source,
- &image_extra);
+ &y_offset);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_surface_acquire_source_image (source_surface, &image, &image_extra);
if (unlikely (status))
return status;
- image = (cairo_image_surface_t *) source;
if (image->base.status)
return image->base.status;
@@ -1969,7 +2091,8 @@ _cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t
ASSERT_NOT_REACHED;
}
- _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source, image_extra);
+ _cairo_surface_release_source_image (source_surface, image, image_extra);
+ _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source_surface);
return status;
}
@@ -2156,14 +2279,9 @@ _cairo_ps_surface_operation_supported (cairo_ps_surface_t *surface,
/* The "standard" implementation limit for PostScript string sizes is
* 65535 characters (see PostScript Language Reference, Appendix
- * B). We go one short of that because we sometimes need two
- * characters in a string to represent a single ASCII85 byte, (for the
- * escape sequences "\\", "\(", and "\)") and we must not split these
- * across two strings. So we'd be in trouble if we went right to the
- * limit and one of these escape sequences just happened to land at
- * the end.
+ * B).
*/
-#define STRING_ARRAY_MAX_STRING_SIZE (65535-1)
+#define STRING_ARRAY_MAX_STRING_SIZE 65535
#define STRING_ARRAY_MAX_COLUMN 72
typedef struct _string_array_stream {
@@ -2171,64 +2289,62 @@ typedef struct _string_array_stream {
cairo_output_stream_t *output;
int column;
int string_size;
+ int tuple_count;
cairo_bool_t use_strings;
} string_array_stream_t;
static cairo_status_t
-_string_array_stream_write (cairo_output_stream_t *base,
- const unsigned char *data,
- unsigned int length)
+_base85_string_wrap_stream_write (cairo_output_stream_t *base,
+ const unsigned char *data,
+ unsigned int length)
{
string_array_stream_t *stream = (string_array_stream_t *) base;
unsigned char c;
- const unsigned char backslash = '\\';
if (length == 0)
return CAIRO_STATUS_SUCCESS;
while (length--) {
- if (stream->string_size == 0 && stream->use_strings) {
- _cairo_output_stream_printf (stream->output, "(");
- stream->column++;
- }
-
- c = *data++;
- if (stream->use_strings) {
- switch (c) {
- case '\\':
- case '(':
- case ')':
- _cairo_output_stream_write (stream->output, &backslash, 1);
- stream->column++;
- stream->string_size++;
- break;
+ if (stream->column == 0) {
+ if (stream->use_strings) {
+ _cairo_output_stream_printf (stream->output, "<~");
+ stream->column = 2;
+ } else {
+ _cairo_output_stream_printf (stream->output, " ");
+ stream->column = 1;
}
}
- /* Have to be careful to never split the final ~> sequence. */
- if (c == '~') {
- _cairo_output_stream_write (stream->output, &c, 1);
- stream->column++;
- stream->string_size++;
-
- if (length-- == 0)
- break;
- c = *data++;
- }
+ c = *data++;
_cairo_output_stream_write (stream->output, &c, 1);
stream->column++;
- stream->string_size++;
+ /* Base85 encodes each 4 byte tuple with a 5 ASCII character
+ * tuple, except for 'z' with represents 4 zero bytes. We need
+ * to keep track of the string length after decoding.
+ */
+ if (c == 'z') {
+ stream->string_size += 4;
+ stream->tuple_count = 0;
+ } else {
+ if (++stream->tuple_count == 5) {
+ stream->string_size += 4;
+ stream->tuple_count = 0;
+ }
+ }
+
+ /* Split string at tuple boundary when there is not enough
+ * space for another tuple */
if (stream->use_strings &&
- stream->string_size >= STRING_ARRAY_MAX_STRING_SIZE)
+ stream->tuple_count == 0 &&
+ stream->string_size > STRING_ARRAY_MAX_STRING_SIZE - 4)
{
- _cairo_output_stream_printf (stream->output, ")\n");
+ _cairo_output_stream_printf (stream->output, "~>\n");
stream->string_size = 0;
stream->column = 0;
}
if (stream->column >= STRING_ARRAY_MAX_COLUMN) {
_cairo_output_stream_printf (stream->output, "\n ");
- stream->string_size += 2;
stream->column = 1;
}
}
@@ -2237,78 +2353,75 @@ _string_array_stream_write (cairo_output_stream_t *base,
}
static cairo_status_t
-_string_array_stream_close (cairo_output_stream_t *base)
+_base85_string_wrap_stream_close (cairo_output_stream_t *base)
{
- cairo_status_t status;
string_array_stream_t *stream = (string_array_stream_t *) base;
- if (stream->use_strings)
- _cairo_output_stream_printf (stream->output, ")\n");
-
- status = _cairo_output_stream_get_status (stream->output);
+ if (!stream->use_strings || stream->string_size != 0)
+ _cairo_output_stream_printf (stream->output, "~>");
- return status;
+ return _cairo_output_stream_get_status (stream->output);
}
-/* A string_array_stream wraps an existing output stream. It takes the
- * data provided to it and output one or more consecutive string
- * objects, each within the standard PostScript implementation limit
- * of 65k characters.
- *
- * The strings are each separated by a space character for easy
- * inclusion within an array object, (but the array delimiters are not
- * added by the string_array_stream).
- *
+/* A _base85_strings_stream wraps an existing output stream. It takes
+ * base85 encoded data and splits it into strings each limited to
+ * STRING_ARRAY_MAX_STRING_SIZE bytes when decoded. Each string is
+ * enclosed in "<~" and "~>".
+
* The string array stream is also careful to wrap the output within
- * STRING_ARRAY_MAX_COLUMN columns (+/- 1). The stream also adds
- * necessary escaping for special characters within a string,
- * (specifically '\', '(', and ')').
+ * STRING_ARRAY_MAX_COLUMN columns. Wrapped lines start with a space
+ * in case an encoded line starts with %% which could be interpreted
+ * as a DSC comment.
*/
static cairo_output_stream_t *
-_string_array_stream_create (cairo_output_stream_t *output)
+_base85_strings_stream_create (cairo_output_stream_t *output)
{
string_array_stream_t *stream;
- stream = malloc (sizeof (string_array_stream_t));
+ stream = _cairo_malloc (sizeof (string_array_stream_t));
if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base,
- _string_array_stream_write,
+ _base85_string_wrap_stream_write,
NULL,
- _string_array_stream_close);
+ _base85_string_wrap_stream_close);
stream->output = output;
stream->column = 0;
stream->string_size = 0;
+ stream->tuple_count = 0;
stream->use_strings = TRUE;
return &stream->base;
}
-/* A base85_array_stream wraps an existing output stream. It wraps the
- * output within STRING_ARRAY_MAX_COLUMN columns (+/- 1). The output
- * is not enclosed in strings like string_array_stream.
+/* A base85_wrap_stream wraps an existing output stream. It wraps the
+ * output within STRING_ARRAY_MAX_COLUMN columns. A base85 EOD "~>" is
+ * appended to the end. Wrapped lines start with a space in case an
+ * encoded line starts with %% which could be interpreted as a DSC
+ * comment.
*/
static cairo_output_stream_t *
-_base85_array_stream_create (cairo_output_stream_t *output)
+_base85_wrap_stream_create (cairo_output_stream_t *output)
{
string_array_stream_t *stream;
- stream = malloc (sizeof (string_array_stream_t));
+ stream = _cairo_malloc (sizeof (string_array_stream_t));
if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base,
- _string_array_stream_write,
+ _base85_string_wrap_stream_write,
NULL,
- _string_array_stream_close);
+ _base85_string_wrap_stream_close);
stream->output = output;
stream->column = 0;
stream->string_size = 0;
+ stream->tuple_count = 0;
stream->use_strings = FALSE;
return &stream->base;
@@ -2370,9 +2483,9 @@ _cairo_ps_surface_emit_base85_string (cairo_ps_surface_t *surface,
cairo_status_t status, status2;
if (use_strings)
- string_array_stream = _string_array_stream_create (surface->stream);
+ string_array_stream = _base85_strings_stream_create (surface->stream);
else
- string_array_stream = _base85_array_stream_create (surface->stream);
+ string_array_stream = _base85_wrap_stream_create (surface->stream);
status = _cairo_output_stream_get_status (string_array_stream);
if (unlikely (status))
@@ -2419,9 +2532,6 @@ _cairo_ps_surface_emit_base85_string (cairo_ps_surface_t *surface,
break;
}
status = _cairo_output_stream_destroy (base85_stream);
-
- /* Mark end of base85 data */
- _cairo_output_stream_printf (string_array_stream, "~>");
status2 = _cairo_output_stream_destroy (string_array_stream);
if (status == CAIRO_STATUS_SUCCESS)
status = status2;
@@ -2429,12 +2539,32 @@ _cairo_ps_surface_emit_base85_string (cairo_ps_surface_t *surface,
return status;
}
+static const char *
+get_interpolate (cairo_filter_t filter)
+{
+ const char *interpolate;
+
+ switch (filter) {
+ default:
+ case CAIRO_FILTER_GOOD:
+ case CAIRO_FILTER_BEST:
+ case CAIRO_FILTER_BILINEAR:
+ interpolate = "true";
+ break;
+ case CAIRO_FILTER_FAST:
+ case CAIRO_FILTER_NEAREST:
+ case CAIRO_FILTER_GAUSSIAN:
+ interpolate = "false";
+ break;
+ }
+
+ return interpolate;
+}
+
static cairo_status_t
-_cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
- cairo_image_surface_t *image_surf,
- cairo_operator_t op,
- cairo_filter_t filter,
- cairo_bool_t stencil_mask)
+_cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
+ cairo_emit_surface_mode_t mode,
+ cairo_emit_surface_params_t *params)
{
cairo_status_t status;
unsigned char *data;
@@ -2450,10 +2580,16 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
const char *interpolate;
cairo_ps_compress_t compress;
const char *compress_filter;
+ cairo_image_surface_t *image_surf;
cairo_image_surface_t *image;
+ void *image_extra;
+
+ if (params->src_surface->status)
+ return params->src_surface->status;
- if (image_surf->base.status)
- return image_surf->base.status;
+ status = _cairo_surface_acquire_source_image (params->src_surface, &image_surf, &image_extra);
+ if (unlikely (status))
+ return status;
image = image_surf;
if (image->format != CAIRO_FORMAT_RGB24 &&
@@ -2464,16 +2600,16 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
cairo_surface_t *surf;
cairo_surface_pattern_t pattern;
- surf = _cairo_image_surface_create_with_content (image_surf->base.content,
- image_surf->width,
- image_surf->height);
+ surf = _cairo_image_surface_create_with_content (image->base.content,
+ image->width,
+ image->height);
image = (cairo_image_surface_t *) surf;
if (surf->status) {
status = surf->status;
goto bail0;
}
- _cairo_pattern_init_for_surface (&pattern, &image_surf->base);
+ _cairo_pattern_init_for_surface (&pattern, &image->base);
status = _cairo_surface_paint (surf,
CAIRO_OPERATOR_SOURCE, &pattern.base,
NULL);
@@ -2482,22 +2618,9 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
goto bail0;
}
ps_image = image;
+ interpolate = get_interpolate (params->filter);
- switch (filter) {
- default:
- case CAIRO_FILTER_GOOD:
- case CAIRO_FILTER_BEST:
- case CAIRO_FILTER_BILINEAR:
- interpolate = "true";
- break;
- case CAIRO_FILTER_FAST:
- case CAIRO_FILTER_NEAREST:
- case CAIRO_FILTER_GAUSSIAN:
- interpolate = "false";
- break;
- }
-
- if (stencil_mask) {
+ if (params->stencil_mask) {
use_mask = FALSE;
color = CAIRO_IMAGE_IS_MONOCHROME;
transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
@@ -2508,7 +2631,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
current image over a white (or black for CONTENT_COLOR
surfaces) RGB surface to eliminate it. */
- if (op == CAIRO_OPERATOR_SOURCE ||
+ if (params->op == CAIRO_OPERATOR_SOURCE ||
transparency == CAIRO_IMAGE_HAS_ALPHA ||
(transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA &&
surface->ps_level == CAIRO_PS_LEVEL_2))
@@ -2550,7 +2673,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
if (use_mask)
data_size += (ps_image->width + 7)/8;
data_size *= ps_image->height;
- data = malloc (data_size);
+ data = _cairo_malloc (data_size);
if (unlikely (data == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto bail1;
@@ -2558,7 +2681,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
i = 0;
for (y = 0; y < ps_image->height; y++) {
- if (stencil_mask || use_mask) {
+ if (params->stencil_mask || use_mask) {
/* mask row */
if (ps_image->format == CAIRO_FORMAT_A1) {
pixel8 = (uint8_t *) (ps_image->data + y * ps_image->stride);
@@ -2599,7 +2722,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
i++;
}
}
- if (stencil_mask)
+ if (params->stencil_mask)
continue;
/* image row*/
@@ -2664,11 +2787,11 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
surface->ps_level_used = CAIRO_PS_LEVEL_3;
}
- if (surface->use_string_datasource) {
+ if (surface->paint_proc) {
/* Emit the image data as a base85-encoded string which will
* be used as the data source for the image operator later. */
_cairo_output_stream_printf (surface->stream,
- "/CairoImageData [\n");
+ "/CairoData [\n");
status = _cairo_ps_surface_emit_base85_string (surface,
data,
@@ -2681,7 +2804,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
_cairo_output_stream_printf (surface->stream,
"] def\n");
_cairo_output_stream_printf (surface->stream,
- "/CairoImageDataIndex 0 def\n");
+ "/CairoDataIndex 0 def\n");
} else {
_cairo_output_stream_printf (surface->stream,
"/cairo_ascii85_file currentfile /ASCII85Decode filter def\n");
@@ -2690,17 +2813,16 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
if (use_mask) {
_cairo_output_stream_printf (surface->stream,
"%s setcolorspace\n"
- "5 dict dup begin\n"
- " /ImageType 3 def\n"
- " /InterleaveType 2 def\n"
- " /DataDict 8 dict def\n"
- " DataDict begin\n"
- " /ImageType 1 def\n"
- " /Width %d def\n"
- " /Height %d def\n"
- " /Interpolate %s def\n"
- " /BitsPerComponent %d def\n"
- " /Decode [ %s ] def\n",
+ "<<\n"
+ " /ImageType 3\n"
+ " /InterleaveType 2\n"
+ " /DataDict <<\n"
+ " /ImageType 1\n"
+ " /Width %d\n"
+ " /Height %d\n"
+ " /Interpolate %s\n"
+ " /BitsPerComponent %d\n"
+ " /Decode [ %s ]\n",
color == CAIRO_IMAGE_IS_COLOR ? "/DeviceRGB" : "/DeviceGray",
ps_image->width,
ps_image->height,
@@ -2708,85 +2830,89 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
color == CAIRO_IMAGE_IS_MONOCHROME ? 1 : 8,
color == CAIRO_IMAGE_IS_COLOR ? "0 1 0 1 0 1" : "0 1");
- if (surface->use_string_datasource) {
+ if (surface->paint_proc) {
_cairo_output_stream_printf (surface->stream,
- " /DataSource {\n"
- " CairoImageData CairoImageDataIndex get\n"
- " /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
- " CairoImageDataIndex CairoImageData length 1 sub gt\n"
- " { /CairoImageDataIndex 0 def } if\n"
- " } /ASCII85Decode filter /%s filter def\n",
+ " /DataSource { cairo_data_source } /%s filter\n",
compress_filter);
} else {
_cairo_output_stream_printf (surface->stream,
- " /DataSource cairo_ascii85_file /%s filter def\n",
+ " /DataSource cairo_ascii85_file /%s filter\n",
compress_filter);
}
_cairo_output_stream_printf (surface->stream,
- " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
- " end\n"
- " /MaskDict 8 dict def\n"
- " MaskDict begin\n"
- " /ImageType 1 def\n"
- " /Width %d def\n"
- " /Height %d def\n"
- " /Interpolate %s def\n"
- " /BitsPerComponent 1 def\n"
- " /Decode [ 1 0 ] def\n"
- " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
- " end\n"
- "end\n"
+ " /ImageMatrix [ %d 0 0 %d 0 %d ]\n"
+ " >>\n"
+ " /MaskDict <<\n"
+ " /ImageType 1\n"
+ " /Width %d\n"
+ " /Height %d\n"
+ " /Interpolate %s\n"
+ " /BitsPerComponent 1\n"
+ " /Decode [ 1 0 ]\n"
+ " /ImageMatrix [ %d 0 0 %d 0 %d ]\n"
+ " >>\n"
+ ">>\n"
"image\n",
+ ps_image->width,
+ -ps_image->height,
ps_image->height,
ps_image->width,
ps_image->height,
interpolate,
+ ps_image->width,
+ -ps_image->height,
ps_image->height);
} else {
- if (!stencil_mask) {
+ const char *decode;
+
+ if (!params->stencil_mask) {
_cairo_output_stream_printf (surface->stream,
"%s setcolorspace\n",
color == CAIRO_IMAGE_IS_COLOR ? "/DeviceRGB" : "/DeviceGray");
}
+ if (params->stencil_mask)
+ decode = "1 0";
+ else if (color == CAIRO_IMAGE_IS_COLOR)
+ decode = "0 1 0 1 0 1";
+ else
+ decode ="0 1";
+
_cairo_output_stream_printf (surface->stream,
- "8 dict dup begin\n"
- " /ImageType 1 def\n"
- " /Width %d def\n"
- " /Height %d def\n"
- " /Interpolate %s def\n"
- " /BitsPerComponent %d def\n"
- " /Decode [ %s ] def\n",
+ "<<\n"
+ " /ImageType 1\n"
+ " /Width %d\n"
+ " /Height %d\n"
+ " /Interpolate %s\n"
+ " /BitsPerComponent %d\n"
+ " /Decode [ %s ]\n",
ps_image->width,
ps_image->height,
interpolate,
color == CAIRO_IMAGE_IS_MONOCHROME ? 1 : 8,
- stencil_mask ? "1 0" : color == CAIRO_IMAGE_IS_COLOR ? "0 1 0 1 0 1" : "0 1");
- if (surface->use_string_datasource) {
+ decode);
+ if (surface->paint_proc) {
_cairo_output_stream_printf (surface->stream,
- " /DataSource {\n"
- " CairoImageData CairoImageDataIndex get\n"
- " /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
- " CairoImageDataIndex CairoImageData length 1 sub gt\n"
- " { /CairoImageDataIndex 0 def } if\n"
- " } /ASCII85Decode filter /%s filter def\n",
+ " /DataSource { cairo_data_source } /%s filter\n",
compress_filter);
} else {
_cairo_output_stream_printf (surface->stream,
- " /DataSource cairo_ascii85_file /%s filter def\n",
+ " /DataSource cairo_ascii85_file /%s filter\n",
compress_filter);
}
_cairo_output_stream_printf (surface->stream,
- " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
- "end\n"
+ " /ImageMatrix [ %d 0 0 %d 0 %d ]\n"
+ ">>\n"
"%s%s\n",
+ ps_image->width,
+ -ps_image->height,
ps_image->height,
- surface->use_string_datasource ? "" : "cairo_",
- stencil_mask ? "imagemask" : "image");
+ surface->paint_proc ? "" : "cairo_",
+ params->stencil_mask ? "imagemask" : "image");
}
- if (!surface->use_string_datasource) {
+ if (!surface->paint_proc) {
/* Emit the image data as a base85-encoded string which will
* be used as the data source for the image operator. */
status = _cairo_ps_surface_emit_base85_string (surface,
@@ -2810,14 +2936,15 @@ bail0:
if (image != image_surf)
cairo_surface_destroy (&image->base);
+ _cairo_surface_release_source_image (params->src_surface, image_surf, image_extra);
+
return status;
}
-static cairo_status_t
-_cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t *surface,
- cairo_surface_t *source,
- int width,
- int height)
+static cairo_int_status_t
+_cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t *surface,
+ cairo_emit_surface_mode_t mode,
+ cairo_emit_surface_params_t *params)
{
cairo_status_t status;
const unsigned char *mime_data;
@@ -2826,10 +2953,11 @@ _cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t *surface,
const char *colorspace;
const char *decode;
- cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
+ if (unlikely (params->src_surface->status))
+ return params->src_surface->status;
+
+ cairo_surface_get_mime_data (params->src_surface, CAIRO_MIME_TYPE_JPEG,
&mime_data, &mime_data_length);
- if (unlikely (source->status))
- return source->status;
if (mime_data == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -2854,11 +2982,18 @@ _cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t *surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
- if (surface->use_string_datasource) {
+ /* At this point we know emitting jpeg will succeed. */
+ if (mode == CAIRO_EMIT_SURFACE_ANALYZE) {
+ params->is_image = TRUE;
+ params->approx_size = mime_data_length;
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (surface->paint_proc) {
/* Emit the image data as a base85-encoded string which will
* be used as the data source for the image operator later. */
_cairo_output_stream_printf (surface->stream,
- "/CairoImageData [\n");
+ "/CairoData [\n");
status = _cairo_ps_surface_emit_base85_string (surface,
mime_data,
@@ -2871,7 +3006,7 @@ _cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t *surface,
_cairo_output_stream_printf (surface->stream,
"] def\n");
_cairo_output_stream_printf (surface->stream,
- "/CairoImageDataIndex 0 def\n");
+ "/CairoDataIndex 0 def\n");
} else {
_cairo_output_stream_printf (surface->stream,
"/cairo_ascii85_file currentfile /ASCII85Decode filter def\n");
@@ -2879,39 +3014,38 @@ _cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t *surface,
_cairo_output_stream_printf (surface->stream,
"%s setcolorspace\n"
- "8 dict dup begin\n"
- " /ImageType 1 def\n"
- " /Width %d def\n"
- " /Height %d def\n"
- " /BitsPerComponent %d def\n"
- " /Decode [ %s ] def\n",
+ "<<\n"
+ " /ImageType 1\n"
+ " /Width %d\n"
+ " /Height %d\n"
+ " /BitsPerComponent %d\n"
+ " /Interpolate %s\n"
+ " /Decode [ %s ]\n",
colorspace,
info.width,
info.height,
info.bits_per_component,
+ get_interpolate (params->filter),
decode);
- if (surface->use_string_datasource) {
+ if (surface->paint_proc) {
_cairo_output_stream_printf (surface->stream,
- " /DataSource {\n"
- " CairoImageData CairoImageDataIndex get\n"
- " /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
- " CairoImageDataIndex CairoImageData length 1 sub gt\n"
- " { /CairoImageDataIndex 0 def } if\n"
- " } /ASCII85Decode filter /DCTDecode filter def\n");
+ " /DataSource { cairo_data_source } /DCTDecode filter\n");
} else {
_cairo_output_stream_printf (surface->stream,
- " /DataSource cairo_ascii85_file /DCTDecode filter def\n");
+ " /DataSource cairo_ascii85_file /DCTDecode filter\n");
}
_cairo_output_stream_printf (surface->stream,
- " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
- "end\n"
+ " /ImageMatrix [ %d 0 0 %d 0 %d ]\n"
+ ">>\n"
"%simage\n",
+ info.width,
+ -info.height,
info.height,
- surface->use_string_datasource ? "" : "cairo_");
+ surface->paint_proc ? "" : "cairo_");
- if (!surface->use_string_datasource) {
+ if (!surface->paint_proc) {
/* Emit the image data as a base85-encoded string which will
* be used as the data source for the image operator. */
status = _cairo_ps_surface_emit_base85_string (surface,
@@ -2924,117 +3058,309 @@ _cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t *surface,
return status;
}
-static cairo_status_t
-_cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t *surface,
- cairo_surface_t *recording_surface)
+static cairo_int_status_t
+_cairo_ps_surface_emit_ccitt_image (cairo_ps_surface_t *surface,
+ cairo_emit_surface_mode_t mode,
+ cairo_emit_surface_params_t *params)
{
- double old_width, old_height;
- cairo_matrix_t old_cairo_to_ps;
- cairo_content_t old_content;
- cairo_rectangle_int_t old_page_bbox;
- cairo_surface_t *free_me = NULL;
- cairo_surface_clipper_t old_clipper;
- cairo_box_t bbox;
- cairo_int_status_t status;
+ cairo_status_t status;
+ const unsigned char *ccitt_data;
+ unsigned long ccitt_data_len;
+ const unsigned char *ccitt_params_data;
+ unsigned long ccitt_params_data_len;
+ char *ccitt_params_string;
+ cairo_ccitt_params_t ccitt_params;
+
+ if (unlikely (params->src_surface->status))
+ return params->src_surface->status;
+
+ cairo_surface_get_mime_data (params->src_surface, CAIRO_MIME_TYPE_CCITT_FAX,
+ &ccitt_data, &ccitt_data_len);
+ if (ccitt_data == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
- old_content = surface->content;
- old_width = surface->width;
- old_height = surface->height;
- old_page_bbox = surface->page_bbox;
- old_cairo_to_ps = surface->cairo_to_ps;
- old_clipper = surface->clipper;
- _cairo_surface_clipper_init (&surface->clipper,
- _cairo_ps_surface_clipper_intersect_clip_path);
+ cairo_surface_get_mime_data (params->src_surface, CAIRO_MIME_TYPE_CCITT_FAX_PARAMS,
+ &ccitt_params_data, &ccitt_params_data_len);
+ if (ccitt_params_data == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
- if (_cairo_surface_is_snapshot (recording_surface))
- free_me = recording_surface = _cairo_surface_snapshot_get_target (recording_surface);
+ /* ensure params_string is null terminated */
+ ccitt_params_string = malloc (ccitt_params_data_len + 1);
+ memcpy (ccitt_params_string, ccitt_params_data, ccitt_params_data_len);
+ ccitt_params_string[ccitt_params_data_len] = 0;
+ status = _cairo_tag_parse_ccitt_params (ccitt_params_string, &ccitt_params);
+ if (unlikely(status))
+ return status;
- status =
- _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface,
- &bbox,
- NULL);
- if (unlikely (status))
- goto err;
+ free (ccitt_params_string);
-#if DEBUG_PS
- _cairo_output_stream_printf (surface->stream,
- "%% _cairo_ps_surface_emit_recording_surface (%f, %f), (%f, %f)\n",
- _cairo_fixed_to_double (bbox.p1.x),
- _cairo_fixed_to_double (bbox.p1.y),
- _cairo_fixed_to_double (bbox.p2.x),
- _cairo_fixed_to_double (bbox.p2.y));
-#endif
+ if (ccitt_params.columns <= 0 || ccitt_params.rows <= 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
- surface->width = _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x);
- surface->height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y);
- _cairo_box_round_to_rectangle (&bbox, &surface->page_bbox);
+ /* At this point we know emitting ccitt will succeed. */
+ if (mode == CAIRO_EMIT_SURFACE_ANALYZE) {
+ params->is_image = TRUE;
+ params->approx_size = ccitt_data_len;
+ return CAIRO_STATUS_SUCCESS;
+ }
- surface->current_pattern_is_solid_color = FALSE;
- _cairo_pdf_operators_reset (&surface->pdf_operators);
- cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height);
- _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
- &surface->cairo_to_ps);
- _cairo_output_stream_printf (surface->stream, " q\n");
+ if (surface->paint_proc) {
+ /* Emit the image data as a base85-encoded string which will
+ * be used as the data source for the image operator later. */
+ _cairo_output_stream_printf (surface->stream,
+ "/CairoData [\n");
+
+ status = _cairo_ps_surface_emit_base85_string (surface,
+ ccitt_data,
+ ccitt_data_len,
+ CAIRO_PS_COMPRESS_NONE,
+ TRUE);
+ if (unlikely (status))
+ return status;
- if (recording_surface->content == CAIRO_CONTENT_COLOR) {
- surface->content = CAIRO_CONTENT_COLOR;
_cairo_output_stream_printf (surface->stream,
- " 0 g %d %d %d %d rectfill\n",
- surface->page_bbox.x,
- surface->page_bbox.y,
- surface->page_bbox.width,
- surface->page_bbox.height);
+ "] def\n");
+ _cairo_output_stream_printf (surface->stream,
+ "/CairoDataIndex 0 def\n");
+ } else {
+ _cairo_output_stream_printf (surface->stream,
+ "/cairo_ascii85_file currentfile /ASCII85Decode filter def\n");
}
- status = _cairo_recording_surface_replay_region (recording_surface,
- NULL,
- &surface->base,
- CAIRO_RECORDING_REGION_NATIVE);
- assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
- if (unlikely (status))
- goto err;
+ if (!params->stencil_mask) {
+ _cairo_output_stream_printf (surface->stream,
+ "/DeviceGray setcolorspace\n");
+ }
- status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (unlikely (status))
- goto err;
+ _cairo_output_stream_printf (surface->stream,
+ "<<\n"
+ " /ImageType 1\n"
+ " /Width %d\n"
+ " /Height %d\n"
+ " /BitsPerComponent 1\n"
+ " /Interpolate %s\n"
+ " /Decode [ 0 1 ]\n",
+ ccitt_params.columns,
+ ccitt_params.rows,
+ get_interpolate (params->filter));
+
+ if (surface->paint_proc) {
+ _cairo_output_stream_printf (surface->stream,
+ " /DataSource { cairo_data_source }\n");
+ } else {
+ _cairo_output_stream_printf (surface->stream,
+ " /DataSource cairo_ascii85_file\n");
+ }
- _cairo_output_stream_printf (surface->stream, " Q\n");
+ _cairo_output_stream_printf (surface->stream,
+ " << /Columns %d /Rows %d /K %d\n",
+ ccitt_params.columns,
+ ccitt_params.rows,
+ ccitt_params.k);
- _cairo_surface_clipper_reset (&surface->clipper);
- surface->clipper = old_clipper;
- surface->content = old_content;
- surface->width = old_width;
- surface->height = old_height;
- surface->page_bbox = old_page_bbox;
- surface->current_pattern_is_solid_color = FALSE;
- _cairo_pdf_operators_reset (&surface->pdf_operators);
- surface->cairo_to_ps = old_cairo_to_ps;
+ if (ccitt_params.end_of_line)
+ _cairo_output_stream_printf (surface->stream, " /EndOfLine true\n");
- _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
- &surface->cairo_to_ps);
+ if (ccitt_params.encoded_byte_align)
+ _cairo_output_stream_printf (surface->stream, " /EncodedByteAlign true\n");
+
+ if (!ccitt_params.end_of_block)
+ _cairo_output_stream_printf (surface->stream, " /EndOfBlock false\n");
+
+ if (ccitt_params.black_is_1)
+ _cairo_output_stream_printf (surface->stream, " /BlackIs1 true\n");
+
+ if (ccitt_params.damaged_rows_before_error > 0) {
+ _cairo_output_stream_printf (surface->stream,
+ " /DamagedRowsBeforeError %d\n",
+ ccitt_params.damaged_rows_before_error);
+ }
+
+ _cairo_output_stream_printf (surface->stream,
+ " >> /CCITTFaxDecode filter\n");
+
+ _cairo_output_stream_printf (surface->stream,
+ " /ImageMatrix [ %d 0 0 %d 0 %d ]\n"
+ ">>\n"
+ "%s%s\n",
+ ccitt_params.columns,
+ -ccitt_params.rows,
+ ccitt_params.rows,
+ surface->paint_proc ? "" : "cairo_",
+ params->stencil_mask ? "imagemask" : "image");
+
+ if (!surface->paint_proc) {
+ /* Emit the image data as a base85-encoded string which will
+ * be used as the data source for the image operator. */
+ status = _cairo_ps_surface_emit_base85_string (surface,
+ ccitt_data,
+ ccitt_data_len,
+ CAIRO_PS_COMPRESS_NONE,
+ FALSE);
+ }
-err:
- cairo_surface_destroy (free_me);
return status;
}
-static cairo_int_status_t
-_cairo_ps_surface_emit_recording_subsurface (cairo_ps_surface_t *surface,
- cairo_surface_t *recording_surface,
- const cairo_rectangle_int_t *extents)
+/* The '|' character is not used in PS (including ASCII85). We can
+ * speed up the search by first searching for the first char before
+ * comparing strings.
+ */
+#define SUBFILE_FILTER_EOD "|EOD|"
+
+/* Count number of non overlapping occurrences of SUBFILE_FILTER_EOD in data. */
+static int
+count_eod_strings (const unsigned char *data, unsigned long data_len)
+{
+ const unsigned char *p = data;
+ const unsigned char *end;
+ int first_char, len, count;
+ const char *eod_str = SUBFILE_FILTER_EOD;
+
+ first_char = eod_str[0];
+ len = strlen (eod_str);
+ p = data;
+ end = data + data_len - len + 1;
+ count = 0;
+ while (p < end) {
+ p = memchr (p, first_char, end - p);
+ if (!p)
+ break;
+
+ if (memcmp (p, eod_str, len) == 0) {
+ count++;
+ p += len;
+ }
+ }
+
+ return count;
+}
+
+static cairo_status_t
+_cairo_ps_surface_emit_eps (cairo_ps_surface_t *surface,
+ cairo_emit_surface_mode_t mode,
+ cairo_emit_surface_params_t *params)
+{
+ cairo_status_t status;
+ const unsigned char *eps_data = NULL;
+ unsigned long eps_data_len;
+ const unsigned char *eps_params_string = NULL;
+ unsigned long eps_params_string_len;
+ char *params_string = NULL;
+ cairo_eps_params_t eps_params;
+ cairo_matrix_t mat;
+ double eps_width, eps_height;
+
+ if (unlikely (params->src_surface->status))
+ return params->src_surface->status;
+
+ /* We only embed EPS with level 3 as we may use ReusableStreamDecode and we
+ * don't know what level the EPS file requires. */
+ if (surface->ps_level == CAIRO_PS_LEVEL_2)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ cairo_surface_get_mime_data (params->src_surface, CAIRO_MIME_TYPE_EPS,
+ &eps_data, &eps_data_len);
+ if (eps_data == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ cairo_surface_get_mime_data (params->src_surface, CAIRO_MIME_TYPE_EPS_PARAMS,
+ &eps_params_string, &eps_params_string_len);
+ if (eps_params_string == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* ensure params_string is null terminated */
+ params_string = malloc (eps_params_string_len + 1);
+ memcpy (params_string, eps_params_string, eps_params_string_len);
+ params_string[eps_params_string_len] = 0;
+ status = _cairo_tag_parse_eps_params (params_string, &eps_params);
+ if (unlikely(status))
+ return status;
+
+ /* At this point we know emitting EPS will succeed. */
+ if (mode == CAIRO_EMIT_SURFACE_ANALYZE) {
+ params->is_image = FALSE;
+ params->approx_size = eps_data_len;
+ surface->contains_eps = TRUE;
+
+ /* Find number of occurrences of SUBFILE_FILTER_EOD in the EPS data.
+ * We will need it before emitting the data if a ReusableStream is used.
+ */
+ params->eod_count = count_eod_strings (eps_data, eps_data_len);
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ surface->ps_level_used = CAIRO_PS_LEVEL_3;
+ _cairo_output_stream_printf (surface->stream, "cairo_eps_begin\n");
+
+ eps_width = eps_params.bbox.p2.x - eps_params.bbox.p1.x;
+ eps_height = eps_params.bbox.p2.y - eps_params.bbox.p1.y;
+ cairo_matrix_init_translate (&mat,
+ params->src_surface_extents->x,
+ params->src_surface_extents->y);
+ cairo_matrix_scale (&mat,
+ params->src_surface_extents->width/eps_width,
+ params->src_surface_extents->height/eps_height);
+ cairo_matrix_scale (&mat, 1, -1);
+ cairo_matrix_translate (&mat, -eps_params.bbox.p1.x, -eps_params.bbox.p2.y);
+
+ if (! _cairo_matrix_is_identity (&mat)) {
+ _cairo_output_stream_printf (surface->stream, "[ ");
+ _cairo_output_stream_print_matrix (surface->stream, &mat);
+ _cairo_output_stream_printf (surface->stream, " ] concat\n");
+ }
+
+ _cairo_output_stream_printf (surface->stream,
+ "%f %f %f %f rectclip\n",
+ eps_params.bbox.p1.x,
+ eps_params.bbox.p1.y,
+ eps_width,
+ eps_height);
+
+ _cairo_output_stream_write (surface->stream, eps_data, eps_data_len);
+ _cairo_output_stream_printf (surface->stream, "\ncairo_eps_end\n");
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t *surface,
+ cairo_surface_t *recording_surface,
+ const cairo_rectangle_int_t *recording_extents,
+ cairo_bool_t subsurface)
{
double old_width, old_height;
+ cairo_rectangle_int_t old_surface_extents;
+ cairo_bool_t old_surface_bounded;
cairo_matrix_t old_cairo_to_ps;
cairo_content_t old_content;
- cairo_rectangle_int_t old_page_bbox;
cairo_surface_clipper_t old_clipper;
- cairo_surface_t *free_me = NULL;
cairo_int_status_t status;
+ cairo_surface_t *free_me = NULL;
+ unsigned int id;
+ int i, recording_surf_stack_size;
+
+ /* Prevent infinite recursion if the recording_surface references a recording
+ * currently being emitted */
+ recording_surf_stack_size = _cairo_array_num_elements (&surface->recording_surf_stack);
+ for (i = 0; i < recording_surf_stack_size; i++) {
+ _cairo_array_copy_element (&surface->recording_surf_stack, i, &id);
+ if (id == recording_surface->unique_id)
+ return CAIRO_STATUS_SUCCESS;
+ }
+ id = recording_surface->unique_id;
+ status = _cairo_array_append (&surface->recording_surf_stack, &id);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_surface_is_snapshot (recording_surface))
+ free_me = recording_surface = _cairo_surface_snapshot_get_target (recording_surface);
old_content = surface->content;
old_width = surface->width;
old_height = surface->height;
- old_page_bbox = surface->page_bbox;
+ old_surface_extents = surface->surface_extents;
+ old_surface_bounded = surface->surface_bounded;
old_cairo_to_ps = surface->cairo_to_ps;
old_clipper = surface->clipper;
_cairo_surface_clipper_init (&surface->clipper,
@@ -3042,46 +3368,44 @@ _cairo_ps_surface_emit_recording_subsurface (cairo_ps_surface_t *surface,
#if DEBUG_PS
_cairo_output_stream_printf (surface->stream,
- "%% _cairo_ps_surface_emit_recording_subsurface (%d, %d), (%d, %d)\n",
- extents->x, extents->y,
- extents->width, extents->height);
+ "%% _cairo_ps_surface_emit_recording_surface"
+ " x: %d, y: %d, w: %d, h: %d subsurface: %d\n",
+ recording_extents->x, recording_extents->y,
+ recording_extents->width, recording_extents->height,
+ subsurface);
#endif
- surface->page_bbox.x = surface->page_bbox.y = 0;
- surface->page_bbox.width = surface->width = extents->width;
- surface->page_bbox.height = surface->height = extents->height;
-
+ surface->width = recording_extents->width;
+ surface->height = recording_extents->height;
+ surface->surface_extents = *recording_extents;
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
- cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height);
+ cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, 1, 0, 0);
_cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
&surface->cairo_to_ps);
_cairo_output_stream_printf (surface->stream, " q\n");
- if (_cairo_surface_is_snapshot (recording_surface))
- free_me = recording_surface = _cairo_surface_snapshot_get_target (recording_surface);
-
if (recording_surface->content == CAIRO_CONTENT_COLOR) {
surface->content = CAIRO_CONTENT_COLOR;
_cairo_output_stream_printf (surface->stream,
" 0 g %d %d %d %d rectfill\n",
- surface->page_bbox.x,
- surface->page_bbox.y,
- surface->page_bbox.width,
- surface->page_bbox.height);
+ recording_extents->x,
+ recording_extents->y,
+ recording_extents->width,
+ recording_extents->height);
}
status = _cairo_recording_surface_replay_region (recording_surface,
- extents,
+ subsurface ? recording_extents : NULL,
&surface->base,
CAIRO_RECORDING_REGION_NATIVE);
assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
if (unlikely (status))
- goto err;
+ return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (unlikely (status))
- goto err;
+ return status;
_cairo_output_stream_printf (surface->stream, " Q\n");
@@ -3090,16 +3414,18 @@ _cairo_ps_surface_emit_recording_subsurface (cairo_ps_surface_t *surface,
surface->content = old_content;
surface->width = old_width;
surface->height = old_height;
- surface->page_bbox = old_page_bbox;
+ surface->surface_extents = old_surface_extents;
+ surface->surface_bounded = old_surface_bounded;
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
surface->cairo_to_ps = old_cairo_to_ps;
_cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
&surface->cairo_to_ps);
-
-err:
cairo_surface_destroy (free_me);
+
+ _cairo_array_truncate (&surface->recording_surf_stack, recording_surf_stack_size);
+
return status;
}
@@ -3145,44 +3471,351 @@ _cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface,
red, green, blue);
}
-static cairo_status_t
-_cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface,
- cairo_pattern_t *source_pattern,
- cairo_surface_t *source_surface,
- cairo_operator_t op,
- int width,
- int height,
- cairo_bool_t stencil_mask)
+/*
+ * PS Forms are used for sources that have CAIRO_MIME_TYPE_UNIQUE_ID. They will be
+ * emitted once in the PS header and can be rendered with the 'execform' operator.
+ *
+ * This function tries adding the source the form hash table. If the source does not
+ * have CAIRO_MIME_TYPE_UNIQUE_ID, CAIRO_INT_STATUS_UNSUPPORTED is returned.
+
+ * @source: [in] the source for the form
+ * @params: [in] source parameters
+ * @test: [in] if TRUE, test if form will be used (excludes size check)
+ * @ps_form [out] the new or exisiting entry int the hash table.
+ * image or recording.
+ */
+static cairo_int_status_t
+_cairo_ps_surface_use_form (cairo_ps_surface_t *surface,
+ cairo_emit_surface_params_t *params,
+ cairo_bool_t test,
+ cairo_ps_form_t **ps_form)
+{
+ cairo_ps_form_t source_key;
+ cairo_ps_form_t *source_entry;
+ unsigned char *unique_id = NULL;
+ unsigned long unique_id_length = 0;
+ cairo_status_t status;
+ long max_size;
+
+ if (params->op != CAIRO_OPERATOR_OVER || params->stencil_mask)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (params->src_surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ cairo_surface_get_mime_data (params->src_surface, CAIRO_MIME_TYPE_UNIQUE_ID,
+ (const unsigned char **) &source_key.unique_id,
+ &source_key.unique_id_length);
+ if (source_key.unique_id == NULL || source_key.unique_id_length == 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (test)
+ return CAIRO_STATUS_SUCCESS;
+
+ source_key.filter = params->filter;
+ _cairo_ps_form_init_key (&source_key);
+ source_entry = _cairo_hash_table_lookup (surface->forms, &source_key.base);
+ if (source_entry) {
+ _cairo_rectangle_union (&source_entry->required_extents, params->src_op_extents);
+ *ps_form = source_entry;
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (surface->ps_level == CAIRO_PS_LEVEL_3)
+ max_size = MAX_L3_FORM_DATA;
+ else
+ max_size = MAX_L3_FORM_DATA;
+
+ /* Don't add any more Forms if we exceed the form memory limit */
+ if (surface->total_form_size + params->approx_size > max_size)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ surface->total_form_size += params->approx_size > max_size;
+ unique_id = _cairo_malloc (source_key.unique_id_length);
+ if (unique_id == NULL)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ unique_id_length = source_key.unique_id_length;
+ memcpy (unique_id, source_key.unique_id, unique_id_length);
+
+ source_entry = calloc (sizeof (cairo_ps_form_t), 1);
+ if (source_entry == NULL) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto fail;
+ }
+
+ source_entry->unique_id_length = unique_id_length;
+ source_entry->unique_id = unique_id;
+ source_entry->id = surface->num_forms++;
+ source_entry->src_surface = cairo_surface_reference (params->src_surface);
+ source_entry->required_extents = *params->src_op_extents;
+ source_entry->filter = params->filter;
+ source_entry->is_image = params->is_image;
+ _cairo_ps_form_init_key (source_entry);
+ status = _cairo_hash_table_insert (surface->forms, &source_entry->base);
+ if (unlikely(status))
+ goto fail;
+
+ *ps_form = source_entry;
+ return CAIRO_STATUS_SUCCESS;
+
+ fail:
+ free (unique_id);
+ free (source_entry);
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_ps_surface_emit_form (cairo_ps_surface_t *surface,
+ cairo_emit_surface_params_t *params,
+ cairo_bool_t test)
+{
+ cairo_ps_form_t *ps_form = NULL;
+ cairo_status_t status;
+
+ status = _cairo_ps_surface_use_form (surface,
+ params,
+ test,
+ &ps_form);
+ if (test || status)
+ return status;
+
+ /* _cairo_ps_form_emit will use Level 3 if permitted by ps_level */
+ if (surface->ps_level == CAIRO_PS_LEVEL_3)
+ surface->ps_level_used = CAIRO_PS_LEVEL_3;
+
+ _cairo_output_stream_printf (surface->stream,
+ "/cairoform-%d /Form findresource execform\n",
+ ps_form->id);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* Emit a surface. This function has three modes.
+ *
+ * CAIRO_EMIT_SURFACE_ANALYZE: This will determine the surface type to
+ * be emitted and approximate size. is_image is set to TRUE if the
+ * emitted surface is an image surface (including mime images). This
+ * is used by the caller to setup the correct CTM. approx_size is set
+ * to the approximate size of the emitted surface and is used as an
+ * input by the emit mode.
+ *
+ * CAIRO_EMIT_SURFACE_EMIT: Emits the surface will be emitted. The
+ * approx_size and the surface unique id values are used to determine
+ * if a Form should be used. If a form is used, the exec form
+ * operation is emitted and the surface is added to the forms hash
+ * table.
+ *
+ * CAIRO_EMIT_SURFACE_EMIT_FORM: Emits the form definition for the surface.
+ *
+ * Usage is:
+ * 1) Setup input params and call with ANALYZE.
+ * 2) Setup CTM for surface and call with EMIT using same params struct.
+ * The EMIT_FORM mode is used when emitting the form definitions.
+ */
+static cairo_int_status_t
+_cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface,
+ cairo_emit_surface_mode_t mode,
+ cairo_emit_surface_params_t *params)
{
cairo_int_status_t status;
+ cairo_output_stream_t *old_stream = NULL;
+ cairo_bool_t use_form;
+
+ /* Try emitting as a form. Returns unsupported if the surface is
+ * deemed unsuitable for a form. */
+ use_form = FALSE;
+ if (mode == CAIRO_EMIT_SURFACE_ANALYZE || mode == CAIRO_EMIT_SURFACE_EMIT) {
+ status = _cairo_ps_surface_emit_form (surface,
+ params,
+ mode == CAIRO_EMIT_SURFACE_ANALYZE);
+ use_form = (status == CAIRO_INT_STATUS_SUCCESS);
+ if (status != CAIRO_INT_STATUS_SUCCESS && status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
- if (source_pattern->type == CAIRO_PATTERN_TYPE_SURFACE &&
- source_pattern->extend != CAIRO_EXTEND_PAD)
- {
- cairo_surface_t *surf = ((cairo_surface_pattern_t *) source_pattern)->surface;
+ if (mode == CAIRO_EMIT_SURFACE_EMIT && status == CAIRO_INT_STATUS_SUCCESS)
+ return status;
+ }
+
+ status = _cairo_ps_surface_emit_eps (surface, mode, params);
+ if (status == CAIRO_INT_STATUS_SUCCESS) {
+ params->is_image = FALSE;
+ goto surface_emitted;
+ }
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
+ status = _cairo_ps_surface_emit_jpeg_image (surface, mode, params);
+ if (status == CAIRO_INT_STATUS_SUCCESS) {
+ params->is_image = TRUE;
+ goto surface_emitted;
+ }
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
- status = _cairo_ps_surface_emit_jpeg_image (surface, surf, width, height);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ status = _cairo_ps_surface_emit_ccitt_image (surface, mode, params);
+ if (status == CAIRO_INT_STATUS_SUCCESS) {
+ params->is_image = TRUE;
+ goto surface_emitted;
+ }
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
+ if (mode == CAIRO_EMIT_SURFACE_ANALYZE) {
+ /* Find size of image or recording surface by emitting to a memory stream */
+ status = _cairo_pdf_operators_flush (&surface->pdf_operators);
+ if (unlikely (status))
return status;
+
+ old_stream = surface->stream;
+ surface->stream = _cairo_memory_stream_create ();
+ _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->stream);
}
- 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);
+ if (params->src_surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
+ params->is_image = FALSE;
+ if (params->src_surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
+ cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) params->src_surface;
+ status = _cairo_ps_surface_emit_recording_surface (surface,
+ sub->target,
+ &sub->extents,
+ TRUE);
} else {
- status = _cairo_ps_surface_emit_recording_surface (surface, source_surface);
+ status = _cairo_ps_surface_emit_recording_surface (surface,
+ params->src_surface,
+ params->src_op_extents,
+ FALSE);
}
} else {
- cairo_image_surface_t *image = (cairo_image_surface_t *) source_surface;
+ params->is_image = TRUE;
+ status = _cairo_ps_surface_emit_image (surface, mode, params);
+ }
+
+ if (mode == CAIRO_EMIT_SURFACE_ANALYZE) {
+ unsigned char *data;
+ unsigned long length;
+
+ status = _cairo_pdf_operators_flush (&surface->pdf_operators);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_memory_stream_destroy (surface->stream, &data, &length);
+ free (data);
+ if (unlikely (status))
+ return status;
- status = _cairo_ps_surface_emit_image (surface, image,
- op, source_pattern->filter, stencil_mask);
+ params->approx_size = length;
+ surface->stream = old_stream;
+ _cairo_pdf_operators_set_stream (&surface->pdf_operators,
+ surface->stream);
}
+ surface_emitted:
+
return status;
}
+static void
+_cairo_ps_form_emit (void *entry, void *closure)
+{
+ cairo_ps_form_t *form = entry;
+ cairo_ps_surface_t *surface = closure;
+ cairo_emit_surface_params_t params;
+ cairo_int_status_t status;
+ cairo_output_stream_t *old_stream;
+
+ params.src_surface = form->src_surface;
+ params.op = CAIRO_OPERATOR_OVER;
+ params.src_op_extents = &form->required_extents;
+ params.filter = form->filter;
+ params.stencil_mask = FALSE;
+ params.is_image = form->is_image;
+ params.approx_size = 0;
+
+ _cairo_output_stream_printf (surface->final_stream,
+ "%%%%BeginResource: form cairoform-%d\n",
+ form->id);
+
+ _cairo_output_stream_printf (surface->final_stream,
+ "/cairo_paint_form-%d",
+ form->id);
+ if (surface->ps_level == CAIRO_PS_LEVEL_3) {
+ surface->paint_proc = FALSE;
+ _cairo_output_stream_printf (surface->final_stream,
+ "\n"
+ "currentfile\n"
+ "<< /Filter /SubFileDecode\n"
+ " /DecodeParms << /EODString (%s) /EODCount 0 >>\n"
+ ">> /ReusableStreamDecode filter\n",
+ SUBFILE_FILTER_EOD);
+ } else {
+ surface->paint_proc = TRUE;
+ _cairo_output_stream_printf (surface->final_stream,
+ " {\n");
+ }
+ _cairo_output_stream_printf (surface->final_stream,
+ "5 dict begin\n");
+
+ old_stream = surface->stream;
+ surface->stream = surface->final_stream;
+ _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->stream);
+ status = _cairo_ps_surface_emit_surface (surface,
+ CAIRO_EMIT_SURFACE_EMIT_FORM,
+ &params);
+ status = _cairo_pdf_operators_flush (&surface->pdf_operators);
+ surface->stream = old_stream;
+ _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->stream);
+
+ _cairo_output_stream_printf (surface->final_stream,
+ "end\n");
+ if (surface->ps_level == CAIRO_PS_LEVEL_3) {
+ _cairo_output_stream_printf (surface->final_stream,
+ "%s\n"
+ "def\n",
+ SUBFILE_FILTER_EOD);
+ } else {
+ _cairo_output_stream_printf (surface->final_stream,
+ "} bind def\n");
+ }
+
+ _cairo_output_stream_printf (surface->final_stream,
+ "\n"
+ "/cairoform-%d\n"
+ "<<\n"
+ " /FormType 1\n",
+ form->id);
+
+ if (form->is_image) {
+ _cairo_output_stream_printf (surface->final_stream,
+ " /BBox [ 0 0 1 1 ]\n");
+ } else {
+ _cairo_output_stream_printf (surface->final_stream,
+ " /BBox [ %d %d %d %d ]\n",
+ form->required_extents.x,
+ form->required_extents.y,
+ form->required_extents.x + form->required_extents.width,
+ form->required_extents.y + form->required_extents.height);
+ }
+
+ _cairo_output_stream_printf (surface->final_stream,
+ " /Matrix [ 1 0 0 1 0 0 ]\n"
+ " /PaintProc { pop cairo_paint_form-%d",
+ form->id);
+
+ if (surface->ps_level == CAIRO_PS_LEVEL_3) {
+ _cairo_output_stream_printf (surface->final_stream,
+ " dup 0 setfileposition cvx exec");
+ }
+ _cairo_output_stream_printf (surface->final_stream,
+ " } bind\n"
+ ">>\n"
+ "/Form defineresource pop\n");
+
+ _cairo_output_stream_printf (surface->final_stream,
+ "%%%%EndResource\n");
+ if (status)
+ surface->base.status = status;
+}
static void
_path_fixed_init_rectangle (cairo_path_fixed_t *path,
@@ -3215,19 +3848,21 @@ _path_fixed_init_rectangle (cairo_path_fixed_t *path,
static cairo_status_t
_cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface,
- cairo_pattern_t *pattern,
+ const cairo_pattern_t *pattern,
cairo_rectangle_int_t *extents,
cairo_operator_t op,
cairo_bool_t stencil_mask)
{
+ cairo_rectangle_int_t src_surface_extents;
+ cairo_bool_t src_surface_bounded;
+ cairo_rectangle_int_t src_op_extents;
+ cairo_surface_t *source_surface;
+ double x_offset, y_offset;
cairo_status_t status;
- int width, height;
cairo_matrix_t cairo_p2d, ps_p2d;
cairo_path_fixed_t path;
- double x_offset, y_offset;
- cairo_surface_t *source;
+ cairo_emit_surface_params_t params;
cairo_image_surface_t *image = NULL;
- void *image_extra;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (unlikely (status))
@@ -3236,10 +3871,12 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface,
status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface,
pattern,
extents,
- &width, &height,
- &x_offset, &y_offset,
- &source,
- &image_extra);
+ &src_surface_extents,
+ &src_surface_bounded,
+ &src_op_extents,
+ &source_surface,
+ &x_offset,
+ &y_offset);
if (unlikely (status))
return status;
@@ -3248,16 +3885,18 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface,
((cairo_surface_pattern_t *)pattern)->surface->type == CAIRO_SURFACE_TYPE_IMAGE) {
cairo_image_surface_t *img;
- img = (cairo_image_surface_t *) source;
+ img = (cairo_image_surface_t *) source_surface;
status = _cairo_ps_surface_create_padded_image_from_image (surface,
img,
&pattern->matrix,
extents,
- &width, &height,
- &x_offset, &y_offset,
- &image);
+ &image,
+ &src_surface_extents);
if (unlikely (status))
goto release_source;
+
+ x_offset = src_surface_extents.x;
+ y_offset = src_surface_extents.y;
}
_path_fixed_init_rectangle (&path, extents);
@@ -3278,8 +3917,8 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface,
"%% Fallback Image: x=%f y=%f w=%d h=%d ",
-cairo_p2d.x0/x_scale,
-cairo_p2d.y0/y_scale,
- (int)(width/x_scale),
- (int)(height/y_scale));
+ (int)(src_surface_extents.width/x_scale),
+ (int)(src_surface_extents.height/y_scale));
if (x_scale == y_scale) {
_cairo_output_stream_printf (surface->stream,
"res=%fppi ",
@@ -3292,14 +3931,16 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface,
}
_cairo_output_stream_printf (surface->stream,
"size=%ld\n",
- (long)width*height*3);
+ (long)src_surface_extents.width * src_surface_extents.height * 3);
} else {
if (op == CAIRO_OPERATOR_SOURCE) {
_cairo_output_stream_printf (surface->stream,
- "%d g 0 0 %f %f rectfill\n",
+ "%d g %d %d %d %d rectfill\n",
surface->content == CAIRO_CONTENT_COLOR ? 0 : 1,
- surface->width,
- surface->height);
+ surface->surface_extents.x,
+ surface->surface_extents.y,
+ surface->surface_extents.width,
+ surface->surface_extents.height);
}
}
@@ -3310,8 +3951,26 @@ _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, x_offset, y_offset);
- cairo_matrix_translate (&ps_p2d, 0.0, height);
- cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
+
+ params.src_surface = image ? &image->base : source_surface;
+ params.op = op;
+ params.src_surface_extents = &src_surface_extents;
+ params.src_surface_bounded = src_surface_bounded;
+ params.src_op_extents = &src_op_extents;
+ params.filter = pattern->filter;
+ params.stencil_mask = stencil_mask;
+ params.is_image = FALSE;
+ params.approx_size = 0;
+
+ status = _cairo_ps_surface_emit_surface (surface, CAIRO_EMIT_SURFACE_ANALYZE, &params);
+ if (unlikely (status))
+ goto release_source;
+
+ if (params.is_image) {
+ cairo_matrix_translate (&ps_p2d, 0.0, src_surface_extents.height);
+ cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
+ cairo_matrix_scale (&ps_p2d, src_surface_extents.width, src_surface_extents.height);
+ }
if (! _cairo_matrix_is_identity (&ps_p2d)) {
_cairo_output_stream_printf (surface->stream, "[ ");
@@ -3319,18 +3978,13 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface,
_cairo_output_stream_printf (surface->stream, " ] concat\n");
}
- status = _cairo_ps_surface_emit_surface (surface,
- pattern,
- image ? &image->base : source,
- op,
- width, height,
- stencil_mask);
+ status = _cairo_ps_surface_emit_surface (surface, CAIRO_EMIT_SURFACE_EMIT, &params);
release_source:
if (image)
cairo_surface_destroy (&image->base);
- _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source, image_extra);
+ _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source_surface);
return status;
}
@@ -3342,15 +3996,17 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
cairo_operator_t op)
{
cairo_status_t status;
- int pattern_width = 0; /* squelch bogus compiler warning */
- int pattern_height = 0; /* squelch bogus compiler warning */
double xstep, ystep;
+ cairo_rectangle_int_t pattern_extents;
+ cairo_bool_t bounded;
cairo_matrix_t cairo_p2d, ps_p2d;
- cairo_bool_t old_use_string_datasource;
+ cairo_bool_t old_paint_proc;
double x_offset, y_offset;
- cairo_surface_t *source;
+ cairo_surface_t *source_surface;
cairo_image_surface_t *image = NULL;
- void *image_extra;
+ cairo_rectangle_int_t src_op_extents;
+ cairo_emit_surface_params_t params;
+ cairo_extend_t extend = cairo_pattern_get_extend (pattern);
cairo_p2d = pattern->matrix;
status = cairo_matrix_invert (&cairo_p2d);
@@ -3360,32 +4016,38 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface,
pattern,
extents,
- &pattern_width, &pattern_height,
- &x_offset, &y_offset,
- &source,
- &image_extra);
+ &pattern_extents,
+ &bounded,
+ &src_op_extents,
+ &source_surface,
+ &x_offset, &y_offset);
if (unlikely (status))
return status;
- if (pattern->extend == CAIRO_EXTEND_PAD) {
+ if (extend == CAIRO_EXTEND_PAD) {
cairo_image_surface_t *img;
- assert (source->type == CAIRO_SURFACE_TYPE_IMAGE);
- img = (cairo_image_surface_t *) source;
+ assert (source_surface->type == CAIRO_SURFACE_TYPE_IMAGE);
+ img = (cairo_image_surface_t *) source_surface;
status = _cairo_ps_surface_create_padded_image_from_image (surface,
img,
&pattern->matrix,
extents,
- &pattern_width, &pattern_height,
- &x_offset, &y_offset,
- &image);
+ &image,
+ &pattern_extents);
if (unlikely (status))
goto release_source;
}
if (unlikely (status))
goto release_source;
- switch (pattern->extend) {
+ if (!bounded)
+ {
+ extend = CAIRO_EXTEND_NONE;
+ _cairo_rectangle_intersect (&pattern_extents, &src_op_extents);
+ }
+
+ switch (extend) {
case CAIRO_EXTEND_PAD:
case CAIRO_EXTEND_NONE:
{
@@ -3402,7 +4064,8 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_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);
@@ -3412,16 +4075,16 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
* required an answer that's large enough, we don't really
* care if it's not as tight as possible.*/
xstep = ystep = ceil ((x2 - x1) + (y2 - y1) +
- pattern_width + pattern_height);
+ pattern_extents.width + pattern_extents.height);
break;
}
case CAIRO_EXTEND_REPEAT:
- xstep = pattern_width;
- ystep = pattern_height;
+ xstep = pattern_extents.width;
+ ystep = pattern_extents.height;
break;
case CAIRO_EXTEND_REFLECT:
- xstep = pattern_width*2;
- ystep = pattern_height*2;
+ xstep = pattern_extents.width*2;
+ ystep = pattern_extents.height*2;
break;
/* All the rest (if any) should have been analyzed away, so these
* cases should be unreachable. */
@@ -3432,27 +4095,49 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
}
_cairo_output_stream_printf (surface->stream,
- "/CairoPattern {\n");
+ "/CairoPattern {\n"
+ "q %d %d %d %d rectclip\n",
+ pattern_extents.x, pattern_extents.y,
+ pattern_extents.width, pattern_extents.height);
+
+ if (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT)
+ src_op_extents = pattern_extents;
+
+ old_paint_proc = surface->paint_proc;
+ surface->paint_proc = TRUE;
+ params.src_surface = image ? &image->base : source_surface;
+ params.op = op;
+ params.src_surface_extents = &pattern_extents;
+ params.src_surface_bounded = bounded;
+ params.src_op_extents = &src_op_extents;
+ params.filter = pattern->filter;
+ params.stencil_mask = FALSE;
+ params.is_image = FALSE;
+ params.approx_size = 0;
+ status = _cairo_ps_surface_emit_surface (surface, CAIRO_EMIT_SURFACE_ANALYZE, &params);
+ if (unlikely (status))
+ goto release_source;
+
+ if (params.is_image) {
+ _cairo_output_stream_printf (surface->stream,
+ "[ %d 0 0 %d 0 0 ] concat\n",
+ pattern_extents.width, pattern_extents.height);
+ }
- old_use_string_datasource = surface->use_string_datasource;
- surface->use_string_datasource = TRUE;
if (op == CAIRO_OPERATOR_SOURCE) {
_cairo_output_stream_printf (surface->stream,
- "%d g 0 0 %f %f rectfill\n",
+ "%d g %d %d %f %f rectfill\n",
surface->content == CAIRO_CONTENT_COLOR ? 0 : 1,
+ pattern_extents.x, pattern_extents.y,
xstep, ystep);
}
- status = _cairo_ps_surface_emit_surface (surface,
- pattern,
- image ? &image->base : source,
- op,
- pattern_width, pattern_height, FALSE);
+
+ status = _cairo_ps_surface_emit_surface (surface, CAIRO_EMIT_SURFACE_EMIT, &params);
if (unlikely (status))
goto release_source;
- surface->use_string_datasource = old_use_string_datasource;
_cairo_output_stream_printf (surface->stream,
- "} bind def\n");
+ " Q } bind def\n");
_cairo_output_stream_printf (surface->stream,
"<< /PatternType 1\n"
@@ -3462,20 +4147,43 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
" /XStep %f /YStep %f\n",
xstep, ystep);
- if (pattern->extend == CAIRO_EXTEND_REFLECT) {
+ if (extend == CAIRO_EXTEND_REFLECT) {
+ cairo_matrix_t mat;
+
_cairo_output_stream_printf (surface->stream,
- " /BBox [0 0 %d %d]\n"
+ " /BBox [%d %d %d %d]\n"
" /PaintProc {\n"
- " pop CairoPattern\n"
- " [-1 0 0 1 %d 0] concat CairoPattern\n"
- " [ 1 0 0 -1 0 %d] concat CairoPattern\n"
- " [-1 0 0 1 %d 0] concat CairoPattern\n"
- " CairoPattern\n"
- " } bind\n",
- pattern_width*2, pattern_height*2,
- pattern_width*2,
- pattern_height*2,
- pattern_width*2);
+ " pop CairoPattern\n",
+ pattern_extents.x,
+ pattern_extents.y,
+ pattern_extents.x + pattern_extents.width*2,
+ pattern_extents.y + pattern_extents.height*2);
+
+ cairo_matrix_init_translate (&mat, pattern_extents.x, pattern_extents.y);
+ cairo_matrix_scale (&mat, -1, 1);
+ cairo_matrix_translate (&mat, -2*pattern_extents.width, 0);
+ cairo_matrix_translate (&mat, -pattern_extents.x, -pattern_extents.y);
+ _cairo_output_stream_printf (surface->stream, " q [");
+ _cairo_output_stream_print_matrix (surface->stream, &mat);
+ _cairo_output_stream_printf (surface->stream, "] concat CairoPattern Q\n");
+
+ cairo_matrix_init_translate (&mat, pattern_extents.x, pattern_extents.y);
+ cairo_matrix_scale (&mat, 1, -1);
+ cairo_matrix_translate (&mat, 0, -2*pattern_extents.height);
+ cairo_matrix_translate (&mat, -pattern_extents.x, -pattern_extents.y);
+ _cairo_output_stream_printf (surface->stream, " q [");
+ _cairo_output_stream_print_matrix (surface->stream, &mat);
+ _cairo_output_stream_printf (surface->stream, "] concat CairoPattern Q\n");
+
+ cairo_matrix_init_translate (&mat, pattern_extents.x, pattern_extents.y);
+ cairo_matrix_scale (&mat, -1, -1);
+ cairo_matrix_translate (&mat, -2*pattern_extents.width, -2*pattern_extents.height);
+ cairo_matrix_translate (&mat, -pattern_extents.x, -pattern_extents.y);
+ _cairo_output_stream_printf (surface->stream, " q [");
+ _cairo_output_stream_print_matrix (surface->stream, &mat);
+ _cairo_output_stream_printf (surface->stream, "] concat CairoPattern Q\n");
+
+ _cairo_output_stream_printf (surface->stream, " } bind\n");
} else {
if (op == CAIRO_OPERATOR_SOURCE) {
_cairo_output_stream_printf (surface->stream,
@@ -3483,8 +4191,11 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
xstep, ystep);
} else {
_cairo_output_stream_printf (surface->stream,
- " /BBox [0 0 %d %d]\n",
- pattern_width, pattern_height);
+ " /BBox [%d %d %d %d]\n",
+ pattern_extents.x,
+ pattern_extents.y,
+ pattern_extents.x + pattern_extents.width,
+ pattern_extents.y + pattern_extents.height);
}
_cairo_output_stream_printf (surface->stream,
" /PaintProc { pop CairoPattern }\n");
@@ -3499,11 +4210,13 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
assert (status == CAIRO_STATUS_SUCCESS);
cairo_matrix_init_identity (&ps_p2d);
- cairo_matrix_translate (&ps_p2d, 0.0, surface->height);
- cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
- cairo_matrix_translate (&ps_p2d, 0.0, pattern_height);
- cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
+ cairo_matrix_translate (&ps_p2d, x_offset, y_offset);
+ if (((cairo_surface_pattern_t *)pattern)->surface->type != CAIRO_SURFACE_TYPE_RECORDING)
+ {
+ cairo_matrix_translate (&ps_p2d, 0.0, pattern_extents.height);
+ cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
+ }
_cairo_output_stream_printf (surface->stream, "[ ");
_cairo_output_stream_print_matrix (surface->stream, &ps_p2d);
@@ -3511,11 +4224,13 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
" ]\n"
"makepattern setpattern\n");
+ surface->paint_proc = old_paint_proc;
+
release_source:
if (image)
cairo_surface_destroy (&image->base);
- _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source, image_extra);
+ _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source_surface);
return status;
}
@@ -4098,7 +4813,7 @@ _cairo_ps_surface_paint_pattern (cairo_ps_surface_t *surface,
case CAIRO_PATTERN_TYPE_SURFACE:
case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
return _cairo_ps_surface_paint_surface (surface,
- (cairo_pattern_t *)source,
+ source,
extents,
op,
stencil_mask);
@@ -4107,8 +4822,8 @@ _cairo_ps_surface_paint_pattern (cairo_ps_surface_t *surface,
case CAIRO_PATTERN_TYPE_RADIAL:
case CAIRO_PATTERN_TYPE_MESH:
return _cairo_ps_surface_paint_gradient (surface,
- source,
- extents);
+ source,
+ extents);
case CAIRO_PATTERN_TYPE_SOLID:
default:
@@ -4146,17 +4861,10 @@ _cairo_ps_surface_get_extents (void *abstract_surface,
{
cairo_ps_surface_t *surface = abstract_surface;
- rectangle->x = 0;
- rectangle->y = 0;
-
- /* XXX: The conversion to integers here is pretty bogus, (not to
- * mention the aribitray limitation of width to a short(!). We
- * may need to come up with a better interface for get_extents.
- */
- rectangle->width = ceil (surface->width);
- rectangle->height = ceil (surface->height);
+ if (surface->surface_bounded)
+ *rectangle = surface->surface_extents;
- return TRUE;
+ return surface->surface_bounded;
}
static void
@@ -4240,8 +4948,11 @@ _cairo_ps_surface_paint (void *abstract_surface,
if (unlikely (status))
goto cleanup_composite;
- _cairo_output_stream_printf (stream, "0 0 %f %f rectfill\n",
- surface->width, surface->height);
+ _cairo_output_stream_printf (stream, "%d %d %d %d rectfill\n",
+ surface->surface_extents.x,
+ surface->surface_extents.y,
+ surface->surface_extents.width,
+ surface->surface_extents.height);
}
cleanup_composite:
@@ -4536,7 +5247,7 @@ _cairo_ps_surface_get_supported_mime_types (void *abstract_surface)
return _cairo_ps_supported_mime_types;
}
-static void
+static cairo_int_status_t
_cairo_ps_surface_set_paginated_mode (void *abstract_surface,
cairo_paginated_mode_t paginated_mode)
{
@@ -4545,34 +5256,57 @@ _cairo_ps_surface_set_paginated_mode (void *abstract_surface,
surface->paginated_mode = paginated_mode;
- if (surface->clipper.clip != NULL) {
- status = _cairo_pdf_operators_flush (&surface->pdf_operators);
+ 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);
- _cairo_output_stream_printf (surface->stream, "Q q\n");
- _cairo_surface_clipper_reset (&surface->clipper);
+ if (surface->clipper.clip != NULL)
+ {
+ status = _cairo_pdf_operators_flush (&surface->pdf_operators);
+
+ _cairo_output_stream_printf (surface->stream, "Q q\n");
+ _cairo_surface_clipper_reset (&surface->clipper);
+ }
}
+
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_ps_surface_set_bounding_box (void *abstract_surface,
- cairo_box_t *bbox)
+ cairo_box_t *analysis_bbox)
{
cairo_ps_surface_t *surface = abstract_surface;
int i, num_comments;
char **comments;
- int x1, y1, x2, y2;
cairo_bool_t has_page_media, has_page_bbox;
const char *page_media;
+ cairo_rectangle_int_t page_bbox;
+ cairo_point_int_t bbox_p1, bbox_p2; /* in PS coordinates */
- x1 = floor (_cairo_fixed_to_double (bbox->p1.x));
- y1 = floor (surface->height - _cairo_fixed_to_double (bbox->p2.y));
- x2 = ceil (_cairo_fixed_to_double (bbox->p2.x));
- y2 = ceil (surface->height - _cairo_fixed_to_double (bbox->p1.y));
+ _cairo_box_round_to_rectangle (analysis_bbox, &page_bbox);
- surface->page_bbox.x = x1;
- surface->page_bbox.y = y1;
- surface->page_bbox.width = x2 - x1;
- surface->page_bbox.height = y2 - y1;
+ /* convert to PS coordinates */
+ bbox_p1.x = page_bbox.x;
+ bbox_p1.y = ceil(surface->height) - (page_bbox.y + page_bbox.height);
+ bbox_p2.x = page_bbox.x + page_bbox.width;
+ bbox_p2.y = ceil(surface->height) - page_bbox.y;
+
+ if (surface->num_pages == 1) {
+ surface->document_bbox_p1 = bbox_p1;
+ surface->document_bbox_p2 = bbox_p2;
+ } else {
+ if (bbox_p1.x < surface->document_bbox_p1.x)
+ surface->document_bbox_p1.x = bbox_p1.x;
+ if (bbox_p1.y < surface->document_bbox_p1.y)
+ surface->document_bbox_p1.y = bbox_p1.y;
+ if (bbox_p2.x < surface->document_bbox_p2.x)
+ surface->document_bbox_p2.x = bbox_p2.x;
+ if (bbox_p2.y < surface->document_bbox_p2.y)
+ surface->document_bbox_p2.y = bbox_p2.y;
+ }
_cairo_output_stream_printf (surface->stream,
"%%%%Page: %d %d\n",
@@ -4613,7 +5347,10 @@ _cairo_ps_surface_set_bounding_box (void *abstract_surface,
if (!has_page_bbox) {
_cairo_output_stream_printf (surface->stream,
"%%%%PageBoundingBox: %d %d %d %d\n",
- x1, y1, x2, y2);
+ bbox_p1.x,
+ bbox_p1.y,
+ bbox_p2.x,
+ bbox_p2.y);
}
if (!surface->eps) {
@@ -4625,27 +5362,14 @@ _cairo_ps_surface_set_bounding_box (void *abstract_surface,
_cairo_output_stream_printf (surface->stream,
"%%%%EndPageSetup\n"
- "q %d %d %d %d rectclip q\n",
- surface->page_bbox.x,
- surface->page_bbox.y,
- surface->page_bbox.width,
- surface->page_bbox.height);
+ "q %d %d %d %d rectclip\n"
+ "1 0 0 -1 0 %f cm q\n",
+ bbox_p1.x,
+ bbox_p1.y,
+ bbox_p2.x - bbox_p1.x,
+ bbox_p2.y - bbox_p1.y,
+ ceil(surface->height));
- if (surface->num_pages == 1) {
- surface->bbox_x1 = x1;
- surface->bbox_y1 = y1;
- surface->bbox_x2 = x2;
- surface->bbox_y2 = y2;
- } else {
- if (x1 < surface->bbox_x1)
- surface->bbox_x1 = x1;
- if (y1 < surface->bbox_y1)
- surface->bbox_y1 = y1;
- if (x2 > surface->bbox_x2)
- surface->bbox_x2 = x2;
- if (y2 > surface->bbox_y2)
- surface->bbox_y2 = y2;
- }
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);