[cairo-commit] 2 commits - src/cairo.c src/cairo-pdf.h src/cairo-pdf-interchange.c src/cairo-pdf-surface.c src/cairo-pdf-surface-private.h src/cairo-tag-attributes.c src/cairo-tag-attributes-private.h test/pdf-tagged-text.c

Adrian Johnson ajohnson at kemper.freedesktop.org
Sat Aug 26 11:18:38 UTC 2017


 src/cairo-pdf-interchange.c        |  181 +++++++++++++++++++++----------------
 src/cairo-pdf-surface-private.h    |    6 -
 src/cairo-pdf-surface.c            |   26 +++--
 src/cairo-pdf.h                    |    2 
 src/cairo-tag-attributes-private.h |    1 
 src/cairo-tag-attributes.c         |    1 
 src/cairo.c                        |    7 -
 test/pdf-tagged-text.c             |   12 +-
 8 files changed, 143 insertions(+), 93 deletions(-)

New commits:
commit 12b875aef374636d1693a631524dd3b622277415
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sat Aug 26 16:32:48 2017 +0930

    pdf: use link attributes instead of dest name for cairo_pdf_surface_add_outline
    
    In PDF outline targets are specified the same way as link targets so
    there is no need to restrict the target to dest names.

diff --git a/src/cairo-pdf-interchange.c b/src/cairo-pdf-interchange.c
index 1521fc25..460f483e 100644
--- a/src/cairo-pdf-interchange.c
+++ b/src/cairo-pdf-interchange.c
@@ -230,6 +230,87 @@ cairo_pdf_interchange_write_node_object (cairo_pdf_surface_t            *surface
 }
 
 static cairo_int_status_t
+cairo_pdf_interchange_write_link_action (cairo_pdf_surface_t   *surface,
+					 cairo_link_attrs_t    *link_attrs)
+{
+    cairo_int_status_t status;
+    double height;
+    char *dest = NULL;
+
+    if (link_attrs->dest) {
+	status = _cairo_utf8_to_pdf_string (link_attrs->dest, &dest);
+	if (unlikely (status))
+	    return status;
+    }
+
+    if (link_attrs->link_type == TAG_LINK_DEST) {
+
+	if (link_attrs->dest) {
+	    _cairo_output_stream_printf (surface->output,
+					 "   /Dest %s\n",
+					 dest);
+	} else {
+	    cairo_pdf_resource_t res;
+	    int page = link_attrs->page;
+
+	    if (page < 1 || page > (int)_cairo_array_num_elements (&surface->pages))
+		return CAIRO_INT_STATUS_TAG_ERROR;
+
+	    _cairo_array_copy_element (&surface->page_heights, page - 1, &height);
+	    _cairo_array_copy_element (&surface->pages, page - 1, &res);
+	    if (link_attrs->has_pos) {
+		_cairo_output_stream_printf (surface->output,
+					     "   /Dest [%d 0 R /XYZ %f %f 0]\n",
+					     res.id,
+					     link_attrs->pos.x,
+					     height - link_attrs->pos.y);
+	    } else {
+		_cairo_output_stream_printf (surface->output,
+					     "   /Dest [%d 0 R /XYZ null null 0]\n",
+					     res.id);
+	    }
+	}
+    } else if (link_attrs->link_type == TAG_LINK_URI) {
+	_cairo_output_stream_printf (surface->output,
+				     "   /A <<\n"
+				     "      /Type /Action\n"
+				     "      /S /URI\n"
+				     "      /URI (%s)\n"
+				     "   >>\n",
+				     link_attrs->uri);
+    } else if (link_attrs->link_type == TAG_LINK_FILE) {
+	_cairo_output_stream_printf (surface->output,
+				     "   /A <<\n"
+				     "      /Type /Action\n"
+				     "      /S /GoToR\n"
+				     "      /F (%s)\n",
+				     link_attrs->file);
+	if (link_attrs->dest) {
+	    _cairo_output_stream_printf (surface->output,
+					 "      /D %s\n",
+					 dest);
+	} else {
+	    if (link_attrs->has_pos) {
+		_cairo_output_stream_printf (surface->output,
+					     "      /D [%d %f %f 0]\n",
+					     link_attrs->page,
+					     link_attrs->pos.x,
+					     link_attrs->pos.y);
+	    } else {
+		_cairo_output_stream_printf (surface->output,
+					     "      /D [%d null null 0]\n",
+					     link_attrs->page);
+	    }
+	}
+	_cairo_output_stream_printf (surface->output,
+				     "   >>\n");
+    }
+    free (dest);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
 cairo_pdf_interchange_write_annot (cairo_pdf_surface_t            *surface,
 				   cairo_pdf_struct_tree_node_t   *node)
 {
@@ -237,7 +318,6 @@ cairo_pdf_interchange_write_annot (cairo_pdf_surface_t            *surface,
     cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
     cairo_pdf_interchange_t *ic = &surface->interchange;
     int sp;
-    char *dest = NULL;
     int i, num_rects;
     double height;
 
@@ -299,73 +379,9 @@ cairo_pdf_interchange_write_annot (cairo_pdf_surface_t            *surface,
 	    _cairo_output_stream_printf (surface->output, " ]\n");
 	}
 
-	if (node->annot.link_attrs.dest) {
-	    status = _cairo_utf8_to_pdf_string (node->annot.link_attrs.dest, &dest);
-	    if (unlikely (status))
-		return status;
-	}
-
-	if (node->annot.link_attrs.link_type == TAG_LINK_DEST) {
-	    if (node->annot.link_attrs.dest) {
-		_cairo_output_stream_printf (surface->output,
-					     "   /Dest %s\n",
-					     dest);
-	    } else {
-		cairo_pdf_resource_t res;
-		int page = node->annot.link_attrs.page;
-
-		if (page < 1 || page > (int)_cairo_array_num_elements (&surface->pages))
-		    return CAIRO_INT_STATUS_TAG_ERROR;
-
-		_cairo_array_copy_element (&surface->page_heights, page - 1, &height);
-		_cairo_array_copy_element (&surface->pages, page - 1, &res);
-		if (node->annot.link_attrs.has_pos) {
-		    _cairo_output_stream_printf (surface->output,
-						 "   /Dest [%d 0 R /XYZ %f %f 0]\n",
-						 res.id,
-						 node->annot.link_attrs.pos.x,
-						 height - node->annot.link_attrs.pos.y);
-		} else {
-		    _cairo_output_stream_printf (surface->output,
-						 "   /Dest [%d 0 R /XYZ null null 0]\n",
-						 res.id);
-		}
-	    }
-	} else if (node->annot.link_attrs.link_type == TAG_LINK_URI) {
-	    _cairo_output_stream_printf (surface->output,
-					 "   /A <<\n"
-					 "      /Type /Action\n"
-					 "      /S /URI\n"
-					 "      /URI (%s)\n"
-					 "   >>\n",
-					 node->annot.link_attrs.uri);
-	} else if (node->annot.link_attrs.link_type == TAG_LINK_FILE) {
-	    _cairo_output_stream_printf (surface->output,
-					 "   /A <<\n"
-					 "      /Type /Action\n"
-					 "      /S /GoToR\n"
-					 "      /F (%s)\n",
-					 node->annot.link_attrs.file);
-	    if (node->annot.link_attrs.dest) {
-		_cairo_output_stream_printf (surface->output,
-					     "      /D %s\n",
-					     dest);
-	    } else {
-		if (node->annot.link_attrs.has_pos) {
-		    _cairo_output_stream_printf (surface->output,
-						 "      /D [%d %f %f 0]\n",
-						 node->annot.link_attrs.page,
-						 node->annot.link_attrs.pos.x,
-						 node->annot.link_attrs.pos.y);
-		} else {
-		    _cairo_output_stream_printf (surface->output,
-						 "      /D [%d null null 0]\n",
-						 node->annot.link_attrs.page);
-		}
-	    }
-	    _cairo_output_stream_printf (surface->output,
-					 "   >>\n");
-	}
+	status = cairo_pdf_interchange_write_link_action (surface, &node->annot.link_attrs);
+	if (unlikely (status))
+	    return status;
 
 	_cairo_output_stream_printf (surface->output,
 				     "   /BS << /W 0 >>"
@@ -373,8 +389,6 @@ cairo_pdf_interchange_write_annot (cairo_pdf_surface_t            *surface,
 				     "endobj\n");
 
 	status = _cairo_output_stream_get_status (surface->output);
-
-	free (dest);
     }
 
     return status;
@@ -520,7 +534,6 @@ cairo_pdf_interchange_write_outline (cairo_pdf_surface_t *surface)
     cairo_pdf_interchange_t *ic = &surface->interchange;
     cairo_int_status_t status;
     char *name = NULL;
-    char *dest = NULL;
 
     num_elems = _cairo_array_num_elements (&ic->outline);
     if (num_elems < 2)
@@ -549,10 +562,6 @@ cairo_pdf_interchange_write_outline (cairo_pdf_surface_t *surface)
 	if (unlikely (status))
 	    return status;
 
-	status = _cairo_utf8_to_pdf_string (outline->dest, &dest);
-	if (unlikely (status))
-	    return status;
-
 	_cairo_output_stream_printf (surface->output,
 				     "%d 0 obj\n"
 				     "<< /Title %s\n"
@@ -594,12 +603,13 @@ cairo_pdf_interchange_write_outline (cairo_pdf_surface_t *surface)
 					 flags);
 	}
 
+	status = cairo_pdf_interchange_write_link_action (surface, &outline->link_attrs);
+	if (unlikely (status))
+	    return status;
+
 	_cairo_output_stream_printf (surface->output,
-				     "   /Dest %s\n"
 				     ">>\n"
-				     "endobj\n",
-				     dest);
-	free (dest);
+				     "endobj\n");
     }
 
     return status;
@@ -1313,7 +1323,7 @@ cairo_int_status_t
 _cairo_pdf_interchange_add_outline (cairo_pdf_surface_t        *surface,
 				    int                         parent_id,
 				    const char                 *name,
-				    const char                 *dest,
+				    const char                 *link_attribs,
 				    cairo_pdf_outline_flags_t   flags,
 				    int                        *id)
 {
@@ -1329,12 +1339,17 @@ _cairo_pdf_interchange_add_outline (cairo_pdf_surface_t        *surface,
     if (unlikely (outline == NULL))
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
+    status = _cairo_tag_parse_link_attributes (link_attribs, &outline->link_attrs);
+    if (unlikely (status)) {
+	free (outline);
+	return status;
+    }
+
     outline->res = _cairo_pdf_surface_new_object (surface);
     if (outline->res.id == 0)
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
     outline->name = strdup (name);
-    outline->dest = strdup (dest);
     outline->flags = flags;
     outline->count = 0;
 
diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index be721af2..09262e0d 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-surface-private.h
@@ -194,7 +194,7 @@ typedef struct _cairo_pdf_named_dest {
 
 typedef struct _cairo_pdf_outline_entry {
     char *name;
-    char *dest;
+    cairo_link_attrs_t link_attrs;
     cairo_pdf_outline_flags_t flags;
     cairo_pdf_resource_t res;
     struct _cairo_pdf_outline_entry *parent;
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index f1ae9eec..c258b738 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -739,14 +739,15 @@ cairo_pdf_surface_set_size (cairo_surface_t	*surface,
  * @surface: a PDF #cairo_surface_t
  * @parent_id: the id of the parent item or %CAIRO_PDF_OUTLINE_ROOT if this is a top level item.
  * @utf8: the name of the outline
- * @dest: the name of the destination
+ * @link_attribs: the link attributes specifying where this outline links to
  * @flags: outline item flags
  *
- * Add an item to the document outline hierarchy with the name @utf8 that links to the
- * destinaton @dest. Destinations are created using
- * cairo_tag_begin()/cairo_tag_end() with the
- * %CAIRO_TAG_DEST. The item will be a child of the item with id @parent_id. Use %CAIRO_PDF_OUTLINE_ROOT
- * as the parent id of top level items.
+ * Add an item to the document outline hierarchy with the name @utf8
+ * that links to the location specified by @link_attribs. Link
+ * attributes have the same keys and values as the [Link Tag][link],
+ * excluding the "rect" attribute. The item will be a child of the
+ * item with id @parent_id. Use %CAIRO_PDF_OUTLINE_ROOT as the parent
+ * id of top level items.
  *
  * Return value: the id for the added item.
  *
@@ -756,7 +757,7 @@ int
 cairo_pdf_surface_add_outline (cairo_surface_t	         *surface,
 			       int                        parent_id,
 			       const char                *utf8,
-			       const char                *dest,
+			       const char                *link_attribs,
 			       cairo_pdf_outline_flags_t  flags)
 {
     cairo_pdf_surface_t *pdf_surface = NULL; /* hide compiler warning */
@@ -769,7 +770,7 @@ cairo_pdf_surface_add_outline (cairo_surface_t	         *surface,
     status = _cairo_pdf_interchange_add_outline (pdf_surface,
 						 parent_id,
 						 utf8,
-						 dest,
+						 link_attribs,
 						 flags,
 						 &id);
     if (status)
diff --git a/src/cairo-pdf.h b/src/cairo-pdf.h
index 040c0ed3..5be0b3f1 100644
--- a/src/cairo-pdf.h
+++ b/src/cairo-pdf.h
@@ -110,7 +110,7 @@ cairo_public int
 cairo_pdf_surface_add_outline (cairo_surface_t	          *surface,
 			       int                         parent_id,
 			       const char                 *utf8,
-			       const char                 *dest,
+			       const char                 *link_attribs,
 			       cairo_pdf_outline_flags_t  flags);
 
 /**
diff --git a/test/pdf-tagged-text.c b/test/pdf-tagged-text.c
index f7978942..afadd6b8 100644
--- a/test/pdf-tagged-text.c
+++ b/test/pdf-tagged-text.c
@@ -229,9 +229,11 @@ draw_section (cairo_surface_t *surface, cairo_t *cr, const struct section *secti
 {
     int flags, i;
     char buf[100];
+    char buf2[100];
 
     cairo_tag_begin (cr, "Sect", NULL);
     sprintf(buf, "name='%s'", section->heading);
+    sprintf(buf2, "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);
@@ -248,7 +250,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,
-							    section->heading,
+							    buf2,
 							    flags);
     } else {
 	if (section->level == 1) {
@@ -280,7 +282,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,
-									 section->heading,
+									 buf2,
 									 flags);
     }
 
@@ -327,6 +329,10 @@ create_document (cairo_surface_t *surface, cairo_t *cr)
     cairo_tag_begin (cr, "Document", NULL);
 
     draw_cover (surface, cr);
+    cairo_pdf_surface_add_outline (surface,
+				   CAIRO_PDF_OUTLINE_ROOT,
+				   "Cover", "page=1",
+                                   CAIRO_PDF_OUTLINE_FLAG_BOLD);
     cairo_show_page (cr);
 
     page_num = 0;
@@ -335,7 +341,7 @@ create_document (cairo_surface_t *surface, cairo_t *cr)
 
     cairo_pdf_surface_add_outline (surface,
 				   CAIRO_PDF_OUTLINE_ROOT,
-				   "Contents", "TOC",
+				   "Contents", "dest='TOC'",
                                    CAIRO_PDF_OUTLINE_FLAG_BOLD);
 
     cairo_tag_begin (cr, CAIRO_TAG_DEST, "name='TOC'");
commit df37baf7895ef9acc71f3627b22e7368c8af3ea1
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sat Aug 26 09:58:48 2017 +0930

    pdf: fix link positions
    
    Converting the link position from cairo to pdf coordinates requires
    the page height. Since the link may point to a different page, build
    an array of the height of each page and use the target page height for
    the conversion.
    
    Don't default to a [0,0] position if "pos" is not specified. PDF
    allows a null destination position to be specified which means don't
    change the position if the page is already displayed or show top left
    if switching to a different page. This is more useful default
    particularly for external files where the coordinates (which must be
    in PDF coordinates as we don't know the page height) of the top left
    corner may not be known.

diff --git a/src/cairo-pdf-interchange.c b/src/cairo-pdf-interchange.c
index baf3e0fe..1521fc25 100644
--- a/src/cairo-pdf-interchange.c
+++ b/src/cairo-pdf-interchange.c
@@ -239,6 +239,7 @@ cairo_pdf_interchange_write_annot (cairo_pdf_surface_t            *surface,
     int sp;
     char *dest = NULL;
     int i, num_rects;
+    double height;
 
     num_rects = _cairo_array_num_elements (&node->annot.link_attrs.rects);
     if (strcmp (node->name, CAIRO_TAG_LINK) == 0 &&
@@ -266,6 +267,7 @@ cairo_pdf_interchange_write_annot (cairo_pdf_surface_t            *surface,
 				     res.id,
 				     sp);
 
+	_cairo_array_copy_element (&surface->page_heights, node->annot.src_page - 1, &height);
 	if (num_rects > 0) {
 	    cairo_rectangle_int_t bbox_rect;
 
@@ -282,18 +284,18 @@ cairo_pdf_interchange_write_annot (cairo_pdf_surface_t            *surface,
 		else
 		    _cairo_rectangle_union (&bbox_rect, &recti);
 
-		write_rect_to_pdf_quad_points (surface->output, &rectf, node->annot.page_height);
+		write_rect_to_pdf_quad_points (surface->output, &rectf, height);
 		_cairo_output_stream_printf (surface->output, " ");
 	    }
 	    _cairo_output_stream_printf (surface->output,
 					 "]\n"
 					 "   /Rect [ ");
-	    write_rect_int_to_pdf_bbox (surface->output, &bbox_rect, node->annot.page_height);
+	    write_rect_int_to_pdf_bbox (surface->output, &bbox_rect, height);
 	    _cairo_output_stream_printf (surface->output, " ]\n");
 	} else {
 	    _cairo_output_stream_printf (surface->output,
 					 "   /Rect [ ");
-	    write_rect_int_to_pdf_bbox (surface->output, &node->annot.extents.extents, node->annot.page_height);
+	    write_rect_int_to_pdf_bbox (surface->output, &node->annot.extents.extents, height);
 	    _cairo_output_stream_printf (surface->output, " ]\n");
 	}
 
@@ -315,12 +317,19 @@ cairo_pdf_interchange_write_annot (cairo_pdf_surface_t            *surface,
 		if (page < 1 || page > (int)_cairo_array_num_elements (&surface->pages))
 		    return CAIRO_INT_STATUS_TAG_ERROR;
 
+		_cairo_array_copy_element (&surface->page_heights, page - 1, &height);
 		_cairo_array_copy_element (&surface->pages, page - 1, &res);
-		_cairo_output_stream_printf (surface->output,
-					     "   /Dest [%d 0 R /XYZ %f %f 0]\n",
-					     res.id,
-					     node->annot.link_attrs.pos.x,
-					     node->annot.page_height - node->annot.link_attrs.pos.y);
+		if (node->annot.link_attrs.has_pos) {
+		    _cairo_output_stream_printf (surface->output,
+						 "   /Dest [%d 0 R /XYZ %f %f 0]\n",
+						 res.id,
+						 node->annot.link_attrs.pos.x,
+						 height - node->annot.link_attrs.pos.y);
+		} else {
+		    _cairo_output_stream_printf (surface->output,
+						 "   /Dest [%d 0 R /XYZ null null 0]\n",
+						 res.id);
+		}
 	    }
 	} else if (node->annot.link_attrs.link_type == TAG_LINK_URI) {
 	    _cairo_output_stream_printf (surface->output,
@@ -342,11 +351,17 @@ cairo_pdf_interchange_write_annot (cairo_pdf_surface_t            *surface,
 					     "      /D %s\n",
 					     dest);
 	    } else {
-		_cairo_output_stream_printf (surface->output,
-					     "      /D [%d %f %f ]\n",
-					     node->annot.link_attrs.page,
-					     node->annot.link_attrs.pos.x,
-					     node->annot.link_attrs.pos.y);
+		if (node->annot.link_attrs.has_pos) {
+		    _cairo_output_stream_printf (surface->output,
+						 "      /D [%d %f %f 0]\n",
+						 node->annot.link_attrs.page,
+						 node->annot.link_attrs.pos.x,
+						 node->annot.link_attrs.pos.y);
+		} else {
+		    _cairo_output_stream_printf (surface->output,
+						 "      /D [%d null null 0]\n",
+						 node->annot.link_attrs.page);
+		}
 	    }
 	    _cairo_output_stream_printf (surface->output,
 					 "   >>\n");
@@ -769,6 +784,7 @@ _cairo_pdf_interchange_write_document_dests (cairo_pdf_surface_t *surface)
 	cairo_pdf_resource_t page_res;
 	double x = 0;
 	double y = 0;
+	double height;
 
 	if (dest->extents.valid) {
 	    x = dest->extents.extents.x;
@@ -782,12 +798,13 @@ _cairo_pdf_interchange_write_document_dests (cairo_pdf_surface_t *surface)
 	    y = dest->attrs.y;
 
 	_cairo_array_copy_element (&surface->pages, dest->page - 1, &page_res);
+	_cairo_array_copy_element (&surface->page_heights, dest->page - 1, &height);
 	_cairo_output_stream_printf (surface->output,
-				     "   (%s) [ %d 0 R /XYZ %f %f ]\n",
+				     "   (%s) [%d 0 R /XYZ %f %f 0]\n",
 				     dest->attrs.name,
 				     page_res.id,
 				     x,
-				     surface->height - y);
+				     height - y);
     }
     _cairo_output_stream_printf (surface->output,
 				     "  ]\n"
@@ -914,7 +931,7 @@ _cairo_pdf_interchange_begin_structure_tag (cairo_pdf_surface_t    *surface,
 	    if (unlikely (status))
 		return status;
 
-	    ic->current_node->annot.page_height = surface->height;
+	    ic->current_node->annot.src_page = _cairo_array_num_elements (&surface->pages);;
 	    cairo_list_add_tail (&ic->current_node->annot.extents.link, &ic->extents_list);
 	}
 
@@ -950,7 +967,6 @@ _cairo_pdf_interchange_begin_dest_tag (cairo_pdf_surface_t    *surface,
 	if (unlikely (status))
 	    return status;
 
-	dest->page_height = surface->height;
 	dest->page = _cairo_array_num_elements (&surface->pages);
 	init_named_dest_key (dest);
 	status = _cairo_hash_table_insert (ic->named_dests, &dest->base);
diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index a5c7d0ed..be721af2 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-surface-private.h
@@ -179,7 +179,7 @@ typedef struct _cairo_pdf_struct_tree_node {
 	struct tag_extents extents;
 	cairo_pdf_resource_t res;
 	cairo_link_attrs_t link_attrs;
-	double page_height;
+	int src_page; /* page number containing the link */
     } annot;
     cairo_list_t link;
 } cairo_pdf_struct_tree_node_t;
@@ -189,7 +189,6 @@ typedef struct _cairo_pdf_named_dest {
     struct tag_extents extents;
     cairo_dest_attrs_t attrs;
     int page;
-    double page_height;
     cairo_bool_t referenced;
 } cairo_pdf_named_dest_t;
 
@@ -267,6 +266,7 @@ struct _cairo_pdf_surface {
     cairo_array_t smask_groups;
     cairo_array_t knockout_group;
     cairo_array_t jbig2_global;
+    cairo_array_t page_heights;
 
     cairo_scaled_font_subsets_t *font_subsets;
     cairo_array_t fonts;
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index e60d0b9a..f1ae9eec 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -387,6 +387,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t	*output,
     _cairo_array_init (&surface->page_patterns, sizeof (cairo_pdf_pattern_t));
     _cairo_array_init (&surface->page_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);
@@ -2313,6 +2314,7 @@ _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++) {
@@ -4876,7 +4878,14 @@ _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;
+
     surface->current_page_label = NULL;
 
     status = _cairo_pdf_interchange_end_page_content (surface);
diff --git a/src/cairo-tag-attributes-private.h b/src/cairo-tag-attributes-private.h
index 0af23dc4..a127abc9 100644
--- a/src/cairo-tag-attributes-private.h
+++ b/src/cairo-tag-attributes-private.h
@@ -55,6 +55,7 @@ typedef struct _cairo_link_attrs {
     char *uri;
     char *file;
     int page;
+    cairo_bool_t has_pos;
     cairo_point_double_t pos;
 } cairo_link_attrs_t;
 
diff --git a/src/cairo-tag-attributes.c b/src/cairo-tag-attributes.c
index 685c26af..b3d08f6f 100644
--- a/src/cairo-tag-attributes.c
+++ b/src/cairo-tag-attributes.c
@@ -495,6 +495,7 @@ _cairo_tag_parse_link_attributes (const char *attributes, cairo_link_attrs_t *li
 	    link_attrs->pos.x = val.f;
 	    _cairo_array_copy_element (&attr->array, 1, &val);
 	    link_attrs->pos.y = val.f;
+	    link_attrs->has_pos = TRUE;
 	} else if (strcmp (attr->name, "rect") == 0) {
 	    cairo_rectangle_t rect;
 	    int i;
diff --git a/src/cairo.c b/src/cairo.c
index eb863efd..49cdbcf6 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -193,7 +193,7 @@
  * @page: An integer specifying the page number in the PDF file to link to.
  *
  * @pos: [optional] An array of two floats specifying the x,y position
- * on the page. Default is 0,0.
+ * on the page.
  *
  * An example of the link attributes to link to a page and x,y position:
  * <programlisting>
@@ -227,8 +227,9 @@
  *
  *  @page: An integer specifying the page number in the PDF file.
  *
- *  @pos: [optional] An array of two floats specifying the x,y position
- *  on the page. Default is 0,0.
+ *  @pos: [optional] An array of two floats specifying the x,y
+ *  position on the page. Position coordinates in external files are in PDF
+ *  coordinates (0,0 at bottom left).
  *
  * An example of the link attributes to PDF file:
  * <programlisting>


More information about the cairo-commit mailing list