зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1722300 - patch 2 - Pull in cairo MR "pdf links: fix forward references to dest names with 'internal' flag". r=jrmuizel
This is https://gitlab.freedesktop.org/cairo/cairo/-/merge_requests/220, required so that we can use the 'internal' attribute when generating link destinations. Differential Revision: https://phabricator.services.mozilla.com/D121239
This commit is contained in:
Родитель
c0b0f4fc91
Коммит
c8767e7306
|
@ -361,21 +361,19 @@ cairo_pdf_interchange_write_dest (cairo_pdf_surface_t *surface,
|
|||
{
|
||||
cairo_int_status_t status;
|
||||
cairo_pdf_interchange_t *ic = &surface->interchange;
|
||||
char *dest = NULL;
|
||||
cairo_pdf_forward_link_t *link;
|
||||
cairo_pdf_resource_t link_res;
|
||||
|
||||
/* If the dest is known, emit an explicit dest */
|
||||
if (link_attrs->dest) {
|
||||
cairo_pdf_named_dest_t key;
|
||||
cairo_pdf_named_dest_t *named_dest;
|
||||
|
||||
/* check if this is a link to an internal named dest */
|
||||
/* check if we already have this dest */
|
||||
key.attrs.name = link_attrs->dest;
|
||||
init_named_dest_key (&key);
|
||||
named_dest = _cairo_hash_table_lookup (ic->named_dests, &key.base);
|
||||
if (named_dest && named_dest->attrs.internal) {
|
||||
/* if dests exists and has internal attribute, use a direct
|
||||
* reference instead of the name */
|
||||
if (named_dest) {
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
|
||||
|
@ -399,50 +397,43 @@ cairo_pdf_interchange_write_dest (cairo_pdf_surface_t *surface,
|
|||
}
|
||||
}
|
||||
|
||||
if (link_attrs->dest) {
|
||||
status = _cairo_utf8_to_pdf_string (link_attrs->dest, &dest);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
_cairo_output_stream_printf (surface->object_stream.stream,
|
||||
" /Dest %s\n",
|
||||
dest);
|
||||
free (dest);
|
||||
} else {
|
||||
/* If the page is known, emit an explicit dest */
|
||||
if (!link_attrs->dest) {
|
||||
if (link_attrs->page < 1)
|
||||
return _cairo_tag_error ("Link attribute: \"page=%d\" page must be >= 1", link_attrs->page);
|
||||
|
||||
if (link_attrs->page <= (int)_cairo_array_num_elements (&surface->pages)) {
|
||||
_cairo_output_stream_printf (surface->object_stream.stream, " /Dest ");
|
||||
status = cairo_pdf_interchange_write_explicit_dest (surface,
|
||||
link_attrs->page,
|
||||
link_attrs->has_pos,
|
||||
link_attrs->pos.x,
|
||||
link_attrs->pos.y);
|
||||
} else {
|
||||
/* Link refers to a future page. Use an indirect object and
|
||||
* write the link at the end of the document */
|
||||
|
||||
link = _cairo_malloc (sizeof (cairo_pdf_forward_link_t));
|
||||
if (unlikely (link == NULL))
|
||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
|
||||
link_res = _cairo_pdf_surface_new_object (surface);
|
||||
if (link_res.id == 0)
|
||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
|
||||
_cairo_output_stream_printf (surface->object_stream.stream,
|
||||
" /Dest %d 0 R\n",
|
||||
link_res.id);
|
||||
|
||||
link->res = link_res;
|
||||
link->page = link_attrs->page;
|
||||
link->has_pos = link_attrs->has_pos;
|
||||
link->pos = link_attrs->pos;
|
||||
status = _cairo_array_append (&surface->forward_links, link);
|
||||
return cairo_pdf_interchange_write_explicit_dest (surface,
|
||||
link_attrs->page,
|
||||
link_attrs->has_pos,
|
||||
link_attrs->pos.x,
|
||||
link_attrs->pos.y);
|
||||
}
|
||||
}
|
||||
|
||||
/* Link refers to a future or unknown page. Use an indirect object
|
||||
* and write the link at the end of the document */
|
||||
|
||||
link = _cairo_malloc (sizeof (cairo_pdf_forward_link_t));
|
||||
if (unlikely (link == NULL))
|
||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
|
||||
link_res = _cairo_pdf_surface_new_object (surface);
|
||||
if (link_res.id == 0)
|
||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
|
||||
_cairo_output_stream_printf (surface->object_stream.stream,
|
||||
" /Dest %d 0 R\n",
|
||||
link_res.id);
|
||||
|
||||
link->res = link_res;
|
||||
link->dest = link_attrs->dest ? strdup (link_attrs->dest) : NULL;
|
||||
link->page = link_attrs->page;
|
||||
link->has_pos = link_attrs->has_pos;
|
||||
link->pos = link_attrs->pos;
|
||||
status = _cairo_array_append (&surface->forward_links, link);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -919,6 +910,9 @@ cairo_pdf_interchange_write_forward_links (cairo_pdf_surface_t *surface)
|
|||
int num_elems, i;
|
||||
cairo_pdf_forward_link_t *link;
|
||||
cairo_int_status_t status;
|
||||
cairo_pdf_named_dest_t key;
|
||||
cairo_pdf_named_dest_t *named_dest;
|
||||
cairo_pdf_interchange_t *ic = &surface->interchange;
|
||||
|
||||
num_elems = _cairo_array_num_elements (&surface->forward_links);
|
||||
for (i = 0; i < num_elems; i++) {
|
||||
|
@ -932,12 +926,39 @@ cairo_pdf_interchange_write_forward_links (cairo_pdf_surface_t *surface)
|
|||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
cairo_pdf_interchange_write_explicit_dest (surface,
|
||||
link->page,
|
||||
link->has_pos,
|
||||
link->pos.x,
|
||||
link->pos.y);
|
||||
if (link->dest) {
|
||||
key.attrs.name = link->dest;
|
||||
init_named_dest_key (&key);
|
||||
named_dest = _cairo_hash_table_lookup (ic->named_dests, &key.base);
|
||||
if (named_dest) {
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
|
||||
if (named_dest->extents.valid) {
|
||||
x = named_dest->extents.extents.x;
|
||||
y = named_dest->extents.extents.y;
|
||||
}
|
||||
|
||||
if (named_dest->attrs.x_valid)
|
||||
x = named_dest->attrs.x;
|
||||
|
||||
if (named_dest->attrs.y_valid)
|
||||
y = named_dest->attrs.y;
|
||||
|
||||
status = cairo_pdf_interchange_write_explicit_dest (surface,
|
||||
named_dest->page,
|
||||
TRUE,
|
||||
x, y);
|
||||
} else {
|
||||
return _cairo_tag_error ("Link to dest=\"%s\" not found", link->dest);
|
||||
}
|
||||
} else {
|
||||
cairo_pdf_interchange_write_explicit_dest (surface,
|
||||
link->page,
|
||||
link->has_pos,
|
||||
link->pos.x,
|
||||
link->pos.y);
|
||||
}
|
||||
_cairo_pdf_surface_object_end (surface);
|
||||
}
|
||||
|
||||
|
@ -1026,13 +1047,14 @@ cairo_pdf_interchange_write_page_labels (cairo_pdf_surface_t *surface)
|
|||
}
|
||||
|
||||
static void
|
||||
_collect_dest (void *entry, void *closure)
|
||||
_collect_external_dest (void *entry, void *closure)
|
||||
{
|
||||
cairo_pdf_named_dest_t *dest = entry;
|
||||
cairo_pdf_surface_t *surface = closure;
|
||||
cairo_pdf_interchange_t *ic = &surface->interchange;
|
||||
|
||||
ic->sorted_dests[ic->num_dests++] = dest;
|
||||
if (!dest->attrs.internal)
|
||||
ic->sorted_dests[ic->num_dests++] = dest;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1061,7 +1083,8 @@ _cairo_pdf_interchange_write_document_dests (cairo_pdf_surface_t *surface)
|
|||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
|
||||
ic->num_dests = 0;
|
||||
_cairo_hash_table_foreach (ic->named_dests, _collect_dest, surface);
|
||||
_cairo_hash_table_foreach (ic->named_dests, _collect_external_dest, surface);
|
||||
|
||||
qsort (ic->sorted_dests, ic->num_dests, sizeof (cairo_pdf_named_dest_t *), _dest_compare);
|
||||
|
||||
ic->dests_res = _cairo_pdf_surface_new_object (surface);
|
||||
|
|
|
@ -211,6 +211,7 @@ typedef struct _cairo_pdf_outline_entry {
|
|||
|
||||
typedef struct _cairo_pdf_forward_link {
|
||||
cairo_pdf_resource_t res;
|
||||
char *dest;
|
||||
int page;
|
||||
cairo_bool_t has_pos;
|
||||
cairo_point_double_t pos;
|
||||
|
|
|
@ -2432,6 +2432,10 @@ _cairo_pdf_surface_finish (void *abstract_surface)
|
|||
char *label;
|
||||
cairo_pdf_resource_t xref_res;
|
||||
|
||||
/* Some of the data may be in an inconistent state if there is an error status. */
|
||||
if (surface->base.status != CAIRO_STATUS_SUCCESS)
|
||||
goto CLEANUP;
|
||||
|
||||
_cairo_pdf_surface_clear (surface);
|
||||
|
||||
status = _cairo_pdf_surface_open_object_stream (surface);
|
||||
|
@ -2491,6 +2495,8 @@ _cairo_pdf_surface_finish (void *abstract_surface)
|
|||
"%%%%EOF\n",
|
||||
offset);
|
||||
|
||||
CLEANUP:
|
||||
|
||||
/* pdf_operators has already been flushed when the last stream was
|
||||
* closed so we should never be writing anything here - however,
|
||||
* the stream may itself be in an error state. */
|
||||
|
|
Загрузка…
Ссылка в новой задаче