[cairo-commit] 5 commits - boilerplate/cairo-boilerplate.c boilerplate/cairo-boilerplate.h boilerplate/cairo-boilerplate-pdf.c boilerplate/cairo-boilerplate-svg.c src/cairo-analysis-surface.c src/cairo-analysis-surface-private.h src/cairo.c src/cairoint.h src/cairo-pdf-operators.c src/cairo-pdf-surface.c test/any2ppm.c

Chris Wilson ickle at kemper.freedesktop.org
Fri Sep 26 05:45:45 PDT 2008


 boilerplate/cairo-boilerplate-pdf.c  |   11 ------
 boilerplate/cairo-boilerplate-svg.c  |   11 ------
 boilerplate/cairo-boilerplate.c      |   57 ++++++++++++++++++++++++++++++++---
 boilerplate/cairo-boilerplate.h      |   11 +++++-
 src/cairo-analysis-surface-private.h |    3 +
 src/cairo-analysis-surface.c         |   50 +++++++++++++++++++++++-------
 src/cairo-pdf-operators.c            |   14 ++++++--
 src/cairo-pdf-surface.c              |   37 ++++++++--------------
 src/cairo.c                          |    3 -
 src/cairoint.h                       |    3 +
 test/any2ppm.c                       |   50 ++++++++++++++++++++++++++----
 11 files changed, 177 insertions(+), 73 deletions(-)

New commits:
commit 48099af9fed7497a230992e41d559a19c5dbdc60
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Sep 25 13:24:58 2008 +0100

    [boilerplate] Retry conversion in process if first attempt fails.
    
    One possibility for a read failure whilst converting the image is if the
    external utility crashed. This information is important for the test suite
    as knowing input that causes the converter to crash is just as vital as
    identifying a crash within the library.

diff --git a/boilerplate/cairo-boilerplate-pdf.c b/boilerplate/cairo-boilerplate-pdf.c
index fb7d1aa..470fb06 100644
--- a/boilerplate/cairo-boilerplate-pdf.c
+++ b/boilerplate/cairo-boilerplate-pdf.c
@@ -178,17 +178,8 @@ _cairo_boilerplate_pdf_convert_to_image (cairo_surface_t *surface)
 {
     pdf_target_closure_t *ptc = cairo_surface_get_user_data (surface,
 							     &pdf_closure_key);
-    FILE *file;
-    cairo_surface_t *image;
-
-    file = cairo_boilerplate_open_any2ppm (ptc->filename, 1);
-    if (file == NULL)
-	return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_READ_ERROR);
-
-    image = cairo_boilerplate_image_surface_create_from_ppm_stream (file);
-    fclose (file);
 
-    return image;
+    return cairo_boilerplate_convert_to_image (ptc->filename, 1);
 }
 
 cairo_surface_t *
diff --git a/boilerplate/cairo-boilerplate-svg.c b/boilerplate/cairo-boilerplate-svg.c
index 7a07d1b..c3ad8d2 100644
--- a/boilerplate/cairo-boilerplate-svg.c
+++ b/boilerplate/cairo-boilerplate-svg.c
@@ -170,17 +170,8 @@ _cairo_boilerplate_svg_convert_to_image (cairo_surface_t *surface)
 {
     svg_target_closure_t *ptc = cairo_surface_get_user_data (surface,
 							     &svg_closure_key);
-    FILE *file;
-    cairo_surface_t *image;
-
-    file = cairo_boilerplate_open_any2ppm (ptc->filename, 0);
-    if (file == NULL)
-	return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_READ_ERROR);
-
-    image = cairo_boilerplate_image_surface_create_from_ppm_stream (file);
-    fclose (file);
 
-    return image;
+    return cairo_boilerplate_convert_to_image (ptc->filename, 0);
 }
 
 cairo_surface_t *
diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c
index 039fb3d..65898e1 100644
--- a/boilerplate/cairo-boilerplate.c
+++ b/boilerplate/cairo-boilerplate.c
@@ -706,7 +706,8 @@ any2ppm_daemon_exists (void)
 
 FILE *
 cairo_boilerplate_open_any2ppm (const char *filename,
-				int page)
+				int page,
+				unsigned int flags)
 {
     char command[4096];
 #if HAS_DAEMON
@@ -714,6 +715,9 @@ cairo_boilerplate_open_any2ppm (const char *filename,
     struct sockaddr_un addr;
     int len;
 
+    if (flags & CAIRO_BOILERPLATE_OPEN_NO_DAEMON)
+	goto POPEN;
+
     if (! any2ppm_daemon_exists ()) {
 	if (system ("./any2ppm") != 0)
 	    goto POPEN;
@@ -747,7 +751,7 @@ POPEN:
 }
 
 static cairo_bool_t
-freadn (char *buf, int len, FILE *file)
+freadn (unsigned char *buf, int len, FILE *file)
 {
     int ret;
 
@@ -822,6 +826,33 @@ FAIL:
     return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_READ_ERROR);
 }
 
+cairo_surface_t *
+cairo_boilerplate_convert_to_image (const char *filename, int page)
+{
+    FILE *file;
+    unsigned int flags = 0;
+    cairo_surface_t *image;
+
+  RETRY:
+    file = cairo_boilerplate_open_any2ppm (filename, 1, flags);
+    if (file == NULL)
+	return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_READ_ERROR);
+
+    image = cairo_boilerplate_image_surface_create_from_ppm_stream (file);
+    fclose (file);
+
+    if (cairo_surface_status (image) == CAIRO_STATUS_READ_ERROR) {
+	if (flags == 0) {
+	    /* Try again in process, e.g. to propagate a CRASH. */
+	    cairo_surface_destroy (image);
+	    flags = CAIRO_BOILERPLATE_OPEN_NO_DAEMON;
+	    goto RETRY;
+	}
+    }
+
+    return image;
+}
+
 int
 cairo_boilerplate_version (void)
 {
diff --git a/boilerplate/cairo-boilerplate.h b/boilerplate/cairo-boilerplate.h
index df2da09..7b6dbc3 100644
--- a/boilerplate/cairo-boilerplate.h
+++ b/boilerplate/cairo-boilerplate.h
@@ -176,13 +176,20 @@ cairo_boilerplate_get_image_surface_from_png (const char *filename,
 cairo_surface_t *
 cairo_boilerplate_surface_create_in_error (cairo_status_t status);
 
+enum {
+    CAIRO_BOILERPLATE_OPEN_NO_DAEMON = 0x1,
+};
+
 FILE *
 cairo_boilerplate_open_any2ppm (const char *filename,
-				int page);
-
+				int page,
+				unsigned int flags);
 cairo_surface_t *
 cairo_boilerplate_image_surface_create_from_ppm_stream (FILE *file);
 
+cairo_surface_t *
+cairo_boilerplate_convert_to_image (const char *filename, int page);
+
 int
 cairo_boilerplate_version (void);
 
commit f2c484d73ce61012a2d9925f15b55e7c51e34b85
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Sep 25 00:16:45 2008 +0100

    [test/any2ppm] Handle short reads/writes.
    
    No excuse other than simple laziness - it manifested itself with random
    "error whilst reading" failures.

diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c
index f7146b7..039fb3d 100644
--- a/boilerplate/cairo-boilerplate.c
+++ b/boilerplate/cairo-boilerplate.c
@@ -746,6 +746,24 @@ POPEN:
     return popen (command, "r");
 }
 
+static cairo_bool_t
+freadn (char *buf, int len, FILE *file)
+{
+    int ret;
+
+    while (len) {
+	ret = fread (buf, 1, len, file);
+	if (ret != len) {
+	    if (ferror (file) || feof (file))
+		return FALSE;
+	}
+	len -= ret;
+	buf += len;
+    }
+
+    return TRUE;
+}
+
 cairo_surface_t *
 cairo_boilerplate_image_surface_create_from_ppm_stream (FILE *file)
 {
@@ -780,18 +798,18 @@ cairo_boilerplate_image_surface_create_from_ppm_stream (FILE *file)
 	unsigned char *buf = data + y *stride;
 	switch (format) {
 	case '7':
-	    if (fread (buf, 4, width, file) != (size_t) width)
+	    if (! freadn (buf, 4 * width, file))
 		goto FAIL;
 	    break;
 	case '6':
 	    for (x = 0; x < width; x++) {
-		if (fread (buf, 1, 3, file) != 3)
+		if (! freadn (buf, 3, file))
 		    goto FAIL;
 		buf += 4;
 	    }
 	    break;
 	case '5':
-	    if (fread (buf, 1, width, file) != (size_t) width)
+	    if (! freadn (buf, width, file))
 		goto FAIL;
 	    break;
 	}
diff --git a/test/any2ppm.c b/test/any2ppm.c
index bca35f3..412bbb8 100644
--- a/test/any2ppm.c
+++ b/test/any2ppm.c
@@ -79,6 +79,7 @@
 #include <sys/socket.h>
 #include <sys/poll.h>
 #include <sys/un.h>
+#include <errno.h>
 
 #define SOCKET_PATH "./.any2ppm"
 #define TIMEOUT 60000 /* 60 seconds */
@@ -89,6 +90,30 @@
 #define ARRAY_LENGTH(A) (sizeof (A) / sizeof (A[0]))
 
 static int
+_writen (int fd, char *buf, int len)
+{
+    while (len) {
+	int ret;
+
+	ret = write (fd, buf, len);
+	if (ret == -1) {
+	    int err = errno;
+	    switch (err) {
+	    case EINTR:
+	    case EAGAIN:
+		continue;
+	    default:
+		return 0;
+	    }
+	}
+	len -= ret;
+	buf += ret;
+    }
+
+    return 1;
+}
+
+static int
 _write (int fd,
 	char *buf, int maxlen, int buflen,
 	const unsigned char *src, int srclen)
@@ -110,8 +135,9 @@ _write (int fd,
 	src += len;
 
 	if (buflen == maxlen) {
-	    if (write (fd, buf, maxlen) != maxlen)
+	    if (! _writen (fd, buf, buflen))
 		return -1;
+
 	    buflen = 0;
 	}
     }
@@ -180,10 +206,8 @@ write_ppm (cairo_surface_t *surface, int fd)
 	    return "write failed";
     }
 
-    if (len) {
-	if (write (fd, buf, len) != len)
-	    return "write failed";
-    }
+    if (len && ! _writen (fd, buf, len))
+	return "write failed";
 
     return NULL;
 }
@@ -548,8 +572,20 @@ any2ppm_daemon (void)
 	    if (_getline (fd, &line, &len) != -1) {
 		char *argv[10];
 
-		if (split_line (line, argv, ARRAY_LENGTH (argv)) > 0)
-		    convert (argv, fd);
+		if (split_line (line, argv, ARRAY_LENGTH (argv)) > 0) {
+		    const char *err;
+
+		    err = convert (argv, fd);
+		    if (err != NULL) {
+			FILE *file = fopen (".any2ppm.errors", "a");
+			if (file != NULL) {
+			    fprintf (file,
+				     "Failed to convert '%s': %s\n",
+				     argv[0], err);
+			    fclose (file);
+			}
+		    }
+		}
 	    }
 	    close (fd);
 	}
commit 681424cbaf94556bf1804547b42ad642c0a066ab
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Sep 25 10:40:32 2008 +0100

    [analysis] Merge two analysis status codes.
    
    Since there is an implicit precedence in the ranking of the analysis
    return codes, provide a function to centralize the logic within the
    analysis surface and isolate the backends from the complexity.

diff --git a/src/cairo-analysis-surface-private.h b/src/cairo-analysis-surface-private.h
index b756a4b..28bfd3b 100644
--- a/src/cairo-analysis-surface-private.h
+++ b/src/cairo-analysis-surface-private.h
@@ -66,6 +66,9 @@ cairo_private void
 _cairo_analysis_surface_get_bounding_box (cairo_surface_t *surface,
 					  cairo_box_t     *bbox);
 
+cairo_private cairo_int_status_t
+_cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
+				      cairo_int_status_t status_b);
 
 cairo_private cairo_surface_t *
 _cairo_null_surface_create (cairo_content_t content);
diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index ed3c9ef..c33260d 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -62,6 +62,38 @@ typedef struct {
 
 } cairo_analysis_surface_t;
 
+cairo_int_status_t
+_cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
+				      cairo_int_status_t status_b)
+{
+    /* fatal errors should be checked and propagated at source */
+    assert (! _cairo_status_is_error (status_a));
+    assert (! _cairo_status_is_error (status_b));
+
+    /* return the most important status */
+    if (status_a == CAIRO_INT_STATUS_UNSUPPORTED ||
+	status_b == CAIRO_INT_STATUS_UNSUPPORTED)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if (status_a == CAIRO_INT_STATUS_IMAGE_FALLBACK ||
+	status_b == CAIRO_INT_STATUS_IMAGE_FALLBACK)
+	return CAIRO_INT_STATUS_IMAGE_FALLBACK;
+
+    if (status_a == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN ||
+	status_b == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
+	return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
+
+    if (status_a == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY ||
+	status_b == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
+	return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
+
+    /* at this point we have checked all the valid internal codes, so... */
+    assert (status_a == CAIRO_STATUS_SUCCESS &&
+	    status_b == CAIRO_STATUS_SUCCESS);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
 static cairo_int_status_t
 _analyze_meta_surface_pattern (cairo_analysis_surface_t	*surface,
 			       cairo_pattern_t		*pattern)
@@ -349,8 +381,7 @@ _cairo_analysis_surface_mask (void		*abstract_surface,
 	    if (_cairo_surface_is_meta (surface_pattern->surface)) {
 		backend_source_status =
 		    _analyze_meta_surface_pattern (surface, source);
-		if (backend_source_status != CAIRO_STATUS_SUCCESS &&
-		    backend_source_status != CAIRO_INT_STATUS_IMAGE_FALLBACK)
+		if (_cairo_status_is_error (backend_source_status))
 		    return backend_source_status;
 	    }
 	}
@@ -360,19 +391,14 @@ _cairo_analysis_surface_mask (void		*abstract_surface,
 	    if (_cairo_surface_is_meta (surface_pattern->surface)) {
 		backend_mask_status =
 		    _analyze_meta_surface_pattern (surface, mask);
-		if (backend_mask_status != CAIRO_STATUS_SUCCESS &&
-		    backend_mask_status != CAIRO_INT_STATUS_IMAGE_FALLBACK)
-		    return backend_status;
+		if (_cairo_status_is_error (backend_mask_status))
+		    return backend_mask_status;
 	    }
 	}
 
-	backend_status = CAIRO_STATUS_SUCCESS;
-
-	if (backend_source_status == CAIRO_INT_STATUS_IMAGE_FALLBACK ||
-	    backend_mask_status == CAIRO_INT_STATUS_IMAGE_FALLBACK)
-	{
-	    backend_status = CAIRO_INT_STATUS_IMAGE_FALLBACK;
-	}
+	backend_status =
+	    _cairo_analysis_surface_merge_status (backend_source_status,
+						  backend_mask_status);
     }
 
     status = _cairo_surface_get_extents (&surface->base, &extents);
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 0c6b219..16abab3 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -44,10 +44,11 @@
 #include "cairo-pdf.h"
 #include "cairo-pdf-surface-private.h"
 #include "cairo-pdf-operators-private.h"
-#include "cairo-scaled-font-subsets-private.h"
-#include "cairo-paginated-private.h"
-#include "cairo-output-stream-private.h"
+#include "cairo-analysis-surface-private.h"
 #include "cairo-meta-surface-private.h"
+#include "cairo-output-stream-private.h"
+#include "cairo-paginated-private.h"
+#include "cairo-scaled-font-subsets-private.h"
 #include "cairo-type3-glyph-surface-private.h"
 
 #include <time.h>
@@ -4475,30 +4476,16 @@ _cairo_pdf_surface_mask	(void			*abstract_surface,
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
 	cairo_status_t source_status, mask_status;
 
-	source_status =  _cairo_pdf_surface_analyze_operation (surface, op, source);
-	if (source_status != CAIRO_STATUS_SUCCESS &&
-	    source_status < CAIRO_INT_STATUS_UNSUPPORTED)
+	source_status = _cairo_pdf_surface_analyze_operation (surface, op, source);
+	if (_cairo_status_is_error (source_status))
 	    return source_status;
 
 	mask_status = _cairo_pdf_surface_analyze_operation (surface, op, mask);
-	if (mask_status != CAIRO_STATUS_SUCCESS &&
-	    mask_status < CAIRO_INT_STATUS_UNSUPPORTED)
+	if (_cairo_status_is_error (mask_status))
 	    return mask_status;
 
-	/* return the most important status from either the source or mask */
-	if (source_status == CAIRO_INT_STATUS_UNSUPPORTED ||
-	    mask_status == CAIRO_INT_STATUS_UNSUPPORTED)
-	    return CAIRO_INT_STATUS_UNSUPPORTED;
-
-	if (source_status == CAIRO_INT_STATUS_IMAGE_FALLBACK ||
-	    mask_status == CAIRO_INT_STATUS_IMAGE_FALLBACK)
-	    return CAIRO_INT_STATUS_IMAGE_FALLBACK;
-
-	if (source_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN ||
-	    mask_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
-	    return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
-
-	return CAIRO_STATUS_SUCCESS;
+	return _cairo_analysis_surface_merge_status (source_status,
+						     mask_status);
     } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
 	status = _cairo_pdf_surface_start_fallback (surface);
 	if (status)
commit 06f0cc81d227a571e011e83cc192050a34d6ea13
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Sep 25 10:29:27 2008 +0100

    Add a macro to determine whether a status is a fatal error.
    
    In a few places we need to check whether we have a fatal error or an
    internal return code, so provide a utility macro to centralise the check.

diff --git a/src/cairo.c b/src/cairo.c
index 9bb2b66..b7a1b86 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -84,8 +84,7 @@ static const cairo_t _cairo_nil = {
 cairo_status_t
 _cairo_error (cairo_status_t status)
 {
-    assert (status > CAIRO_STATUS_SUCCESS &&
-	    status <= CAIRO_STATUS_LAST_STATUS);
+    assert (_cairo_status_is_error (status));
 
     return status;
 }
diff --git a/src/cairoint.h b/src/cairoint.h
index 1a3d164..343b6f8 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2370,6 +2370,9 @@ _cairo_utf8_to_utf16 (const char *str,
 		      int	 *items_written);
 #endif
 
+#define _cairo_status_is_error(status) \
+    (status != CAIRO_STATUS_SUCCESS && status <= CAIRO_STATUS_LAST_STATUS)
+
 cairo_private cairo_status_t
 _cairo_error (cairo_status_t status);
 
commit ba18d57339dbedbbdb7f3ca35b06ce6b5dbcd972
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Sep 25 09:39:41 2008 +0100

    [pdf] Propagate status
    
    Check and return a few forgotten error codes from static functions.

diff --git a/src/cairo-pdf-operators.c b/src/cairo-pdf-operators.c
index baa36de..819318a 100644
--- a/src/cairo-pdf-operators.c
+++ b/src/cairo-pdf-operators.c
@@ -1303,7 +1303,10 @@ _cairo_pdf_operators_emit_cluster (cairo_pdf_operators_t      *pdf_operators,
 
     /* Fallback to using ActualText to map zero or more glyphs to a
      * unicode string. */
-    _cairo_pdf_operators_flush_glyphs (pdf_operators);
+    status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
+    if (status)
+	return status;
+
     status = _cairo_pdf_operators_begin_actualtext (pdf_operators, utf8, utf8_len);
     if (status)
 	return status;
@@ -1367,7 +1370,9 @@ _cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t	  *pdf_operators,
 
     pdf_operators->is_new_text_object = FALSE;
     if (pdf_operators->in_text_object == FALSE) {
-	_cairo_pdf_operators_begin_text (pdf_operators);
+	status = _cairo_pdf_operators_begin_text (pdf_operators);
+	if (status)
+	    return status;
 
 	/* Force Tm and Tf to be emitted when starting a new text
 	 * object.*/
@@ -1386,7 +1391,10 @@ _cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t	  *pdf_operators,
     if (pdf_operators->is_new_text_object ||
 	! _cairo_matrix_scale_equal (&pdf_operators->text_matrix, &text_matrix))
     {
-	_cairo_pdf_operators_flush_glyphs (pdf_operators);
+	status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
+	if (status)
+	    return status;
+
 	x = glyphs[0].x;
 	y = glyphs[0].y;
 	cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &x, &y);
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index f96e1fc..0c6b219 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -2956,7 +2956,11 @@ _cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t		*surface,
                                          "<%02x> ",
                                          i + 1);
         }
-	_cairo_pdf_surface_emit_unicode_for_glyph (surface, font_subset->utf8[i + 1]);
+	status = _cairo_pdf_surface_emit_unicode_for_glyph (surface,
+							    font_subset->utf8[i + 1]);
+	if (status)
+	    return status;
+
 	_cairo_output_stream_printf (surface->output,
 				     "\n");
     }


More information about the cairo-commit mailing list