mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2025-12-20 07:00:08 +01:00
parent
e7ed40a71d
commit
b53b48116e
39 changed files with 2911 additions and 505 deletions
|
|
@ -263,7 +263,8 @@ static cairo_int_status_t
|
|||
_analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
|
||||
const cairo_pattern_t *pattern,
|
||||
cairo_rectangle_int_t *extents,
|
||||
unsigned int *regions_id)
|
||||
unsigned int *regions_id,
|
||||
cairo_analysis_source_t source_type)
|
||||
{
|
||||
const cairo_surface_pattern_t *surface_pattern;
|
||||
cairo_analysis_surface_t *tmp;
|
||||
|
|
@ -273,6 +274,7 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
|
|||
cairo_int_status_t analysis_status = CAIRO_INT_STATUS_SUCCESS;
|
||||
cairo_bool_t surface_is_unbounded;
|
||||
cairo_bool_t unused;
|
||||
cairo_bool_t replay_all;
|
||||
|
||||
assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
|
||||
surface_pattern = (const cairo_surface_pattern_t *) pattern;
|
||||
|
|
@ -288,7 +290,7 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
|
|||
tmp = (cairo_analysis_surface_t *)
|
||||
_cairo_analysis_surface_create (surface->target, surface->create_region_ids);
|
||||
if (unlikely (tmp->base.status)) {
|
||||
status =tmp->base.status;
|
||||
status = tmp->base.status;
|
||||
goto cleanup1;
|
||||
}
|
||||
proxy = attach_proxy (source, &tmp->base);
|
||||
|
|
@ -298,7 +300,6 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
|
|||
assert (status == CAIRO_INT_STATUS_SUCCESS);
|
||||
_cairo_analysis_surface_set_ctm (&tmp->base, &p2d);
|
||||
|
||||
|
||||
source = _cairo_surface_get_source (source, NULL);
|
||||
surface_is_unbounded = (pattern->extend == CAIRO_EXTEND_REPEAT
|
||||
|| pattern->extend == CAIRO_EXTEND_REFLECT);
|
||||
|
|
@ -307,22 +308,54 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
|
|||
status = _cairo_recording_surface_region_array_attach (source, regions_id);
|
||||
if (unlikely (status))
|
||||
goto cleanup2;
|
||||
}
|
||||
|
||||
replay_all = FALSE;
|
||||
if (surface->target->backend->analyze_recording_surface) {
|
||||
status = surface->target->backend->analyze_recording_surface (
|
||||
surface->target,
|
||||
surface_pattern,
|
||||
surface->create_region_ids ? *regions_id : 0,
|
||||
source_type,
|
||||
TRUE);
|
||||
if (status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
|
||||
/* Ensure all commands are replayed even if previously
|
||||
* replayed and assigned to a region.*/
|
||||
replay_all = TRUE;
|
||||
status = CAIRO_INT_STATUS_SUCCESS;
|
||||
}
|
||||
if (unlikely (status))
|
||||
goto cleanup3;
|
||||
}
|
||||
|
||||
if (surface->create_region_ids) {
|
||||
status = _cairo_recording_surface_replay_and_create_regions (source,
|
||||
*regions_id,
|
||||
&pattern->matrix,
|
||||
&tmp->base,
|
||||
surface_is_unbounded);
|
||||
surface_is_unbounded,
|
||||
replay_all);
|
||||
if (unlikely (status))
|
||||
goto cleanup2;
|
||||
goto cleanup3;
|
||||
} else {
|
||||
status = _cairo_recording_surface_replay_with_clip (source,
|
||||
status = _cairo_recording_surface_replay_with_transform (source,
|
||||
&pattern->matrix,
|
||||
&tmp->base,
|
||||
NULL, /* target clip */
|
||||
surface_is_unbounded);
|
||||
surface_is_unbounded,
|
||||
replay_all);
|
||||
if (unlikely (status))
|
||||
goto cleanup2;
|
||||
goto cleanup3;
|
||||
}
|
||||
|
||||
if (surface->target->backend->analyze_recording_surface) {
|
||||
status = surface->target->backend->analyze_recording_surface (
|
||||
surface->target,
|
||||
surface_pattern,
|
||||
surface->create_region_ids ? *regions_id : 0,
|
||||
source_type,
|
||||
FALSE);
|
||||
if (unlikely (status))
|
||||
goto cleanup3;
|
||||
}
|
||||
|
||||
/* black background or mime data fills entire extents */
|
||||
|
|
@ -339,7 +372,7 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
|
|||
if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK)
|
||||
status = CAIRO_INT_STATUS_SUCCESS;
|
||||
if (unlikely (status))
|
||||
goto cleanup2;
|
||||
goto cleanup3;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -363,6 +396,10 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
|
|||
_cairo_box_round_to_rectangle (&tmp->page_bbox, extents);
|
||||
}
|
||||
|
||||
cleanup3:
|
||||
if (surface->create_region_ids && unlikely (status)) {
|
||||
_cairo_recording_surface_region_array_remove (source, *regions_id);
|
||||
}
|
||||
cleanup2:
|
||||
detach_proxy (proxy);
|
||||
cleanup1:
|
||||
|
|
@ -454,7 +491,8 @@ _cairo_analysis_surface_paint (void *abstract_surface,
|
|||
backend_status = _analyze_recording_surface_pattern (surface,
|
||||
source,
|
||||
&rec_extents,
|
||||
&surface->source_region_id);
|
||||
&surface->source_region_id,
|
||||
CAIRO_ANALYSIS_SOURCE_PAINT);
|
||||
_cairo_rectangle_intersect (&extents, &rec_extents);
|
||||
}
|
||||
|
||||
|
|
@ -500,7 +538,8 @@ _cairo_analysis_surface_mask (void *abstract_surface,
|
|||
_analyze_recording_surface_pattern (surface,
|
||||
source,
|
||||
&rec_extents,
|
||||
&surface->source_region_id);
|
||||
&surface->source_region_id,
|
||||
CAIRO_ANALYSIS_SOURCE_MASK);
|
||||
if (_cairo_int_status_is_error (backend_source_status))
|
||||
return backend_source_status;
|
||||
|
||||
|
|
@ -516,7 +555,8 @@ _cairo_analysis_surface_mask (void *abstract_surface,
|
|||
_analyze_recording_surface_pattern (surface,
|
||||
mask,
|
||||
&rec_extents,
|
||||
&surface->mask_region_id);
|
||||
&surface->mask_region_id,
|
||||
CAIRO_ANALYSIS_MASK_MASK);
|
||||
if (_cairo_int_status_is_error (backend_mask_status))
|
||||
return backend_mask_status;
|
||||
|
||||
|
|
@ -578,7 +618,8 @@ _cairo_analysis_surface_stroke (void *abstract_surface,
|
|||
backend_status = _analyze_recording_surface_pattern (surface,
|
||||
source,
|
||||
&rec_extents,
|
||||
&surface->source_region_id);
|
||||
&surface->source_region_id,
|
||||
CAIRO_ANALYSIS_SOURCE_STROKE);
|
||||
_cairo_rectangle_intersect (&extents, &rec_extents);
|
||||
}
|
||||
|
||||
|
|
@ -633,7 +674,8 @@ _cairo_analysis_surface_fill (void *abstract_surface,
|
|||
backend_status = _analyze_recording_surface_pattern (surface,
|
||||
source,
|
||||
&rec_extents,
|
||||
&surface->source_region_id);
|
||||
&surface->source_region_id,
|
||||
CAIRO_ANALYSIS_SOURCE_FILL);
|
||||
_cairo_rectangle_intersect (&extents, &rec_extents);
|
||||
}
|
||||
|
||||
|
|
@ -703,7 +745,8 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
|
|||
backend_status = _analyze_recording_surface_pattern (surface,
|
||||
source,
|
||||
&rec_extents,
|
||||
&surface->source_region_id);
|
||||
&surface->source_region_id,
|
||||
CAIRO_ANALYSIS_SOURCE_SHOW_GLYPHS);
|
||||
_cairo_rectangle_intersect (&extents, &rec_extents);
|
||||
}
|
||||
|
||||
|
|
@ -787,7 +830,8 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
|
|||
_analyze_recording_surface_pattern (surface,
|
||||
source,
|
||||
&rec_extents,
|
||||
&surface->source_region_id);
|
||||
&surface->source_region_id,
|
||||
CAIRO_ANALYSIS_SOURCE_SHOW_GLYPHS);
|
||||
_cairo_rectangle_intersect (&extents, &rec_extents);
|
||||
}
|
||||
|
||||
|
|
@ -839,6 +883,25 @@ _cairo_analysis_surface_supports_color_glyph (void *abstract_sur
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
_cairo_analysis_surface_command_id (void *abstract_surface,
|
||||
unsigned int recording_id,
|
||||
unsigned int command_id)
|
||||
{
|
||||
cairo_analysis_surface_t *surface = abstract_surface;
|
||||
cairo_int_status_t backend_status;
|
||||
|
||||
backend_status = CAIRO_INT_STATUS_SUCCESS;
|
||||
if (surface->target->backend->command_id != NULL) {
|
||||
backend_status =
|
||||
surface->target->backend->command_id (surface->target,
|
||||
recording_id,
|
||||
command_id);
|
||||
}
|
||||
|
||||
return backend_status;
|
||||
}
|
||||
|
||||
static const cairo_surface_backend_t cairo_analysis_surface_backend = {
|
||||
CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
|
||||
|
||||
|
|
@ -874,7 +937,9 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = {
|
|||
_cairo_analysis_surface_show_text_glyphs,
|
||||
NULL, /* get_supported_mime_types */
|
||||
_cairo_analysis_surface_tag,
|
||||
_cairo_analysis_surface_supports_color_glyph
|
||||
_cairo_analysis_surface_supports_color_glyph,
|
||||
NULL, /* analyze_recording_surface */
|
||||
_cairo_analysis_surface_command_id,
|
||||
};
|
||||
|
||||
cairo_surface_t *
|
||||
|
|
@ -1135,7 +1200,12 @@ static const cairo_surface_backend_t cairo_null_surface_backend = {
|
|||
NULL, /* fill_stroke */
|
||||
_show_glyphs_return_success, /* show_glyphs */
|
||||
NULL, /* has_show_text_glyphs */
|
||||
NULL /* show_text_glyphs */
|
||||
NULL, /* show_text_glyphs */
|
||||
NULL, /* get_supported_mime_types */
|
||||
NULL, /* tag */
|
||||
NULL, /* supports_color_glyph */
|
||||
NULL, /* analyze_recording_surface */
|
||||
NULL, /* command_id*/
|
||||
};
|
||||
|
||||
cairo_surface_t *
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
|
||||
/* cairo - a vector graphics library with display and print output
|
||||
*
|
||||
* Copyright © 2002 University of Southern California
|
||||
|
|
@ -88,6 +89,12 @@ _cairo_array_size (const cairo_array_t *array);
|
|||
cairo_private void
|
||||
_cairo_array_sort (const cairo_array_t *array, int (*compar)(const void *, const void *));
|
||||
|
||||
cairo_private cairo_bool_t
|
||||
_cairo_array_pop_element (cairo_array_t *array, void *dst);
|
||||
|
||||
cairo_private void *
|
||||
_cairo_array_last_element (cairo_array_t *array);
|
||||
|
||||
CAIRO_END_DECLS
|
||||
|
||||
#endif /* CAIRO_ARRAY_PRIVATE_H */
|
||||
|
|
|
|||
|
|
@ -542,3 +542,39 @@ _cairo_array_sort (const cairo_array_t *array, int (*compar)(const void *, const
|
|||
{
|
||||
qsort (array->elements, array->num_elements, array->element_size, compar);
|
||||
}
|
||||
|
||||
/**
|
||||
* _cairo_array_pop_element:
|
||||
* @array: a #cairo_array_t
|
||||
* Returns: A TRUE if element successfully popped, FALSE if the array is empty.
|
||||
*
|
||||
* Copy the last element out of the array from index @index into the
|
||||
* location pointed to by @dst and remove the element from the array.
|
||||
**/
|
||||
cairo_bool_t
|
||||
_cairo_array_pop_element (cairo_array_t *array, void *dst)
|
||||
{
|
||||
if (array->num_elements > 0) {
|
||||
_cairo_array_copy_element (array, array->num_elements - 1, dst);
|
||||
array->num_elements--;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* _cairo_array_top_element:
|
||||
* @array: a #cairo_array_t
|
||||
* Returns: A pointer to the last of object or NULL if array is empty.
|
||||
*
|
||||
* Get the pointer to the last element of of the array.
|
||||
**/
|
||||
void *
|
||||
_cairo_array_last_element (cairo_array_t *array)
|
||||
{
|
||||
if (array->num_elements > 0)
|
||||
return _cairo_array_index (array, array->num_elements - 1);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1225,7 +1225,7 @@ _pixman_image_for_recording (cairo_image_surface_t *dst,
|
|||
|
||||
/* Handle recursion by returning future reads from the current image */
|
||||
proxy = attach_proxy (source, clone);
|
||||
status = _cairo_recording_surface_replay_with_clip (source, m, clone, NULL, FALSE);
|
||||
status = _cairo_recording_surface_replay_with_clip (source, m, clone, NULL);
|
||||
if (clone->foreground_used)
|
||||
dst->base.foreground_used = clone->foreground_used;
|
||||
detach_proxy (source, proxy);
|
||||
|
|
|
|||
|
|
@ -403,6 +403,7 @@ _paint_page (cairo_paginated_surface_t *surface)
|
|||
cairo_int_status_t status;
|
||||
cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback;
|
||||
unsigned int regions_id = 0;
|
||||
cairo_bool_t replay_all;
|
||||
|
||||
if (unlikely (surface->target->status))
|
||||
return surface->target->status;
|
||||
|
|
@ -416,13 +417,20 @@ _paint_page (cairo_paginated_surface_t *surface)
|
|||
if (unlikely (status))
|
||||
goto FAIL;
|
||||
|
||||
replay_all = FALSE;
|
||||
if (surface->target->backend->analyze_recording_surface &&
|
||||
_cairo_recording_surface_has_tags (surface->recording_surface))
|
||||
{
|
||||
replay_all = TRUE;
|
||||
}
|
||||
|
||||
status = _cairo_recording_surface_region_array_attach (surface->recording_surface, ®ions_id);
|
||||
if (status)
|
||||
goto FAIL;
|
||||
|
||||
status = _cairo_recording_surface_replay_and_create_regions (surface->recording_surface,
|
||||
regions_id,
|
||||
NULL, analysis, FALSE);
|
||||
NULL, analysis, FALSE, replay_all);
|
||||
if (status)
|
||||
goto FAIL;
|
||||
|
||||
|
|
@ -467,12 +475,12 @@ _paint_page (cairo_paginated_surface_t *surface)
|
|||
has_finegrained_fallback = FALSE;
|
||||
}
|
||||
|
||||
if (has_supported) {
|
||||
status = surface->backend->set_paginated_mode (surface->target,
|
||||
CAIRO_PAGINATED_MODE_RENDER);
|
||||
if (unlikely (status))
|
||||
goto FAIL;
|
||||
|
||||
if (has_supported) {
|
||||
status = _cairo_recording_surface_replay_region (surface->recording_surface,
|
||||
regions_id,
|
||||
NULL,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1568,10 +1568,16 @@ _cairo_pdf_operators_tag_begin (cairo_pdf_operators_t *pdf_operators,
|
|||
return status;
|
||||
}
|
||||
|
||||
if (mcid >= 0) {
|
||||
_cairo_output_stream_printf (pdf_operators->stream,
|
||||
"/%s << /MCID %d >> BDC\n",
|
||||
tag_name,
|
||||
mcid);
|
||||
} else {
|
||||
_cairo_output_stream_printf (pdf_operators->stream,
|
||||
"/%s BMC\n",
|
||||
tag_name);
|
||||
}
|
||||
|
||||
return _cairo_output_stream_get_status (pdf_operators->stream);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,10 @@ typedef struct _cairo_pdf_source_surface_entry {
|
|||
unsigned char *unique_id;
|
||||
unsigned long unique_id_length;
|
||||
cairo_operator_t operator;
|
||||
|
||||
/* If not 0, this is the recording surface region id of the source surface. */
|
||||
int region_id;
|
||||
|
||||
cairo_bool_t interpolate;
|
||||
cairo_bool_t stencil_mask;
|
||||
cairo_bool_t smask;
|
||||
|
|
@ -110,6 +114,9 @@ typedef struct _cairo_pdf_pattern {
|
|||
cairo_operator_t operator;
|
||||
cairo_bool_t is_shading;
|
||||
|
||||
/* Index into nodes array in cairo_pdf_surface_node_entry_t or -1 if not used */
|
||||
int region_id;
|
||||
|
||||
/* PDF pattern space is the pattern matrix concatenated with the
|
||||
* initial space of the parent object. If the parent object is the
|
||||
* page, the initial space does not include the Y-axis flipping
|
||||
|
|
@ -161,38 +168,87 @@ typedef struct _cairo_pdf_jbig2_global {
|
|||
cairo_bool_t emitted;
|
||||
} cairo_pdf_jbig2_global_t;
|
||||
|
||||
typedef struct _cairo_pdf_page_info {
|
||||
double width;
|
||||
double height;
|
||||
cairo_pdf_resource_t page_res;
|
||||
cairo_pdf_resource_t content;
|
||||
cairo_pdf_resource_t resources;
|
||||
cairo_pdf_resource_t thumbnail;
|
||||
cairo_array_t annots; /* <cairo_pdf_resource_t> */
|
||||
int struct_parents;
|
||||
} cairo_pdf_page_info_t;
|
||||
|
||||
|
||||
/* cairo-pdf-interchange.c types */
|
||||
|
||||
struct page_mcid {
|
||||
int page;
|
||||
int mcid;
|
||||
};
|
||||
|
||||
struct tag_extents {
|
||||
typedef struct _pdf_tag_extents {
|
||||
cairo_rectangle_int_t extents;
|
||||
cairo_bool_t valid;
|
||||
cairo_list_t link;
|
||||
};
|
||||
} cairo_pdf_tag_extents_t;
|
||||
|
||||
typedef struct _pdf_page_mcid {
|
||||
int order;
|
||||
int page;
|
||||
cairo_pdf_resource_t xobject_res; /* 0 if not in an XObject */
|
||||
int mcid;
|
||||
struct _cairo_pdf_struct_tree_node *child_node;
|
||||
} cairo_pdf_page_mcid_t;
|
||||
|
||||
/* The non PDF_NODE_STRUCT types are excluded from the struct tree embedded in
|
||||
* the PDF. */
|
||||
typedef enum _cairo_pdf_tree_node_type {
|
||||
PDF_NODE_STRUCT,
|
||||
PDF_NODE_CONTENT,
|
||||
PDF_NODE_CONTENT_REF,
|
||||
PDF_NODE_ARTIFACT,
|
||||
} cairo_pdf_tree_node_type_t;
|
||||
|
||||
typedef struct _cairo_pdf_struct_tree_node {
|
||||
cairo_hash_entry_t hash;
|
||||
cairo_pdf_tree_node_type_t type;
|
||||
char *name;
|
||||
cairo_pdf_resource_t res;
|
||||
struct _cairo_pdf_struct_tree_node *parent;
|
||||
cairo_list_t children;
|
||||
cairo_array_t mcid; /* array of struct page_mcid */
|
||||
cairo_pdf_resource_t annot_res; /* 0 if no annot */
|
||||
struct tag_extents extents;
|
||||
cairo_list_t link;
|
||||
cairo_array_t mcid; /* array of cairo_pdf_page_mcid_t */
|
||||
struct _cairo_pdf_annotation *annot;
|
||||
cairo_pdf_tag_extents_t extents;
|
||||
|
||||
union {
|
||||
cairo_content_attrs_t content; /* type == PDF_NODE_CONTENT */
|
||||
cairo_content_ref_attrs_t content_ref; /* type == PDF_NODE_CONTENT_REF */
|
||||
} attributes;
|
||||
|
||||
cairo_list_t link; /* linked list of parent's children */
|
||||
} cairo_pdf_struct_tree_node_t;
|
||||
|
||||
typedef struct _cairo_pdf_command_entry {
|
||||
cairo_hash_entry_t base;
|
||||
unsigned int recording_id;
|
||||
unsigned int command_id;
|
||||
cairo_pdf_struct_tree_node_t *node;
|
||||
} cairo_pdf_command_entry_t;
|
||||
|
||||
typedef struct _cairo_recording_surface_stack_entry {
|
||||
cairo_bool_t ignore_surface;
|
||||
cairo_pdf_struct_tree_node_t *current_node;
|
||||
} cairo_recording_surface_stack_entry_t;
|
||||
|
||||
typedef struct _cairo_pdf_content_tag {
|
||||
cairo_hash_entry_t base;
|
||||
cairo_pdf_struct_tree_node_t *node;
|
||||
} cairo_pdf_content_tag_t;
|
||||
|
||||
typedef struct _cairo_pdf_annotation {
|
||||
cairo_pdf_struct_tree_node_t *node; /* node containing the annotation */
|
||||
cairo_link_attrs_t link_attrs;
|
||||
cairo_pdf_resource_t res;
|
||||
} cairo_pdf_annotation_t;
|
||||
|
||||
typedef struct _cairo_pdf_named_dest {
|
||||
cairo_hash_entry_t base;
|
||||
struct tag_extents extents;
|
||||
cairo_pdf_tag_extents_t extents;
|
||||
cairo_dest_attrs_t attrs;
|
||||
int page;
|
||||
} cairo_pdf_named_dest_t;
|
||||
|
|
@ -233,19 +289,65 @@ struct metadata {
|
|||
char *value;
|
||||
};
|
||||
|
||||
typedef enum _cairo_pdf_operation_flags_t {
|
||||
PDF_NONE = 0,
|
||||
PDF_CONTENT,
|
||||
PDF_BEGIN,
|
||||
PDF_END,
|
||||
PDF_GROUP,
|
||||
} cairo_pdf_operation_flags_t;
|
||||
|
||||
typedef struct _pdf_command_list {
|
||||
cairo_array_t commands;
|
||||
struct _pdf_command_list *parent;
|
||||
} cairo_pdf_command_list_t;
|
||||
|
||||
typedef struct _pdf_operation {
|
||||
cairo_pdf_command_list_t *group;
|
||||
cairo_pdf_struct_tree_node_t *node;
|
||||
unsigned int command_id;
|
||||
int mcid_index;
|
||||
cairo_pdf_operation_flags_t flags;
|
||||
} cairo_pdf_command_t;
|
||||
|
||||
typedef struct _pdf_recording_surface_commands {
|
||||
cairo_surface_t *recording_surface;
|
||||
cairo_pdf_command_list_t *command_list;
|
||||
unsigned int region_id;
|
||||
} cairo_pdf_recording_surface_commands_t;
|
||||
|
||||
typedef struct _cairo_pdf_interchange {
|
||||
cairo_tag_stack_t analysis_tag_stack;
|
||||
cairo_tag_stack_t render_tag_stack;
|
||||
cairo_array_t push_data; /* records analysis_tag_stack data field for each push */
|
||||
int push_data_index;
|
||||
cairo_pdf_struct_tree_node_t *struct_root;
|
||||
cairo_pdf_struct_tree_node_t *current_node;
|
||||
cairo_pdf_struct_tree_node_t *begin_page_node;
|
||||
cairo_pdf_struct_tree_node_t *end_page_node;
|
||||
cairo_array_t parent_tree; /* parent tree resources */
|
||||
cairo_array_t mcid_to_tree; /* mcid to tree node mapping for current page */
|
||||
|
||||
/* Current position in the tree during the analysis stage and across
|
||||
* pages as each page adds to the tree */
|
||||
cairo_pdf_struct_tree_node_t *current_analyze_node;
|
||||
|
||||
/* Currently open tag content containing content. NULL if no content tag open.
|
||||
* A content containg tag may be open across pages */
|
||||
cairo_pdf_struct_tree_node_t *current_render_node;
|
||||
cairo_pdf_struct_tree_node_t *next_page_render_node;
|
||||
|
||||
cairo_array_t recording_surface_stack; /* cairo_recording_surface_stack_entry_t */
|
||||
cairo_pdf_resource_t current_recording_surface_res;
|
||||
cairo_hash_table_t *command_to_node_map; /* <cairo_pdf_surface_node_entry_t> */
|
||||
cairo_bool_t ignore_current_surface;
|
||||
cairo_hash_table_t *content_tag_map; /* <char*,cairo_pdf_content_tag_t> */
|
||||
|
||||
cairo_array_t parent_tree; /* <cairo_pdf_resource_t> */
|
||||
cairo_array_t annots; /* array of pointers to cairo_pdf_annotation_t */
|
||||
cairo_pdf_resource_t content_parent_res;
|
||||
cairo_pdf_resource_t parent_tree_res;
|
||||
|
||||
/* mcid to tree node for current page or group */
|
||||
cairo_array_t mcid_to_tree; /* <cairo_pdf_struct_tree_node_t *> */
|
||||
|
||||
cairo_array_t page_commands; /* <cairo_pdf_command_list_t> */
|
||||
cairo_pdf_command_list_t *current_commands; /* <cairo_pdf_command_list_t> */
|
||||
cairo_array_t recording_surface_commands; /* <cairo_pdf_recording_surface_commands_t> */
|
||||
|
||||
cairo_list_t extents_list;
|
||||
cairo_hash_table_t *named_dests;
|
||||
int num_dests;
|
||||
|
|
@ -255,6 +357,12 @@ typedef struct _cairo_pdf_interchange {
|
|||
cairo_array_t outline; /* array of pointers to cairo_pdf_outline_entry_t; */
|
||||
struct docinfo docinfo;
|
||||
cairo_array_t custom_metadata; /* array of struct metadata */
|
||||
cairo_bool_t content_emitted;
|
||||
cairo_bool_t marked_content_open;
|
||||
unsigned int recording_id;
|
||||
unsigned int command_id;
|
||||
cairo_bool_t render_next_command_has_content;
|
||||
int mcid_order;
|
||||
|
||||
} cairo_pdf_interchange_t;
|
||||
|
||||
|
|
@ -283,18 +391,18 @@ struct _cairo_pdf_surface {
|
|||
cairo_matrix_t cairo_to_pdf;
|
||||
cairo_bool_t in_xobject;
|
||||
|
||||
cairo_array_t objects;
|
||||
cairo_array_t pages;
|
||||
cairo_array_t objects; /* cairo_pdf_resource_t - list of every resource in the PDF */
|
||||
cairo_array_t pages; /* <cairo_pdf_page_info_t> */
|
||||
cairo_array_t rgb_linear_functions;
|
||||
cairo_array_t alpha_linear_functions;
|
||||
cairo_array_t page_patterns; /* cairo_pdf_pattern_t */
|
||||
cairo_array_t page_surfaces; /* cairo_pdf_source_surface_t */
|
||||
cairo_array_t doc_surfaces; /* cairo_pdf_source_surface_t */
|
||||
cairo_hash_table_t *all_surfaces;
|
||||
cairo_hash_table_t *all_surfaces; /* cairo_pdf_source_surface_entry_t* */
|
||||
int duplicate_surface_number;
|
||||
cairo_array_t smask_groups;
|
||||
cairo_array_t knockout_group;
|
||||
cairo_array_t jbig2_global;
|
||||
cairo_array_t page_heights;
|
||||
cairo_hash_table_t *color_glyphs;
|
||||
|
||||
cairo_scaled_font_subsets_t *font_subsets;
|
||||
|
|
@ -374,6 +482,8 @@ struct _cairo_pdf_surface {
|
|||
cairo_image_surface_t *thumbnail_image;
|
||||
|
||||
cairo_surface_t *paginated_surface;
|
||||
|
||||
cairo_bool_t debug;
|
||||
};
|
||||
|
||||
cairo_private cairo_pdf_resource_t
|
||||
|
|
@ -410,14 +520,55 @@ _cairo_pdf_surface_object_begin (cairo_pdf_surface_t *surface,
|
|||
cairo_private void
|
||||
_cairo_pdf_surface_object_end (cairo_pdf_surface_t *surface);
|
||||
|
||||
cairo_private cairo_bool_t
|
||||
_cairo_pdf_interchange_struct_tree_requires_recording_surface (
|
||||
cairo_pdf_surface_t *surface,
|
||||
const cairo_surface_pattern_t *recording_surface,
|
||||
cairo_analysis_source_t source_type);
|
||||
|
||||
cairo_private cairo_int_status_t
|
||||
_cairo_pdf_interchange_recording_source_surface_begin (
|
||||
cairo_pdf_surface_t *surface,
|
||||
const cairo_surface_pattern_t *recording_surface_pattern,
|
||||
unsigned int region_id,
|
||||
cairo_analysis_source_t source_type);
|
||||
|
||||
cairo_private cairo_int_status_t
|
||||
_cairo_pdf_interchange_recording_source_surface_end (
|
||||
cairo_pdf_surface_t *surface,
|
||||
const cairo_surface_pattern_t *recording_surface_pattern,
|
||||
unsigned int region_id,
|
||||
cairo_analysis_source_t source_type);
|
||||
|
||||
cairo_private cairo_int_status_t
|
||||
_cairo_pdf_interchange_emit_recording_surface_begin (
|
||||
cairo_pdf_surface_t *surface,
|
||||
cairo_surface_t *recording_surface,
|
||||
int region_id,
|
||||
cairo_pdf_resource_t surface_resource,
|
||||
int *struct_parents);
|
||||
|
||||
cairo_private cairo_int_status_t
|
||||
_cairo_pdf_interchange_emit_recording_surface_end (
|
||||
cairo_pdf_surface_t *surface,
|
||||
cairo_surface_t *recording_surface);
|
||||
|
||||
cairo_private cairo_int_status_t
|
||||
_cairo_pdf_interchange_tag_end (cairo_pdf_surface_t *surface,
|
||||
const char *name);
|
||||
|
||||
cairo_private cairo_int_status_t
|
||||
_cairo_pdf_interchange_command_id (cairo_pdf_surface_t *surface,
|
||||
unsigned int recording_id,
|
||||
unsigned int command_id);
|
||||
|
||||
cairo_private cairo_int_status_t
|
||||
_cairo_pdf_interchange_add_operation_extents (cairo_pdf_surface_t *surface,
|
||||
const cairo_rectangle_int_t *extents);
|
||||
|
||||
cairo_private cairo_int_status_t
|
||||
_cairo_pdf_interchange_add_content (cairo_pdf_surface_t *surface);
|
||||
|
||||
cairo_private cairo_int_status_t
|
||||
_cairo_pdf_interchange_write_page_objects (cairo_pdf_surface_t *surface);
|
||||
|
||||
|
|
|
|||
|
|
@ -471,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));
|
||||
|
|
@ -482,7 +482,6 @@ _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);
|
||||
|
|
@ -495,6 +494,8 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
|
|||
goto BAIL1;
|
||||
}
|
||||
|
||||
surface->duplicate_surface_number = 0;
|
||||
|
||||
_cairo_pdf_group_resources_init (&surface->resources);
|
||||
|
||||
surface->font_subsets = _cairo_scaled_font_subsets_create_composite ();
|
||||
|
|
@ -565,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,
|
||||
|
|
@ -1457,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);
|
||||
|
||||
|
|
@ -1472,6 +1479,9 @@ _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
|
||||
|
|
@ -1601,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
|
||||
|
|
@ -1628,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,
|
||||
|
|
@ -1653,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:
|
||||
|
|
@ -1700,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) {
|
||||
|
|
@ -1746,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;
|
||||
|
|
@ -1810,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))
|
||||
|
|
@ -1858,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,
|
||||
|
|
@ -1865,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;
|
||||
|
|
@ -1923,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);
|
||||
|
|
@ -1954,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,
|
||||
|
|
@ -1964,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)
|
||||
|
|
@ -1971,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,
|
||||
|
|
@ -2242,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;
|
||||
}
|
||||
|
|
@ -2249,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);
|
||||
|
|
@ -2305,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;
|
||||
|
|
@ -2427,9 +2472,11 @@ _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;
|
||||
char buf[1000];
|
||||
|
||||
assert (surface->pdf_stream.active == FALSE);
|
||||
assert (surface->group_stream.active == FALSE);
|
||||
|
|
@ -2442,10 +2489,8 @@ _cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t *surface,
|
|||
assert (bbox != NULL);
|
||||
|
||||
if (is_group) {
|
||||
status =
|
||||
_cairo_pdf_surface_open_stream (surface,
|
||||
resource,
|
||||
surface->compress_streams,
|
||||
snprintf(buf,
|
||||
sizeof(buf),
|
||||
" /Type /XObject\n"
|
||||
" /Subtype /Form\n"
|
||||
" /BBox [ %f %f %f %f ]\n"
|
||||
|
|
@ -2462,10 +2507,8 @@ _cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t *surface,
|
|||
bbox->p2.y,
|
||||
surface->content_resources.id);
|
||||
} else {
|
||||
status =
|
||||
_cairo_pdf_surface_open_stream (surface,
|
||||
resource,
|
||||
surface->compress_streams,
|
||||
snprintf(buf,
|
||||
sizeof(buf),
|
||||
" /Type /XObject\n"
|
||||
" /Subtype /Form\n"
|
||||
" /BBox [ %f %f %f %f ]\n"
|
||||
|
|
@ -2476,6 +2519,16 @@ _cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t *surface,
|
|||
bbox->p2.y,
|
||||
surface->content_resources.id);
|
||||
}
|
||||
if (struct_parents >= 0) {
|
||||
snprintf(buf + strlen(buf),
|
||||
sizeof(buf) - strlen(buf),
|
||||
" /StructParents %d\n", struct_parents);
|
||||
}
|
||||
status =
|
||||
_cairo_pdf_surface_open_stream (surface,
|
||||
resource,
|
||||
surface->compress_streams,
|
||||
buf);
|
||||
} else {
|
||||
status =
|
||||
_cairo_pdf_surface_open_stream (surface,
|
||||
|
|
@ -2550,6 +2603,73 @@ _cairo_pdf_color_glyph_pluck (void *entry, void *closure)
|
|||
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)
|
||||
{
|
||||
|
|
@ -2594,6 +2714,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);
|
||||
|
|
@ -2606,7 +2730,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,
|
||||
|
|
@ -2669,6 +2793,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);
|
||||
|
|
@ -2705,7 +2834,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++) {
|
||||
|
|
@ -2725,7 +2853,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 */
|
||||
|
|
@ -2758,11 +2886,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;
|
||||
|
||||
|
|
@ -2777,13 +2913,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;
|
||||
|
||||
|
|
@ -2883,6 +3023,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 */
|
||||
|
|
@ -3722,6 +3863,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);
|
||||
|
||||
|
|
@ -3780,11 +3922,20 @@ _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;
|
||||
|
||||
|
|
@ -3823,6 +3974,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);
|
||||
|
|
@ -3964,6 +4119,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 */
|
||||
|
|
@ -5108,6 +5264,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,
|
||||
|
|
@ -5119,6 +5276,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 &&
|
||||
|
|
@ -5132,9 +5290,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,
|
||||
|
|
@ -5269,6 +5437,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)
|
||||
|
|
@ -5279,6 +5448,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,
|
||||
|
|
@ -5474,10 +5644,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;
|
||||
|
|
@ -5530,7 +5696,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;
|
||||
|
||||
|
|
@ -5544,8 +5710,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");
|
||||
|
|
@ -6605,7 +6771,7 @@ cairo_pdf_surface_emit_color_glyph (cairo_pdf_surface_t *surface,
|
|||
goto cleanup;
|
||||
|
||||
status = _cairo_recording_surface_replay_and_create_regions (glyph_surface, regions_id,
|
||||
NULL, analysis, TRUE);
|
||||
NULL, analysis, TRUE, FALSE);
|
||||
if (status)
|
||||
goto cleanup;
|
||||
|
||||
|
|
@ -6667,6 +6833,7 @@ cairo_pdf_surface_emit_color_glyph (cairo_pdf_surface_t *surface,
|
|||
_cairo_pdf_surface_paint_surface_pattern (surface,
|
||||
CAIRO_OPERATOR_OVER,
|
||||
&surface_pattern.base,
|
||||
CAIRO_ANALYSIS_SOURCE_NONE,
|
||||
&extents,
|
||||
1.0, /* alpha */
|
||||
NULL, /* smask_res */
|
||||
|
|
@ -6738,6 +6905,7 @@ cairo_pdf_surface_emit_color_glyph_image (cairo_pdf_surface_t *surface,
|
|||
_cairo_pdf_surface_paint_surface_pattern (surface,
|
||||
CAIRO_OPERATOR_OVER,
|
||||
image_pattern,
|
||||
CAIRO_ANALYSIS_SOURCE_NONE,
|
||||
&extents,
|
||||
1.0, /* alpha */
|
||||
NULL, /* smask_res */
|
||||
|
|
@ -7267,6 +7435,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 */
|
||||
|
|
@ -7279,6 +7448,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))
|
||||
|
|
@ -7344,6 +7514,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 */
|
||||
|
|
@ -7356,6 +7527,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))
|
||||
|
|
@ -7593,10 +7765,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))
|
||||
|
|
@ -7642,7 +7816,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;
|
||||
|
||||
|
|
@ -7658,70 +7832,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))
|
||||
|
|
@ -7968,7 +8090,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;
|
||||
|
||||
|
|
@ -8115,6 +8237,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 */
|
||||
|
|
@ -8135,7 +8258,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);
|
||||
|
|
@ -8200,7 +8325,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;
|
||||
|
||||
|
|
@ -8282,6 +8409,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 */
|
||||
|
|
@ -8296,6 +8424,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))
|
||||
|
|
@ -8467,6 +8596,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 */
|
||||
|
|
@ -8596,6 +8726,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))
|
||||
|
|
@ -8754,6 +8885,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 */
|
||||
|
|
@ -8768,6 +8900,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))
|
||||
|
|
@ -8947,6 +9080,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);
|
||||
|
|
@ -8960,6 +9094,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);
|
||||
|
|
@ -9038,6 +9173,10 @@ _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;
|
||||
|
|
@ -9063,6 +9202,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))
|
||||
|
|
@ -9191,9 +9331,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);
|
||||
|
|
@ -9203,6 +9344,16 @@ _cairo_pdf_surface_tag (void *abstract_surface,
|
|||
return status;
|
||||
}
|
||||
|
||||
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
|
||||
|
|
@ -9265,6 +9416,33 @@ _cairo_pdf_surface_supports_color_glyph (void *abstract_surface
|
|||
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)
|
||||
|
|
@ -9273,6 +9451,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;
|
||||
|
|
@ -9324,6 +9503,8 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = {
|
|||
_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
|
||||
|
|
|
|||
|
|
@ -722,8 +722,7 @@ _cairo_surface_to_cgimage (cairo_surface_t *source,
|
|||
status = _cairo_recording_surface_replay_with_clip (source,
|
||||
matrix,
|
||||
&surface->base,
|
||||
NULL,
|
||||
FALSE);
|
||||
NULL);
|
||||
if (unlikely (status)) {
|
||||
cairo_surface_destroy (&surface->base);
|
||||
return status;
|
||||
|
|
|
|||
|
|
@ -155,6 +155,7 @@ typedef struct _cairo_recording_surface {
|
|||
cairo_bool_t optimize_clears;
|
||||
cairo_bool_t has_bilevel_alpha;
|
||||
cairo_bool_t has_only_op_over;
|
||||
cairo_bool_t has_tags;
|
||||
|
||||
struct bbtree {
|
||||
cairo_box_t extents;
|
||||
|
|
@ -203,19 +204,27 @@ _cairo_recording_surface_replay_with_foreground_color (cairo_surface_t *surf
|
|||
const cairo_color_t *foreground_color,
|
||||
cairo_bool_t *foreground_used);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_recording_surface_replay_with_transform (cairo_surface_t *surface,
|
||||
const cairo_matrix_t *surface_transform,
|
||||
cairo_surface_t *target,
|
||||
cairo_bool_t surface_is_unbounded,
|
||||
cairo_bool_t replay_all);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_recording_surface_replay_with_clip (cairo_surface_t *surface,
|
||||
const cairo_matrix_t *surface_transform,
|
||||
cairo_surface_t *target,
|
||||
const cairo_clip_t *target_clip,
|
||||
cairo_bool_t surface_is_unbounded);
|
||||
const cairo_clip_t *target_clip);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
|
||||
unsigned int regions_id,
|
||||
const cairo_matrix_t *surface_transform,
|
||||
cairo_surface_t *target,
|
||||
cairo_bool_t surface_is_unbounded);
|
||||
cairo_bool_t surface_is_unbounded,
|
||||
cairo_bool_t replay_all);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_recording_surface_replay_region (cairo_surface_t *surface,
|
||||
unsigned int regions_id,
|
||||
|
|
@ -239,6 +248,9 @@ _cairo_recording_surface_has_only_bilevel_alpha (cairo_recording_surface_t *surf
|
|||
cairo_private cairo_bool_t
|
||||
_cairo_recording_surface_has_only_op_over (cairo_recording_surface_t *surface);
|
||||
|
||||
cairo_private cairo_bool_t
|
||||
_cairo_recording_surface_has_tags (cairo_surface_t *surface);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_recording_surface_region_array_attach (cairo_surface_t *surface,
|
||||
unsigned int *id);
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ typedef struct _cairo_recording_surface_replay_params {
|
|||
unsigned int regions_id;
|
||||
const cairo_color_t *foreground_color;
|
||||
cairo_bool_t foreground_used;
|
||||
cairo_bool_t replay_all;
|
||||
} cairo_recording_surface_replay_params_t;
|
||||
|
||||
static const cairo_surface_backend_t cairo_recording_surface_backend;
|
||||
|
|
@ -436,6 +437,7 @@ cairo_recording_surface_create (cairo_content_t content,
|
|||
surface->optimize_clears = TRUE;
|
||||
surface->has_bilevel_alpha = FALSE;
|
||||
surface->has_only_op_over = FALSE;
|
||||
surface->has_tags = FALSE;
|
||||
|
||||
CAIRO_MUTEX_INIT (surface->mutex);
|
||||
|
||||
|
|
@ -1190,6 +1192,8 @@ _cairo_recording_surface_tag (void *abstract_surface,
|
|||
|
||||
TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id));
|
||||
|
||||
surface->has_tags = TRUE;
|
||||
|
||||
command = calloc (1, sizeof (cairo_command_tag_t));
|
||||
if (unlikely (command == NULL)) {
|
||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
|
|
@ -1635,6 +1639,7 @@ _cairo_recording_surface_snapshot (void *abstract_other)
|
|||
surface->unbounded = other->unbounded;
|
||||
surface->has_bilevel_alpha = other->has_bilevel_alpha;
|
||||
surface->has_only_op_over = other->has_only_op_over;
|
||||
surface->has_tags = other->has_tags;
|
||||
|
||||
surface->base.is_clear = other->base.is_clear;
|
||||
|
||||
|
|
@ -1644,8 +1649,6 @@ _cairo_recording_surface_snapshot (void *abstract_other)
|
|||
surface->indices = NULL;
|
||||
surface->num_indices = 0;
|
||||
surface->optimize_clears = TRUE;
|
||||
surface->has_bilevel_alpha = other->has_bilevel_alpha;
|
||||
surface->has_only_op_over = other->has_only_op_over;
|
||||
|
||||
CAIRO_MUTEX_INIT (surface->mutex);
|
||||
|
||||
|
|
@ -1715,6 +1718,8 @@ static const cairo_surface_backend_t cairo_recording_surface_backend = {
|
|||
NULL, /* get_supported_mime_types */
|
||||
_cairo_recording_surface_tag,
|
||||
_cairo_recording_surface_supports_color_glyph,
|
||||
NULL, /* analyze_recording_surface */
|
||||
NULL, /* command_id */
|
||||
};
|
||||
|
||||
static unsigned int
|
||||
|
|
@ -2078,7 +2083,7 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
|
|||
if (regions_array)
|
||||
region_elements = _cairo_array_index (®ions_array->regions, 0);
|
||||
|
||||
if (extents.width < r->width || extents.height < r->height) {
|
||||
if (!params->replay_all && (extents.width < r->width || extents.height < r->height)) {
|
||||
num_elements =
|
||||
_cairo_recording_surface_get_visible_commands (surface, &extents);
|
||||
use_indices = num_elements != surface->commands.num_elements;
|
||||
|
|
@ -2106,6 +2111,13 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
|
|||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (params->target->backend->command_id) {
|
||||
status = params->target->backend->command_id (params->target, params->regions_id, i);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
}
|
||||
|
||||
switch (command->header.type) {
|
||||
case CAIRO_COMMAND_PAINT:
|
||||
if (region_element)
|
||||
|
|
@ -2457,6 +2469,7 @@ _cairo_recording_surface_replay (cairo_surface_t *surface,
|
|||
params.region = CAIRO_RECORDING_REGION_ALL;
|
||||
params.regions_id = 0;
|
||||
params.foreground_color = NULL;
|
||||
params.replay_all = FALSE;
|
||||
|
||||
return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, ¶ms);
|
||||
}
|
||||
|
|
@ -2480,6 +2493,7 @@ _cairo_recording_surface_replay_with_foreground_color (cairo_surface_t *surf
|
|||
params.regions_id = 0;
|
||||
params.foreground_color = foreground_color;
|
||||
params.foreground_used = FALSE;
|
||||
params.replay_all = FALSE;
|
||||
|
||||
status = _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, ¶ms);
|
||||
*foreground_used = params.foreground_used;
|
||||
|
|
@ -2487,12 +2501,34 @@ _cairo_recording_surface_replay_with_foreground_color (cairo_surface_t *surf
|
|||
return status;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_recording_surface_replay_with_transform (cairo_surface_t *surface,
|
||||
const cairo_matrix_t *surface_transform,
|
||||
cairo_surface_t *target,
|
||||
cairo_bool_t surface_is_unbounded,
|
||||
cairo_bool_t replay_all)
|
||||
{
|
||||
cairo_recording_surface_replay_params_t params;
|
||||
|
||||
params.surface_extents = NULL;
|
||||
params.surface_transform = surface_transform;
|
||||
params.target = target;
|
||||
params.target_clip = NULL;
|
||||
params.surface_is_unbounded = surface_is_unbounded;
|
||||
params.type = CAIRO_RECORDING_REPLAY;
|
||||
params.region = CAIRO_RECORDING_REGION_ALL;
|
||||
params.regions_id = 0;
|
||||
params.foreground_color = NULL;
|
||||
params.replay_all = replay_all;
|
||||
|
||||
return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, ¶ms);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_recording_surface_replay_with_clip (cairo_surface_t *surface,
|
||||
const cairo_matrix_t *surface_transform,
|
||||
cairo_surface_t *target,
|
||||
const cairo_clip_t *target_clip,
|
||||
cairo_bool_t surface_is_unbounded)
|
||||
const cairo_clip_t *target_clip)
|
||||
{
|
||||
cairo_recording_surface_replay_params_t params;
|
||||
|
||||
|
|
@ -2500,11 +2536,12 @@ _cairo_recording_surface_replay_with_clip (cairo_surface_t *surface,
|
|||
params.surface_transform = surface_transform;
|
||||
params.target = target;
|
||||
params.target_clip = target_clip;
|
||||
params.surface_is_unbounded = surface_is_unbounded;
|
||||
params.surface_is_unbounded = FALSE;
|
||||
params.type = CAIRO_RECORDING_REPLAY;
|
||||
params.region = CAIRO_RECORDING_REGION_ALL;
|
||||
params.regions_id = 0;
|
||||
params.foreground_color = NULL;
|
||||
params.replay_all = FALSE;
|
||||
|
||||
return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, ¶ms);
|
||||
}
|
||||
|
|
@ -2520,7 +2557,8 @@ _cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
|
|||
unsigned int regions_id,
|
||||
const cairo_matrix_t *surface_transform,
|
||||
cairo_surface_t *target,
|
||||
cairo_bool_t surface_is_unbounded)
|
||||
cairo_bool_t surface_is_unbounded,
|
||||
cairo_bool_t replay_all)
|
||||
{
|
||||
cairo_recording_surface_replay_params_t params;
|
||||
|
||||
|
|
@ -2533,6 +2571,7 @@ _cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
|
|||
params.region = CAIRO_RECORDING_REGION_ALL;
|
||||
params.regions_id = regions_id;
|
||||
params.foreground_color = NULL;
|
||||
params.replay_all = replay_all;
|
||||
|
||||
return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, ¶ms);
|
||||
}
|
||||
|
|
@ -2555,6 +2594,7 @@ _cairo_recording_surface_replay_region (cairo_surface_t *surface,
|
|||
params.region = region;
|
||||
params.regions_id = regions_id;
|
||||
params.foreground_color = NULL;
|
||||
params.replay_all = FALSE;
|
||||
|
||||
return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, ¶ms);
|
||||
}
|
||||
|
|
@ -2702,6 +2742,21 @@ _cairo_recording_surface_has_only_op_over (cairo_recording_surface_t *surface)
|
|||
return surface->has_only_op_over;
|
||||
}
|
||||
|
||||
cairo_bool_t
|
||||
_cairo_recording_surface_has_tags (cairo_surface_t *surface)
|
||||
{
|
||||
cairo_recording_surface_t *record;
|
||||
|
||||
if (surface->status || ! _cairo_surface_is_recording (surface)) {
|
||||
_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
record = (cairo_recording_surface_t *)surface;
|
||||
|
||||
return record->has_tags;
|
||||
}
|
||||
|
||||
static void
|
||||
print_indent (FILE *file, int indent)
|
||||
{
|
||||
|
|
@ -2875,7 +2930,10 @@ _cairo_debug_print_recording_surface (FILE *file,
|
|||
|
||||
case CAIRO_COMMAND_TAG:
|
||||
print_indent (file, indent);
|
||||
fprintf(file, "%d TAG\n", i);
|
||||
fprintf(file, "%d %s %s '%s'\n",
|
||||
i,
|
||||
command->tag.begin ? "BEGIN TAG" : "END TAG",
|
||||
command->tag.tag_name, command->tag.attributes);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -612,7 +612,7 @@ composite_aligned_boxes (const cairo_spans_compositor_t *compositor,
|
|||
|
||||
recording_clip = _cairo_clip_from_boxes (boxes);
|
||||
status = _cairo_recording_surface_replay_with_clip (unwrap_source (source),
|
||||
m, dst, recording_clip, FALSE);
|
||||
m, dst, recording_clip);
|
||||
_cairo_clip_destroy (recording_clip);
|
||||
|
||||
return status;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
|
||||
/* cairo - a vector graphics library with display and print output
|
||||
*
|
||||
* Copyright © 2002 University of Southern California
|
||||
|
|
@ -40,6 +41,7 @@
|
|||
|
||||
#include "cairo-compiler-private.h"
|
||||
#include "cairo-error-private.h"
|
||||
#include "cairo-pattern-private.h"
|
||||
|
||||
CAIRO_BEGIN_DECLS
|
||||
|
||||
|
|
@ -211,6 +213,29 @@ struct _cairo_surface_backend {
|
|||
(*supports_color_glyph) (void *surface,
|
||||
cairo_scaled_font_t *scaled_font,
|
||||
unsigned long glyph_index);
|
||||
|
||||
/* Paginated surfaces only. During the analysis stage, if any
|
||||
* recording surfaces used as a source are to be replayed, this
|
||||
* function will be called at the begining and end of the replay.
|
||||
*
|
||||
* @recording_surface - the recording surface used as a source
|
||||
* @source_type - a type indicating the combination of drawing
|
||||
* operation and source type
|
||||
* @begin - TRUE when called before the replay, FALSE when called
|
||||
* after the replay has finished.
|
||||
*/
|
||||
cairo_warn cairo_int_status_t
|
||||
(*analyze_recording_surface)(void *surface,
|
||||
const cairo_surface_pattern_t *recording_surface_pattern,
|
||||
unsigned int region_id,
|
||||
cairo_analysis_source_t source_type,
|
||||
cairo_bool_t begin);
|
||||
|
||||
cairo_warn cairo_int_status_t
|
||||
(*command_id) (void *surface,
|
||||
unsigned int recording_id,
|
||||
unsigned int command_id);
|
||||
|
||||
};
|
||||
|
||||
cairo_private cairo_status_t
|
||||
|
|
|
|||
|
|
@ -49,6 +49,15 @@ typedef enum {
|
|||
TAG_LINK_FILE,
|
||||
} cairo_tag_link_type_t;
|
||||
|
||||
typedef struct _cairo_content_attrs {
|
||||
char *id;
|
||||
char *tag_name;
|
||||
} cairo_content_attrs_t;
|
||||
|
||||
typedef struct _cairo_content_ref_attrs {
|
||||
char *ref;
|
||||
} cairo_content_ref_attrs_t;
|
||||
|
||||
typedef struct _cairo_link_attrs {
|
||||
cairo_tag_link_type_t link_type;
|
||||
cairo_array_t rects;
|
||||
|
|
@ -58,6 +67,9 @@ typedef struct _cairo_link_attrs {
|
|||
int page;
|
||||
cairo_bool_t has_pos;
|
||||
cairo_point_double_t pos;
|
||||
char *id;
|
||||
char *ref;
|
||||
int link_page;
|
||||
} cairo_link_attrs_t;
|
||||
|
||||
typedef struct _cairo_dest_attrs {
|
||||
|
|
@ -90,10 +102,28 @@ _cairo_tag_parse_link_attributes (const char *attributes, cairo_link_attrs_t *li
|
|||
cairo_private cairo_int_status_t
|
||||
_cairo_tag_parse_dest_attributes (const char *attributes, cairo_dest_attrs_t *dest_attrs);
|
||||
|
||||
cairo_private cairo_int_status_t
|
||||
_cairo_tag_parse_content_attributes (const char *attributes, cairo_content_attrs_t *content_attrs);
|
||||
|
||||
cairo_private cairo_int_status_t
|
||||
_cairo_tag_parse_content_ref_attributes (const char *attributes, cairo_content_ref_attrs_t *content_ref_attrs);
|
||||
|
||||
cairo_private cairo_int_status_t
|
||||
_cairo_tag_parse_ccitt_params (const char *attributes, cairo_ccitt_params_t *dest_attrs);
|
||||
|
||||
cairo_private cairo_int_status_t
|
||||
_cairo_tag_parse_eps_params (const char *attributes, cairo_eps_params_t *dest_attrs);
|
||||
|
||||
cairo_private void
|
||||
_cairo_tag_free_link_attributes (cairo_link_attrs_t *link_attrs);
|
||||
|
||||
cairo_private void
|
||||
_cairo_tag_free_dest_attributes (cairo_dest_attrs_t *link_attrs);
|
||||
|
||||
cairo_private void
|
||||
_cairo_tag_free_content_attributes (cairo_content_attrs_t *link_attrs);
|
||||
|
||||
cairo_private void
|
||||
_cairo_tag_free_content_ref_attributes (cairo_content_ref_attrs_t *link_attrs);
|
||||
|
||||
#endif /* CAIRO_TAG_ATTRIBUTES_PRIVATE_H */
|
||||
|
|
|
|||
|
|
@ -59,6 +59,25 @@ typedef struct _attribute_spec {
|
|||
int array_size; /* 0 = scalar, -1 = variable size array */
|
||||
} attribute_spec_t;
|
||||
|
||||
/*
|
||||
* id [optional] content id
|
||||
* content [optional] One or more content ids
|
||||
*/
|
||||
static const attribute_spec_t _content_attrib_spec[] = {
|
||||
{ "tag_name", ATTRIBUTE_STRING },
|
||||
{ "id", ATTRIBUTE_STRING },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/*
|
||||
* id [optional] content id
|
||||
* content [optional] One or more content ids
|
||||
*/
|
||||
static const attribute_spec_t _content_ref_attrib_spec[] = {
|
||||
{ "ref", ATTRIBUTE_STRING },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/*
|
||||
* name [required] Unique name of this destination (UTF-8)
|
||||
* x [optional] x coordinate of destination on page. Default is x coord of
|
||||
|
|
@ -68,7 +87,7 @@ typedef struct _attribute_spec {
|
|||
* internal [optional] If true, the name may be optimized out of the PDF where
|
||||
* possible. Default false.
|
||||
*/
|
||||
static attribute_spec_t _dest_attrib_spec[] = {
|
||||
static const attribute_spec_t _dest_attrib_spec[] = {
|
||||
{ "name", ATTRIBUTE_STRING },
|
||||
{ "x", ATTRIBUTE_FLOAT },
|
||||
{ "y", ATTRIBUTE_FLOAT },
|
||||
|
|
@ -103,7 +122,7 @@ static attribute_spec_t _dest_attrib_spec[] = {
|
|||
* page - Page number in the PDF file to link to
|
||||
* pos - [optional] Position of destination on page. Default is 0,0.
|
||||
*/
|
||||
static attribute_spec_t _link_attrib_spec[] =
|
||||
static const attribute_spec_t _link_attrib_spec[] =
|
||||
{
|
||||
{ "rect", ATTRIBUTE_FLOAT, -1 },
|
||||
{ "dest", ATTRIBUTE_STRING },
|
||||
|
|
@ -111,6 +130,9 @@ static attribute_spec_t _link_attrib_spec[] =
|
|||
{ "file", ATTRIBUTE_STRING },
|
||||
{ "page", ATTRIBUTE_INT },
|
||||
{ "pos", ATTRIBUTE_FLOAT, 2 },
|
||||
{ "id", ATTRIBUTE_STRING },
|
||||
{ "ref", ATTRIBUTE_STRING },
|
||||
{ "link_page", ATTRIBUTE_INT },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
|
@ -131,7 +153,7 @@ static attribute_spec_t _link_attrib_spec[] =
|
|||
* DamagedRowsBeforeError - Number of damages rows tolerated before an error
|
||||
* occurs. Default: 0.
|
||||
*/
|
||||
static attribute_spec_t _ccitt_params_spec[] =
|
||||
static const attribute_spec_t _ccitt_params_spec[] =
|
||||
{
|
||||
{ "Columns", ATTRIBUTE_INT },
|
||||
{ "Rows", ATTRIBUTE_INT },
|
||||
|
|
@ -152,7 +174,7 @@ static attribute_spec_t _ccitt_params_spec[] =
|
|||
* ury - upper right y xoordinate
|
||||
* all coordinates are in PostScript coordinates.
|
||||
*/
|
||||
static attribute_spec_t _eps_params_spec[] =
|
||||
static const attribute_spec_t _eps_params_spec[] =
|
||||
{
|
||||
{ "bbox", ATTRIBUTE_FLOAT, 4 },
|
||||
{ NULL }
|
||||
|
|
@ -362,7 +384,7 @@ parse_name (const char *attributes, const char *p, const char **end, char **s)
|
|||
attributes, p);
|
||||
|
||||
p2 = p;
|
||||
while (_cairo_isalpha (*p2) || _cairo_isdigit (*p2))
|
||||
while (_cairo_isalpha (*p2) || _cairo_isdigit (*p2) || *p2 == '_')
|
||||
p2++;
|
||||
|
||||
len = p2 - p;
|
||||
|
|
@ -376,9 +398,9 @@ parse_name (const char *attributes, const char *p, const char **end, char **s)
|
|||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
parse_attributes (const char *attributes, attribute_spec_t *attrib_def, cairo_list_t *list)
|
||||
parse_attributes (const char *attributes, const attribute_spec_t *attrib_def, cairo_list_t *list)
|
||||
{
|
||||
attribute_spec_t *def;
|
||||
const attribute_spec_t *def;
|
||||
attribute_t *attrib;
|
||||
char *name = NULL;
|
||||
cairo_int_status_t status;
|
||||
|
|
@ -489,6 +511,73 @@ free_attributes_list (cairo_list_t *list)
|
|||
}
|
||||
}
|
||||
|
||||
cairo_int_status_t
|
||||
_cairo_tag_parse_content_attributes (const char *attributes, cairo_content_attrs_t *content_attrs)
|
||||
{
|
||||
cairo_list_t list;
|
||||
cairo_int_status_t status;
|
||||
attribute_t *attr;
|
||||
|
||||
cairo_list_init (&list);
|
||||
status = parse_attributes (attributes, _content_attrib_spec, &list);
|
||||
if (unlikely (status))
|
||||
goto cleanup;
|
||||
|
||||
memset (content_attrs, 0, sizeof (cairo_content_attrs_t));
|
||||
cairo_list_foreach_entry (attr, attribute_t, &list, link)
|
||||
{
|
||||
if (strcmp (attr->name, "tag_name") == 0) {
|
||||
content_attrs->tag_name = strdup (attr->scalar.s);
|
||||
} else if (strcmp (attr->name, "id") == 0) {
|
||||
content_attrs->id = strdup (attr->scalar.s);
|
||||
}
|
||||
}
|
||||
|
||||
if (! content_attrs->tag_name) {
|
||||
status = _cairo_tag_error ("CONTENT attributes: \"%s\" missing tag_name attribute",
|
||||
attributes);
|
||||
} else if (! content_attrs->tag_name) {
|
||||
status = _cairo_tag_error ("CONTENT attributes: \"%s\" missing id attribute",
|
||||
attributes);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free_attributes_list (&list);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
cairo_int_status_t
|
||||
_cairo_tag_parse_content_ref_attributes (const char *attributes, cairo_content_ref_attrs_t *content_ref_attrs)
|
||||
{
|
||||
cairo_list_t list;
|
||||
cairo_int_status_t status;
|
||||
attribute_t *attr;
|
||||
|
||||
cairo_list_init (&list);
|
||||
status = parse_attributes (attributes, _content_ref_attrib_spec, &list);
|
||||
if (unlikely (status))
|
||||
goto cleanup;
|
||||
|
||||
memset (content_ref_attrs, 0, sizeof (cairo_content_ref_attrs_t));
|
||||
cairo_list_foreach_entry (attr, attribute_t, &list, link)
|
||||
{
|
||||
if (strcmp (attr->name, "ref") == 0) {
|
||||
content_ref_attrs->ref = strdup (attr->scalar.s);
|
||||
}
|
||||
}
|
||||
|
||||
if (! content_ref_attrs->ref) {
|
||||
status = _cairo_tag_error ("CONTENT_REF attributes: \"%s\" missing ref attribute",
|
||||
attributes);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free_attributes_list (&list);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
cairo_int_status_t
|
||||
_cairo_tag_parse_link_attributes (const char *attributes, cairo_link_attrs_t *link_attrs)
|
||||
{
|
||||
|
|
@ -496,7 +585,6 @@ _cairo_tag_parse_link_attributes (const char *attributes, cairo_link_attrs_t *li
|
|||
cairo_int_status_t status;
|
||||
attribute_t *attr;
|
||||
attrib_val_t val;
|
||||
cairo_bool_t has_rect = FALSE;
|
||||
cairo_bool_t invalid_combination = FALSE;
|
||||
|
||||
cairo_list_init (&list);
|
||||
|
|
@ -554,7 +642,16 @@ _cairo_tag_parse_link_attributes (const char *attributes, cairo_link_attrs_t *li
|
|||
if (unlikely (status))
|
||||
goto cleanup;
|
||||
}
|
||||
has_rect = TRUE;
|
||||
} else if (strcmp (attr->name, "id") == 0) {
|
||||
link_attrs->id = strdup (attr->scalar.s);
|
||||
} else if (strcmp (attr->name, "ref") == 0) {
|
||||
link_attrs->ref = strdup (attr->scalar.s);
|
||||
} else if (strcmp (attr->name, "link_page") == 0) {
|
||||
link_attrs->link_page = attr->scalar.i;
|
||||
if (link_attrs->link_page < 1) {
|
||||
status = _cairo_tag_error ("Link attributes: \"%s\" page must be >= 1", attributes);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -723,3 +820,33 @@ _cairo_tag_parse_eps_params (const char *attributes, cairo_eps_params_t *eps_par
|
|||
|
||||
return status;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_tag_free_link_attributes (cairo_link_attrs_t *link_attrs)
|
||||
{
|
||||
_cairo_array_fini (&link_attrs->rects);
|
||||
free (link_attrs->dest);
|
||||
free (link_attrs->uri);
|
||||
free (link_attrs->file);
|
||||
free (link_attrs->id);
|
||||
free (link_attrs->ref);
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_tag_free_dest_attributes (cairo_dest_attrs_t *dest_attrs)
|
||||
{
|
||||
free (dest_attrs->name);
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_tag_free_content_attributes (cairo_content_attrs_t *content_attrs)
|
||||
{
|
||||
free (content_attrs->id);
|
||||
free (content_attrs->tag_name);
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_tag_free_content_ref_attributes (cairo_content_ref_attrs_t *content_ref_attrs)
|
||||
{
|
||||
free (content_ref_attrs->ref);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@ typedef enum {
|
|||
TAG_TYPE_STRUCTURE = 1,
|
||||
TAG_TYPE_LINK = 2,
|
||||
TAG_TYPE_DEST = 4,
|
||||
TAG_TYPE_CONTENT = 8,
|
||||
TAG_TYPE_CONTENT_REF = 16,
|
||||
TAG_TYPE_ARTIFACT = 16,
|
||||
} cairo_tag_type_t;
|
||||
|
||||
/* The type of the structure tree. */
|
||||
|
|
@ -98,6 +101,12 @@ _cairo_tag_stack_pop (cairo_tag_stack_t *stack,
|
|||
cairo_private cairo_tag_stack_elem_t *
|
||||
_cairo_tag_stack_top_elem (cairo_tag_stack_t *stack);
|
||||
|
||||
cairo_private void
|
||||
_cairo_tag_stack_foreach (cairo_tag_stack_t *stack,
|
||||
void (*func)(cairo_tag_stack_elem_t *elem,
|
||||
void *closure),
|
||||
void *closure);
|
||||
|
||||
cairo_private void
|
||||
_cairo_tag_stack_free_elem (cairo_tag_stack_elem_t *elem);
|
||||
|
||||
|
|
|
|||
|
|
@ -99,6 +99,9 @@ static const char * _cairo_tag_stack_struct_pdf_list[] =
|
|||
"Formula",
|
||||
"Form",
|
||||
|
||||
/* Section 14.8.2.2.2 - Artifacts */
|
||||
"Artifact",
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -106,6 +109,8 @@ static const char * _cairo_tag_stack_struct_pdf_list[] =
|
|||
static const char * _cairo_tag_stack_cairo_tag_list[] =
|
||||
{
|
||||
CAIRO_TAG_DEST,
|
||||
CAIRO_TAG_CONTENT,
|
||||
CAIRO_TAG_CONTENT_REF,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -166,6 +171,17 @@ _cairo_tag_stack_push (cairo_tag_stack_t *stack,
|
|||
return _cairo_tag_error ("Invalid tag: %s", name);
|
||||
}
|
||||
|
||||
cairo_tag_stack_elem_t *top = _cairo_tag_stack_top_elem (stack);
|
||||
if (top &&
|
||||
(strcmp (top->name, CAIRO_TAG_CONTENT) == 0 ||
|
||||
strcmp (top->name, CAIRO_TAG_CONTENT_REF) == 0 ||
|
||||
strcmp (top->name, "Artifact") == 0))
|
||||
{
|
||||
return _cairo_tag_error ("%s tag can not contain nested tags",
|
||||
(strcmp (top->name, CAIRO_TAG_CONTENT) == 0) ? "CAIRO_TAG_CONTENT" :
|
||||
((strcmp (top->name, CAIRO_TAG_CONTENT_REF) == 0) ? "CAIRO_TAG_CONTENT_REF" : top->name));
|
||||
}
|
||||
|
||||
if (stack->type == TAG_TREE_TYPE_NO_TAGS) {
|
||||
if (name_in_list (name, _cairo_tag_stack_tagged_pdf_top_level_element_list))
|
||||
stack->type = TAG_TREE_TYPE_TAGGED;
|
||||
|
|
@ -256,6 +272,19 @@ _cairo_tag_stack_top_elem (cairo_tag_stack_t *stack)
|
|||
return cairo_list_last_entry (&stack->list, cairo_tag_stack_elem_t, link);
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_tag_stack_foreach (cairo_tag_stack_t *stack,
|
||||
void (*func)(cairo_tag_stack_elem_t *elem,
|
||||
void *closure),
|
||||
void *closure)
|
||||
{
|
||||
cairo_tag_stack_elem_t *elem;
|
||||
|
||||
cairo_list_foreach_entry (elem, cairo_tag_stack_elem_t, &stack->list, link) {
|
||||
func (elem, closure);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_tag_stack_free_elem (cairo_tag_stack_elem_t *elem)
|
||||
{
|
||||
|
|
@ -274,9 +303,15 @@ _cairo_tag_get_type (const char *name)
|
|||
if (strcmp(name, "Link") == 0)
|
||||
return (TAG_TYPE_LINK | TAG_TYPE_STRUCTURE);
|
||||
|
||||
if (strcmp(name, "cairo.dest") == 0)
|
||||
if (strcmp(name, CAIRO_TAG_DEST) == 0)
|
||||
return TAG_TYPE_DEST;
|
||||
|
||||
if (strcmp(name, CAIRO_TAG_CONTENT) == 0)
|
||||
return TAG_TYPE_CONTENT;
|
||||
|
||||
if (strcmp(name, CAIRO_TAG_CONTENT_REF) == 0)
|
||||
return TAG_TYPE_CONTENT_REF;
|
||||
|
||||
return TAG_TYPE_STRUCTURE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1240,7 +1240,7 @@ composite_aligned_boxes (const cairo_traps_compositor_t *compositor,
|
|||
|
||||
recording_clip = _cairo_clip_from_boxes (boxes);
|
||||
status = _cairo_recording_surface_replay_with_clip (recording_pattern_get_surface (source),
|
||||
m, dst, recording_clip, FALSE);
|
||||
m, dst, recording_clip);
|
||||
_cairo_clip_destroy (recording_clip);
|
||||
|
||||
return status;
|
||||
|
|
|
|||
|
|
@ -437,6 +437,17 @@ typedef struct _cairo_unscaled_font {
|
|||
cairo_reference_count_t ref_count;
|
||||
const cairo_unscaled_font_backend_t *backend;
|
||||
} cairo_unscaled_font_t;
|
||||
|
||||
typedef enum _cairo_analysis_source {
|
||||
CAIRO_ANALYSIS_SOURCE_PAINT,
|
||||
CAIRO_ANALYSIS_SOURCE_MASK,
|
||||
CAIRO_ANALYSIS_MASK_MASK,
|
||||
CAIRO_ANALYSIS_SOURCE_FILL,
|
||||
CAIRO_ANALYSIS_SOURCE_STROKE,
|
||||
CAIRO_ANALYSIS_SOURCE_SHOW_GLYPHS,
|
||||
CAIRO_ANALYSIS_SOURCE_NONE /* Used when analysis_source is not applicable. */
|
||||
} cairo_analysis_source_t;
|
||||
|
||||
CAIRO_END_DECLS
|
||||
|
||||
#endif /* CAIRO_TYPES_PRIVATE_H */
|
||||
|
|
|
|||
|
|
@ -1112,8 +1112,7 @@ record_to_picture (cairo_surface_t *target,
|
|||
|
||||
status = _cairo_recording_surface_replay_with_clip (source,
|
||||
&matrix, tmp,
|
||||
NULL,
|
||||
FALSE);
|
||||
NULL);
|
||||
if (unlikely (status)) {
|
||||
cairo_surface_destroy (tmp);
|
||||
return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
|
||||
|
|
|
|||
|
|
@ -920,8 +920,7 @@ record_source (cairo_xlib_surface_t *dst,
|
|||
recording = recording_pattern_get_surface (&pattern->base),
|
||||
status = _cairo_recording_surface_replay_with_clip (recording,
|
||||
&matrix, &src->base,
|
||||
NULL,
|
||||
FALSE);
|
||||
NULL);
|
||||
cairo_surface_destroy (recording);
|
||||
if (unlikely (status)) {
|
||||
cairo_surface_destroy (&src->base);
|
||||
|
|
|
|||
|
|
@ -1039,6 +1039,8 @@ cairo_rectangle_list_destroy (cairo_rectangle_list_t *rectangle_list);
|
|||
|
||||
#define CAIRO_TAG_DEST "cairo.dest"
|
||||
#define CAIRO_TAG_LINK "Link"
|
||||
#define CAIRO_TAG_CONTENT "cairo.content"
|
||||
#define CAIRO_TAG_CONTENT_REF "cairo.content_ref"
|
||||
|
||||
cairo_public void
|
||||
cairo_tag_begin (cairo_t *cr, const char *tag_name, const char *attributes);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
|
||||
/* cairo - a vector graphics library with display and print output
|
||||
*
|
||||
* Copyright © 2002 University of Southern California
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ _cairo_test_init (cairo_test_context_t *ctx,
|
|||
ctx->own_targets = FALSE;
|
||||
|
||||
ctx->srcdir = parent->srcdir;
|
||||
ctx->refdir = parent->refdir;
|
||||
ctx->refdir = xstrdup (parent->refdir);
|
||||
} else {
|
||||
int tmp_num_targets;
|
||||
cairo_bool_t tmp_limited_targets;
|
||||
|
|
@ -204,7 +204,10 @@ _cairo_test_init (cairo_test_context_t *ctx,
|
|||
ctx->srcdir = "srcdir";
|
||||
#endif
|
||||
}
|
||||
ctx->refdir = getenv ("CAIRO_REF_DIR");
|
||||
|
||||
ctx->refdir = xstrdup (getenv ("CAIRO_REF_DIR"));
|
||||
if (ctx->refdir == NULL)
|
||||
xasprintf (&ctx->refdir, "%s/reference", ctx->srcdir);
|
||||
}
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
|
|
@ -246,6 +249,7 @@ cairo_test_fini (cairo_test_context_t *ctx)
|
|||
fclose (ctx->log_file);
|
||||
ctx->log_file = NULL;
|
||||
|
||||
free (ctx->refdir);
|
||||
free (ctx->ref_name);
|
||||
cairo_surface_destroy (ctx->ref_image);
|
||||
cairo_surface_destroy (ctx->ref_image_flattened);
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ struct _cairo_test_context {
|
|||
FILE *log_file;
|
||||
const char *output;
|
||||
const char *srcdir; /* directory containing sources and input data */
|
||||
const char *refdir; /* directory containing reference images */
|
||||
char *refdir; /* directory containing reference images */
|
||||
|
||||
char *ref_name; /* cache of the current reference image */
|
||||
cairo_surface_t *ref_image;
|
||||
|
|
|
|||
21
test/check-pdf-structure.sh
Executable file
21
test/check-pdf-structure.sh
Executable file
|
|
@ -0,0 +1,21 @@
|
|||
#!/bin/sh
|
||||
|
||||
if test $# -ne 4 ; then
|
||||
echo "Usage: $0 <pdf-file> <pdfinfo-output> <pdfinfo-ref> <diff-output>"
|
||||
exit 3
|
||||
fi
|
||||
|
||||
# Check for pdfinfo version >= 21.10.00
|
||||
if pdfinfo -v 2>& 1 | awk '/pdfinfo version/ { split($3,v,/[.]/); if (v[1] > 21 || (v[1] == 21 && v[2] >= 10) ) { print "yes" } } ' | grep -q 'yes'; then
|
||||
pdfinfo -struct-text "$1" > "$2"
|
||||
if test -f "$3" ; then
|
||||
diff -u "$3" "$2" > "$4"
|
||||
# diff exit codes: 0 = match, 1 = different, 2 = error
|
||||
exit $?
|
||||
else
|
||||
exit 3 # missing ref file
|
||||
fi
|
||||
fi
|
||||
|
||||
# pdfinfo missing or wrong version
|
||||
exit 4
|
||||
|
|
@ -452,6 +452,10 @@ test_pdf_sources = [
|
|||
'pdf-tagged-text.c',
|
||||
]
|
||||
|
||||
test_pdf_structure_sources = [
|
||||
'pdf-structure.c',
|
||||
]
|
||||
|
||||
test_ps_sources = [
|
||||
'ps-eps.c',
|
||||
'ps-features.c',
|
||||
|
|
@ -555,6 +559,9 @@ endif
|
|||
|
||||
if feature_conf.get('CAIRO_HAS_PDF_SURFACE', 0) == 1
|
||||
test_sources += test_pdf_sources
|
||||
if host_machine.system() != 'windows'
|
||||
test_sources += test_pdf_structure_sources
|
||||
endif
|
||||
has_multipage_surfaces = true
|
||||
add_fallback_resolution = true
|
||||
build_any2ppm = true
|
||||
|
|
|
|||
568
test/pdf-structure.c
Normal file
568
test/pdf-structure.c
Normal file
|
|
@ -0,0 +1,568 @@
|
|||
/*
|
||||
* Copyright © 2023 Adrian Johnson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Author: Adrian Johnson <ajohnson@redneon.com>
|
||||
*/
|
||||
|
||||
#include "cairo-test.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h> /* __unix__ */
|
||||
#endif
|
||||
|
||||
#include <cairo.h>
|
||||
#include <cairo-pdf.h>
|
||||
|
||||
/* Test PDF logical structure
|
||||
*/
|
||||
|
||||
#define BASENAME "pdf-structure"
|
||||
|
||||
#define PAGE_WIDTH 595
|
||||
#define PAGE_HEIGHT 842
|
||||
|
||||
#define PDF_VERSION CAIRO_PDF_VERSION_1_4
|
||||
|
||||
struct pdf_structure_test {
|
||||
const char *name;
|
||||
void (*func)(cairo_t *cr);
|
||||
};
|
||||
|
||||
static void
|
||||
text(cairo_t *cr, const char *text)
|
||||
{
|
||||
double x, y;
|
||||
|
||||
cairo_show_text (cr, text);
|
||||
cairo_get_current_point (cr, &x, &y);
|
||||
cairo_move_to (cr, 20, y + 15);
|
||||
}
|
||||
|
||||
static void
|
||||
test_simple (cairo_t *cr)
|
||||
{
|
||||
cairo_tag_begin (cr, "Document", NULL);
|
||||
|
||||
cairo_tag_begin (cr, "H", "");
|
||||
text (cr, "Heading");
|
||||
cairo_tag_end (cr, "H");
|
||||
|
||||
cairo_tag_begin (cr, "Sect", NULL);
|
||||
|
||||
cairo_tag_begin (cr, "P", "");
|
||||
text (cr, "Para1");
|
||||
text (cr, "Para2");
|
||||
cairo_tag_end (cr, "P");
|
||||
|
||||
cairo_tag_begin (cr, "P", "");
|
||||
text (cr, "Para3");
|
||||
|
||||
cairo_tag_begin (cr, "Note", "");
|
||||
text (cr, "Note");
|
||||
cairo_tag_end (cr, "Note");
|
||||
|
||||
text (cr, "Para4");
|
||||
cairo_tag_end (cr, "P");
|
||||
|
||||
cairo_tag_end (cr, "Sect");
|
||||
|
||||
cairo_tag_end (cr, "Document");
|
||||
}
|
||||
|
||||
static void
|
||||
test_simple_ref (cairo_t *cr)
|
||||
{
|
||||
cairo_tag_begin (cr, CAIRO_TAG_CONTENT, "tag_name='H' id='heading'");
|
||||
text (cr, "Heading");
|
||||
cairo_tag_end (cr, CAIRO_TAG_CONTENT);
|
||||
|
||||
cairo_tag_begin (cr, CAIRO_TAG_CONTENT, "tag_name='P' id='para1'");
|
||||
text (cr, "Para1");
|
||||
text (cr, "Para2");
|
||||
cairo_tag_end (cr, CAIRO_TAG_CONTENT);
|
||||
|
||||
cairo_tag_begin (cr, CAIRO_TAG_CONTENT, "tag_name='P' id='para2'");
|
||||
text (cr, "Para3");
|
||||
cairo_tag_end (cr, CAIRO_TAG_CONTENT);
|
||||
|
||||
cairo_tag_begin (cr, CAIRO_TAG_CONTENT, "tag_name='Note' id='note'");
|
||||
text (cr, "Note");
|
||||
cairo_tag_end (cr, CAIRO_TAG_CONTENT);
|
||||
|
||||
cairo_tag_begin (cr, CAIRO_TAG_CONTENT, "tag_name='P' id='para3'");
|
||||
text (cr, "Para4");
|
||||
cairo_tag_end (cr, CAIRO_TAG_CONTENT);
|
||||
|
||||
cairo_tag_begin (cr, "Document", NULL);
|
||||
|
||||
cairo_tag_begin (cr, "H", "");
|
||||
cairo_tag_begin (cr, CAIRO_TAG_CONTENT_REF, "ref='heading'");
|
||||
cairo_tag_end (cr, CAIRO_TAG_CONTENT_REF);
|
||||
cairo_tag_end (cr, "H");
|
||||
|
||||
cairo_tag_begin (cr, "Sect", NULL);
|
||||
|
||||
cairo_tag_begin (cr, "P", "");
|
||||
cairo_tag_begin (cr, CAIRO_TAG_CONTENT_REF, "ref='para1'");
|
||||
cairo_tag_end (cr, CAIRO_TAG_CONTENT_REF);
|
||||
cairo_tag_end (cr, "P");
|
||||
|
||||
cairo_tag_begin (cr, "P", "");
|
||||
|
||||
cairo_tag_begin (cr, CAIRO_TAG_CONTENT_REF, "ref='para2'");
|
||||
cairo_tag_end (cr, CAIRO_TAG_CONTENT_REF);
|
||||
|
||||
cairo_tag_begin (cr, "Note", "");
|
||||
cairo_tag_begin (cr, CAIRO_TAG_CONTENT_REF, "ref='note'");
|
||||
cairo_tag_end (cr, CAIRO_TAG_CONTENT_REF);
|
||||
cairo_tag_end (cr, "Note");
|
||||
|
||||
cairo_tag_begin (cr, CAIRO_TAG_CONTENT_REF, "ref='para3'");
|
||||
cairo_tag_end (cr, CAIRO_TAG_CONTENT_REF);
|
||||
|
||||
cairo_tag_end (cr, "P");
|
||||
|
||||
cairo_tag_end (cr, "Sect");
|
||||
|
||||
cairo_tag_end (cr, "Document");
|
||||
}
|
||||
|
||||
static void
|
||||
test_group (cairo_t *cr)
|
||||
{
|
||||
cairo_tag_begin (cr, "Document", NULL);
|
||||
|
||||
cairo_tag_begin (cr, "H", "");
|
||||
text (cr, "Heading");
|
||||
cairo_tag_end (cr, "H");
|
||||
|
||||
cairo_tag_begin (cr, "Sect", NULL);
|
||||
|
||||
cairo_push_group (cr);
|
||||
|
||||
cairo_tag_begin (cr, "P", "");
|
||||
text (cr, "Para1");
|
||||
text (cr, "Para2");
|
||||
cairo_tag_end (cr, "P");
|
||||
|
||||
cairo_pop_group_to_source (cr);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_tag_end (cr, "Sect");
|
||||
|
||||
cairo_tag_end (cr, "Document");
|
||||
}
|
||||
|
||||
static void
|
||||
test_group_ref (cairo_t *cr)
|
||||
{
|
||||
cairo_tag_begin (cr, CAIRO_TAG_CONTENT, "tag_name='H' id='heading'");
|
||||
text (cr, "Heading");
|
||||
cairo_tag_end (cr, CAIRO_TAG_CONTENT);
|
||||
|
||||
cairo_push_group (cr);
|
||||
|
||||
cairo_tag_begin (cr, CAIRO_TAG_CONTENT, "tag_name='P' id='para'");
|
||||
text (cr, "Para1");
|
||||
text (cr, "Para2");
|
||||
cairo_tag_end (cr, CAIRO_TAG_CONTENT);
|
||||
|
||||
cairo_pop_group_to_source (cr);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_tag_begin (cr, "Document", NULL);
|
||||
|
||||
cairo_tag_begin (cr, "H", "");
|
||||
cairo_tag_begin (cr, CAIRO_TAG_CONTENT_REF, "ref='heading'");
|
||||
cairo_tag_end (cr, CAIRO_TAG_CONTENT_REF);
|
||||
cairo_tag_end (cr, "H");
|
||||
|
||||
cairo_tag_begin (cr, "Sect", NULL);
|
||||
|
||||
cairo_tag_begin (cr, "P", "");
|
||||
cairo_tag_begin (cr, CAIRO_TAG_CONTENT_REF, "ref='para'");
|
||||
cairo_tag_end (cr, CAIRO_TAG_CONTENT_REF);
|
||||
cairo_tag_end (cr, "P");
|
||||
|
||||
cairo_tag_end (cr, "Sect");
|
||||
|
||||
cairo_tag_end (cr, "Document");
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
test_repeated_group (cairo_t *cr)
|
||||
{
|
||||
cairo_pattern_t *pat;
|
||||
|
||||
cairo_tag_begin (cr, "Document", NULL);
|
||||
|
||||
cairo_tag_begin (cr, "H", "");
|
||||
text (cr, "Heading");
|
||||
cairo_tag_end (cr, "H");
|
||||
|
||||
cairo_tag_begin (cr, "Sect", NULL);
|
||||
|
||||
cairo_push_group (cr);
|
||||
|
||||
cairo_tag_begin (cr, "P", "");
|
||||
text (cr, "Para1");
|
||||
text (cr, "Para2");
|
||||
cairo_tag_end (cr, "P");
|
||||
|
||||
pat = cairo_pop_group (cr);
|
||||
|
||||
cairo_set_source (cr, pat);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_translate (cr, 0, 100);
|
||||
cairo_set_source (cr, pat);
|
||||
cairo_rectangle (cr, 0, 0, 100, 100);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_translate (cr, 0, 100);
|
||||
cairo_set_source_rgb (cr, 1, 0, 0);
|
||||
cairo_mask (cr, pat);
|
||||
|
||||
cairo_translate (cr, 0, 100);
|
||||
cairo_set_source_rgb (cr, 0, 1, 0);
|
||||
cairo_move_to (cr, 20, 0);
|
||||
cairo_line_to (cr, 100, 0);
|
||||
cairo_stroke (cr);
|
||||
|
||||
cairo_translate (cr, 0, 100);
|
||||
cairo_set_source_rgb (cr, 0, 0, 1);
|
||||
cairo_move_to (cr, 20, 0);
|
||||
cairo_show_text (cr, "Text");
|
||||
|
||||
cairo_tag_end (cr, "Sect");
|
||||
|
||||
cairo_tag_end (cr, "Document");
|
||||
}
|
||||
|
||||
static void
|
||||
test_multipage_simple (cairo_t *cr)
|
||||
{
|
||||
cairo_tag_begin (cr, "Document", NULL);
|
||||
|
||||
cairo_tag_begin (cr, "H", "");
|
||||
|
||||
cairo_tag_begin (cr, CAIRO_TAG_LINK, "dest='para1-dest'");
|
||||
text (cr, "Heading1");
|
||||
cairo_tag_end (cr, CAIRO_TAG_LINK);
|
||||
|
||||
cairo_tag_begin (cr, CAIRO_TAG_LINK, "dest='para2-dest'");
|
||||
text (cr, "Heading2");
|
||||
cairo_tag_end (cr, CAIRO_TAG_LINK);
|
||||
|
||||
cairo_tag_end (cr, "H");
|
||||
|
||||
cairo_tag_begin (cr, "Sect", NULL);
|
||||
|
||||
cairo_show_page (cr);
|
||||
|
||||
cairo_tag_begin (cr, "P", "");
|
||||
|
||||
cairo_tag_begin (cr, CAIRO_TAG_DEST, "name='para1-dest' internal");
|
||||
text (cr, "Para1");
|
||||
cairo_tag_end (cr, CAIRO_TAG_DEST);
|
||||
|
||||
cairo_show_page (cr);
|
||||
|
||||
cairo_tag_begin (cr, CAIRO_TAG_DEST, "name='para2-dest' internal");
|
||||
text (cr, "Para2");
|
||||
cairo_tag_end (cr, CAIRO_TAG_DEST);
|
||||
|
||||
cairo_tag_end (cr, "P");
|
||||
|
||||
cairo_tag_end (cr, "Sect");
|
||||
|
||||
cairo_tag_end (cr, "Document");
|
||||
}
|
||||
|
||||
static void
|
||||
test_multipage_simple_ref (cairo_t *cr)
|
||||
{
|
||||
cairo_tag_begin (cr, CAIRO_TAG_CONTENT, "tag_name='H' id='heading1'");
|
||||
text (cr, "Heading1");
|
||||
cairo_tag_end (cr, CAIRO_TAG_CONTENT);
|
||||
|
||||
cairo_tag_begin (cr, CAIRO_TAG_CONTENT, "tag_name='H' id='heading2'");
|
||||
text (cr, "Heading2");
|
||||
cairo_tag_end (cr, CAIRO_TAG_CONTENT);
|
||||
|
||||
cairo_show_page (cr);
|
||||
|
||||
cairo_tag_begin (cr, CAIRO_TAG_DEST, "name='para1-dest' internal");
|
||||
cairo_tag_begin (cr, CAIRO_TAG_CONTENT, "tag_name='P' id='para1'");
|
||||
text (cr, "Para1");
|
||||
cairo_tag_end (cr, CAIRO_TAG_CONTENT);
|
||||
cairo_tag_end (cr, CAIRO_TAG_DEST);
|
||||
|
||||
cairo_show_page (cr);
|
||||
|
||||
cairo_tag_begin (cr, CAIRO_TAG_DEST, "name='para2-dest' internal");
|
||||
cairo_tag_begin (cr, CAIRO_TAG_CONTENT, "tag_name='P' id='para2'");
|
||||
text (cr, "Para2");
|
||||
cairo_tag_end (cr, CAIRO_TAG_CONTENT);
|
||||
cairo_tag_end (cr, CAIRO_TAG_DEST);
|
||||
|
||||
cairo_tag_begin (cr, "Document", NULL);
|
||||
|
||||
cairo_tag_begin (cr, "H", "");
|
||||
|
||||
cairo_tag_begin (cr, CAIRO_TAG_LINK, "dest='para1-dest' link_page=1");
|
||||
cairo_tag_begin (cr, CAIRO_TAG_CONTENT_REF, "ref='heading1'");
|
||||
cairo_tag_end (cr, CAIRO_TAG_CONTENT_REF);
|
||||
cairo_tag_end (cr, CAIRO_TAG_LINK);
|
||||
|
||||
cairo_tag_begin (cr, CAIRO_TAG_LINK, "dest='para2-dest' link_page=1");
|
||||
cairo_tag_begin (cr, CAIRO_TAG_CONTENT_REF, "ref='heading2'");
|
||||
cairo_tag_end (cr, CAIRO_TAG_CONTENT_REF);
|
||||
cairo_tag_end (cr, CAIRO_TAG_LINK);
|
||||
|
||||
cairo_tag_end (cr, "H");
|
||||
|
||||
cairo_tag_begin (cr, "Sect", NULL);
|
||||
|
||||
cairo_tag_begin (cr, "P", "");
|
||||
cairo_tag_begin (cr, CAIRO_TAG_CONTENT_REF, "ref='para1'");
|
||||
cairo_tag_end (cr, CAIRO_TAG_CONTENT_REF);
|
||||
cairo_tag_begin (cr, CAIRO_TAG_CONTENT_REF, "ref='para2'");
|
||||
cairo_tag_end (cr, CAIRO_TAG_CONTENT_REF);
|
||||
cairo_tag_end (cr, "P");
|
||||
|
||||
cairo_tag_end (cr, "Sect");
|
||||
|
||||
cairo_tag_end (cr, "Document");
|
||||
}
|
||||
|
||||
static void
|
||||
test_multipage_group (cairo_t *cr)
|
||||
{
|
||||
cairo_tag_begin (cr, "Document", NULL);
|
||||
|
||||
cairo_tag_begin (cr, "H", "");
|
||||
text (cr, "Heading");
|
||||
cairo_tag_end (cr, "H");
|
||||
|
||||
cairo_tag_begin (cr, "Sect", NULL);
|
||||
|
||||
cairo_push_group (cr);
|
||||
|
||||
cairo_tag_begin (cr, "P", "");
|
||||
text (cr, "Para1");
|
||||
text (cr, "Para2");
|
||||
cairo_tag_end (cr, "P");
|
||||
|
||||
cairo_pop_group_to_source (cr);
|
||||
cairo_paint (cr);
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
|
||||
cairo_show_page (cr);
|
||||
|
||||
cairo_tag_begin (cr, "P", "");
|
||||
text (cr, "Para3");
|
||||
cairo_tag_end (cr, "P");
|
||||
|
||||
cairo_tag_end (cr, "Sect");
|
||||
|
||||
cairo_tag_end (cr, "Document");
|
||||
}
|
||||
|
||||
/* Same as test_multipage_group but but repeat the group on the second page. */
|
||||
static void
|
||||
test_multipage_group2 (cairo_t *cr)
|
||||
{
|
||||
cairo_tag_begin (cr, "Document", NULL);
|
||||
|
||||
cairo_tag_begin (cr, "H", "");
|
||||
text (cr, "Heading");
|
||||
cairo_tag_end (cr, "H");
|
||||
|
||||
cairo_tag_begin (cr, "Sect", NULL);
|
||||
|
||||
cairo_push_group (cr);
|
||||
|
||||
cairo_tag_begin (cr, "P", "");
|
||||
text (cr, "Para1");
|
||||
text (cr, "Para2");
|
||||
cairo_tag_end (cr, "P");
|
||||
|
||||
cairo_pop_group_to_source (cr);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_show_page (cr);
|
||||
|
||||
cairo_paint (cr);
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
|
||||
cairo_tag_begin (cr, "P", "");
|
||||
text (cr, "Para3");
|
||||
cairo_tag_end (cr, "P");
|
||||
|
||||
cairo_tag_end (cr, "Sect");
|
||||
|
||||
cairo_tag_end (cr, "Document");
|
||||
}
|
||||
|
||||
static const struct pdf_structure_test pdf_structure_tests[] = {
|
||||
{ "simple", test_simple },
|
||||
{ "simple-ref", test_simple_ref },
|
||||
{ "group", test_group },
|
||||
{ "group-ref", test_group_ref },
|
||||
{ "repeated-group", test_repeated_group },
|
||||
{ "multipage-simple", test_multipage_simple },
|
||||
{ "multipage-simple-ref", test_multipage_simple_ref },
|
||||
{ "multipage-group", test_multipage_group },
|
||||
{ "multipage-group2", test_multipage_group2 },
|
||||
};
|
||||
|
||||
static cairo_test_status_t
|
||||
create_pdf (cairo_test_context_t *ctx, const struct pdf_structure_test *test, const char *output)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
cairo_status_t status, status2;
|
||||
|
||||
surface = cairo_pdf_surface_create (output, PAGE_WIDTH, PAGE_HEIGHT);
|
||||
|
||||
cairo_pdf_surface_restrict_to_version (surface, PDF_VERSION);
|
||||
|
||||
cr = cairo_create (surface);
|
||||
|
||||
cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Serif",
|
||||
CAIRO_FONT_SLANT_NORMAL,
|
||||
CAIRO_FONT_WEIGHT_NORMAL);
|
||||
cairo_set_font_size (cr, 10);
|
||||
cairo_move_to (cr, 20, 20);
|
||||
|
||||
test->func(cr);
|
||||
|
||||
status = cairo_status (cr);
|
||||
cairo_destroy (cr);
|
||||
cairo_surface_finish (surface);
|
||||
status2 = cairo_surface_status (surface);
|
||||
if (status == CAIRO_STATUS_SUCCESS)
|
||||
status = status2;
|
||||
|
||||
cairo_surface_destroy (surface);
|
||||
if (status) {
|
||||
cairo_test_log (ctx, "Failed to create pdf surface for file %s: %s\n",
|
||||
output, cairo_status_to_string (status));
|
||||
return CAIRO_TEST_FAILURE;
|
||||
}
|
||||
|
||||
return CAIRO_TEST_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_test_status_t
|
||||
check_pdf (cairo_test_context_t *ctx, const struct pdf_structure_test *test, const char *output)
|
||||
{
|
||||
char *command;
|
||||
int ret;
|
||||
cairo_test_status_t result = CAIRO_TEST_FAILURE;
|
||||
|
||||
/* check-pdf-structure.sh <pdf-file> <pdfinfo-output> <pdfinfo-ref> <diff-output> */
|
||||
xasprintf (&command,
|
||||
"%s/check-pdf-structure.sh %s %s/%s-%s.out.txt %s/%s-%s.ref.txt %s/%s-%s.diff.txt ",
|
||||
ctx->srcdir,
|
||||
output,
|
||||
ctx->output, BASENAME, test->name,
|
||||
ctx->refdir, BASENAME, test->name,
|
||||
ctx->output, BASENAME, test->name);
|
||||
|
||||
ret = system (command);
|
||||
cairo_test_log (ctx, "%s exit code %d\n", command,
|
||||
WIFEXITED (ret) ? WEXITSTATUS (ret) : -1);
|
||||
|
||||
if (WIFEXITED (ret)) {
|
||||
if (WEXITSTATUS (ret) == 0)
|
||||
result = CAIRO_TEST_SUCCESS;
|
||||
else if (WEXITSTATUS (ret) == 4)
|
||||
result = CAIRO_TEST_UNTESTED; /* pdfinfo not found, wrong version, missing ref */
|
||||
}
|
||||
|
||||
free (command);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
merge_test_status (cairo_test_status_t *current, cairo_test_status_t new)
|
||||
{
|
||||
if (new == CAIRO_TEST_FAILURE || *current == CAIRO_TEST_FAILURE)
|
||||
*current = CAIRO_TEST_FAILURE;
|
||||
else if (new == CAIRO_TEST_UNTESTED)
|
||||
*current = CAIRO_TEST_UNTESTED;
|
||||
else
|
||||
*current = new;
|
||||
}
|
||||
|
||||
static cairo_test_status_t
|
||||
preamble (cairo_test_context_t *ctx)
|
||||
{
|
||||
int i;
|
||||
char *filename;
|
||||
cairo_test_status_t result, all_results;
|
||||
cairo_bool_t can_check = FALSE;
|
||||
|
||||
/* Need a POSIX shell to run the check. */
|
||||
#ifdef __unix__
|
||||
can_check = TRUE;
|
||||
#endif
|
||||
|
||||
all_results = CAIRO_TEST_SUCCESS;
|
||||
if (! cairo_test_is_target_enabled (ctx, "pdf"))
|
||||
return CAIRO_TEST_UNTESTED;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(pdf_structure_tests); i++) {
|
||||
xasprintf (&filename, "%s/%s-%s.out.pdf",
|
||||
ctx->output,
|
||||
BASENAME,
|
||||
pdf_structure_tests[i].name);
|
||||
|
||||
result = create_pdf (ctx, &pdf_structure_tests[i], filename);
|
||||
merge_test_status (&all_results, result);
|
||||
|
||||
if (can_check && result == CAIRO_TEST_SUCCESS) {
|
||||
result = check_pdf (ctx, &pdf_structure_tests[i], filename);
|
||||
merge_test_status (&all_results, result);
|
||||
} else {
|
||||
merge_test_status (&all_results, CAIRO_TEST_UNTESTED);
|
||||
}
|
||||
}
|
||||
|
||||
free (filename);
|
||||
return all_results;
|
||||
}
|
||||
|
||||
CAIRO_TEST (pdf_structure,
|
||||
"Check PDF Structure",
|
||||
"pdf", /* keywords */
|
||||
NULL, /* requirements */
|
||||
0, 0,
|
||||
preamble, NULL)
|
||||
|
|
@ -149,7 +149,7 @@ layout_paragraph (cairo_t *cr)
|
|||
*end = ' ';
|
||||
if (text_extents.width + 2*MARGIN > PAGE_WIDTH) {
|
||||
int len = prev_end - begin;
|
||||
char *s = malloc (len);
|
||||
char *s = xmalloc (len);
|
||||
memcpy (s, begin, len);
|
||||
s[len-1] = 0;
|
||||
paragraph_text[paragraph_num_lines++] = s;
|
||||
|
|
@ -204,9 +204,9 @@ draw_page_num (cairo_surface_t *surface, cairo_t *cr, const char *prefix, int nu
|
|||
static void
|
||||
draw_contents (cairo_surface_t *surface, cairo_t *cr, const struct section *section)
|
||||
{
|
||||
char buf[100];
|
||||
char *attrib;
|
||||
|
||||
sprintf(buf, "dest='%s'", section->heading);
|
||||
xasprintf (&attrib, "dest='%s'", section->heading);
|
||||
cairo_select_font_face (cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
|
||||
switch (section->level) {
|
||||
case 0:
|
||||
|
|
@ -230,25 +230,26 @@ draw_contents (cairo_surface_t *surface, cairo_t *cr, const struct section *sect
|
|||
cairo_set_source_rgb (cr, 0, 0, 1);
|
||||
cairo_tag_begin (cr, "TOCI", NULL);
|
||||
cairo_tag_begin (cr, "Reference", NULL);
|
||||
cairo_tag_begin (cr, CAIRO_TAG_LINK, buf);
|
||||
cairo_tag_begin (cr, CAIRO_TAG_LINK, attrib);
|
||||
cairo_show_text (cr, section->heading);
|
||||
cairo_tag_end (cr, CAIRO_TAG_LINK);
|
||||
cairo_tag_end (cr, "Reference");
|
||||
cairo_tag_end (cr, "TOCI");
|
||||
cairo_restore (cr);
|
||||
y_pos += HEADING_HEIGHT;
|
||||
free (attrib);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_section (cairo_surface_t *surface, cairo_t *cr, const struct section *section)
|
||||
{
|
||||
int flags, i;
|
||||
char buf[100];
|
||||
char buf2[100];
|
||||
char *name_attrib;
|
||||
char *dest_attrib;
|
||||
|
||||
cairo_tag_begin (cr, "Sect", NULL);
|
||||
sprintf(buf, "name='%s'", section->heading);
|
||||
sprintf(buf2, "dest='%s'", section->heading);
|
||||
xasprintf(&name_attrib, "name='%s'", section->heading);
|
||||
xasprintf(&dest_attrib, "dest='%s'", section->heading);
|
||||
cairo_select_font_face (cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
|
||||
if (section->level == 0) {
|
||||
cairo_show_page (cr);
|
||||
|
|
@ -256,7 +257,7 @@ draw_section (cairo_surface_t *surface, cairo_t *cr, const struct section *secti
|
|||
cairo_set_font_size(cr, HEADING1_SIZE);
|
||||
cairo_move_to (cr, MARGIN, MARGIN);
|
||||
cairo_tag_begin (cr, "H1", NULL);
|
||||
cairo_tag_begin (cr, CAIRO_TAG_DEST, buf);
|
||||
cairo_tag_begin (cr, CAIRO_TAG_DEST, name_attrib);
|
||||
cairo_show_text (cr, section->heading);
|
||||
cairo_tag_end (cr, CAIRO_TAG_DEST);
|
||||
cairo_tag_end (cr, "H1");
|
||||
|
|
@ -265,7 +266,7 @@ draw_section (cairo_surface_t *surface, cairo_t *cr, const struct section *secti
|
|||
outline_parents[0] = cairo_pdf_surface_add_outline (surface,
|
||||
CAIRO_PDF_OUTLINE_ROOT,
|
||||
section->heading,
|
||||
buf2,
|
||||
dest_attrib,
|
||||
flags);
|
||||
} else {
|
||||
if (section->level == 1) {
|
||||
|
|
@ -286,7 +287,7 @@ draw_section (cairo_surface_t *surface, cairo_t *cr, const struct section *secti
|
|||
cairo_tag_begin (cr, "H2", NULL);
|
||||
else
|
||||
cairo_tag_begin (cr, "H3", NULL);
|
||||
cairo_tag_begin (cr, CAIRO_TAG_DEST, buf);
|
||||
cairo_tag_begin (cr, CAIRO_TAG_DEST, name_attrib);
|
||||
cairo_show_text (cr, section->heading);
|
||||
cairo_tag_end (cr, CAIRO_TAG_DEST);
|
||||
if (section->level == 1)
|
||||
|
|
@ -297,7 +298,7 @@ draw_section (cairo_surface_t *surface, cairo_t *cr, const struct section *secti
|
|||
outline_parents[section->level] = cairo_pdf_surface_add_outline (surface,
|
||||
outline_parents[section->level - 1],
|
||||
section->heading,
|
||||
buf2,
|
||||
dest_attrib,
|
||||
flags);
|
||||
}
|
||||
|
||||
|
|
@ -310,13 +311,15 @@ draw_section (cairo_surface_t *surface, cairo_t *cr, const struct section *secti
|
|||
draw_paragraph (cr);
|
||||
}
|
||||
cairo_tag_end (cr, "Sect");
|
||||
free (name_attrib);
|
||||
free (dest_attrib);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_cover (cairo_surface_t *surface, cairo_t *cr)
|
||||
{
|
||||
cairo_text_extents_t text_extents;
|
||||
char buf[200];
|
||||
char *attrib;
|
||||
cairo_rectangle_t url_box;
|
||||
const char *cairo_url = "https://www.cairographics.org/";
|
||||
const double url_box_margin = 20.0;
|
||||
|
|
@ -344,10 +347,11 @@ draw_cover (cairo_surface_t *surface, cairo_t *cr)
|
|||
url_box.height = -text_extents.height + 2*url_box_margin;
|
||||
cairo_rectangle(cr, url_box.x, url_box.y, url_box.width, url_box.height);
|
||||
cairo_stroke(cr);
|
||||
snprintf(buf, sizeof(buf), "rect=[%f %f %f %f] uri=\'%s\'",
|
||||
xasprintf(&attrib, "rect=[%f %f %f %f] uri=\'%s\'",
|
||||
url_box.x, url_box.y, url_box.width, url_box.height, cairo_url);
|
||||
cairo_tag_begin (cr, CAIRO_TAG_LINK, buf);
|
||||
cairo_tag_begin (cr, CAIRO_TAG_LINK, attrib);
|
||||
cairo_tag_end (cr, CAIRO_TAG_LINK);
|
||||
free (attrib);
|
||||
|
||||
/* Create link to not yet emmited page number */
|
||||
cairo_tag_begin (cr, CAIRO_TAG_LINK, "page=5");
|
||||
|
|
@ -419,6 +423,32 @@ create_document (cairo_surface_t *surface, cairo_t *cr)
|
|||
cairo_tag_begin (cr, CAIRO_TAG_LINK, "uri='http://127.0.0.1/' rect=[10.0 -10.0 100.0 100.0]");
|
||||
cairo_tag_end (cr, CAIRO_TAG_LINK);
|
||||
|
||||
|
||||
/* Distilled from Mozilla bug https://bugzilla.mozilla.org/show_bug.cgi?id=1725743:
|
||||
* attempting to emit a Destination tag within a pushed group will lead to an
|
||||
* assertion in _cairo_pdf_interchange_end_structure_tag when processing a
|
||||
* following LINK tag that is outside the pushed group.
|
||||
*/
|
||||
|
||||
/* PushLayer */
|
||||
cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA);
|
||||
|
||||
/* Destination */
|
||||
cairo_tag_begin (cr, CAIRO_TAG_DEST, "name='a' x=42 y=42");
|
||||
cairo_tag_end (cr, CAIRO_TAG_DEST);
|
||||
|
||||
/* PopLayer */
|
||||
cairo_pop_group_to_source (cr);
|
||||
cairo_paint_with_alpha (cr, 1);
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
|
||||
/* Link */
|
||||
cairo_tag_begin (cr, CAIRO_TAG_LINK, "rect=[100 200 300 400] uri='http://127.0.0.1/'");
|
||||
cairo_tag_end (cr, CAIRO_TAG_LINK);
|
||||
|
||||
/* End of extra Mozilla testcase. */
|
||||
|
||||
|
||||
cairo_show_page (cr);
|
||||
|
||||
page_num = 0;
|
||||
|
|
@ -449,6 +479,8 @@ create_document (cairo_surface_t *surface, cairo_t *cr)
|
|||
|
||||
cairo_show_page (cr);
|
||||
|
||||
cairo_set_source_rgb (cr, 0, 0, 1);
|
||||
|
||||
cairo_tag_begin (cr, CAIRO_TAG_LINK, "dest='cover'");
|
||||
cairo_move_to (cr, PAGE_WIDTH/3, 2*PAGE_HEIGHT/5);
|
||||
cairo_show_text (cr, "link to cover");
|
||||
|
|
|
|||
6
test/reference/pdf-structure-group-ref.ref.txt
Normal file
6
test/reference/pdf-structure-group-ref.ref.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
Document
|
||||
H (block)
|
||||
"Heading"
|
||||
Sect
|
||||
P (block)
|
||||
"Para1Para2"
|
||||
6
test/reference/pdf-structure-group.ref.txt
Normal file
6
test/reference/pdf-structure-group.ref.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
Document
|
||||
H (block)
|
||||
"Heading"
|
||||
Sect
|
||||
P (block)
|
||||
"Para1Para2"
|
||||
8
test/reference/pdf-structure-multipage-group.ref.txt
Normal file
8
test/reference/pdf-structure-multipage-group.ref.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
Document
|
||||
H (block)
|
||||
"Heading"
|
||||
Sect
|
||||
P (block)
|
||||
"Para1Para2"
|
||||
P (block)
|
||||
"Para3"
|
||||
10
test/reference/pdf-structure-multipage-group2.ref.txt
Normal file
10
test/reference/pdf-structure-multipage-group2.ref.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
Document
|
||||
H (block)
|
||||
"Heading"
|
||||
Sect
|
||||
P (block)
|
||||
"Para1Para2"
|
||||
P (block)
|
||||
"Para1Para2"
|
||||
P (block)
|
||||
"Para3"
|
||||
12
test/reference/pdf-structure-multipage-simple-ref.ref.txt
Normal file
12
test/reference/pdf-structure-multipage-simple-ref.ref.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
Document
|
||||
H (block)
|
||||
Link (inline)
|
||||
Object 21 0
|
||||
"Heading1"
|
||||
Link (inline)
|
||||
Object 24 0
|
||||
"Heading2"
|
||||
Sect
|
||||
P (block)
|
||||
"Para1"
|
||||
"Para2"
|
||||
12
test/reference/pdf-structure-multipage-simple.ref.txt
Normal file
12
test/reference/pdf-structure-multipage-simple.ref.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
Document
|
||||
H (block)
|
||||
Link (inline)
|
||||
Object 6 0
|
||||
"Heading1"
|
||||
Link (inline)
|
||||
Object 8 0
|
||||
"Heading2"
|
||||
Sect
|
||||
P (block)
|
||||
"Para1"
|
||||
"Para2"
|
||||
9
test/reference/pdf-structure-repeated-group.ref.txt
Normal file
9
test/reference/pdf-structure-repeated-group.ref.txt
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
Document
|
||||
H (block)
|
||||
"Heading"
|
||||
Sect
|
||||
P (block)
|
||||
"Para1Para2"
|
||||
P (block)
|
||||
"Para1Para2"
|
||||
"Para1Para2Text"
|
||||
11
test/reference/pdf-structure-simple-ref.ref.txt
Normal file
11
test/reference/pdf-structure-simple-ref.ref.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
Document
|
||||
H (block)
|
||||
"Heading"
|
||||
Sect
|
||||
P (block)
|
||||
"Para1Para2"
|
||||
P (block)
|
||||
"Para3"
|
||||
Note (inline)
|
||||
"Note"
|
||||
"Para4"
|
||||
11
test/reference/pdf-structure-simple.ref.txt
Normal file
11
test/reference/pdf-structure-simple.ref.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
Document
|
||||
H (block)
|
||||
"Heading"
|
||||
Sect
|
||||
P (block)
|
||||
"Para1Para2"
|
||||
P (block)
|
||||
"Para3"
|
||||
Note (inline)
|
||||
"Note"
|
||||
"Para4"
|
||||
Loading…
Add table
Reference in a new issue