summaryrefslogtreecommitdiffstats
path: root/gfx/cairo/cairo/src/cairo-pdf-surface.c
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/cairo/cairo/src/cairo-pdf-surface.c')
-rw-r--r--gfx/cairo/cairo/src/cairo-pdf-surface.c1008
1 files changed, 786 insertions, 222 deletions
diff --git a/gfx/cairo/cairo/src/cairo-pdf-surface.c b/gfx/cairo/cairo/src/cairo-pdf-surface.c
index 9496941113..50f4daa57a 100644
--- a/gfx/cairo/cairo/src/cairo-pdf-surface.c
+++ b/gfx/cairo/cairo/src/cairo-pdf-surface.c
@@ -54,6 +54,7 @@
#include "cairo-error-private.h"
#include "cairo-image-surface-inline.h"
#include "cairo-image-info-private.h"
+#include "cairo-recording-surface-inline.h"
#include "cairo-recording-surface-private.h"
#include "cairo-output-stream-private.h"
#include "cairo-paginated-private.h"
@@ -132,10 +133,10 @@
* The PDF surface is used to render cairo graphics to Adobe
* PDF files and is a multi-page vector surface backend.
*
- * The following mime types are supported: %CAIRO_MIME_TYPE_JPEG,
- * %CAIRO_MIME_TYPE_JP2, %CAIRO_MIME_TYPE_UNIQUE_ID,
- * %CAIRO_MIME_TYPE_JBIG2, %CAIRO_MIME_TYPE_JBIG2_GLOBAL,
- * %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID,
+ * The following mime types are supported on source patterns:
+ * %CAIRO_MIME_TYPE_JPEG, %CAIRO_MIME_TYPE_JP2,
+ * %CAIRO_MIME_TYPE_UNIQUE_ID, %CAIRO_MIME_TYPE_JBIG2,
+ * %CAIRO_MIME_TYPE_JBIG2_GLOBAL, %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID,
* %CAIRO_MIME_TYPE_CCITT_FAX, %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS.
*
* # JBIG2 Images #
@@ -209,7 +210,9 @@ _cairo_pdf_surface_get_extents (void *abstract_surface,
static const cairo_pdf_version_t _cairo_pdf_versions[] =
{
CAIRO_PDF_VERSION_1_4,
- CAIRO_PDF_VERSION_1_5
+ CAIRO_PDF_VERSION_1_5,
+ CAIRO_PDF_VERSION_1_6,
+ CAIRO_PDF_VERSION_1_7
};
#define CAIRO_PDF_VERSION_LAST ARRAY_LENGTH (_cairo_pdf_versions)
@@ -217,7 +220,9 @@ static const cairo_pdf_version_t _cairo_pdf_versions[] =
static const char * _cairo_pdf_version_strings[CAIRO_PDF_VERSION_LAST] =
{
"PDF 1.4",
- "PDF 1.5"
+ "PDF 1.5",
+ "PDF 1.6",
+ "PDF 1.7"
};
static const char *_cairo_pdf_supported_mime_types[] =
@@ -243,7 +248,7 @@ typedef enum {
typedef struct _cairo_pdf_object {
cairo_pdf_object_type_t type;
union {
- long offset; /* type == PDF_OBJECT_UNCOMPRESSED */
+ long long offset; /* type == PDF_OBJECT_UNCOMPRESSED */
struct compressed_obj { /* type == PDF_OBJECT_COMPRESSED */
cairo_pdf_resource_t xref_stream;
int index;
@@ -253,7 +258,7 @@ typedef struct _cairo_pdf_object {
typedef struct _cairo_xref_stream_object {
cairo_pdf_resource_t resource;
- long offset;
+ long long offset;
} cairo_xref_stream_object_t;
typedef struct _cairo_pdf_font {
@@ -275,7 +280,8 @@ typedef struct _cairo_pdf_alpha_linear_function {
} cairo_pdf_alpha_linear_function_t;
static void
-_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface);
+_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface,
+ cairo_bool_t clear_doc_surfaces);
static void
_cairo_pdf_smask_group_destroy (cairo_pdf_smask_group_t *group);
@@ -313,7 +319,7 @@ static cairo_int_status_t
_cairo_pdf_surface_write_catalog (cairo_pdf_surface_t *surface,
cairo_pdf_resource_t catalog);
-static long
+static long long
_cairo_pdf_surface_write_xref (cairo_pdf_surface_t *surface);
static cairo_int_status_t
@@ -321,7 +327,7 @@ _cairo_pdf_surface_write_xref_stream (cairo_pdf_surface_t *surface,
cairo_pdf_resource_t xref_res,
cairo_pdf_resource_t root_res,
cairo_pdf_resource_t info_res,
- long *xref_offset);
+ long long *xref_offset);
static cairo_int_status_t
_cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface,
@@ -333,6 +339,9 @@ _cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface);
static cairo_bool_t
_cairo_pdf_source_surface_equal (const void *key_a, const void *key_b);
+static cairo_bool_t
+_cairo_pdf_color_glyph_equal (const void *key_a, const void *key_b);
+
static const cairo_surface_backend_t cairo_pdf_surface_backend;
static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend;
@@ -462,7 +471,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
surface->surface_bounded = TRUE;
_cairo_array_init (&surface->objects, sizeof (cairo_pdf_object_t));
- _cairo_array_init (&surface->pages, sizeof (cairo_pdf_resource_t));
+ _cairo_array_init (&surface->pages, sizeof (cairo_pdf_page_info_t));
_cairo_array_init (&surface->rgb_linear_functions, sizeof (cairo_pdf_rgb_linear_function_t));
_cairo_array_init (&surface->alpha_linear_functions, sizeof (cairo_pdf_alpha_linear_function_t));
_cairo_array_init (&surface->fonts, sizeof (cairo_pdf_font_t));
@@ -473,19 +482,26 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
_cairo_array_init (&surface->page_surfaces, sizeof (cairo_pdf_source_surface_t));
_cairo_array_init (&surface->doc_surfaces, sizeof (cairo_pdf_source_surface_t));
_cairo_array_init (&surface->jbig2_global, sizeof (cairo_pdf_jbig2_global_t));
- _cairo_array_init (&surface->page_heights, sizeof (double));
surface->all_surfaces = _cairo_hash_table_create (_cairo_pdf_source_surface_equal);
if (unlikely (surface->all_surfaces == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL0;
}
+ surface->color_glyphs = _cairo_hash_table_create (_cairo_pdf_color_glyph_equal);
+ if (unlikely (surface->color_glyphs == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto BAIL1;
+ }
+
+ surface->duplicate_surface_number = 0;
+
_cairo_pdf_group_resources_init (&surface->resources);
surface->font_subsets = _cairo_scaled_font_subsets_create_composite ();
if (! surface->font_subsets) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL1;
+ goto BAIL2;
}
_cairo_scaled_font_subsets_enable_latin_subset (surface->font_subsets, TRUE);
@@ -494,11 +510,11 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
surface->pages_resource = _cairo_pdf_surface_new_object (surface);
if (surface->pages_resource.id == 0) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL2;
+ goto BAIL3;
}
surface->struct_tree_root.id = 0;
- surface->pdf_version = CAIRO_PDF_VERSION_1_5;
+ surface->pdf_version = CAIRO_PDF_VERSION_1_7;
surface->compress_streams = TRUE;
surface->pdf_stream.active = FALSE;
surface->pdf_stream.old_output = NULL;
@@ -510,11 +526,13 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
_cairo_array_init (&surface->object_stream.objects, sizeof (cairo_xref_stream_object_t));
surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
+ surface->type3_replay = FALSE;
surface->force_fallbacks = FALSE;
surface->select_pattern_gstate_saved = FALSE;
surface->current_pattern_is_solid_color = FALSE;
surface->current_operator = CAIRO_OPERATOR_OVER;
+ surface->reset_gs_required = FALSE;
surface->header_emitted = FALSE;
_cairo_surface_clipper_init (&surface->clipper,
@@ -532,7 +550,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
status = _cairo_pdf_interchange_init (surface);
if (unlikely (status))
- goto BAIL2;
+ goto BAIL3;
surface->page_parent_tree = -1;
_cairo_array_init (&surface->page_annots, sizeof (cairo_pdf_resource_t));
@@ -548,8 +566,11 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
surface->thumbnail_height = 0;
surface->thumbnail_image = NULL;
- if (getenv ("CAIRO_DEBUG_PDF") != NULL)
+ surface->debug = FALSE;
+ if (getenv ("CAIRO_DEBUG_PDF") != NULL) {
+ surface->debug = TRUE;
surface->compress_streams = FALSE;
+ }
surface->paginated_surface = _cairo_paginated_surface_create (
&surface->base,
@@ -563,8 +584,10 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
return surface->paginated_surface;
}
-BAIL2:
+BAIL3:
_cairo_scaled_font_subsets_destroy (surface->font_subsets);
+BAIL2:
+ _cairo_hash_table_destroy (surface->color_glyphs);
BAIL1:
_cairo_hash_table_destroy (surface->all_surfaces);
BAIL0:
@@ -775,7 +798,7 @@ cairo_pdf_get_versions (cairo_pdf_version_t const **versions,
const char *
cairo_pdf_version_to_string (cairo_pdf_version_t version)
{
- if (version >= CAIRO_PDF_VERSION_LAST)
+ if (version < 0 || version >= CAIRO_PDF_VERSION_LAST)
return NULL;
return _cairo_pdf_version_strings[version];
@@ -909,6 +932,42 @@ cairo_pdf_surface_set_metadata (cairo_surface_t *surface,
}
/**
+ * cairo_pdf_surface_set_custom_metadata:
+ * @surface: a PDF #cairo_surface_t
+ * @name: The name of the custom metadata item to set (utf8).
+ * @value: The value of the metadata (utf8).
+ *
+ * Set custom document metadata. @name may be any string except for
+ * the following names reserved by PDF: "Title", "Author", "Subject",
+ * "Keywords", "Creator", "Producer", "CreationDate", "ModDate",
+ * "Trapped".
+ *
+ * If @value is NULL or an empty string, the @name metadata will not be set.
+ *
+ * For example:
+ * <informalexample><programlisting>
+ * cairo_pdf_surface_set_custom_metadata (surface, "ISBN", "978-0123456789");
+ * </programlisting></informalexample>
+ *
+ * Since: 1.18
+ **/
+void
+cairo_pdf_surface_set_custom_metadata (cairo_surface_t *surface,
+ const char *name,
+ const char *value)
+{
+ cairo_pdf_surface_t *pdf_surface = NULL; /* hide compiler warning */
+ cairo_status_t status;
+
+ if (! _extract_pdf_surface (surface, &pdf_surface))
+ return;
+
+ status = _cairo_pdf_interchange_set_custom_metadata (pdf_surface, name, value);
+ if (status)
+ status = _cairo_surface_set_error (surface, status);
+}
+
+/**
* cairo_pdf_surface_set_page_label:
* @surface: a PDF #cairo_surface_t
* @utf8: The page label.
@@ -957,12 +1016,14 @@ cairo_pdf_surface_set_thumbnail_size (cairo_surface_t *surface,
}
static void
-_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
+_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface,
+ cairo_bool_t clear_doc_surfaces)
{
int i, size;
cairo_pdf_pattern_t *pattern;
cairo_pdf_source_surface_t *src_surface;
cairo_pdf_smask_group_t *group;
+ cairo_pdf_source_surface_t doc_surface;
size = _cairo_array_num_elements (&surface->page_patterns);
for (i = 0; i < size; i++) {
@@ -974,7 +1035,13 @@ _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
size = _cairo_array_num_elements (&surface->page_surfaces);
for (i = 0; i < size; i++) {
src_surface = (cairo_pdf_source_surface_t *) _cairo_array_index (&surface->page_surfaces, i);
- cairo_surface_destroy (src_surface->surface);
+ if (src_surface->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) {
+ cairo_pattern_destroy (src_surface->raster_pattern);
+ } else {
+ if (_cairo_surface_is_recording (src_surface->surface) && src_surface->region_id != 0)
+ _cairo_recording_surface_region_array_remove (src_surface->surface, src_surface->region_id);
+ cairo_surface_destroy (src_surface->surface);
+ }
}
_cairo_array_truncate (&surface->page_surfaces, 0);
@@ -990,6 +1057,21 @@ _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
if (surface->thumbnail_image)
cairo_surface_destroy (&surface->thumbnail_image->base);
surface->thumbnail_image = NULL;
+
+ if (clear_doc_surfaces) {
+ size = _cairo_array_num_elements (&surface->doc_surfaces);
+ for (i = 0; i < size; i++) {
+ _cairo_array_copy_element (&surface->doc_surfaces, i, &doc_surface);
+ if (doc_surface.type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) {
+ cairo_pattern_destroy (doc_surface.raster_pattern);
+ } else {
+ if (_cairo_surface_is_recording (doc_surface.surface) && doc_surface.region_id != 0)
+ _cairo_recording_surface_region_array_remove (doc_surface.surface, doc_surface.region_id);
+ cairo_surface_destroy (doc_surface.surface);
+ }
+ }
+ _cairo_array_truncate (&surface->doc_surfaces, 0);
+ }
}
static void
@@ -1379,6 +1461,9 @@ _cairo_pdf_source_surface_equal (const void *key_a, const void *key_b)
if (a->interpolate != b->interpolate)
return FALSE;
+ if (a->region_id != b->region_id)
+ return FALSE;
+
if (a->unique_id && b->unique_id && a->unique_id_length == b->unique_id_length)
return (memcmp (a->unique_id, b->unique_id, a->unique_id_length) == 0);
@@ -1394,6 +1479,28 @@ _cairo_pdf_source_surface_init_key (cairo_pdf_source_surface_entry_t *key)
} else {
key->base.hash = key->id;
}
+ key->base.hash = _cairo_hash_bytes (key->base.hash,
+ &key->region_id,
+ sizeof(key->region_id));
+}
+
+static cairo_bool_t
+_cairo_pdf_color_glyph_equal (const void *key_a, const void *key_b)
+{
+ const cairo_pdf_color_glyph_t *a = key_a;
+ const cairo_pdf_color_glyph_t *b = key_b;
+
+ if (a->scaled_font != b->scaled_font)
+ return FALSE;
+
+ return (a->glyph_index == b->glyph_index);
+}
+
+static void
+_cairo_pdf_color_glyph_init_key (cairo_pdf_color_glyph_t *key)
+{
+ key->base.hash = _cairo_hash_uintptr (_CAIRO_HASH_INIT_VALUE, (uintptr_t)key->scaled_font);
+ key->base.hash = _cairo_hash_uintptr (key->base.hash, key->glyph_index);
}
static cairo_int_status_t
@@ -1504,6 +1611,11 @@ _get_source_surface_extents (cairo_surface_t *source,
* @surface: [in] the pdf surface
* @source_surface: [in] A #cairo_surface_t to use as the source surface
* @source_pattern: [in] A #cairo_pattern_t of type SURFACE or RASTER_SOURCE to use as the source
+ * @region_id: [in] Surfaces containing tags set this to the recording
+ * surface region id. When tags are used in a XObject, PDF requires a
+ * separate object for each use (section 14.7.4.2) @region_id is used
+ * as a key to ensure a separate object is emitted for each use. Set
+ * to 0 for surfaces without tags.
* @op: [in] the operator used to composite this source
* @filter: [in] filter type of the source pattern
* @stencil_mask: [in] if true, the surface will be written to the PDF as an /ImageMask
@@ -1531,6 +1643,7 @@ static cairo_int_status_t
_cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
cairo_surface_t *source_surface,
const cairo_pattern_t *source_pattern,
+ int region_id,
cairo_operator_t op,
cairo_filter_t filter,
cairo_bool_t stencil_mask,
@@ -1556,6 +1669,7 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
cairo_rectangle_int_t op_extents;
double x, y;
cairo_bool_t subsurface;
+ cairo_bool_t emit_image;
switch (filter) {
default:
@@ -1603,10 +1717,21 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
*source_extents = op_extents;
surface_key.id = source_surface->unique_id;
- surface_key.interpolate = interpolate;
+
+ /* Recording surfaces do not use interpolate. Ensure it is always
+ * false for recording surfaces. This is because pdf-interchange
+ * needs to lookup recording surfaces in the hash table using
+ * interpolate = FALSE in the key since it does not know the
+ * interpolate value passed to this function.
+ */
+ emit_image = source_surface->type != CAIRO_SURFACE_TYPE_RECORDING;
+ surface_key.interpolate = emit_image ? interpolate : FALSE;
+
cairo_surface_get_mime_data (source_surface, CAIRO_MIME_TYPE_UNIQUE_ID,
(const unsigned char **) &surface_key.unique_id,
&surface_key.unique_id_length);
+
+ surface_key.region_id = region_id;
_cairo_pdf_source_surface_init_key (&surface_key);
surface_entry = _cairo_hash_table_lookup (surface->all_surfaces, &surface_key.base);
if (surface_entry) {
@@ -1649,9 +1774,12 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
if (pdf_source)
*pdf_source = surface_entry;
+
surface_entry->id = surface_key.id;
+ surface_entry->region_id = region_id;
surface_entry->operator = op;
- surface_entry->interpolate = interpolate;
+ surface_entry->interpolate = emit_image ? interpolate : FALSE;
+ surface_entry->emit_image = emit_image;
surface_entry->stencil_mask = stencil_mask;
surface_entry->smask = smask;
surface_entry->need_transp_group = need_transp_group;
@@ -1683,6 +1811,7 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
_cairo_pdf_source_surface_init_key (surface_entry);
src_surface.hash_entry = surface_entry;
+ src_surface.region_id = 0;
if (source_pattern && source_pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) {
src_surface.type = CAIRO_PATTERN_TYPE_RASTER_SOURCE;
src_surface.surface = NULL;
@@ -1694,6 +1823,16 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
src_surface.type = CAIRO_PATTERN_TYPE_SURFACE;
src_surface.surface = cairo_surface_reference (source_surface);
src_surface.raster_pattern = NULL;
+ if (source_pattern) {
+ cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source_pattern;
+ src_surface.region_id = surface_pattern->region_array_id;
+ if (_cairo_surface_is_recording (surface_pattern->surface) &&
+ surface_pattern->region_array_id != 0)
+ {
+ _cairo_recording_surface_region_array_reference (surface_pattern->surface,
+ surface_pattern->region_array_id);
+ }
+ }
}
surface_entry->surface_res = _cairo_pdf_surface_new_object (surface);
@@ -1702,11 +1841,6 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
goto fail3;
}
- /* Test if surface will be emitted as image or recording */
- status = _cairo_pdf_surface_emit_surface (surface, &src_surface, TRUE, &surface_entry->emit_image);
- if (unlikely (status))
- goto fail3;
-
if (surface_entry->bounded) {
status = _cairo_array_append (&surface->page_surfaces, &src_surface);
if (unlikely (status))
@@ -1750,6 +1884,7 @@ static cairo_int_status_t
_cairo_pdf_surface_add_pdf_pattern_or_shading (cairo_pdf_surface_t *surface,
const cairo_pattern_t *pattern,
cairo_operator_t op,
+ cairo_analysis_source_t source_type,
const cairo_rectangle_int_t *extents,
cairo_bool_t is_shading,
cairo_pdf_resource_t *pattern_res,
@@ -1757,6 +1892,7 @@ _cairo_pdf_surface_add_pdf_pattern_or_shading (cairo_pdf_surface_t *surface,
{
cairo_pdf_pattern_t pdf_pattern;
cairo_int_status_t status;
+ int region_id = 0;
pdf_pattern.is_shading = is_shading;
pdf_pattern.operator = op;
@@ -1815,6 +1951,17 @@ _cairo_pdf_surface_add_pdf_pattern_or_shading (cairo_pdf_surface_t *surface,
* Y-axis. */
pdf_pattern.inverted_y_axis = pdf_pattern.gstate_res.id ? TRUE : surface->in_xobject;
+ if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
+ if (_cairo_pdf_interchange_struct_tree_requires_recording_surface (surface,
+ surface_pattern,
+ source_type))
+ {
+ region_id = surface_pattern->region_array_id;
+ }
+ }
+ pdf_pattern.region_id = region_id;
+
status = _cairo_array_append (&surface->page_patterns, &pdf_pattern);
if (unlikely (status)) {
cairo_pattern_destroy (pdf_pattern.pattern);
@@ -1846,6 +1993,7 @@ _cairo_pdf_surface_add_pdf_shading (cairo_pdf_surface_t *surface,
return _cairo_pdf_surface_add_pdf_pattern_or_shading (surface,
pattern,
op,
+ CAIRO_ANALYSIS_SOURCE_NONE,
extents,
TRUE,
shading_res,
@@ -1856,6 +2004,7 @@ static cairo_int_status_t
_cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
const cairo_pattern_t *pattern,
cairo_operator_t op,
+ cairo_analysis_source_t source_type,
const cairo_rectangle_int_t *extents,
cairo_pdf_resource_t *pattern_res,
cairo_pdf_resource_t *gstate_res)
@@ -1863,6 +2012,7 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
return _cairo_pdf_surface_add_pdf_pattern_or_shading (surface,
pattern,
op,
+ source_type,
extents,
FALSE,
pattern_res,
@@ -1943,7 +2093,7 @@ static cairo_int_status_t
_cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface)
{
cairo_int_status_t status;
- long length;
+ long long length;
if (! surface->pdf_stream.active)
return CAIRO_INT_STATUS_SUCCESS;
@@ -1973,7 +2123,7 @@ _cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface)
surface->pdf_stream.length);
_cairo_output_stream_printf (surface->output,
"%d 0 obj\n"
- " %ld\n"
+ " %lld\n"
"endobj\n",
surface->pdf_stream.length.id,
length);
@@ -2073,7 +2223,7 @@ _cairo_pdf_surface_open_group (cairo_pdf_surface_t *surface,
surface->group_stream.bbox = *bbox;
/* Reset gstate */
- _cairo_output_stream_printf (surface->output, "/gs0 gs\n");
+ surface->reset_gs_required = TRUE;
surface->current_pattern_is_solid_color = FALSE;
surface->current_operator = CAIRO_OPERATOR_OVER;
_cairo_pdf_operators_reset (&surface->pdf_operators);
@@ -2134,6 +2284,7 @@ _cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface,
surface->group_stream.mem_stream = NULL;
surface->group_stream.stream = NULL;
+ surface->reset_gs_required = FALSE;
return status;
}
@@ -2141,7 +2292,7 @@ _cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface,
static cairo_int_status_t
_cairo_pdf_surface_open_object_stream (cairo_pdf_surface_t *surface)
{
- if (surface->pdf_version < CAIRO_PDF_VERSION_1_5) {
+ if (surface->debug || surface->pdf_version < CAIRO_PDF_VERSION_1_5) {
/* Object streams not supported. All objects will be written
* directly to the file. */
assert (surface->pdf_stream.active == FALSE);
@@ -2197,7 +2348,9 @@ _cairo_pdf_surface_object_end (cairo_pdf_surface_t *surface)
}
}
-static int _cairo_xref_stream_object_compare (const void *a, const void *b)
+static int
+_cairo_xref_stream_object_compare (const void *a,
+ const void *b)
{
const cairo_xref_stream_object_t *a_obj = a;
const cairo_xref_stream_object_t *b_obj = b;
@@ -2215,7 +2368,7 @@ _cairo_pdf_surface_close_object_stream (cairo_pdf_surface_t *surface)
{
int i, num_objects;
cairo_xref_stream_object_t *xref_obj;
- long start_pos, length;
+ long long start_pos, length;
cairo_output_stream_t *index_stream;
cairo_output_stream_t *deflate_stream;
cairo_pdf_resource_t length_res;
@@ -2240,7 +2393,7 @@ _cairo_pdf_surface_close_object_stream (cairo_pdf_surface_t *surface)
for (i = 0; i < num_objects; i++) {
xref_obj = _cairo_array_index (&surface->object_stream.objects, i);
_cairo_output_stream_printf (index_stream,
- "%d %ld\n",
+ "%d %lld\n",
xref_obj->resource.id,
xref_obj->offset);
}
@@ -2295,7 +2448,7 @@ _cairo_pdf_surface_close_object_stream (cairo_pdf_surface_t *surface)
length_res);
_cairo_output_stream_printf (surface->output,
"%d 0 obj\n"
- " %ld\n"
+ " %lld\n"
"endobj\n",
length_res.id,
length);
@@ -2319,7 +2472,8 @@ _cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t *surface,
const cairo_box_double_t *bbox,
cairo_pdf_resource_t *resource,
cairo_bool_t is_form,
- cairo_bool_t is_group)
+ cairo_bool_t is_group,
+ int struct_parents)
{
cairo_int_status_t status;
@@ -2333,41 +2487,57 @@ _cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t *surface,
if (is_form) {
assert (bbox != NULL);
+ cairo_output_stream_t *mem_stream = _cairo_memory_stream_create ();
if (is_group) {
- status =
- _cairo_pdf_surface_open_stream (surface,
- resource,
- surface->compress_streams,
- " /Type /XObject\n"
- " /Subtype /Form\n"
- " /BBox [ %f %f %f %f ]\n"
- " /Group <<\n"
- " /Type /Group\n"
- " /S /Transparency\n"
- " /I true\n"
- " /CS /DeviceRGB\n"
- " >>\n"
- " /Resources %d 0 R\n",
- bbox->p1.x,
- bbox->p1.y,
- bbox->p2.x,
- bbox->p2.y,
- surface->content_resources.id);
+ _cairo_output_stream_printf (mem_stream,
+ " /Type /XObject\n"
+ " /Subtype /Form\n"
+ " /BBox [ %f %f %f %f ]\n"
+ " /Group <<\n"
+ " /Type /Group\n"
+ " /S /Transparency\n"
+ " /I true\n"
+ " /CS /DeviceRGB\n"
+ " >>\n"
+ " /Resources %d 0 R\n",
+ bbox->p1.x,
+ bbox->p1.y,
+ bbox->p2.x,
+ bbox->p2.y,
+ surface->content_resources.id);
} else {
- status =
- _cairo_pdf_surface_open_stream (surface,
- resource,
- surface->compress_streams,
- " /Type /XObject\n"
- " /Subtype /Form\n"
- " /BBox [ %f %f %f %f ]\n"
- " /Resources %d 0 R\n",
- bbox->p1.x,
- bbox->p1.y,
- bbox->p2.x,
- bbox->p2.y,
- surface->content_resources.id);
+ _cairo_output_stream_printf (mem_stream,
+ " /Type /XObject\n"
+ " /Subtype /Form\n"
+ " /BBox [ %f %f %f %f ]\n"
+ " /Resources %d 0 R\n",
+ bbox->p1.x,
+ bbox->p1.y,
+ bbox->p2.x,
+ bbox->p2.y,
+ surface->content_resources.id);
}
+ if (struct_parents >= 0) {
+ _cairo_output_stream_printf (mem_stream,
+ " /StructParents %d\n", struct_parents);
+ }
+
+ unsigned char *data;
+ unsigned long length;
+ status = _cairo_memory_stream_destroy (mem_stream, &data, &length);
+ if (unlikely (status))
+ return status;
+
+ char *str = _cairo_strndup ((const char*)data, length); /* Add NULL terminator */
+
+ status =
+ _cairo_pdf_surface_open_stream (surface,
+ resource,
+ surface->compress_streams,
+ "%s",
+ str);
+ free (str);
+ free (data);
} else {
status =
_cairo_pdf_surface_open_stream (surface,
@@ -2430,15 +2600,93 @@ _cairo_pdf_source_surface_entry_pluck (void *entry, void *closure)
free (surface_entry);
}
+static void
+_cairo_pdf_color_glyph_pluck (void *entry, void *closure)
+{
+ cairo_pdf_color_glyph_t *glyph_entry = entry;
+ cairo_hash_table_t *patterns = closure;
+
+ _cairo_hash_table_remove (patterns, &glyph_entry->base);
+ cairo_scaled_font_destroy (glyph_entry->scaled_font);
+
+ free (glyph_entry);
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_write_page_dicts (cairo_pdf_surface_t *surface)
+{
+ cairo_int_status_t status;
+ cairo_pdf_page_info_t *page_info;
+ int num_annots;
+ cairo_pdf_resource_t res;
+
+ for (unsigned i = 0; i < _cairo_array_num_elements (&surface->pages); i++) {
+ page_info = _cairo_array_index (&surface->pages, i);
+
+ status = _cairo_pdf_surface_object_begin (surface, page_info->page_res);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_printf (surface->object_stream.stream,
+ "<< /Type /Page %% %d\n"
+ " /Parent %d 0 R\n"
+ " /MediaBox [ 0 0 %f %f ]\n"
+ " /Contents %d 0 R\n"
+ " /Group <<\n"
+ " /Type /Group\n"
+ " /S /Transparency\n"
+ " /I true\n"
+ " /CS /DeviceRGB\n"
+ " >>\n"
+ " /Resources %d 0 R\n",
+ i + 1,
+ surface->pages_resource.id,
+ page_info->width,
+ page_info->height,
+ page_info->content.id,
+ page_info->resources.id);
+
+ if (page_info->struct_parents >= 0) {
+ _cairo_output_stream_printf (surface->object_stream.stream,
+ " /StructParents %d\n",
+ page_info->struct_parents);
+ }
+
+ num_annots = _cairo_array_num_elements (&page_info->annots);
+ if (num_annots > 0) {
+ _cairo_output_stream_printf (surface->object_stream.stream,
+ " /Annots [ ");
+ for (int j = 0; j < num_annots; j++) {
+ _cairo_array_copy_element (&page_info->annots, j, &res);
+ _cairo_output_stream_printf (surface->object_stream.stream,
+ "%d 0 R ",
+ res.id);
+ }
+ _cairo_output_stream_printf (surface->object_stream.stream, "]\n");
+ }
+
+ if (page_info->thumbnail.id) {
+ _cairo_output_stream_printf (surface->object_stream.stream,
+ " /Thumb %d 0 R\n",
+ page_info->thumbnail.id);
+ }
+
+ _cairo_output_stream_printf (surface->object_stream.stream,
+ ">>\n");
+ _cairo_pdf_surface_object_end (surface);
+ }
+
+ return status;
+}
+
static cairo_status_t
_cairo_pdf_surface_finish (void *abstract_surface)
{
cairo_pdf_surface_t *surface = abstract_surface;
- long offset;
+ long long offset;
cairo_pdf_resource_t catalog;
cairo_status_t status = CAIRO_STATUS_SUCCESS, status2;
int size, i;
- cairo_pdf_source_surface_t doc_surface;
cairo_pdf_jbig2_global_t *global;
char *label;
cairo_pdf_resource_t xref_res;
@@ -2447,7 +2695,7 @@ _cairo_pdf_surface_finish (void *abstract_surface)
if (surface->base.status != CAIRO_STATUS_SUCCESS)
goto CLEANUP;
- _cairo_pdf_surface_clear (surface);
+ _cairo_pdf_surface_clear (surface, FALSE);
status = _cairo_pdf_surface_open_object_stream (surface);
if (unlikely (status))
@@ -2456,10 +2704,17 @@ _cairo_pdf_surface_finish (void *abstract_surface)
/* Emit unbounded surfaces */
_cairo_pdf_surface_write_patterns_and_smask_groups (surface, TRUE);
+ _cairo_pdf_surface_clear (surface, TRUE);
+
status = surface->base.status;
if (status == CAIRO_STATUS_SUCCESS)
status = _cairo_pdf_surface_emit_font_subsets (surface);
+ /* Emit any new patterns or surfaces created by the Type 3 font subset. */
+ _cairo_pdf_surface_write_patterns_and_smask_groups (surface, TRUE);
+
+ _cairo_pdf_surface_clear (surface, TRUE);
+
status = _cairo_pdf_surface_write_pages (surface);
if (unlikely (status))
return status;
@@ -2468,6 +2723,10 @@ _cairo_pdf_surface_finish (void *abstract_surface)
if (unlikely (status))
return status;
+ status = _cairo_pdf_surface_write_page_dicts (surface);
+ if (unlikely (status))
+ return status;
+
catalog = _cairo_pdf_surface_new_object (surface);
if (catalog.id == 0)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -2480,7 +2739,7 @@ _cairo_pdf_surface_finish (void *abstract_surface)
if (unlikely (status))
return status;
- if (surface->pdf_version >= CAIRO_PDF_VERSION_1_5)
+ if (!surface->debug && surface->pdf_version >= CAIRO_PDF_VERSION_1_5)
{
xref_res = _cairo_pdf_surface_new_object (surface);
status = _cairo_pdf_surface_write_xref_stream (surface,
@@ -2502,7 +2761,7 @@ _cairo_pdf_surface_finish (void *abstract_surface)
}
_cairo_output_stream_printf (surface->output,
"startxref\n"
- "%ld\n"
+ "%lld\n"
"%%%%EOF\n",
offset);
@@ -2543,6 +2802,11 @@ _cairo_pdf_surface_finish (void *abstract_surface)
_cairo_pdf_group_resources_fini (&surface->resources);
_cairo_array_fini (&surface->objects);
+ size = _cairo_array_num_elements (&surface->pages);
+ for (i = 0; i < size; i++) {
+ cairo_pdf_page_info_t *page_info = _cairo_array_index (&surface->pages, i);
+ _cairo_array_fini (&page_info->annots);
+ }
_cairo_array_fini (&surface->pages);
_cairo_array_fini (&surface->rgb_linear_functions);
_cairo_array_fini (&surface->alpha_linear_functions);
@@ -2550,11 +2814,6 @@ _cairo_pdf_surface_finish (void *abstract_surface)
_cairo_array_fini (&surface->page_surfaces);
_cairo_array_fini (&surface->object_stream.objects);
- size = _cairo_array_num_elements (&surface->doc_surfaces);
- for (i = 0; i < size; i++) {
- _cairo_array_copy_element (&surface->doc_surfaces, i, &doc_surface);
- cairo_surface_destroy (doc_surface.surface);
- }
_cairo_array_fini (&surface->doc_surfaces);
_cairo_hash_table_foreach (surface->all_surfaces,
_cairo_pdf_source_surface_entry_pluck,
@@ -2566,6 +2825,11 @@ _cairo_pdf_surface_finish (void *abstract_surface)
_cairo_array_fini (&surface->page_annots);
_cairo_array_fini (&surface->forward_links);
+ _cairo_hash_table_foreach (surface->color_glyphs,
+ _cairo_pdf_color_glyph_pluck,
+ surface->color_glyphs);
+ _cairo_hash_table_destroy (surface->color_glyphs);
+
if (surface->font_subsets) {
_cairo_scaled_font_subsets_destroy (surface->font_subsets);
surface->font_subsets = NULL;
@@ -2579,7 +2843,6 @@ _cairo_pdf_surface_finish (void *abstract_surface)
return _cairo_error (CAIRO_STATUS_JBIG2_GLOBAL_MISSING);
}
_cairo_array_fini (&surface->jbig2_global);
- _cairo_array_fini (&surface->page_heights);
size = _cairo_array_num_elements (&surface->page_labels);
for (i = 0; i < size; i++) {
@@ -2599,7 +2862,7 @@ static cairo_int_status_t
_cairo_pdf_surface_start_page (void *abstract_surface)
{
cairo_pdf_surface_t *surface = abstract_surface;
- cairo_pdf_resource_t page;
+ cairo_pdf_page_info_t page_info;
cairo_int_status_t status;
/* Document header */
@@ -2610,10 +2873,16 @@ _cairo_pdf_surface_start_page (void *abstract_surface)
case CAIRO_PDF_VERSION_1_4:
version = "1.4";
break;
- default:
case CAIRO_PDF_VERSION_1_5:
version = "1.5";
break;
+ case CAIRO_PDF_VERSION_1_6:
+ version = "1.6";
+ break;
+ default:
+ case CAIRO_PDF_VERSION_1_7:
+ version = "1.7";
+ break;
}
_cairo_output_stream_printf (surface->output,
@@ -2626,11 +2895,19 @@ _cairo_pdf_surface_start_page (void *abstract_surface)
_cairo_pdf_group_resources_clear (&surface->resources);
surface->in_xobject = FALSE;
- page = _cairo_pdf_surface_new_object (surface);
- if (page.id == 0)
+ page_info.page_res = _cairo_pdf_surface_new_object (surface);
+ if (page_info.page_res.id == 0)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- status = _cairo_array_append (&surface->pages, &page);
+ page_info.width = surface->width;
+ page_info.height = surface->height;
+ page_info.content.id = 0;
+ page_info.resources.id = 0;
+ page_info.thumbnail.id = 0;
+ page_info.struct_parents = -1;
+ _cairo_array_init (&page_info.annots, sizeof (cairo_pdf_resource_t));
+
+ status = _cairo_array_append (&surface->pages, &page_info);
if (unlikely (status))
return status;
@@ -2645,13 +2922,17 @@ _cairo_pdf_surface_has_fallback_images (void *abstract_surface,
cairo_pdf_surface_t *surface = abstract_surface;
cairo_box_double_t bbox;
+ status = _cairo_pdf_interchange_end_page_content (surface);
+ if (unlikely (status))
+ return status;
+
surface->has_fallback_images = has_fallbacks;
surface->in_xobject = has_fallbacks;
bbox.p1.x = 0;
bbox.p1.y = 0;
bbox.p2.x = surface->width;
bbox.p2.y = surface->height;
- status = _cairo_pdf_surface_open_content_stream (surface, &bbox, NULL, has_fallbacks, has_fallbacks);
+ status = _cairo_pdf_surface_open_content_stream (surface, &bbox, NULL, has_fallbacks, has_fallbacks, -1);
if (unlikely (status))
return status;
@@ -2751,6 +3032,7 @@ _cairo_pdf_surface_add_padded_image_surface (cairo_pdf_surface_t *surfa
status = _cairo_pdf_surface_add_source_surface (surface,
pad_image,
NULL,
+ -1 , /* node_surface_index */
CAIRO_OPERATOR_OVER, /* not used for images */
source->filter,
FALSE, /* stencil mask */
@@ -3489,9 +3771,10 @@ _cairo_pdf_surface_emit_ccitt_image (cairo_pdf_surface_t *surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
/* ensure params_string is null terminated */
- params = malloc (ccitt_params_string_len + 1);
- memcpy (params, ccitt_params_string, ccitt_params_string_len);
- params[ccitt_params_string_len] = 0;
+ params = _cairo_strndup ((const char *)ccitt_params_string, ccitt_params_string_len);
+ if (unlikely (params == NULL))
+ return _cairo_surface_set_error (&surface->base, CAIRO_STATUS_NO_MEMORY);
+
status = _cairo_tag_parse_ccitt_params (params, &ccitt_params);
if (unlikely(status))
return source->status;
@@ -3589,6 +3872,7 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface,
cairo_bool_t is_subsurface;
cairo_bool_t transparency_group;
cairo_recording_surface_t *recording;
+ int struct_parents = -1;
assert (pdf_source->type == CAIRO_PATTERN_TYPE_SURFACE);
@@ -3647,16 +3931,25 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface,
_cairo_recording_surface_has_only_bilevel_alpha (recording) &&
_cairo_recording_surface_has_only_op_over (recording));
+ status = _cairo_pdf_interchange_emit_recording_surface_begin (surface,
+ pdf_source->surface,
+ pdf_source->hash_entry->region_id,
+ pdf_source->hash_entry->surface_res,
+ &struct_parents);
+ if (unlikely (status))
+ goto err;
+
status = _cairo_pdf_surface_open_content_stream (surface,
&bbox,
&pdf_source->hash_entry->surface_res,
TRUE,
- transparency_group);
+ transparency_group,
+ struct_parents);
if (unlikely (status))
goto err;
/* Reset gstate */
- _cairo_output_stream_printf (surface->output, "/gs0 gs\n");
+ surface->reset_gs_required = TRUE;
if (source->content == CAIRO_CONTENT_COLOR) {
status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
@@ -3673,6 +3966,7 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface,
}
status = _cairo_recording_surface_replay_region (source,
+ pdf_source->region_id,
is_subsurface ? extents : NULL,
&surface->base,
CAIRO_RECORDING_REGION_NATIVE);
@@ -3689,6 +3983,10 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface,
surface->paginated_mode = old_paginated_mode;
surface->surface_extents = old_surface_extents;
surface->surface_bounded = old_surface_bounded;
+ surface->reset_gs_required = FALSE;
+
+ if (pdf_source->hash_entry->region_id > 0)
+ status = _cairo_pdf_interchange_emit_recording_surface_end (surface, pdf_source->surface);
err:
cairo_surface_destroy (free_me);
@@ -3830,6 +4128,7 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface,
status = _cairo_pdf_surface_add_source_surface (surface,
NULL,
pattern,
+ pdf_pattern->region_id,
pdf_pattern->operator,
pattern->filter,
FALSE, /* stencil mask */
@@ -4974,6 +5273,7 @@ static cairo_int_status_t
_cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
+ cairo_analysis_source_t source_type,
const cairo_rectangle_int_t *extents,
double alpha,
cairo_pdf_resource_t *smask_res,
@@ -4985,6 +5285,7 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface,
double x_offset;
double y_offset;
cairo_pdf_source_surface_entry_t *pdf_source;
+ int region_id = 0;
if (source->extend == CAIRO_EXTEND_PAD &&
!(source->type == CAIRO_PATTERN_TYPE_SURFACE &&
@@ -4998,9 +5299,19 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface,
&y_offset,
NULL);
} else {
+ if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source;
+ if (_cairo_pdf_interchange_struct_tree_requires_recording_surface (surface,
+ surface_pattern,
+ source_type))
+ {
+ region_id = surface_pattern->region_array_id;
+ }
+ }
status = _cairo_pdf_surface_add_source_surface (surface,
NULL,
source,
+ region_id,
op,
source->filter,
stencil_mask,
@@ -5008,6 +5319,7 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface,
alpha != 1.0, /* need_transp_group */
extents,
smask_res,
+
&pdf_source,
&x_offset,
&y_offset,
@@ -5134,6 +5446,7 @@ static cairo_int_status_t
_cairo_pdf_surface_paint_pattern (cairo_pdf_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
+ cairo_analysis_source_t source_type,
const cairo_rectangle_int_t *extents,
double alpha,
cairo_bool_t mask)
@@ -5144,6 +5457,7 @@ _cairo_pdf_surface_paint_pattern (cairo_pdf_surface_t *surface,
return _cairo_pdf_surface_paint_surface_pattern (surface,
op,
source,
+ source_type,
extents,
alpha,
NULL,
@@ -5195,6 +5509,11 @@ _cairo_pdf_surface_select_operator (cairo_pdf_surface_t *surface,
{
cairo_int_status_t status;
+ if (surface->reset_gs_required) {
+ _cairo_output_stream_printf (surface->output, "/gs0 gs\n");
+ surface->reset_gs_required = FALSE;
+ }
+
if (op == surface->current_operator)
return CAIRO_STATUS_SUCCESS;
@@ -5334,10 +5653,6 @@ _cairo_pdf_surface_show_page (void *abstract_surface)
cairo_pdf_surface_t *surface = abstract_surface;
cairo_int_status_t status;
- status = _cairo_array_append (&surface->page_heights, &surface->height);
- if (unlikely (status))
- return status;
-
status = _cairo_array_append (&surface->page_labels, &surface->current_page_label);
if (unlikely (status))
return status;
@@ -5358,7 +5673,7 @@ _cairo_pdf_surface_show_page (void *abstract_surface)
if (unlikely (status))
return status;
- _cairo_pdf_surface_clear (surface);
+ _cairo_pdf_surface_clear (surface, FALSE);
return CAIRO_STATUS_SUCCESS;
}
@@ -5390,7 +5705,7 @@ _cairo_pdf_surface_get_font_options (void *abstract_surface,
static cairo_int_status_t
_cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface)
{
- cairo_pdf_resource_t page;
+ cairo_pdf_page_info_t *page_info;
int num_pages, i;
cairo_int_status_t status;
@@ -5404,8 +5719,8 @@ _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface)
num_pages = _cairo_array_num_elements (&surface->pages);
for (i = 0; i < num_pages; i++) {
- _cairo_array_copy_element (&surface->pages, i, &page);
- _cairo_output_stream_printf (surface->object_stream.stream, "%d 0 R ", page.id);
+ page_info = _cairo_array_index (&surface->pages, i);
+ _cairo_output_stream_printf (surface->object_stream.stream, "%d 0 R ", page_info->page_res.id);
}
_cairo_output_stream_printf (surface->object_stream.stream, "]\n");
@@ -6408,42 +6723,205 @@ _cairo_pdf_emit_imagemask (cairo_image_surface_t *image,
}
static cairo_int_status_t
-_cairo_pdf_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_subset,
- void *closure)
-{
- cairo_pdf_surface_t *surface = closure;
- cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
- cairo_int_status_t status2;
- unsigned int i;
- cairo_surface_t *type3_surface;
- cairo_output_stream_t *null_stream;
+cairo_pdf_surface_emit_color_glyph (cairo_pdf_surface_t *surface,
+ cairo_scaled_font_t *scaled_font,
+ unsigned long glyph_index,
+ cairo_box_t *bbox,
+ double *width)
+{
+ cairo_rectangle_int_t extents;
+ cairo_scaled_glyph_t *scaled_glyph;
+ cairo_matrix_t mat;
+ cairo_int_status_t status;
+ double x_advance, y_advance;
+ cairo_matrix_t font_matrix_inverse;
+ cairo_surface_t *analysis;
+ cairo_rectangle_int_t old_surface_extents;
+ cairo_bool_t old_surface_bounded;
+ cairo_paginated_mode_t old_paginated_mode;
+ cairo_surface_t *glyph_surface = NULL;
+ unsigned int regions_id = 0;
+ cairo_surface_pattern_t surface_pattern;
+
+ _cairo_scaled_font_freeze_cache (scaled_font);
+ status = _cairo_scaled_glyph_lookup (scaled_font,
+ glyph_index,
+ CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE,
+ NULL, /* foreground color */
+ &scaled_glyph);
+ if (status == CAIRO_INT_STATUS_SUCCESS)
+ glyph_surface = cairo_surface_reference (scaled_glyph->recording_surface);
- null_stream = _cairo_null_stream_create ();
- type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
- null_stream,
- _cairo_pdf_emit_imagemask,
- surface->font_subsets,
- FALSE);
- if (unlikely (type3_surface->status)) {
- status2 = _cairo_output_stream_destroy (null_stream);
- return type3_surface->status;
+ _cairo_scaled_font_thaw_cache (scaled_font);
+ if (unlikely (status))
+ return status;
+
+ analysis = _cairo_analysis_surface_create (&surface->base, TRUE);
+ if (unlikely (analysis->status)) {
+ status = _cairo_surface_set_error (&surface->base, analysis->status);
+ goto cleanup;
}
- _cairo_type3_glyph_surface_set_font_subsets_callback (type3_surface,
- _cairo_pdf_surface_add_font,
- surface);
+ extents.x = _cairo_fixed_to_double (scaled_glyph->bbox.p1.x);
+ extents.y = _cairo_fixed_to_double (scaled_glyph->bbox.p1.y);
+ extents.width = _cairo_fixed_to_double (scaled_glyph->bbox.p2.x) - extents.x;
+ extents.height = _cairo_fixed_to_double (scaled_glyph->bbox.p2.y) - extents.y;
- for (i = 0; i < font_subset->num_glyphs; i++) {
- status = _cairo_type3_glyph_surface_analyze_glyph (type3_surface,
- font_subset->glyphs[i]);
- if (unlikely (status))
- break;
+ old_surface_extents = surface->surface_extents;
+ old_surface_bounded = surface->surface_bounded;
+ old_paginated_mode = surface->paginated_mode;
+ surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
+ surface->type3_replay = TRUE;
+ surface->surface_extents = extents;
+ surface->surface_bounded = TRUE;
+
+ status = _cairo_recording_surface_region_array_attach (glyph_surface, &regions_id);
+ if (status)
+ goto cleanup;
+
+ status = _cairo_recording_surface_replay_and_create_regions (glyph_surface, regions_id,
+ NULL, analysis, TRUE, FALSE);
+ if (status)
+ goto cleanup;
+
+ surface->surface_extents = old_surface_extents;
+ surface->surface_bounded = old_surface_bounded;
+ surface->paginated_mode = old_paginated_mode;
+ surface->type3_replay = FALSE;
+
+ if (status == CAIRO_INT_STATUS_SUCCESS &&
+ _cairo_analysis_surface_has_unsupported (analysis))
+ {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
}
- cairo_surface_destroy (type3_surface);
- status2 = _cairo_output_stream_destroy (null_stream);
- if (status == CAIRO_INT_STATUS_SUCCESS)
- status = status2;
+ cairo_surface_destroy (analysis);
+ if (status)
+ goto cleanup;
+
+ _cairo_pattern_init_for_surface (&surface_pattern, glyph_surface);
+ surface_pattern.region_array_id = regions_id;
+
+ cairo_matrix_init_identity (&mat);
+ cairo_matrix_multiply (&mat, &mat, &scaled_font->scale_inverse);
+
+ /* transform glyph extents to operation space */
+ cairo_box_t box;
+ _cairo_box_from_rectangle (&box, &extents);
+ _cairo_matrix_transform_bounding_box_fixed (&mat, &box, NULL);
+ _cairo_box_round_to_rectangle (&box, &extents);
+
+ status = cairo_matrix_invert (&mat);
+ if (status) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto cleanup;
+ }
+
+ cairo_pattern_set_matrix (&surface_pattern.base, &mat);
+
+ x_advance = scaled_glyph->metrics.x_advance;
+ y_advance = scaled_glyph->metrics.y_advance;
+ font_matrix_inverse = scaled_font->font_matrix;
+ status = cairo_matrix_invert (&font_matrix_inverse);
+ if (status) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto cleanup;
+ }
+
+ cairo_matrix_transform_distance (&font_matrix_inverse, &x_advance, &y_advance);
+ *width = x_advance;
+
+ *bbox = scaled_glyph->bbox;
+ _cairo_matrix_transform_bounding_box_fixed (&scaled_font->scale_inverse,
+ bbox, NULL);
+
+ _cairo_output_stream_printf (surface->output,
+ "%f 0 d0\n",
+ x_advance);
+
+ _cairo_pdf_surface_paint_surface_pattern (surface,
+ CAIRO_OPERATOR_OVER,
+ &surface_pattern.base,
+ CAIRO_ANALYSIS_SOURCE_NONE,
+ &extents,
+ 1.0, /* alpha */
+ NULL, /* smask_res */
+ FALSE); /* mask */
+
+ cleanup:
+ cairo_surface_destroy (glyph_surface);
+
+ return status;
+}
+
+static cairo_int_status_t
+cairo_pdf_surface_emit_color_glyph_image (cairo_pdf_surface_t *surface,
+ cairo_scaled_font_t *scaled_font,
+ unsigned long glyph_index,
+ cairo_box_t *bbox,
+ double *width)
+{
+ cairo_rectangle_int_t extents;
+ cairo_pattern_t *image_pattern;
+ cairo_scaled_glyph_t *scaled_glyph;
+ cairo_matrix_t mat;
+ cairo_int_status_t status, status2;
+ double x_advance, y_advance;
+ cairo_matrix_t font_matrix_inverse;
+
+ _cairo_scaled_font_freeze_cache (scaled_font);
+ status = _cairo_scaled_glyph_lookup (scaled_font,
+ glyph_index,
+ CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE,
+ NULL, /* foreground color */
+ &scaled_glyph);
+ if (unlikely (status))
+ goto FAIL;
+
+ extents.x = _cairo_fixed_to_double (scaled_glyph->bbox.p1.x);
+ extents.y = _cairo_fixed_to_double (scaled_glyph->bbox.p1.y);
+ extents.width = _cairo_fixed_to_double (scaled_glyph->bbox.p2.x) - extents.x;
+ extents.height = _cairo_fixed_to_double (scaled_glyph->bbox.p2.y) - extents.y;
+
+ image_pattern = cairo_pattern_create_for_surface (&scaled_glyph->color_surface->base);
+
+ cairo_matrix_init_translate (&mat, extents.x, extents.y);
+ cairo_matrix_multiply (&mat, &mat, &scaled_font->scale_inverse);
+ status2 = cairo_matrix_invert (&mat);
+ cairo_pattern_set_matrix (image_pattern, &mat);
+
+ x_advance = scaled_glyph->metrics.x_advance;
+ y_advance = scaled_glyph->metrics.y_advance;
+ font_matrix_inverse = scaled_font->font_matrix;
+ status2 = cairo_matrix_invert (&font_matrix_inverse);
+
+ /* The invertability of font_matrix is tested in
+ * pdf_operators_show_glyphs before any glyphs are mapped to the
+ * subset. */
+ assert (status2 == CAIRO_INT_STATUS_SUCCESS);
+
+ cairo_matrix_transform_distance (&font_matrix_inverse, &x_advance, &y_advance);
+ *width = x_advance;
+
+ *bbox = scaled_glyph->bbox;
+ _cairo_matrix_transform_bounding_box_fixed (&scaled_font->scale_inverse,
+ bbox, NULL);
+
+ _cairo_output_stream_printf (surface->output,
+ "%f 0 d0\n",
+ x_advance);
+
+ _cairo_pdf_surface_paint_surface_pattern (surface,
+ CAIRO_OPERATOR_OVER,
+ image_pattern,
+ CAIRO_ANALYSIS_SOURCE_NONE,
+ &extents,
+ 1.0, /* alpha */
+ NULL, /* smask_res */
+ FALSE); /* mask */
+ cairo_pattern_destroy (image_pattern);
+ FAIL:
+ _cairo_scaled_font_thaw_cache (scaled_font);
return status;
}
@@ -6510,6 +6988,20 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface,
font_subset->glyphs[i],
&bbox,
&widths[i]);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ status = cairo_pdf_surface_emit_color_glyph (surface,
+ font_subset->scaled_font,
+ font_subset->glyphs[i],
+ &bbox,
+ &widths[i]);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ status = cairo_pdf_surface_emit_color_glyph_image (surface,
+ font_subset->scaled_font,
+ font_subset->glyphs[i],
+ &bbox,
+ &widths[i]);
+ }
+ }
if (unlikely (status))
break;
@@ -6685,12 +7177,6 @@ _cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface)
{
cairo_int_status_t status;
- status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
- _cairo_pdf_surface_analyze_user_font_subset,
- surface);
- if (unlikely (status))
- goto BAIL;
-
status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets,
_cairo_pdf_surface_emit_unscaled_font_subset,
surface);
@@ -6700,12 +7186,6 @@ _cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface)
status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets,
_cairo_pdf_surface_emit_scaled_font_subset,
surface);
- if (unlikely (status))
- goto BAIL;
-
- status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
- _cairo_pdf_surface_emit_scaled_font_subset,
- surface);
BAIL:
_cairo_scaled_font_subsets_destroy (surface->font_subsets);
@@ -6764,13 +7244,12 @@ _cairo_pdf_surface_write_catalog (cairo_pdf_surface_t *surface,
return status;
}
-static long
+static long long
_cairo_pdf_surface_write_xref (cairo_pdf_surface_t *surface)
{
cairo_pdf_object_t *object;
int num_objects, i;
- long offset;
- char buffer[11];
+ long long offset;
num_objects = _cairo_array_num_elements (&surface->objects);
@@ -6784,9 +7263,8 @@ _cairo_pdf_surface_write_xref (cairo_pdf_surface_t *surface)
"0000000000 65535 f \n");
for (i = 0; i < num_objects; i++) {
object = _cairo_array_index (&surface->objects, i);
- snprintf (buffer, sizeof buffer, "%010ld", object->u.offset);
_cairo_output_stream_printf (surface->output,
- "%s 00000 n \n", buffer);
+ "%010lld 00000 n \n", object->u.offset);
}
return offset;
@@ -6797,7 +7275,7 @@ _cairo_write_xref_stream_entry (cairo_output_stream_t *stream,
int id,
int type,
int field2_size,
- long field2,
+ long long field2,
int field3,
cairo_bool_t write_as_comments)
{
@@ -6805,7 +7283,7 @@ _cairo_write_xref_stream_entry (cairo_output_stream_t *stream,
int i;
if (write_as_comments) {
- _cairo_output_stream_printf (stream, "%% %5d %2d %10ld %d\n", id, type, field2, field3);
+ _cairo_output_stream_printf (stream, "%% %5d %2d %10lld %d\n", id, type, field2, field3);
} else {
/* Each field is big endian */
buf[0] = type; /* field 1 */
@@ -6820,10 +7298,10 @@ _cairo_write_xref_stream_entry (cairo_output_stream_t *stream,
}
static void
-_cairo_write_xref_stream_entrys (cairo_pdf_surface_t *surface,
- cairo_output_stream_t *stream,
- int field2_size,
- cairo_bool_t write_as_comments)
+_cairo_write_xref_stream_entries (cairo_pdf_surface_t *surface,
+ cairo_output_stream_t *stream,
+ int field2_size,
+ cairo_bool_t write_as_comments)
{
cairo_pdf_object_t *object;
int num_objects, i;
@@ -6873,11 +7351,11 @@ _cairo_pdf_surface_write_xref_stream (cairo_pdf_surface_t *surface,
cairo_pdf_resource_t xref_res,
cairo_pdf_resource_t root_res,
cairo_pdf_resource_t info_res,
- long *xref_offset)
+ long long *xref_offset)
{
cairo_output_stream_t *mem_stream;
cairo_output_stream_t *xref_stream;
- long offset;
+ long long offset;
int offset_bytes;
cairo_status_t status;
@@ -6893,7 +7371,7 @@ _cairo_pdf_surface_write_xref_stream (cairo_pdf_surface_t *surface,
mem_stream = _cairo_memory_stream_create ();
xref_stream = _cairo_deflate_stream_create (mem_stream);
- _cairo_write_xref_stream_entrys (surface, xref_stream, offset_bytes, FALSE);
+ _cairo_write_xref_stream_entries (surface, xref_stream, offset_bytes, FALSE);
status = _cairo_output_stream_destroy (xref_stream);
if (unlikely (status))
@@ -6926,7 +7404,7 @@ _cairo_pdf_surface_write_xref_stream (cairo_pdf_surface_t *surface,
*/
_cairo_output_stream_printf (surface->output,
"%% id type offset/obj gen/index\n");
- _cairo_write_xref_stream_entrys (surface, surface->output, offset_bytes, TRUE);
+ _cairo_write_xref_stream_entries (surface, surface->output, offset_bytes, TRUE);
}
_cairo_output_stream_printf (surface->output,
@@ -6966,6 +7444,7 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface,
status = _cairo_pdf_surface_paint_pattern (surface,
CAIRO_OPERATOR_OVER,
group->mask,
+ CAIRO_ANALYSIS_MASK_MASK,
&group->extents,
1.0, /* alpha */
FALSE); /* mask */
@@ -6978,6 +7457,7 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface,
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface, group->mask,
CAIRO_OPERATOR_OVER,
+ CAIRO_ANALYSIS_MASK_MASK,
NULL,
&pattern_res, &gstate_res);
if (unlikely (status))
@@ -7043,6 +7523,7 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface,
status = _cairo_pdf_surface_paint_pattern (surface,
CAIRO_OPERATOR_OVER,
group->source,
+ CAIRO_ANALYSIS_MASK_MASK,
&group->extents,
1.0, /* alpha */
FALSE); /* mask */
@@ -7055,6 +7536,7 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface,
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface, group->source,
CAIRO_OPERATOR_OVER,
+ CAIRO_ANALYSIS_MASK_MASK,
NULL,
&pattern_res, &gstate_res);
if (unlikely (status))
@@ -7292,10 +7774,12 @@ _cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface
static cairo_int_status_t
_cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
{
- cairo_pdf_resource_t knockout, res, thumbnail_res;
- cairo_pdf_resource_t *page;
+ cairo_pdf_resource_t knockout, res;
cairo_int_status_t status;
- unsigned int i, len, page_num, num_annots;
+ unsigned int i, len;
+ cairo_pdf_page_info_t *page_info;
+
+ page_info = _cairo_array_last_element (&surface->pages);
status = _cairo_pdf_surface_open_object_stream (surface);
if (unlikely (status))
@@ -7341,7 +7825,7 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
return status;
_cairo_pdf_group_resources_clear (&surface->resources);
- status = _cairo_pdf_surface_open_content_stream (surface, NULL, NULL, FALSE, FALSE);
+ status = _cairo_pdf_surface_open_content_stream (surface, NULL, NULL, FALSE, FALSE, -1);
if (unlikely (status))
return status;
@@ -7357,70 +7841,18 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
return status;
}
- thumbnail_res.id = 0;
if (surface->thumbnail_image) {
cairo_pdf_source_surface_entry_t entry;
memset (&entry, 0, sizeof (entry));
- thumbnail_res = _cairo_pdf_surface_new_object (surface);
- entry.surface_res = thumbnail_res;
+ page_info->thumbnail = _cairo_pdf_surface_new_object (surface);
+ entry.surface_res = page_info->thumbnail;
_cairo_pdf_surface_emit_image (surface, surface->thumbnail_image, &entry);
}
- page_num = _cairo_array_num_elements (&surface->pages);
- page = _cairo_array_index (&surface->pages, page_num - 1);
-
- status = _cairo_pdf_surface_object_begin (surface, *page);
- if (unlikely (status))
- return status;
-
- _cairo_output_stream_printf (surface->object_stream.stream,
- "<< /Type /Page %% %d\n"
- " /Parent %d 0 R\n"
- " /MediaBox [ 0 0 %f %f ]\n"
- " /Contents %d 0 R\n"
- " /Group <<\n"
- " /Type /Group\n"
- " /S /Transparency\n"
- " /I true\n"
- " /CS /DeviceRGB\n"
- " >>\n"
- " /Resources %d 0 R\n",
- page_num,
- surface->pages_resource.id,
- surface->width,
- surface->height,
- surface->content.id,
- surface->content_resources.id);
-
- if (surface->page_parent_tree >= 0) {
- _cairo_output_stream_printf (surface->object_stream.stream,
- " /StructParents %d\n",
- surface->page_parent_tree);
- }
-
- num_annots = _cairo_array_num_elements (&surface->page_annots);
- if (num_annots > 0) {
- _cairo_output_stream_printf (surface->object_stream.stream,
- " /Annots [ ");
- for (i = 0; i < num_annots; i++) {
- _cairo_array_copy_element (&surface->page_annots, i, &res);
- _cairo_output_stream_printf (surface->object_stream.stream,
- "%d 0 R ",
- res.id);
- }
- _cairo_output_stream_printf (surface->object_stream.stream, "]\n");
- }
-
- if (thumbnail_res.id) {
- _cairo_output_stream_printf (surface->object_stream.stream,
- " /Thumb %d 0 R\n",
- thumbnail_res.id);
- }
-
- _cairo_output_stream_printf (surface->object_stream.stream,
- ">>\n");
- _cairo_pdf_surface_object_end (surface);
+ page_info->content = surface->content;
+ page_info->resources = surface->content_resources;
+ page_info->struct_parents = surface->page_parent_tree;
status = _cairo_pdf_surface_write_patterns_and_smask_groups (surface, FALSE);
if (unlikely (status))
@@ -7604,6 +8036,9 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface,
/* The SOURCE operator is supported if the pattern is opaque or if
* there is nothing painted underneath. */
if (op == CAIRO_OPERATOR_SOURCE) {
+ if (surface->type3_replay)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
@@ -7664,7 +8099,7 @@ _cairo_pdf_surface_start_fallback (cairo_pdf_surface_t *surface)
bbox.p1.y = 0;
bbox.p2.x = surface->width;
bbox.p2.y = surface->height;
- status = _cairo_pdf_surface_open_content_stream (surface, &bbox, NULL, TRUE, TRUE);
+ status = _cairo_pdf_surface_open_content_stream (surface, &bbox, NULL, TRUE, TRUE, -1);
if (unlikely (status))
return status;
@@ -7811,6 +8246,7 @@ _cairo_pdf_surface_emit_combined_smask (cairo_pdf_surface_t *surface,
status = _cairo_pdf_surface_add_source_surface (surface,
NULL,
mask,
+ -1, /* node_surface_index */
op,
source->filter,
FALSE, /* stencil mask */
@@ -7831,7 +8267,9 @@ _cairo_pdf_surface_emit_combined_smask (cairo_pdf_surface_t *surface,
return status;
_cairo_output_stream_printf (surface->output, "q\n");
- status = _cairo_pdf_surface_paint_surface_pattern (surface, op, source, extents,
+ status = _cairo_pdf_surface_paint_surface_pattern (surface, op, source,
+ CAIRO_ANALYSIS_SOURCE_NONE,
+ extents,
1.0, /* alpha */
need_smask ? &pdf_source->surface_res : NULL,
FALSE);
@@ -7896,7 +8334,9 @@ _cairo_pdf_surface_emit_stencil_mask (cairo_pdf_surface_t *surface,
return status;
_cairo_output_stream_printf (surface->output, "q\n");
- status = _cairo_pdf_surface_paint_surface_pattern (surface, op, mask, extents, 1.0, NULL, TRUE);
+ status = _cairo_pdf_surface_paint_surface_pattern (surface, op, mask,
+ CAIRO_ANALYSIS_SOURCE_NONE,
+ extents, 1.0, NULL, TRUE);
if (unlikely (status))
return status;
@@ -7978,6 +8418,7 @@ _cairo_pdf_surface_paint (void *abstract_surface,
status = _cairo_pdf_surface_paint_pattern (surface,
op,
source,
+ CAIRO_ANALYSIS_SOURCE_PAINT,
&extents.bounded,
1.0, /* alpha */
FALSE); /* mask */
@@ -7992,6 +8433,7 @@ _cairo_pdf_surface_paint (void *abstract_surface,
pattern_res.id = 0;
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface, source, op,
+ CAIRO_ANALYSIS_SOURCE_PAINT,
&extents.bounded,
&pattern_res, &gstate_res);
if (unlikely (status))
@@ -8163,6 +8605,7 @@ _cairo_pdf_surface_mask (void *abstract_surface,
status = _cairo_pdf_surface_paint_pattern (surface,
op,
source,
+ CAIRO_ANALYSIS_SOURCE_MASK,
&extents.bounded,
alpha,
FALSE); /* mask */
@@ -8292,6 +8735,7 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
pattern_res.id = 0;
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface, source, op,
+ CAIRO_ANALYSIS_SOURCE_STROKE,
&extents.bounded,
&pattern_res, &gstate_res);
if (unlikely (status))
@@ -8450,6 +8894,7 @@ _cairo_pdf_surface_fill (void *abstract_surface,
status = _cairo_pdf_surface_paint_pattern (surface,
op,
source,
+ CAIRO_ANALYSIS_SOURCE_FILL,
&extents.bounded,
1.0, /* alpha */
FALSE); /* mask */
@@ -8464,6 +8909,7 @@ _cairo_pdf_surface_fill (void *abstract_surface,
pattern_res.id = 0;
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface, source, op,
+ CAIRO_ANALYSIS_SOURCE_FILL,
&extents.bounded,
&pattern_res, &gstate_res);
if (unlikely (status))
@@ -8643,6 +9089,7 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface, fill_source,
fill_op,
+ CAIRO_ANALYSIS_SOURCE_FILL,
&extents.bounded,
&fill_pattern_res,
&gstate_res);
@@ -8656,6 +9103,7 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
status = _cairo_pdf_surface_add_pdf_pattern (surface,
stroke_source,
stroke_op,
+ CAIRO_ANALYSIS_SOURCE_STROKE,
&extents.bounded,
&stroke_pattern_res,
&gstate_res);
@@ -8734,11 +9182,22 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
if (unlikely (status))
return status;
+ status = _cairo_pdf_interchange_add_content (surface);
+ if (unlikely (status))
+ return status;
+
status = _cairo_pdf_interchange_add_operation_extents (surface, &extents.bounded);
if (unlikely (status))
return status;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+ /* Enabling text in Type 3 fonts currently crashes cairo. Most
+ * PDF viewers don't seem to suport text in Type 3 so we let
+ * this go to image fallback.
+ */
+ if (surface->type3_replay)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
goto cleanup;
}
@@ -8752,6 +9211,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
pattern_res.id = 0;
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface, source, op,
+ CAIRO_ANALYSIS_SOURCE_SHOW_GLYPHS,
&extents.bounded,
&pattern_res, &gstate_res);
if (unlikely (status))
@@ -8880,9 +9340,10 @@ _cairo_pdf_surface_tag (void *abstract_surface,
cairo_bool_t begin,
const char *tag_name,
const char *attributes)
+
{
cairo_pdf_surface_t *surface = abstract_surface;
- cairo_int_status_t status = 0;
+ cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
if (begin)
status = _cairo_pdf_interchange_tag_begin (surface, tag_name, attributes);
@@ -8893,6 +9354,105 @@ _cairo_pdf_surface_tag (void *abstract_surface,
}
static cairo_int_status_t
+_cairo_pdf_surface_command_id (void *abstract_surface,
+ unsigned int recording_id,
+ unsigned int command_id)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+
+ return _cairo_pdf_interchange_command_id (surface, recording_id, command_id);
+}
+
+/* The Type 3 font subset support will the embed the
+ * CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE image if vector operations
+ * are not supported. The only case we don't currently handle is if a
+ * foreground color is used.
+ */
+static cairo_bool_t
+_cairo_pdf_surface_supports_color_glyph (void *abstract_surface,
+ cairo_scaled_font_t *scaled_font,
+ unsigned long glyph_index)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+ cairo_pdf_color_glyph_t glyph_key;
+ cairo_pdf_color_glyph_t *glyph_entry;
+ cairo_scaled_glyph_t *scaled_glyph;
+ cairo_status_t status;
+
+ glyph_key.scaled_font = scaled_font;
+ glyph_key.glyph_index = glyph_index;
+
+ _cairo_pdf_color_glyph_init_key (&glyph_key);
+ glyph_entry = _cairo_hash_table_lookup (surface->color_glyphs, &glyph_key.base);
+ if (glyph_entry)
+ return glyph_entry->supported;
+
+ glyph_entry = _cairo_malloc (sizeof (cairo_pdf_color_glyph_t));
+ if (glyph_entry == NULL) {
+ status = _cairo_surface_set_error (&surface->base,
+ _cairo_error (CAIRO_STATUS_NO_MEMORY));
+ return FALSE;
+ }
+
+ glyph_entry->scaled_font = cairo_scaled_font_reference (scaled_font);
+ glyph_entry->glyph_index = glyph_index;
+ _cairo_pdf_color_glyph_init_key (glyph_entry);
+
+ glyph_entry->supported = FALSE;
+ _cairo_scaled_font_freeze_cache (scaled_font);
+ status = _cairo_scaled_glyph_lookup (scaled_font,
+ glyph_index,
+ CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE,
+ NULL, /* foreground color */
+ &scaled_glyph);
+ if (unlikely (status))
+ goto done;
+
+ glyph_entry->supported = !(scaled_glyph->recording_uses_foreground_color ||
+ scaled_glyph->recording_uses_foreground_marker);
+
+ done:
+ _cairo_scaled_font_thaw_cache (scaled_font);
+
+ status = _cairo_hash_table_insert (surface->color_glyphs,
+ &glyph_entry->base);
+ if (unlikely(status)) {
+ status = _cairo_surface_set_error (&surface->base,
+ _cairo_error (CAIRO_STATUS_NO_MEMORY));
+ return FALSE;
+ }
+
+ return glyph_entry->supported;
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_analyze_recording_surface(void *abstract_surface,
+ const cairo_surface_pattern_t *recording_surface_pattern,
+ unsigned int region_id,
+ cairo_analysis_source_t source_type,
+ cairo_bool_t begin)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+ cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
+
+ if (begin) {
+ status = _cairo_pdf_interchange_recording_source_surface_begin (
+ surface,
+ recording_surface_pattern,
+ region_id,
+ source_type);
+ } else {
+ status = _cairo_pdf_interchange_recording_source_surface_end (
+ surface,
+ recording_surface_pattern,
+ region_id,
+ source_type);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
_cairo_pdf_surface_set_paginated_mode (void *abstract_surface,
cairo_paginated_mode_t paginated_mode)
{
@@ -8900,6 +9460,7 @@ _cairo_pdf_surface_set_paginated_mode (void *abstract_surface,
cairo_int_status_t status;
surface->paginated_mode = paginated_mode;
+
status = _cairo_pdf_interchange_begin_page_content (surface);
if (unlikely (status))
return status;
@@ -8950,6 +9511,9 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = {
_cairo_pdf_surface_show_text_glyphs,
_cairo_pdf_surface_get_supported_mime_types,
_cairo_pdf_surface_tag,
+ _cairo_pdf_surface_supports_color_glyph,
+ _cairo_pdf_surface_analyze_recording_surface,
+ _cairo_pdf_surface_command_id,
};
static const cairo_paginated_surface_backend_t