[cairo-commit] 4 commits - build/aclocal.cairo.m4 src/cairo-atomic-private.h src/cairo-ft.h src/cairoint.h src/cairo-misc.c src/cairo-output-stream.c src/cairo-pdf-interchange.c src/cairo-pdf-surface.c src/cairo-pdf-surface-private.h src/cairo-png.c src/cairo-tag-attributes.c

Adrian Johnson ajohnson at kemper.freedesktop.org
Sun Nov 26 09:51:54 UTC 2017


 build/aclocal.cairo.m4          |    8 -
 src/cairo-atomic-private.h      |    9 --
 src/cairo-ft.h                  |    4 
 src/cairo-misc.c                |   62 +++++++++++++++
 src/cairo-output-stream.c       |    7 +
 src/cairo-pdf-interchange.c     |  165 ++++++++++++++++++++++++++++++----------
 src/cairo-pdf-surface-private.h |   14 +--
 src/cairo-pdf-surface.c         |    3 
 src/cairo-png.c                 |   20 +++-
 src/cairo-tag-attributes.c      |    4 
 src/cairoint.h                  |    4 
 11 files changed, 232 insertions(+), 68 deletions(-)

New commits:
commit 84fc0ce91d1a57d20500f710abc0e17de82c67df
Author: Tom Schoonjans <Tom.Schoonjans at diamond.ac.uk>
Date:   Thu Nov 2 16:55:22 2017 +0000

    Use UTF-8 filenames on Windows
    
    Until now fopen was used on Windows to open files for reading and
    writing. This assumed however that the filename would be encoded in the
    current codepage, which is a major inconvenience and makes it even
    impossible to use filenames that use characters from more than one
    codepage. This patch enforces the use of UTF-8 filenames on all
    platforms.
    
    Based on the work of Owen Taylor (https://lists.cairographics.org/archives/cairo/2007-February/009591.html)

diff --git a/src/cairo-misc.c b/src/cairo-misc.c
index 19629fec..07ffa9ff 100644
--- a/src/cairo-misc.c
+++ b/src/cairo-misc.c
@@ -41,6 +41,9 @@
 #include "cairoint.h"
 #include "cairo-error-private.h"
 
+#include <stdio.h>
+#include <errno.h>
+
 COMPILE_TIME_ASSERT ((int)CAIRO_STATUS_LAST_STATUS < (int)CAIRO_INT_STATUS_UNSUPPORTED);
 COMPILE_TIME_ASSERT (CAIRO_INT_STATUS_LAST_STATUS <= 127);
 
@@ -842,6 +845,65 @@ _cairo_strtod (const char *nptr, char **endptr)
     return value;
 }
 
+/**
+ * _cairo_fopen:
+ * @filename: filename to open
+ * @mode: mode string with which to open the file
+ * @file_out: reference to file handle
+ *
+ * Exactly like the C library function, but possibly doing encoding
+ * conversion on the filename. On all platforms, the filename is
+ * passed directly to the system, but on Windows, the filename is
+ * interpreted as UTF-8, rather than in a codepage that would depend
+ * on system settings.
+ *
+ * Return value: CAIRO_STATUS_SUCCESS when the filename was converted
+ * successfully to the native encoding, or the error reported by
+ * _cairo_utf8_to_utf16 otherwise. To check if the file handle could
+ * be obtained, dereference file_out and compare its value against
+ * NULL
+ **/
+cairo_status_t
+_cairo_fopen (const char *filename, const char *mode, FILE **file_out)
+{
+    FILE *result;
+#ifdef _WIN32 /* also defined on x86_64 */
+    uint16_t *filename_w;
+    uint16_t *mode_w;
+    cairo_status_t status;
+
+    *file_out = NULL;
+
+    if (filename == NULL || mode == NULL) {
+	errno = EINVAL;
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    if ((status = _cairo_utf8_to_utf16 (filename, -1, &filename_w, NULL)) != CAIRO_STATUS_SUCCESS) {
+	errno = EINVAL;
+	return status;
+    }
+
+    if ((status = _cairo_utf8_to_utf16 (mode, -1, &mode_w, NULL)) != CAIRO_STATUS_SUCCESS) {
+	free (filename_w);
+	errno = EINVAL;
+	return status;
+    }
+
+    result = _wfopen(filename_w, mode_w);
+
+    free (filename_w);
+    free (mode_w);
+
+#else /* Use fopen directly */
+    result = fopen (filename, mode);
+#endif
+
+    *file_out = result;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
 #ifdef _WIN32
 
 #define WIN32_LEAN_AND_MEAN
diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c
index f43f212e..cbb60c74 100644
--- a/src/cairo-output-stream.c
+++ b/src/cairo-output-stream.c
@@ -657,11 +657,16 @@ _cairo_output_stream_create_for_filename (const char *filename)
 {
     stdio_stream_t *stream;
     FILE *file;
+    cairo_status_t status;
 
     if (filename == NULL)
 	return _cairo_null_stream_create ();
 
-    file = fopen (filename, "wb");
+    status = _cairo_fopen (filename, "wb", &file);
+
+    if (status != CAIRO_STATUS_SUCCESS)
+	return _cairo_output_stream_create_in_error (status);
+
     if (file == NULL) {
 	switch (errno) {
 	case ENOMEM:
diff --git a/src/cairo-png.c b/src/cairo-png.c
index 5ea49f09..fe23fcf9 100644
--- a/src/cairo-png.c
+++ b/src/cairo-png.c
@@ -345,7 +345,8 @@ stdio_write_func (png_structp png, png_bytep data, png_size_t size)
 /**
  * cairo_surface_write_to_png:
  * @surface: a #cairo_surface_t with pixel contents
- * @filename: the name of a file to write to
+ * @filename: the name of a file to write to; on Windows this filename
+ *   is encoded in UTF-8.
  *
  * Writes the contents of @surface to a new file @filename as a PNG
  * image.
@@ -373,7 +374,11 @@ cairo_surface_write_to_png (cairo_surface_t	*surface,
     if (surface->finished)
 	return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
 
-    fp = fopen (filename, "wb");
+    status = _cairo_fopen (filename, "wb", &fp);
+
+    if (status != CAIRO_STATUS_SUCCESS)
+	return _cairo_error (status);
+
     if (fp == NULL) {
 	switch (errno) {
 	case ENOMEM:
@@ -738,7 +743,8 @@ read_png (struct png_read_closure_t *png_closure)
 
 /**
  * cairo_image_surface_create_from_png:
- * @filename: name of PNG file to load
+ * @filename: name of PNG file to load. On Windows this filename
+ *   is encoded in UTF-8.
  *
  * Creates a new image surface and initializes the contents to the
  * given PNG file.
@@ -764,10 +770,14 @@ cairo_image_surface_create_from_png (const char *filename)
 {
     struct png_read_closure_t png_closure;
     cairo_surface_t *surface;
+    cairo_status_t status;
+
+    status = _cairo_fopen (filename, "rb", (FILE **) &png_closure.closure);
+
+    if (status != CAIRO_STATUS_SUCCESS)
+	return _cairo_surface_create_in_error (status);
 
-    png_closure.closure = fopen (filename, "rb");
     if (png_closure.closure == NULL) {
-	cairo_status_t status;
 	switch (errno) {
 	case ENOMEM:
 	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
diff --git a/src/cairoint.h b/src/cairoint.h
index c44242a6..15427065 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1922,6 +1922,10 @@ _cairo_matrix_multiply (cairo_matrix_t *r,
 cairo_private void
 _cairo_observers_notify (cairo_list_t *observers, void *arg);
 
+/* Open a file with a UTF-8 filename */
+cairo_private cairo_status_t
+_cairo_fopen (const char *filename, const char *mode, FILE **file_out);
+
 /* Avoid unnecessary PLT entries.  */
 slim_hidden_proto (cairo_clip_preserve);
 slim_hidden_proto (cairo_close_path);
commit e5532f5ad7f5493d703f9a7110b0816b5fa33e54
Author: Mikhail Fludkov <misha at pexip.com>
Date:   Mon Nov 6 13:07:00 2017 +0100

    Fix code generation when using GCC legacy atomic operations
    
    https://bugs.freedesktop.org/show_bug.cgi?id=103559

diff --git a/build/aclocal.cairo.m4 b/build/aclocal.cairo.m4
index f0ea23c0..64c1a2e2 100644
--- a/build/aclocal.cairo.m4
+++ b/build/aclocal.cairo.m4
@@ -165,7 +165,7 @@ AC_DEFUN([CAIRO_CHECK_NATIVE_ATOMIC_PRIMITIVES],
 int atomic_add(int i) { return __sync_fetch_and_add (&i, 1); }
 int atomic_cmpxchg(int i, int j, int k) { return __sync_val_compare_and_swap (&i, j, k); }
 ], [],
-		  cairo_cv_atomic_primitives="Intel"
+		  cairo_cv_atomic_primitives="gcc-legacy"
 		  )
 
 		AC_TRY_LINK([
@@ -190,9 +190,9 @@ int atomic_cmpxchg(int i, int j, int k) { return __atomic_compare_exchange_n(&i,
 			  [Enable if your compiler supports the GCC __atomic_* atomic primitives])
 	fi
 
-	if test "x$cairo_cv_atomic_primitives" = xIntel; then
-		AC_DEFINE(HAVE_INTEL_ATOMIC_PRIMITIVES, 1,
-			  [Enable if your compiler supports the Intel __sync_* atomic primitives])
+	if test "x$cairo_cv_atomic_primitives" = xgcc-legacy; then
+		AC_DEFINE(HAVE_GCC_LEGACY_ATOMICS, 1,
+			  [Enable if your compiler supports the legacy GCC __sync_* atomic primitives])
 	fi
 
 	if test "x$cairo_cv_atomic_primitives" = "xlibatomic-ops"; then
diff --git a/src/cairo-atomic-private.h b/src/cairo-atomic-private.h
index 723a326c..46761856 100644
--- a/src/cairo-atomic-private.h
+++ b/src/cairo-atomic-private.h
@@ -157,13 +157,12 @@ _cairo_atomic_ptr_cmpxchg_return_old_impl(void **x, void *oldv, void *newv)
 
 #endif
 
-#if HAVE_INTEL_ATOMIC_PRIMITIVES
+#if HAVE_GCC_LEGACY_ATOMICS
 
 #define HAS_ATOMIC_OPS 1
 
 typedef int cairo_atomic_int_t;
 
-#ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER
 static cairo_always_inline cairo_atomic_int_t
 _cairo_atomic_int_get (cairo_atomic_int_t *x)
 {
@@ -189,12 +188,6 @@ _cairo_atomic_ptr_get (void **x)
     __sync_synchronize ();
     return *x;
 }
-#else
-# define _cairo_atomic_int_get(x) (*x)
-# define _cairo_atomic_int_get_relaxed(x) (*x)
-# define _cairo_atomic_int_set_relaxed(x, val) (*x) = (val)
-# define _cairo_atomic_ptr_get(x) (*x)
-#endif
 
 # define _cairo_atomic_int_inc(x) ((void) __sync_fetch_and_add(x, 1))
 # define _cairo_atomic_int_dec(x) ((void) __sync_fetch_and_add(x, -1))
commit f614f588e67daebd123bb6698b56d4b8054616c4
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sat Nov 11 16:59:47 2017 +1030

    Prevent -Wundef warnings in when cairo-ft.h is used without fontconfig

diff --git a/src/cairo-ft.h b/src/cairo-ft.h
index 29c43c96..3f775a88 100644
--- a/src/cairo-ft.h
+++ b/src/cairo-ft.h
@@ -46,7 +46,7 @@
 #include <ft2build.h>
 #include FT_FREETYPE_H
 
-#if CAIRO_HAS_FC_FONT
+#ifdef CAIRO_HAS_FC_FONT
 #include <fontconfig/fontconfig.h>
 #endif
 
@@ -98,7 +98,7 @@ cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *scaled_font);
 cairo_public void
 cairo_ft_scaled_font_unlock_face (cairo_scaled_font_t *scaled_font);
 
-#if CAIRO_HAS_FC_FONT
+#ifdef CAIRO_HAS_FC_FONT
 
 cairo_public cairo_font_face_t *
 cairo_ft_font_face_create_for_pattern (FcPattern *pattern);
commit a709197121c8e405c2dd99e408ee3046ccf50a6a
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Nov 26 13:03:18 2017 +1030

    pdf: fix some annotation bugs
    
    - each annotation was emitted on every page instead of just the page
      that contains the annotation
    
    - the document structure did not correctly link to annotation objects
    
    - fix some annotation related memory leaks

diff --git a/src/cairo-pdf-interchange.c b/src/cairo-pdf-interchange.c
index 461986fb..ea516660 100644
--- a/src/cairo-pdf-interchange.c
+++ b/src/cairo-pdf-interchange.c
@@ -112,8 +112,9 @@ add_tree_node (cairo_pdf_surface_t           *surface,
     node->parent = parent;
     cairo_list_init (&node->children);
     _cairo_array_init (&node->mcid, sizeof(struct page_mcid));
-    memset (&node->annot, 0, sizeof(node->annot));
-    cairo_list_init (&node->children);
+    node->annot_res.id = 0;
+    node->extents.valid = FALSE;
+    cairo_list_init (&node->extents.link);
 
     cairo_list_add_tail (&node->link, &parent->children);
 
@@ -167,6 +168,59 @@ add_mcid_to_node (cairo_pdf_surface_t          *surface,
 }
 
 static cairo_int_status_t
+add_annotation (cairo_pdf_surface_t           *surface,
+		cairo_pdf_struct_tree_node_t  *node,
+		const char                    *name,
+		const char                    *attributes)
+{
+    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
+    cairo_pdf_interchange_t *ic = &surface->interchange;
+    cairo_pdf_annotation_t *annot;
+
+    annot = malloc (sizeof(cairo_pdf_annotation_t));
+    if (unlikely (annot == NULL))
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    status = _cairo_tag_parse_link_attributes (attributes, &annot->link_attrs);
+    if (unlikely (status)) {
+	free (annot);
+	return status;
+    }
+
+    annot->node = node;
+
+    status = _cairo_array_append (&ic->annots, &annot);
+
+    return status;
+}
+
+static void
+free_annotation (cairo_pdf_annotation_t *annot)
+{
+    _cairo_array_fini (&annot->link_attrs.rects);
+    free (annot->link_attrs.dest);
+    free (annot->link_attrs.uri);
+    free (annot->link_attrs.file);
+    free (annot);
+}
+
+static void
+cairo_pdf_interchange_clear_annotations (cairo_pdf_surface_t *surface)
+{
+    cairo_pdf_interchange_t *ic = &surface->interchange;
+    int num_elems, i;
+
+    num_elems = _cairo_array_num_elements (&ic->annots);
+    for (i = 0; i < num_elems; i++) {
+	cairo_pdf_annotation_t * annot;
+
+	_cairo_array_copy_element (&ic->annots, i, &annot);
+	free_annotation (annot);
+    }
+    _cairo_array_truncate (&ic->annots, 0);
+}
+
+static cairo_int_status_t
 cairo_pdf_interchange_write_node_object (cairo_pdf_surface_t            *surface,
 					 cairo_pdf_struct_tree_node_t   *node)
 {
@@ -186,12 +240,16 @@ cairo_pdf_interchange_write_node_object (cairo_pdf_surface_t            *surface
 				 node->parent->res.id);
 
     if (! cairo_list_is_empty (&node->children)) {
-	if (cairo_list_is_singular (&node->children)) {
+	if (cairo_list_is_singular (&node->children) && node->annot_res.id == 0) {
 	    child = cairo_list_first_entry (&node->children, cairo_pdf_struct_tree_node_t, link);
 	    _cairo_output_stream_printf (surface->output, "   /K %d 0 R\n", child->res.id);
 	} else {
 	    _cairo_output_stream_printf (surface->output, "   /K [ ");
-
+	    if (node->annot_res.id != 0) {
+		_cairo_output_stream_printf (surface->output,
+					     "<< /Type /OBJR /Obj %d 0 R >> ",
+					     node->annot_res.id);
+	    }
 	    cairo_list_foreach_entry (child, cairo_pdf_struct_tree_node_t,
 				      &node->children, link)
 	    {
@@ -207,14 +265,14 @@ cairo_pdf_interchange_write_node_object (cairo_pdf_surface_t            *surface
 	    page_res = _cairo_array_index (&surface->pages, first_page - 1);
 	    _cairo_output_stream_printf (surface->output, "   /Pg %d 0 R\n", page_res->id);
 
-	    if (num_mcid == 1 && node->annot.res.id == 0) {
+	    if (num_mcid == 1 && node->annot_res.id == 0) {
 		_cairo_output_stream_printf (surface->output, "   /K %d\n", mcid_elem->mcid);
 	    } else {
 		_cairo_output_stream_printf (surface->output, "   /K [ ");
-		if (node->annot.res.id != 0) {
+		if (node->annot_res.id != 0) {
 		    _cairo_output_stream_printf (surface->output,
-						 "%d 0 R ",
-						 node->annot.res.id);
+						 "<< /Type /OBJR /Obj %d 0 R >> ",
+						 node->annot_res.id);
 		}
 		for (i = 0; i < num_mcid; i++) {
 		    mcid_elem = _cairo_array_index (&node->mcid, i);
@@ -415,43 +473,43 @@ cairo_pdf_interchange_write_link_action (cairo_pdf_surface_t   *surface,
 }
 
 static cairo_int_status_t
-cairo_pdf_interchange_write_annot (cairo_pdf_surface_t            *surface,
-				   cairo_pdf_struct_tree_node_t   *node)
+cairo_pdf_interchange_write_annot (cairo_pdf_surface_t    *surface,
+				   cairo_pdf_annotation_t *annot)
 {
-    cairo_pdf_resource_t res;
     cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
     cairo_pdf_interchange_t *ic = &surface->interchange;
+    cairo_pdf_struct_tree_node_t *node = annot->node;
     int sp;
     int i, num_rects;
     double height;
 
-    num_rects = _cairo_array_num_elements (&node->annot.link_attrs.rects);
+    num_rects = _cairo_array_num_elements (&annot->link_attrs.rects);
     if (strcmp (node->name, CAIRO_TAG_LINK) == 0 &&
-	node->annot.link_attrs.link_type != TAG_LINK_EMPTY &&
-	(node->annot.extents.valid || num_rects > 0))
+	annot->link_attrs.link_type != TAG_LINK_EMPTY &&
+	(node->extents.valid || num_rects > 0))
     {
-	res = _cairo_pdf_surface_new_object (surface);
-
-	status = _cairo_array_append (&ic->parent_tree, &res);
+	status = _cairo_array_append (&ic->parent_tree, &node->res);
 	if (unlikely (status))
 	    return status;
 
 	sp = _cairo_array_num_elements (&ic->parent_tree) - 1;
 
-	status = _cairo_array_append (&surface->page_annots, &res);
+	node->annot_res = _cairo_pdf_surface_new_object (surface);
+
+	status = _cairo_array_append (&surface->page_annots, &node->annot_res);
 	if (unlikely (status))
 	    return status;
 
-	_cairo_pdf_surface_update_object (surface, res);
+	_cairo_pdf_surface_update_object (surface, node->annot_res);
 	_cairo_output_stream_printf (surface->output,
 				     "%d 0 obj\n"
 				     "<< /Type /Annot\n"
 				     "   /Subtype /Link\n"
 				     "   /StructParent %d\n",
-				     res.id,
+				     node->annot_res.id,
 				     sp);
 
-	_cairo_array_copy_element (&surface->page_heights, node->annot.src_page - 1, &height);
+	height = surface->height;
 	if (num_rects > 0) {
 	    cairo_rectangle_int_t bbox_rect;
 
@@ -461,7 +519,7 @@ cairo_pdf_interchange_write_annot (cairo_pdf_surface_t            *surface,
 		cairo_rectangle_t rectf;
 		cairo_rectangle_int_t recti;
 
-		_cairo_array_copy_element (&node->annot.link_attrs.rects, i, &rectf);
+		_cairo_array_copy_element (&annot->link_attrs.rects, i, &rectf);
 		_cairo_rectangle_int_from_double (&recti, &rectf);
 		if (i == 0)
 		    bbox_rect = recti;
@@ -479,11 +537,11 @@ cairo_pdf_interchange_write_annot (cairo_pdf_surface_t            *surface,
 	} else {
 	    _cairo_output_stream_printf (surface->output,
 					 "   /Rect [ ");
-	    write_rect_int_to_pdf_bbox (surface->output, &node->annot.extents.extents, height);
+	    write_rect_int_to_pdf_bbox (surface->output, &node->extents.extents, height);
 	    _cairo_output_stream_printf (surface->output, " ]\n");
 	}
 
-	status = cairo_pdf_interchange_write_link_action (surface, &node->annot.link_attrs);
+	status = cairo_pdf_interchange_write_link_action (surface, &annot->link_attrs);
 	if (unlikely (status))
 	    return status;
 
@@ -572,13 +630,20 @@ static cairo_int_status_t
 cairo_pdf_interchange_write_page_annots (cairo_pdf_surface_t *surface)
 {
     cairo_pdf_interchange_t *ic = &surface->interchange;
+    int num_elems, i;
+    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
 
-    _cairo_array_truncate (&surface->page_annots, 0);
-    ic->annot_page = _cairo_array_num_elements (&surface->pages);
+    num_elems = _cairo_array_num_elements (&ic->annots);
+    for (i = 0; i < num_elems; i++) {
+	cairo_pdf_annotation_t * annot;
 
-    cairo_pdf_interchange_walk_struct_tree (surface, ic->struct_root, cairo_pdf_interchange_write_annot);
+	_cairo_array_copy_element (&ic->annots, i, &annot);
+	status = cairo_pdf_interchange_write_annot (surface, annot);
+	if (unlikely (status))
+	    return status;
+    }
 
-    return CAIRO_STATUS_SUCCESS;
+    return status;
 }
 
 static cairo_int_status_t
@@ -676,6 +741,7 @@ cairo_pdf_interchange_write_outline (cairo_pdf_surface_t *surface)
     for (i = 1; i < num_elems; i++) {
 	_cairo_array_copy_element (&ic->outline, i, &outline);
 	_cairo_pdf_surface_update_object (surface, outline->res);
+
 	status = _cairo_utf8_to_pdf_string (outline->name, &name);
 	if (unlikely (status))
 	    return status;
@@ -687,6 +753,7 @@ cairo_pdf_interchange_write_outline (cairo_pdf_surface_t *surface)
 				     outline->res.id,
 				     name,
 				     outline->parent->res.id);
+	free (name);
 
 	if (outline->prev) {
 	    _cairo_output_stream_printf (surface->output,
@@ -1030,12 +1097,11 @@ _cairo_pdf_interchange_begin_structure_tag (cairo_pdf_surface_t    *surface,
 	_cairo_tag_stack_set_top_data (&ic->analysis_tag_stack, ic->current_node);
 
 	if (tag_type & TAG_TYPE_LINK) {
-	    status = _cairo_tag_parse_link_attributes (attributes, &ic->current_node->annot.link_attrs);
+	    status = add_annotation (surface, ic->current_node, name, attributes);
 	    if (unlikely (status))
 		return status;
 
-	    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);
+	    cairo_list_add_tail (&ic->current_node->extents.link, &ic->extents_list);
 	}
 
     } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER) {
@@ -1143,7 +1209,7 @@ _cairo_pdf_interchange_end_structure_tag (cairo_pdf_surface_t    *surface,
 	if (tag_type & TAG_TYPE_LINK) {
 	    cairo_list_foreach_entry_safe (tag, next, struct tag_extents,
 					   &ic->extents_list, link) {
-		if (tag == &node->annot.extents) {
+		if (tag == &node->extents) {
 		    cairo_list_del (&tag->link);
 		    break;
 		}
@@ -1294,6 +1360,8 @@ _cairo_pdf_interchange_write_page_objects (cairo_pdf_surface_t *surface)
      if (unlikely (status))
 	return status;
 
+     cairo_pdf_interchange_clear_annotations (surface);
+
     return cairo_pdf_interchange_write_page_parent_elems (surface);
 }
 
@@ -1396,6 +1464,7 @@ _cairo_pdf_interchange_init (cairo_pdf_surface_t *surface)
     ic->end_page_node = NULL;
     _cairo_array_init (&ic->parent_tree, sizeof(cairo_pdf_resource_t));
     _cairo_array_init (&ic->mcid_to_tree, sizeof(cairo_pdf_struct_tree_node_t *));
+    _cairo_array_init (&ic->annots, sizeof(cairo_pdf_annotation_t *));
     ic->parent_tree_res.id = 0;
     cairo_list_init (&ic->extents_list);
     ic->named_dests = _cairo_hash_table_create (_named_dest_equal);
@@ -1418,29 +1487,43 @@ _cairo_pdf_interchange_init (cairo_pdf_surface_t *surface)
     return status;
 }
 
+static void
+_cairo_pdf_interchange_free_outlines (cairo_pdf_surface_t *surface)
+{
+    cairo_pdf_interchange_t *ic = &surface->interchange;
+    int num_elems, i;
+
+    num_elems = _cairo_array_num_elements (&ic->outline);
+    for (i = 0; i < num_elems; i++) {
+	cairo_pdf_outline_entry_t *outline;
+
+	_cairo_array_copy_element (&ic->outline, i, &outline);
+	free (outline->name);
+	free (outline->link_attrs.dest);
+	free (outline->link_attrs.uri);
+	free (outline->link_attrs.file);
+	free (outline);
+    }
+    _cairo_array_fini (&ic->outline);
+}
+
 cairo_int_status_t
 _cairo_pdf_interchange_fini (cairo_pdf_surface_t *surface)
 {
     cairo_pdf_interchange_t *ic = &surface->interchange;
-    unsigned i;
 
     _cairo_tag_stack_fini (&ic->analysis_tag_stack);
     _cairo_tag_stack_fini (&ic->render_tag_stack);
     _cairo_array_fini (&ic->push_data);
     free_node (ic->struct_root);
     _cairo_array_fini (&ic->mcid_to_tree);
+    cairo_pdf_interchange_clear_annotations (surface);
+    _cairo_array_fini (&ic->annots);
     _cairo_array_fini (&ic->parent_tree);
     _cairo_hash_table_foreach (ic->named_dests, _named_dest_pluck, ic->named_dests);
     _cairo_hash_table_destroy (ic->named_dests);
     free (ic->sorted_dests);
-
-    for (i = 0; i < _cairo_array_num_elements (&ic->outline); i++) {
-	cairo_pdf_outline_entry_t *outline;
-
-	_cairo_array_copy_element (&ic->outline, i, &outline);
-	free (outline);
-    }
-    _cairo_array_fini (&ic->outline);
+    _cairo_pdf_interchange_free_outlines (surface);
     free (ic->docinfo.title);
     free (ic->docinfo.author);
     free (ic->docinfo.subject);
diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index 51be6825..84fcf5f6 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-surface-private.h
@@ -178,15 +178,16 @@ typedef struct _cairo_pdf_struct_tree_node {
     struct _cairo_pdf_struct_tree_node *parent;
     cairo_list_t children;
     cairo_array_t mcid; /* array of struct page_mcid */
-    struct {
-	struct tag_extents extents;
-	cairo_pdf_resource_t res;
-	cairo_link_attrs_t link_attrs;
-	int src_page; /* page number containing the link */
-    } annot;
+    cairo_pdf_resource_t annot_res; /* 0 if no annot */
+    struct tag_extents extents;
     cairo_list_t link;
 } cairo_pdf_struct_tree_node_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_annotation_t;
+
 typedef struct _cairo_pdf_named_dest {
     cairo_hash_entry_t base;
     struct tag_extents extents;
@@ -228,6 +229,7 @@ typedef struct _cairo_pdf_interchange {
     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 */
+    cairo_array_t annots; /* array of pointers to cairo_pdf_annotation_t */
     cairo_pdf_resource_t parent_tree_res;
     cairo_list_t extents_list;
     cairo_hash_table_t *named_dests;
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 07f9c308..bf01fbaf 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -6934,7 +6934,7 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
     _cairo_pdf_surface_update_object (surface, *page);
     _cairo_output_stream_printf (surface->output,
 				 "%d 0 obj\n"
-				 "<< /Type /Page\n"
+				 "<< /Type /Page %% %d\n"
 				 "   /Parent %d 0 R\n"
 				 "   /MediaBox [ 0 0 %f %f ]\n"
 				 "   /Contents %d 0 R\n"
@@ -6946,6 +6946,7 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
 				 "   >>\n"
 				 "   /Resources %d 0 R\n",
 				 page->id,
+				 page_num,
 				 surface->pages_resource.id,
 				 surface->width,
 				 surface->height,
diff --git a/src/cairo-tag-attributes.c b/src/cairo-tag-attributes.c
index 05902b9c..91cd5aeb 100644
--- a/src/cairo-tag-attributes.c
+++ b/src/cairo-tag-attributes.c
@@ -432,6 +432,8 @@ parse_attributes (const char *attributes, attribute_spec_t *attrib_def, cairo_li
 
   fail2:
     _cairo_array_fini (&attrib->array);
+    if (attrib->type == ATTRIBUTE_STRING)
+	free (attrib->scalar.s);
     free (attrib);
   fail1:
     free (name);
@@ -449,6 +451,8 @@ free_attributes_list (cairo_list_t *list)
 	cairo_list_del (&attr->link);
 	free (attr->name);
 	_cairo_array_fini (&attr->array);
+	if (attr->type == ATTRIBUTE_STRING)
+	    free (attr->scalar.s);
 	free (attr);
     }
 }


More information about the cairo-commit mailing list