[cairo-commit] cairo/src cairo-array.c, 1.4, 1.5 cairo-atsui-font.c, 1.13, 1.14 cairo-font.c, 1.55, 1.56 cairo-ft-font.c, 1.78, 1.79 cairo-glitz-surface.c, 1.52, 1.53 cairo-gstate.c, 1.148, 1.149 cairo-image-surface.c, 1.50, 1.51 cairo-meta-surface.c, 1.4, 1.5 cairo-path-data.c, 1.7, 1.8 cairo-pattern.c, 1.50, 1.51 cairo-pdf-surface.c, 1.53, 1.54 cairo-png.c, 1.17, 1.18 cairo-ps-surface.c, 1.43, 1.44 cairo-quartz-surface.c, 1.14, 1.15 cairo-surface.c, 1.80, 1.81 cairo-win32-font.c, 1.26, 1.27 cairo-win32-surface.c, 1.29, 1.30 cairo-xcb-surface.c, 1.40, 1.41 cairo-xlib-surface.c, 1.97, 1.98 cairo.c, 1.114, 1.115 cairo.h, 1.139, 1.140 cairoint.h, 1.169, 1.170

Carl Worth commit at pdx.freedesktop.org
Wed Jul 27 15:39:39 PDT 2005


Committed by: cworth

Update of /cvs/cairo/cairo/src
In directory gabe:/tmp/cvs-serv415/src

Modified Files:
	cairo-array.c cairo-atsui-font.c cairo-font.c cairo-ft-font.c 
	cairo-glitz-surface.c cairo-gstate.c cairo-image-surface.c 
	cairo-meta-surface.c cairo-path-data.c cairo-pattern.c 
	cairo-pdf-surface.c cairo-png.c cairo-ps-surface.c 
	cairo-quartz-surface.c cairo-surface.c cairo-win32-font.c 
	cairo-win32-surface.c cairo-xcb-surface.c cairo-xlib-surface.c 
	cairo.c cairo.h cairoint.h 
Log Message:

        * src/cairo.h: Add CAIRO_STATUS_INVALID_CONTENT,
        CAIRO_STATUS_INVALID_FORMAT, and CAIRO_STATUS_INVALID_VISUAL.

        Change functions to return type of void:

                cairo_scaled_font_extents
                cairo_surface_finish

        Add new functions to query object status:

                cairo_scaled_font_status
                cairo_surface_status

        * doc/public/tmpl/cairo.sgml:
        * src/cairo-array.c:
        * src/cairo-atsui-font.c:
        * src/cairo-font.c:
        * src/cairo-ft-font.c:
        * src/cairo-glitz-surface.c:
        * src/cairo-gstate.c:
        * src/cairo-image-surface.c:
        * src/cairo-meta-surface.c:
        * src/cairo-path-data.c:
        * src/cairo-pattern.c:
        * src/cairo-pdf-surface.c:
        * src/cairo-png.c:
        * src/cairo-ps-surface.c:
        * src/cairo-quartz-surface.c:
        * src/cairo-surface.c:
        * src/cairo-win32-font.c:
        * src/cairo-win32-surface.c:
        * src/cairo-xcb-surface.c:
        * src/cairo-xlib-surface.c:
        * src/cairo.c:
        * src/cairoint.h: Implementation of new error handling scheme for
        cairo_surface_t and cairo_scaled_font_t.

        * test/surface-finish-twice.c: Track change in return value of
        cairo_surface_finish.


Index: cairo-array.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-array.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- cairo-array.c	3 Jun 2005 23:16:44 -0000	1.4
+++ cairo-array.c	27 Jul 2005 22:39:35 -0000	1.5
@@ -198,6 +198,11 @@
     int i, num_slots;
     cairo_user_data_slot_t *slots;
 
+    /* We allow this to support degenerate objects such as
+     * cairo_image_surface_nil. */
+    if (array == NULL)
+	return NULL;
+
     num_slots = array->num_elements;
     slots = (cairo_user_data_slot_t *) array->elements;
     for (i = 0; i < num_slots; i++) {

Index: cairo-atsui-font.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-atsui-font.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- cairo-atsui-font.c	28 Jun 2005 18:52:42 -0000	1.13
+++ cairo-atsui-font.c	27 Jul 2005 22:39:35 -0000	1.14
@@ -68,7 +68,6 @@
 
 const cairo_scaled_font_backend_t cairo_atsui_scaled_font_backend;
 
-
 static CGAffineTransform
 CGAffineTransformMakeWithCairoFontScale(cairo_matrix_t *scale)
 {
@@ -77,7 +76,6 @@
                                  0, 0);
 }
 
-
 static ATSUStyle
 CreateSizedCopyOfStyle(ATSUStyle inStyle, cairo_matrix_t *scale)
 {
@@ -691,7 +689,6 @@
     return CAIRO_STATUS_SUCCESS;
 }
 
-
 const cairo_scaled_font_backend_t cairo_atsui_scaled_font_backend = {
     _cairo_atsui_font_create,
     _cairo_atsui_font_destroy_font,

Index: cairo-font.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-font.c,v
retrieving revision 1.55
retrieving revision 1.56
diff -u -d -r1.55 -r1.56
--- cairo-font.c	25 Jul 2005 23:23:05 -0000	1.55
+++ cairo-font.c	27 Jul 2005 22:39:35 -0000	1.56
@@ -421,6 +421,56 @@
 
 /* cairo_scaled_font_t */
 
+const cairo_scaled_font_t _cairo_scaled_font_nil = {
+    CAIRO_STATUS_NO_MEMORY,	/* status */
+    -1,				/* ref_count */
+    { 1., 0., 0., 1., 0, 0},	/* font_matrix */
+    { 1., 0., 0., 1., 0, 0},	/* ctm */
+    { 1., 0., 0., 1., 0, 0},	/* scale */
+    NULL,			/* font_face */
+    CAIRO_SCALED_FONT_BACKEND_DEFAULT,
+};
+
+/**
+ * _cairo_scaled_font_set_error:
+ * @scaled_font: a scaled_font
+ * @status: a status value indicating an error, (eg. not
+ * CAIRO_STATUS_SUCCESS)
+ * 
+ * Sets scaled_font->status to @status and calls _cairo_error;
+ *
+ * All assignments of an error status to scaled_font->status should happen
+ * through _cairo_scaled_font_set_error() or else _cairo_error() should be
+ * called immediately after the assignment.
+ *
+ * The purpose of this function is to allow the user to set a
+ * breakpoint in _cairo_error() to generate a stack trace for when the
+ * user causes cairo to detect an error.
+ **/
+void
+_cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
+			      cairo_status_t status)
+{
+    scaled_font->status = status;
+
+    _cairo_error (status);
+}
+
+/**
+ * cairo_scaled_font_status:
+ * @surface: a #cairo_scaled_font_t
+ * 
+ * Checks whether an error has previously occurred for this
+ * scaled_font.
+ * 
+ * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NULL_POINTER.
+ **/
+cairo_status_t
+cairo_scaled_font_status (cairo_scaled_font_t *scaled_font)
+{
+    return scaled_font->status;
+}
+
 /* Here we keep a cache from cairo_font_face_t/matrix/ctm => cairo_scaled_font_t.
  *
  * The implementation is messy because we want
@@ -750,7 +800,8 @@
     cache = _get_outer_font_cache ();
     if (cache == NULL) {
 	_unlock_global_font_cache ();
-	return NULL;
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_scaled_font_t*) &_cairo_scaled_font_nil;
     }
     
     status = _cairo_cache_lookup (cache, &key, (void **) &entry, NULL);
@@ -758,8 +809,10 @@
 	cairo_scaled_font_reference (entry->scaled_font);
     
     _unlock_global_font_cache ();
-    if (status)
-	return NULL;
+    if (status) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_scaled_font_t*) &_cairo_scaled_font_nil;
+    }
     
     return entry->scaled_font;
 }
@@ -770,6 +823,8 @@
 			 const cairo_matrix_t              *ctm,
 			 const cairo_scaled_font_backend_t *backend)
 {
+    scaled_font->status = CAIRO_STATUS_SUCCESS;
+
     scaled_font->font_matrix = *font_matrix;
     scaled_font->ctm = *ctm;
     cairo_matrix_multiply (&scaled_font->scale, &scaled_font->font_matrix, &scaled_font->ctm);
@@ -784,6 +839,9 @@
 				   cairo_glyph_t      **glyphs, 
 				   int 		       *num_glyphs)
 {
+    if (scaled_font->status)
+	return scaled_font->status;
+
     return scaled_font->backend->text_to_glyphs (scaled_font, utf8, glyphs, num_glyphs);
 }
 
@@ -793,6 +851,9 @@
 				  int 			 num_glyphs,
 				  cairo_text_extents_t  *extents)
 {
+    if (scaled_font->status)
+	return scaled_font->status;
+
     return scaled_font->backend->glyph_extents (scaled_font, glyphs, num_glyphs, extents);
 }
 
@@ -803,6 +864,9 @@
 			       int                  num_glyphs,
 			       cairo_box_t	   *bbox)
 {
+    if (scaled_font->status)
+	return scaled_font->status;
+
     return scaled_font->backend->glyph_bbox (scaled_font, glyphs, num_glyphs, bbox);
 }
 
@@ -822,6 +886,9 @@
 {
     cairo_status_t status;
 
+    if (scaled_font->status)
+	return scaled_font->status;
+
     status = _cairo_surface_show_glyphs (scaled_font, operator, pattern, 
 					 surface,
 					 source_x, source_y,
@@ -846,20 +913,31 @@
 			       int		    num_glyphs,
 			       cairo_path_fixed_t  *path)
 {
+    if (scaled_font->status)
+	return scaled_font->status;
+
     return scaled_font->backend->glyph_path (scaled_font, glyphs, num_glyphs, path);
 }
 
-void
+cairo_status_t
 _cairo_scaled_font_get_glyph_cache_key (cairo_scaled_font_t     *scaled_font,
 					cairo_glyph_cache_key_t *key)
 {
+    if (scaled_font->status)
+	return scaled_font->status;
+
     scaled_font->backend->get_glyph_cache_key (scaled_font, key);
+
+    return CAIRO_STATUS_SUCCESS;
 }
 
 cairo_status_t
 _cairo_scaled_font_font_extents (cairo_scaled_font_t  *scaled_font,
 				 cairo_font_extents_t *extents)
 {
+    if (scaled_font->status)
+	return scaled_font->status;
+
     return scaled_font->backend->font_extents (scaled_font, extents);
 }
 
@@ -913,6 +991,9 @@
     if (scaled_font == NULL)
 	return;
 
+    if (scaled_font->ref_count == (unsigned int)-1)
+	return;
+
     scaled_font->ref_count++;
 }
 
@@ -933,6 +1014,9 @@
     if (scaled_font == NULL)
 	return;
 
+    if (scaled_font->ref_count == (unsigned int)-1)
+	return;
+
     if (--(scaled_font->ref_count) > 0)
 	return;
 
@@ -966,17 +1050,23 @@
  * Return value: %CAIRO_STATUS_SUCCESS on success. Otherwise, an
  *  error such as %CAIRO_STATUS_NO_MEMORY.
  **/
-cairo_status_t
+void
 cairo_scaled_font_extents (cairo_scaled_font_t  *scaled_font,
 			   cairo_font_extents_t *extents)
 {
     cairo_int_status_t status;
     double  font_scale_x, font_scale_y;
+    
+    if (scaled_font->status) {
+	_cairo_scaled_font_set_error (scaled_font, scaled_font->status);
+	return;
+    }
 
     status = _cairo_scaled_font_font_extents (scaled_font, extents);
-
-    if (status)
-      return status;
+    if (status) {
+	_cairo_scaled_font_set_error (scaled_font, status);
+	return;
+    }
     
     _cairo_matrix_compute_scale_factors (&scaled_font->font_matrix,
 					 &font_scale_x, &font_scale_y,
@@ -992,8 +1082,6 @@
     extents->height *= font_scale_y;
     extents->max_x_advance *= font_scale_x;
     extents->max_y_advance *= font_scale_y;
-      
-    return status;
 }
 
 /**
@@ -1020,6 +1108,11 @@
     double x_pos = 0.0, y_pos = 0.0;
     int set = 0;
 
+    if (scaled_font->status) {
+	_cairo_scaled_font_set_error (scaled_font, scaled_font->status);
+	return;
+    }
+
     if (!num_glyphs)
     {
 	extents->x_bearing = 0.0;

Index: cairo-ft-font.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-ft-font.c,v
retrieving revision 1.78
retrieving revision 1.79
diff -u -d -r1.78 -r1.79
--- cairo-ft-font.c	27 Jul 2005 11:07:46 -0000	1.78
+++ cairo-ft-font.c	27 Jul 2005 22:39:35 -0000	1.79
@@ -88,7 +88,6 @@
  * just create a one-off version with a permanent face value.
  */
 
-
 typedef struct _ft_font_face ft_font_face_t;
 
 typedef struct {
@@ -796,10 +795,9 @@
 	    cairo_image_surface_create_for_data (data,
 						 format,
 						 width, height, stride);
-	if (val->image == NULL) {
+	if (val->image->base.status) {
 	    free (data);
-	    
-	    return CAIRO_STATUS_NO_MEMORY;
+	    return val->image->base.status;
 	}
 	
 	if (subpixel)
@@ -1063,8 +1061,8 @@
     /* We need to pad out the width to 32-bit intervals for cairo-xlib-surface.c */
     width = (width + 3) & ~3;
     image = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
-    if (!image)
-	return CAIRO_STATUS_NO_MEMORY;
+    if (image->status)
+	return image->status;
 
     /* Initialize it to empty
      */
@@ -1380,7 +1378,7 @@
 
     f = malloc (sizeof(cairo_ft_scaled_font_t));
     if (f == NULL) 
-	return NULL;
+	return (cairo_scaled_font_t*) &_cairo_scaled_font_nil;
 
     f->unscaled = unscaled;
     _cairo_unscaled_font_reference (&unscaled->base);
@@ -1875,7 +1873,7 @@
 
 
 static int
-_move_to (FT_Vector *to, void *closure)
+_move_to (const FT_Vector *to, void *closure)
 {
     cairo_path_fixed_t *path = closure;
     cairo_fixed_t x, y;
@@ -1890,7 +1888,7 @@
 }
 
 static int
-_line_to (FT_Vector *to, void *closure)
+_line_to (const FT_Vector *to, void *closure)
 {
     cairo_path_fixed_t *path = closure;
     cairo_fixed_t x, y;
@@ -1904,7 +1902,7 @@
 }
 
 static int
-_conic_to (FT_Vector *control, FT_Vector *to, void *closure)
+_conic_to (const FT_Vector *control, const FT_Vector *to, void *closure)
 {
     cairo_path_fixed_t *path = closure;
 
@@ -1937,7 +1935,8 @@
 }
 
 static int
-_cubic_to (FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *closure)
+_cubic_to (const FT_Vector *control1, const FT_Vector *control2,
+	   const FT_Vector *to, void *closure)
 {
     cairo_path_fixed_t *path = closure;
     cairo_fixed_t x0, y0;
@@ -2351,7 +2350,9 @@
  * implemented, so this function cannot be currently safely used in a
  * threaded application.)
  
- * Return value: The #FT_Face object for @font, scaled appropriately.
+ * Return value: The #FT_Face object for @font, scaled appropriately,
+ * or %NULL if @scaled_font is in an error state (see
+ * cairo_scaled_font_status()) or there is insufficient memory.
  **/
 FT_Face
 cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font)
@@ -2359,9 +2360,14 @@
     cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font;
     FT_Face face;
 
+    if (scaled_font->base.status)
+	return NULL;
+
     face = _ft_unscaled_font_lock_face (scaled_font->unscaled);
-    if (!face)
+    if (face == NULL) {
+	_cairo_scaled_font_set_error (&scaled_font->base, CAIRO_STATUS_NO_MEMORY);
 	return NULL;
+    }
     
     _ft_unscaled_font_set_scale (scaled_font->unscaled, &scaled_font->base.scale);
 
@@ -2383,6 +2389,9 @@
 {
     cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font;
 
+    if (scaled_font->base.status)
+	return;
+
     _ft_unscaled_font_unlock_face (scaled_font->unscaled);
 }
 

Index: cairo-glitz-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-glitz-surface.c,v
retrieving revision 1.52
retrieving revision 1.53
diff -u -d -r1.52 -r1.53
--- cairo-glitz-surface.c	25 Jul 2005 23:23:05 -0000	1.52
+++ cairo-glitz-surface.c	27 Jul 2005 22:39:35 -0000	1.53
@@ -83,12 +83,16 @@
     
     gformat = glitz_find_standard_format (drawable,
 					  _glitz_format_from_content (content));
-    if (!gformat)
-	return NULL;
+    if (!gformat) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
     
     surface = glitz_surface_create (drawable, gformat, width, height, 0, NULL);
-    if (!surface)
-	return NULL;
+    if (surface == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
 
     crsurface = cairo_glitz_surface_create (surface);
     
@@ -206,11 +210,10 @@
 						&format,
 						width, height,
 						pf.bytes_per_line);
-
-    if (!image)
+    if (image->base.status)
     {
 	free (pixels);
-	return CAIRO_STATUS_NO_MEMORY;
+	return image->base.status;
     }
 
     _cairo_image_surface_assume_ownership_of_data (image);
@@ -341,6 +344,9 @@
     cairo_glitz_surface_t *surface = abstract_surface;
     cairo_glitz_surface_t *clone;
 
+    if (surface->base.status)
+	return surface->base.status;
+
     if (src->backend == surface->base.backend)
     {
 	*clone_out = src;
@@ -357,8 +363,8 @@
 	    _cairo_glitz_surface_create_similar (surface, content,
 						 image_src->width,
 						 image_src->height);
-	if (!clone)
-	    return CAIRO_STATUS_NO_MEMORY;
+	if (clone->base.status)
+	    return clone->base.status;
 
 	_cairo_glitz_surface_set_image (clone, image_src, 0, 0);
 	
@@ -570,11 +576,11 @@
 	    _cairo_surface_create_similar_scratch (&dst->base,
 						   CAIRO_CONTENT_COLOR_ALPHA,
 						   gradient->n_stops, 1);
-	if (!src)
+	if (src->base.status)
 	{
 	    glitz_buffer_destroy (buffer);
 	    free (data);
-	    return CAIRO_STATUS_NO_MEMORY;
+	    return src->base.status;
 	}
 
 	for (i = 0; i < gradient->n_stops; i++)
@@ -900,8 +906,8 @@
 						 CAIRO_CONTENT_COLOR_ALPHA,
 						 1, 1,
 						 (cairo_color_t *) color);
-	if (!src)
-	    return CAIRO_STATUS_NO_MEMORY;
+	if (src->base.status)
+	    return src->base.status;
 
 	glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT);
 	
@@ -951,6 +957,9 @@
     cairo_int_status_t		     status;
     unsigned short		     alpha;
 
+    if (dst->base.status)
+	return dst->base.status;
+
     if (op == CAIRO_OPERATOR_SATURATE)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
@@ -1002,13 +1011,13 @@
 	    _cairo_glitz_surface_create_similar (&dst->base,
 						 CAIRO_CONTENT_ALPHA,
 						 2, 1);
-	if (!mask)
+	if (mask->base.status)
 	{
 	    _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes);
 	    if (src_pattern == &tmp_src_pattern.base)
 		_cairo_pattern_fini (&tmp_src_pattern.base);
 
-	    return CAIRO_INT_STATUS_UNSUPPORTED;
+	    return mask->base.status;
 	}
 
 	color.red = color.green = color.blue = color.alpha = 0xffff;
@@ -1097,11 +1106,11 @@
 						 CAIRO_FORMAT_A8,
 						 width, height,
 						 -stride);
-	if (!image)
+	if (image->base.status)
 	{
 	    cairo_surface_destroy (&src->base);
 	    free (data);
-	    return CAIRO_STATUS_NO_MEMORY;
+	    return image->base.status;
 	}
 
 	pixman_add_trapezoids (image->pixman_image, -dst_x, -dst_y,
@@ -1111,12 +1120,12 @@
 	    _cairo_surface_create_similar_scratch (&dst->base,
 						   CAIRO_CONTENT_ALPHA,
 						   width, height);
-	if (!mask)
+	if (mask->base.status)
 	{
 	    _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes);
 	    free (data);
 	    cairo_surface_destroy (&image->base);
-	    return CAIRO_STATUS_NO_MEMORY;
+	    return mask->base.status;
 	}
 
 	_cairo_glitz_surface_set_image (mask, image, 0, 0);
@@ -1694,7 +1703,7 @@
 			      GLYPH_CACHE_TEXTURE_SIZE,
 			      GLYPH_CACHE_TEXTURE_SIZE,
 			      0, NULL);
-    if (!cache->surface)
+    if (cache->surface == NULL)
     {
 	free (cache);
 	return NULL;
@@ -1898,7 +1907,9 @@
 	goto UNLOCK;
     }
 
-    _cairo_scaled_font_get_glyph_cache_key (scaled_font, &key);
+    status = _cairo_scaled_font_get_glyph_cache_key (scaled_font, &key);
+    if (status)
+	goto UNLOCK;
 
     for (i = 0; i < num_glyphs; i++)
     {
@@ -2123,12 +2134,14 @@
 {
     cairo_glitz_surface_t *crsurface;
 
-    if (!surface)
-	return NULL;
+    if (surface == NULL)
+	return _cairo_surface_create_in_error (CAIRO_STATUS_NULL_POINTER);
 
     crsurface = malloc (sizeof (cairo_glitz_surface_t));
-    if (crsurface == NULL)
-	return NULL;
+    if (crsurface == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
 
     _cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend);
 

Index: cairo-gstate.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-gstate.c,v
retrieving revision 1.148
retrieving revision 1.149
diff -u -d -r1.148 -r1.149
--- cairo-gstate.c	25 Jul 2005 19:29:24 -0000	1.148
+++ cairo-gstate.c	27 Jul 2005 22:39:35 -0000	1.149
@@ -282,8 +282,8 @@
 	return CAIRO_STATUS_NO_MEMORY;
 
     gstate->target = cairo_surface_create (gstate->dpy);
-    if (gstate->target == NULL)
-	return CAIRO_STATUS_NO_MEMORY;
+    if (gstate->target->status)
+	return gstate->target->status;
 
     _cairo_surface_set_drawableWH (gstate->target, pix, width, height);
 
@@ -904,12 +904,15 @@
 	 */
 	cairo_surface_t *intermediate;
 
+	if (gstate->clip.surface->status)
+	    return gstate->clip.surface->status;
+
 	intermediate = cairo_surface_create_similar (gstate->clip.surface,
 						     CAIRO_CONTENT_ALPHA,
 						     extents.width,
 						     extents.height);
-	if (intermediate == NULL)
-	    return CAIRO_STATUS_NO_MEMORY;
+	if (intermediate->status)
+	    return intermediate->status;
 
 	status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
 					   mask, NULL, intermediate,
@@ -1244,13 +1247,16 @@
 
     translate_traps (traps, -extents->x, -extents->y);
 
+    if (gstate->clip.surface->status)
+	return gstate->clip.surface->status;
+
     intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
 							CAIRO_CONTENT_ALPHA,
 							extents->width,
 							extents->height,
 							CAIRO_COLOR_TRANSPARENT);
-    if (intermediate == NULL)
-	return CAIRO_STATUS_NO_MEMORY;
+    if (intermediate->status)
+	return intermediate->status;
     
     _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
     
@@ -1720,13 +1726,16 @@
     if (gstate->clip.surface != NULL)
 	_cairo_rectangle_intersect (&surface_rect, &gstate->clip.surface_rect);
 
+    if (gstate->target->status)
+	return gstate->target->status;
+    
     surface = _cairo_surface_create_similar_solid (gstate->target,
 						   CAIRO_CONTENT_ALPHA,
 						   surface_rect.width,
 						   surface_rect.height,
 						   CAIRO_COLOR_WHITE);
-    if (surface == NULL)
-	return CAIRO_STATUS_NO_MEMORY;
+    if (surface->status)
+	return surface->status;
 
     /* Render the new clipping path into the new mask surface. */
 
@@ -2025,7 +2034,9 @@
     if (status)
 	return status;
 
-    return cairo_scaled_font_extents (gstate->scaled_font, extents);
+    cairo_scaled_font_extents (gstate->scaled_font, extents);
+
+    return CAIRO_STATUS_SUCCESS;
 }
 
 cairo_status_t
@@ -2156,13 +2167,18 @@
 	    goto BAIL1;
 	}
 
+	if (gstate->clip.surface->status) {
+	    status = gstate->clip.surface->status;
+	    goto BAIL1;
+	}
+
 	intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
 							    CAIRO_CONTENT_ALPHA,
 							    extents.width,
 							    extents.height,
 							    CAIRO_COLOR_TRANSPARENT);
-	if (intermediate == NULL) {
-	    status = CAIRO_STATUS_NO_MEMORY;
+	if (intermediate->status) {
+	    status = intermediate->status;
 	    goto BAIL1;
 	}
 

Index: cairo-image-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-image-surface.c,v
retrieving revision 1.50
retrieving revision 1.51
diff -u -d -r1.50 -r1.51
--- cairo-image-surface.c	14 Jul 2005 22:10:48 -0000	1.50
+++ cairo-image-surface.c	27 Jul 2005 22:39:35 -0000	1.51
@@ -36,8 +36,6 @@
 
 #include "cairoint.h"
 
-static const cairo_surface_backend_t cairo_image_surface_backend;
-
 static int
 _cairo_format_bpp (cairo_format_t format)
 {
@@ -53,15 +51,17 @@
     }
 }
 
-static cairo_image_surface_t *
+static cairo_surface_t *
 _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
 					      cairo_format_t  format)
 {
     cairo_image_surface_t *surface;
 
     surface = malloc (sizeof (cairo_image_surface_t));
-    if (surface == NULL)
-	return NULL;
+    if (surface == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
 
     _cairo_surface_init (&surface->base, &cairo_image_surface_backend);
 
@@ -76,17 +76,17 @@
     surface->stride = pixman_image_get_stride (pixman_image);
     surface->depth = pixman_image_get_depth (pixman_image);
 
-    return surface;
+    return &surface->base;
 }
 
-cairo_image_surface_t *
+cairo_surface_t *
 _cairo_image_surface_create_with_masks (unsigned char	       *data,
 					cairo_format_masks_t   *format,
 					int			width,
 					int			height,
 					int			stride)
 {
-    cairo_image_surface_t *surface;
+    cairo_surface_t *surface;
     pixman_format_t *pixman_format;
     pixman_image_t *pixman_image;
 
@@ -96,16 +96,20 @@
 						format->green_mask,
 						format->blue_mask);
 
-    if (pixman_format == NULL)
-	return NULL;
+    if (pixman_format == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
 
     pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, pixman_format,
 						 width, height, format->bpp, stride);
 
     pixman_format_destroy (pixman_format);
 
-    if (pixman_image == NULL)
-	return NULL;
+    if (pixman_image == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
 
     surface = _cairo_image_surface_create_for_pixman_image (pixman_image,
 							    (cairo_format_t)-1);
@@ -152,28 +156,31 @@
 			    int			width,
 			    int			height)
 {
-    cairo_image_surface_t *surface;
+    cairo_surface_t *surface;
     pixman_format_t *pixman_format;
     pixman_image_t *pixman_image;
 
-    /* XXX: Really need to make this kind of thing pass through _cairo_error. */
     if (! CAIRO_FORMAT_VALID (format))
-	return NULL;
+	return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_FORMAT);
 
     pixman_format = _create_pixman_format (format);
-    if (pixman_format == NULL)
-	return NULL;
+    if (pixman_format == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
 
     pixman_image = pixman_image_create (pixman_format, width, height);
 
     pixman_format_destroy (pixman_format);
 
-    if (pixman_image == NULL)
-	return NULL;
+    if (pixman_image == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
 
     surface = _cairo_image_surface_create_for_pixman_image (pixman_image, format);
 
-    return &surface->base;
+    return surface;
 }
 
 /**
@@ -205,17 +212,18 @@
 				     int		height,
 				     int		stride)
 {
-    cairo_image_surface_t *surface;
+    cairo_surface_t *surface;
     pixman_format_t *pixman_format;
     pixman_image_t *pixman_image;
 
-    /* XXX: Really need to make this kind of thing pass through _cairo_error. */
     if (! CAIRO_FORMAT_VALID (format))
-	return NULL;
+	return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_FORMAT);
 
     pixman_format = _create_pixman_format (format);
-    if (pixman_format == NULL)
-	return NULL;
+    if (pixman_format == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
     
     pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, pixman_format,
 						 width, height,
@@ -224,12 +232,14 @@
 
     pixman_format_destroy (pixman_format);
 
-    if (pixman_image == NULL)
-	return NULL;
+    if (pixman_image == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
 
     surface = _cairo_image_surface_create_for_pixman_image (pixman_image, format);
 
-    return &surface->base;
+    return surface;
 }
 
 /**
@@ -303,9 +313,7 @@
 				     int		width,
 				     int		height)
 {
-    /* XXX: Really need to make this kind of thing pass through _cairo_error. */
-    if (! CAIRO_CONTENT_VALID (content))
-	return NULL;
+    assert (CAIRO_CONTENT_VALID (content));
 
     return cairo_image_surface_create (_cairo_format_from_content (content),
 				       width, height);
@@ -724,15 +732,15 @@
  * 
  * Checks if a surface is an #cairo_image_surface_t
  * 
- * Return value: True if the surface is an image surface
+ * Return value: TRUE if the surface is an image surface
  **/
-int
+cairo_bool_t
 _cairo_surface_is_image (cairo_surface_t *surface)
 {
     return surface->backend == &cairo_image_surface_backend;
 }
 
-static const cairo_surface_backend_t cairo_image_surface_backend = {
+const cairo_surface_backend_t cairo_image_surface_backend = {
     _cairo_image_surface_create_similar,
     _cairo_image_abstract_surface_finish,
     _cairo_image_surface_acquire_source_image,

Index: cairo-meta-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-meta-surface.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- cairo-meta-surface.c	13 Jul 2005 19:32:51 -0000	1.4
+++ cairo-meta-surface.c	27 Jul 2005 22:39:35 -0000	1.5
@@ -53,8 +53,10 @@
     cairo_meta_surface_t *meta;
 
     meta = malloc (sizeof (cairo_meta_surface_t));
-    if (meta == NULL)
-	return NULL;
+    if (meta == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
 
     meta->width = width;
     meta->height = height;

Index: cairo-path-data.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-path-data.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- cairo-path-data.c	13 Jun 2005 23:29:26 -0000	1.7
+++ cairo-path-data.c	27 Jul 2005 22:39:35 -0000	1.8
@@ -460,6 +460,8 @@
     path->data = NULL;
     path->num_data = 0;
 
+    _cairo_error (status);
+
     return path;
 }
 

Index: cairo-pattern.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-pattern.c,v
retrieving revision 1.50
retrieving revision 1.51
diff -u -d -r1.50 -r1.51
--- cairo-pattern.c	14 Jul 2005 22:47:18 -0000	1.50
+++ cairo-pattern.c	27 Jul 2005 22:39:35 -0000	1.51
@@ -96,6 +96,31 @@
     1.0, 1.0,			/* radius0, radius1 */
 };
 
+/**
+ * _cairo_pattern_set_error:
+ * @pattern: a pattern
+ * @status: a status value indicating an error, (eg. not
+ * CAIRO_STATUS_SUCCESS)
+ * 
+ * Sets pattern->status to @status and calls _cairo_error;
+ *
+ * All assignments of an error status to pattern->status should happen
+ * through _cairo_pattern_set_error() or else _cairo_error() should be
+ * called immediately after the assignment.
+ *
+ * The purpose of this function is to allow the user to set a
+ * breakpoint in _cairo_error() to generate a stack trace for when the
+ * user causes cairo to detect an error.
+ **/
+static void
+_cairo_pattern_set_error (cairo_pattern_t *pattern,
+			  cairo_status_t status)
+{
+    pattern->status = status;
+
+    _cairo_error (status);
+}
+
 static void
 _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
 {
@@ -127,10 +152,13 @@
 	*dst = *src;
     }
 
+    if (other->base.status)
+	_cairo_pattern_set_error (&pattern->base, other->base.status);
+
     if (other->n_stops)
     {
 	pattern->stops = malloc (other->n_stops * sizeof (cairo_color_stop_t));
-	if (!pattern->stops) {
+	if (pattern->stops == NULL) {
 	    if (other->base.type == CAIRO_PATTERN_LINEAR)
 		_cairo_gradient_pattern_init_copy (pattern, &cairo_linear_pattern_nil.base);
 	    else
@@ -289,7 +317,7 @@
 
     _cairo_pattern_init_solid (pattern, CAIRO_COLOR_BLACK);
 
-    pattern->base.status = status;
+    _cairo_pattern_set_error (&pattern->base, status);
 
     return &pattern->base;
 }
@@ -317,6 +345,7 @@
 cairo_pattern_t *
 cairo_pattern_create_rgb (double red, double green, double blue)
 {
+    cairo_pattern_t *pattern;
     cairo_color_t color;
 
     _cairo_restrict_value (&red,   0.0, 1.0);
@@ -325,7 +354,11 @@
 
     _cairo_color_init_rgb (&color, red, green, blue);
 
-    return _cairo_pattern_create_solid (&color);
+    pattern = _cairo_pattern_create_solid (&color);
+    if (pattern->status)
+	_cairo_pattern_set_error (pattern, pattern->status);
+
+    return pattern;
 }
 
 /**
@@ -353,6 +386,7 @@
 cairo_pattern_create_rgba (double red, double green, double blue,
 			   double alpha)
 {
+    cairo_pattern_t *pattern;
     cairo_color_t color;
 
     _cairo_restrict_value (&red,   0.0, 1.0);
@@ -362,7 +396,11 @@
 
     _cairo_color_init_rgba (&color, red, green, blue, alpha);
 
-    return _cairo_pattern_create_solid (&color);
+    pattern = _cairo_pattern_create_solid (&color);
+    if (pattern->status)
+	_cairo_pattern_set_error (pattern, pattern->status);
+
+    return pattern;
 }
 
 /**
@@ -386,8 +424,10 @@
     cairo_surface_pattern_t *pattern;
 
     pattern = malloc (sizeof (cairo_surface_pattern_t));
-    if (pattern == NULL)
+    if (pattern == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
 	return (cairo_pattern_t *)&cairo_surface_pattern_nil.base;
+    }
 
     _cairo_pattern_init_for_surface (pattern, surface);
 
@@ -422,8 +462,10 @@
     cairo_linear_pattern_t *pattern;
 
     pattern = malloc (sizeof (cairo_linear_pattern_t));
-    if (pattern == NULL)
+    if (pattern == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
 	return (cairo_pattern_t *) &cairo_linear_pattern_nil.base;
+    }
 
     _cairo_pattern_init_linear (pattern, x0, y0, x1, y1);
 
@@ -461,8 +503,10 @@
     cairo_radial_pattern_t *pattern;
     
     pattern = malloc (sizeof (cairo_radial_pattern_t));
-    if (pattern == NULL)
+    if (pattern == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
 	return (cairo_pattern_t *) &cairo_radial_pattern_nil.base;
+    }
 
     _cairo_pattern_init_radial (pattern, cx0, cy0, radius0, cx1, cy1, radius1);
 
@@ -541,7 +585,7 @@
     new_stops = realloc (pattern->stops,
 			 pattern->n_stops * sizeof (cairo_color_stop_t));
     if (new_stops == NULL) {
-	pattern->base.status = CAIRO_STATUS_NO_MEMORY;
+	_cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY);
 	return;
     }
     
@@ -568,7 +612,7 @@
     if (pattern->type != CAIRO_PATTERN_LINEAR &&
 	pattern->type != CAIRO_PATTERN_RADIAL)
     {
-	pattern->status = CAIRO_STATUS_PATTERN_TYPE_MISMATCH;
+	_cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
 	return;
     }
 
@@ -599,7 +643,7 @@
     if (pattern->type != CAIRO_PATTERN_LINEAR &&
 	pattern->type != CAIRO_PATTERN_RADIAL)
     {
-	pattern->status = CAIRO_STATUS_PATTERN_TYPE_MISMATCH;
+	_cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
 	return;
     }
 
@@ -619,8 +663,10 @@
 cairo_pattern_set_matrix (cairo_pattern_t      *pattern,
 			  const cairo_matrix_t *matrix)
 {
-    if (pattern->status)
+    if (pattern->status) {
+	_cairo_pattern_set_error (pattern, pattern->status);
 	return;
+    }
 
     pattern->matrix = *matrix;
 }
@@ -634,8 +680,10 @@
 void
 cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter)
 {
-    if (pattern->status)
+    if (pattern->status) {
+	_cairo_pattern_set_error (pattern, pattern->status);
 	return;
+    }
 
     pattern->filter = filter;
 }
@@ -649,8 +697,10 @@
 void
 cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend)
 {
-    if (pattern->status)
+    if (pattern->status) {
+	_cairo_pattern_set_error (pattern, pattern->status);
 	return;
+    }
 
     pattern->extend = extend;
 }
@@ -1164,7 +1214,7 @@
     }
     
     data = malloc (width * height * 4);
-    if (!data)
+    if (data == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
     
     if (pattern->base.type == CAIRO_PATTERN_LINEAR)
@@ -1228,9 +1278,8 @@
 						CAIRO_CONTENT_COLOR_ALPHA,
 						1, 1,
 						&pattern->color);
-    
-    if (*out == NULL)
-	return CAIRO_STATUS_NO_MEMORY;
+    if ((*out)->status)
+	return (*out)->status;
 
     attribs->x_offset = attribs->y_offset = 0;
     cairo_matrix_init_identity (&attribs->matrix);

Index: cairo-pdf-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-pdf-surface.c,v
retrieving revision 1.53
retrieving revision 1.54
diff -u -d -r1.53 -r1.54
--- cairo-pdf-surface.c	25 Jul 2005 23:23:05 -0000	1.53
+++ cairo-pdf-surface.c	27 Jul 2005 22:39:35 -0000	1.54
@@ -290,8 +290,10 @@
     cairo_surface_t *surface;
 
     document = _cairo_pdf_document_create (stream, width, height);
-    if (document == NULL)
-      return NULL;
+    if (document == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
 
     surface = _cairo_pdf_surface_create_for_document (document, width, height);
 
@@ -310,8 +312,10 @@
     cairo_output_stream_t *stream;
 
     stream = _cairo_output_stream_create (write, closure);
-    if (stream == NULL)
-	return NULL;
+    if (stream == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
 
     return _cairo_pdf_surface_create_for_stream_internal (stream, width, height);
 }
@@ -324,8 +328,10 @@
     cairo_output_stream_t *stream;
 
     stream = _cairo_output_stream_create_for_file (filename);
-    if (stream == NULL)
-	return NULL;
+    if (stream == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
 
     return _cairo_pdf_surface_create_for_stream_internal (stream, width, height);
 }
@@ -349,8 +355,10 @@
     cairo_pdf_surface_t *surface;
 
     surface = malloc (sizeof (cairo_pdf_surface_t));
-    if (surface == NULL)
-	return NULL;
+    if (surface == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
 
     _cairo_surface_init (&surface->base, &cairo_pdf_surface_backend);
 

Index: cairo-png.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-png.c,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- cairo-png.c	27 Jul 2005 16:23:29 -0000	1.17
+++ cairo-png.c	27 Jul 2005 22:39:35 -0000	1.18
@@ -36,6 +36,7 @@
  */
 
 #include <png.h>
+#include <errno.h>
 #include "cairoint.h"
 
 /* Unpremultiplies data and converts native endian ARGB => RGBA bytes */
@@ -315,19 +316,15 @@
 read_png (png_rw_ptr	read_func,
 	  void		*closure)
 {
-    cairo_surface_t *surface;
-    png_byte *data;
+    cairo_surface_t *surface = (cairo_surface_t*) &_cairo_surface_nil;
+    png_byte *data = NULL;
     int i;
-    png_struct *png;
+    png_struct *png = NULL;
     png_info *info;
     png_uint_32 png_width, png_height, stride;
     int depth, color_type, interlace;
     unsigned int pixel_size;
-    png_byte **row_pointers;
-
-    surface = NULL;
-    data = NULL;
-    row_pointers = NULL;
+    png_byte **row_pointers = NULL;
 
     /* XXX: Perhaps we'll want some other error handlers? */
     png = png_create_read_struct (PNG_LIBPNG_VER_STRING,
@@ -335,7 +332,7 @@
                                   NULL,
                                   NULL);
     if (png == NULL)
-	return NULL;
+	goto BAIL;
 
     info = png_create_info_struct (png);
     if (info == NULL)
@@ -402,13 +399,22 @@
     surface = cairo_image_surface_create_for_data (data,
 						   CAIRO_FORMAT_ARGB32,
 						   png_width, png_height, stride);
+    if (surface->status)
+	goto BAIL;
+
     _cairo_image_surface_assume_ownership_of_data ((cairo_image_surface_t*)surface);
     data = NULL;
 
  BAIL:
-    free (row_pointers);
-    free (data);
-    png_destroy_read_struct (&png, &info, NULL);
+    if (row_pointers)
+	free (row_pointers);
+    if (data)
+	free (data);
+    if (png)
+	png_destroy_read_struct (&png, &info, NULL);
+
+    if (surface == &_cairo_surface_nil)
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
 
     return surface;
 }
@@ -441,8 +447,12 @@
     cairo_surface_t *surface;
 
     fp = fopen (filename, "rb");
-    if (fp == NULL)
-	return NULL;
+    if (fp == NULL) {
+	if (errno == ENOMEM)
+	    return (cairo_surface_t*) &_cairo_surface_nil;
+	else
+	    return _cairo_surface_create_in_error (CAIRO_STATUS_READ_ERROR);
+    }
   
     surface = read_png (stdio_read_func, fp);
 

Index: cairo-ps-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-ps-surface.c,v
retrieving revision 1.43
retrieving revision 1.44
diff -u -d -r1.43 -r1.44
--- cairo-ps-surface.c	14 Jul 2005 18:48:40 -0000	1.43
+++ cairo-ps-surface.c	27 Jul 2005 22:39:35 -0000	1.44
@@ -89,8 +89,10 @@
     cairo_ps_surface_t *surface;
 
     surface = malloc (sizeof (cairo_ps_surface_t));
-    if (surface == NULL)
-	return NULL;
+    if (surface == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
 
     _cairo_surface_init (&surface->base, &cairo_ps_surface_backend);
 
@@ -103,9 +105,10 @@
 
     surface->current_page = _cairo_meta_surface_create (width,
 							height);
-    if (surface->current_page == NULL) {
+    if (surface->current_page->status) {
 	free (surface);
-	return NULL;
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
     }
 
     _cairo_array_init (&surface->pages, sizeof (cairo_surface_t *));
@@ -122,8 +125,10 @@
     cairo_output_stream_t *stream;
 
     stream = _cairo_output_stream_create_for_file (filename);
-    if (stream == NULL)
-	return NULL;
+    if (stream == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
 
     return _cairo_ps_surface_create_for_stream_internal (stream,
 							 width_in_points,
@@ -139,23 +144,16 @@
     cairo_output_stream_t *stream;
 
     stream = _cairo_output_stream_create (write_func, closure);
-    if (stream == NULL)
-	return NULL;
+    if (stream == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
 
     return _cairo_ps_surface_create_for_stream_internal (stream,
 							 width_in_points,
 							 height_in_points);
 }
 
-static cairo_surface_t *
-_cairo_ps_surface_create_similar (void		 *abstract_src,
-				  cairo_content_t content,
-				  int		  width,
-				  int		  height)
-{
-    return NULL;
-}
-
 static cairo_status_t
 _cairo_ps_surface_finish (void *abstract_surface)
 {
@@ -316,8 +314,8 @@
     _cairo_array_append (&surface->pages, &surface->current_page, 1);
     surface->current_page = _cairo_meta_surface_create (surface->width,
 							surface->height);
-    if (surface->current_page == NULL)
-	return CAIRO_STATUS_NO_MEMORY;
+    if (surface->current_page->status)
+	return surface->current_page->status;
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -453,7 +451,7 @@
 }
 
 static const cairo_surface_backend_t cairo_ps_surface_backend = {
-    _cairo_ps_surface_create_similar,
+    NULL, /* create_similar */
     _cairo_ps_surface_finish,
     NULL, /* acquire_source_image */
     NULL, /* release_source_image */
@@ -652,7 +650,7 @@
 	    cairo_image_surface_t *image,
 	    cairo_matrix_t	  *matrix)
 {
-    cairo_status_t status = CAIRO_STATUS_NO_MEMORY;
+    cairo_status_t status;
     unsigned char *rgb, *compressed;
     unsigned long rgb_size, compressed_size;
     cairo_surface_t *opaque;
@@ -663,13 +661,18 @@
     /* PostScript can not represent the alpha channel, so we blend the
        current image over a white RGB surface to eliminate it. */
 
+    if (image->base.status)
+	return image->base.status;
+
     opaque = _cairo_surface_create_similar_solid (&image->base,
 						  CAIRO_CONTENT_COLOR,
 						  image->width,
 						  image->height, 
 						  CAIRO_COLOR_WHITE);
-    if (opaque == NULL)
+    if (opaque->status) {
+	status = opaque->status;
 	goto bail0;
+    }
 
     _cairo_pattern_init_for_surface (&pattern.surface, &image->base);
 
@@ -687,8 +690,10 @@
 
     rgb_size = 3 * image->width * image->height;
     rgb = malloc (rgb_size);
-    if (rgb == NULL)
+    if (rgb == NULL) {
+	status = CAIRO_STATUS_NO_MEMORY;
 	goto bail1;
+    }
 
     i = 0;
     for (y = 0; y < image->height; y++) {
@@ -701,8 +706,10 @@
     }
 
     compressed = compress_dup (rgb, rgb_size, &compressed_size);
-    if (compressed == NULL)
+    if (compressed == NULL) {
+	status = CAIRO_STATUS_NO_MEMORY;
 	goto bail2;
+    }
 
     /* matrix transforms from user space to image space.  We need to
      * transform from device space to image space to compensate for
@@ -1242,8 +1249,8 @@
     height = ps_output->parent->height * ps_output->parent->y_dpi / 72;
 
     image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
-    if (image == NULL)
-	return CAIRO_STATUS_NO_MEMORY;
+    if (image->status)
+	return image->status;
 
     status = _cairo_surface_fill_rectangle (image,
 					    CAIRO_OPERATOR_SOURCE,
@@ -1278,8 +1285,10 @@
     ps_output_surface_t *ps_output;
 
     ps_output = malloc (sizeof (ps_output_surface_t));
-    if (ps_output == NULL)
-	return NULL;
+    if (ps_output == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
 
     _cairo_surface_init (&ps_output->base, &ps_output_backend);
     ps_output->parent = parent;
@@ -1301,8 +1310,8 @@
 				 page_number);
 
     ps_output = _ps_output_surface_create (surface);
-    if (ps_output == NULL)
-	return CAIRO_STATUS_NO_MEMORY;
+    if (ps_output->status)
+	return ps_output->status;
 
     status = _cairo_meta_surface_replay (page, ps_output);
 

Index: cairo-quartz-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-quartz-surface.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- cairo-quartz-surface.c	18 Jul 2005 16:23:34 -0000	1.14
+++ cairo-quartz-surface.c	27 Jul 2005 22:39:35 -0000	1.15
@@ -58,15 +58,6 @@
     }
 }
 
-static cairo_surface_t *
-_cairo_quartz_surface_create_similar (void	     *abstract_src,
-				      cairo_content_t content,
-				      int	      width,
-				      int	      height)
-{
-    return NULL;
-}
-
 static cairo_status_t
 _cairo_quartz_surface_finish(void *abstract_surface)
 {
@@ -209,7 +200,7 @@
 }
 
 static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
-    _cairo_quartz_surface_create_similar,
+    NULL, /* create_similar */
     _cairo_quartz_surface_finish,
     _cairo_quartz_surface_acquire_source_image,
     NULL, /* release_source_image */
@@ -234,8 +225,10 @@
     cairo_quartz_surface_t *surface;
 
     surface = malloc(sizeof(cairo_quartz_surface_t));
-    if (surface == NULL)
-        return NULL;
+    if (surface == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+        return &_cairo_surface_nil;
+    }
 
     _cairo_surface_init(&surface->base, &cairo_quartz_surface_backend);
 

Index: cairo-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-surface.c,v
retrieving revision 1.80
retrieving revision 1.81
diff -u -d -r1.80 -r1.81
--- cairo-surface.c	21 Jul 2005 13:52:13 -0000	1.80
+++ cairo-surface.c	27 Jul 2005 22:39:35 -0000	1.81
@@ -40,6 +40,65 @@
 #include "cairoint.h"
 #include "cairo-gstate-private.h"
 
+const cairo_surface_t _cairo_surface_nil = {
+    &cairo_image_surface_backend,	/* backend */
+    -1,					/* ref_count */
+    CAIRO_STATUS_NO_MEMORY,		/* status */
+    FALSE,				/* finished */
+    { 0,	/* size */
+      0,	/* num_elements */
+      0,	/* element_size */
+      NULL,	/* elements */
+    },					/* user_data */
+    0.0,				/* device_x_offset */
+    0.0,				/* device_y_offset */
+    0,					/* next_clip_serial */
+    0					/* current_clip_serial */
+};
+
+/**
+ * _cairo_surface_set_error:
+ * @surface: a surface
+ * @status: a status value indicating an error, (eg. not
+ * CAIRO_STATUS_SUCCESS)
+ * 
+ * Sets surface->status to @status and calls _cairo_error;
+ *
+ * All assignments of an error status to surface->status should happen
+ * through _cairo_surface_set_error() or else _cairo_error() should be
+ * called immediately after the assignment.
+ *
+ * The purpose of this function is to allow the user to set a
+ * breakpoint in _cairo_error() to generate a stack trace for when the
+ * user causes cairo to detect an error.
+ **/
+static void
+_cairo_surface_set_error (cairo_surface_t *surface,
+			  cairo_status_t status)
+{
+    surface->status = status;
+
+    _cairo_error (status);
+}
+
+/**
+ * cairo_surface_status:
+ * @surface: a #cairo_surface_t
+ * 
+ * Checks whether an error has previously occurred for this
+ * surface.
+ * 
+ * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_STATUS_NULL_POINTER,
+ * %CAIRO_STATUS_NO_MEMORY, %CAIRO_STATUS_READ_ERROR,
+ * %CAIRO_STATUS_INVALID_CONTENT, %CAIRO_STATUS_INVALUE_FORMAT, or
+ * %CAIRO_STATUS_INVALID_VISUAL.
+ **/
+cairo_status_t
+cairo_surface_status (cairo_surface_t *surface)
+{
+    return surface->status;
+}
+
 void
 _cairo_surface_init (cairo_surface_t			*surface,
 		     const cairo_surface_backend_t	*backend)
@@ -47,6 +106,7 @@
     surface->backend = backend;
 
     surface->ref_count = 1;
+    surface->status = CAIRO_STATUS_SUCCESS;
     surface->finished = FALSE;
 
     _cairo_user_data_array_init (&surface->user_data);
@@ -64,10 +124,15 @@
 				       int		width,
 				       int		height)
 {
-    if (other == NULL)
-	return NULL;
+    cairo_format_t format = _cairo_format_from_content (content);
 
-    return other->backend->create_similar (other, content, width, height);
+    if (other->status)
+	return _cairo_surface_create_in_error (other->status);
+
+    if (other->backend->create_similar)
+	return other->backend->create_similar (other, content, width, height);
+    else
+	return cairo_image_surface_create (format, width, height);
 }
 
 /**
@@ -91,12 +156,11 @@
 			      int		width,
 			      int		height)
 {
-    if (other == NULL)
-	return NULL;
+    if (other->status)
+	return _cairo_surface_create_in_error (other->status);
 
-    /* XXX: Really need to make this kind of thing pass through _cairo_error. */
     if (! CAIRO_CONTENT_VALID (content))
-	return NULL;
+	return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_CONTENT);
 
     return _cairo_surface_create_similar_solid (other, content,
 						width, height,
@@ -112,25 +176,40 @@
 {
     cairo_status_t status;
     cairo_surface_t *surface;
-    cairo_format_t format = _cairo_format_from_content (content);
 
     surface = _cairo_surface_create_similar_scratch (other, content,
 						     width, height);
     
-    if (surface == NULL)
-	surface = cairo_image_surface_create (format, width, height);
-    
     status = _cairo_surface_fill_rectangle (surface,
 					    CAIRO_OPERATOR_SOURCE, color,
 					    0, 0, width, height);
     if (status) {
 	cairo_surface_destroy (surface);
-	return NULL;
+	return _cairo_surface_create_in_error (status);
     }
 
     return surface;
 }
 
+cairo_surface_t *
+_cairo_surface_create_in_error (cairo_status_t status)
+{
+    cairo_surface_t *surface;
+
+    /* The format here is totally arbitrary. */
+    surface = cairo_image_surface_create_for_data (NULL, CAIRO_FORMAT_ARGB32,
+						   0, 0, 0);
+    /* If that failed, then there are bigger problems than the error
+     * we want to stash here. */
+    if (surface->ref_count == -1)
+	return surface;
+
+    _cairo_surface_set_error (surface, status);
+
+    return surface;
+}
+
+
 cairo_clip_mode_t
 _cairo_surface_get_clip_mode (cairo_surface_t *surface)
 {
@@ -148,6 +227,9 @@
     if (surface == NULL)
 	return;
 
+    if (surface->ref_count == (unsigned int)-1)
+	return;
+
     surface->ref_count++;
 }
 
@@ -157,6 +239,9 @@
     if (surface == NULL)
 	return;
 
+    if (surface->ref_count == (unsigned int)-1)
+	return;
+
     surface->ref_count--;
     if (surface->ref_count)
 	return;
@@ -178,36 +263,37 @@
  * that cairo will no longer access the drawable, which can be freed.
  * After calling cairo_surface_finish() the only valid operations on a
  * surface are getting and setting user data and referencing and
- * destroying it.  Further drawing the the surface will not affect the
- * surface but set the surface status to
- * CAIRO_STATUS_SURFACE_FINISHED.
+ * destroying it.  Further drawing to the surface will not affect the
+ * surface but will instead trigger a CAIRO_STATUS_SURFACE_FINISHED
+ * error.
  *
  * When the last call to cairo_surface_destroy() decreases the
  * reference count to zero, cairo will call cairo_surface_finish() if
  * it hasn't been called already, before freeing the resources
  * associated with the surface.
- * 
- * Return value: CAIRO_STATUS_SUCCESS if the surface was finished
- * successfully, otherwise CAIRO_STATUS_NO_MEMORY or
- * CAIRO_STATUS_WRITE_ERROR.
  **/
-cairo_status_t
+void
 cairo_surface_finish (cairo_surface_t *surface)
 {
     cairo_status_t status;
 
-    if (surface->finished)
-	return CAIRO_STATUS_SURFACE_FINISHED;
+    if (surface->finished) {
+	_cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED);
+	return;
+    }
 
-    if (surface->backend->finish) {
-	status = surface->backend->finish (surface);
-	if (status)
-	    return status;
+    if (surface->backend->finish == NULL) {
+	surface->finished = TRUE;
+	return;
+    }
+	
+    status = surface->backend->finish (surface);
+    if (status) {
+	_cairo_surface_set_error (surface, status);
+	return;
     }
 
     surface->finished = TRUE;
-
-    return CAIRO_STATUS_SUCCESS;
 }
 
 /**
@@ -272,14 +358,10 @@
 cairo_surface_get_font_options (cairo_surface_t       *surface,
 				cairo_font_options_t  *options)
 {
-    
     if (!surface->finished && surface->backend->get_font_options) {
 	surface->backend->get_font_options (surface, options);
     } else {
-	options->antialias = CAIRO_ANTIALIAS_DEFAULT;
-	options->subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
-	options->hint_style = CAIRO_HINT_STYLE_DEFAULT;
-	options->hint_metrics = CAIRO_HINT_METRICS_DEFAULT;
+	_cairo_font_options_init_default (options);
     }
 }
 
@@ -306,6 +388,16 @@
 				 double           x_offset,
 				 double           y_offset)
 {
+    if (surface->status) {
+	_cairo_surface_set_error (surface, surface->status);
+	return;
+    }
+
+    if (surface->finished) {
+	_cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED);
+	return;
+    }
+
     surface->device_x_offset = x_offset;
     surface->device_y_offset = y_offset;
 }
@@ -480,7 +572,17 @@
     void *image_extra;
 } fallback_state_t;
 
-static cairo_status_t
+/**
+ * _fallback_init:
+ * 
+ * Acquire destination image surface needed for an image-based
+ * fallback.
+ * 
+ * Return value: CAIRO_INT_STATUS_NOTHING_TO_DO if the extents are not
+ * visible, CAIRO_STATUS_SUCCESS if some portion is visible and all
+ * went well, or some error status otherwise.
+ **/
+static cairo_int_status_t
 _fallback_init (fallback_state_t *state,
 		cairo_surface_t  *dst,
 		int               x,
@@ -488,6 +590,8 @@
 		int               width,
 		int               height)
 {
+    cairo_status_t status;
+
     state->extents.x = x;
     state->extents.y = y;
     state->extents.width = width;
@@ -495,15 +599,29 @@
     
     state->dst = dst;
 
-    return _cairo_surface_acquire_dest_image (dst, &state->extents,
-					      &state->image, &state->image_rect, &state->image_extra);
+    status = _cairo_surface_acquire_dest_image (dst, &state->extents,
+						&state->image, &state->image_rect,
+						&state->image_extra);
+    if (status)
+	return status;
+
+    /* XXX: This NULL value tucked away in state->image is a rather
+     * ugly interface. Cleaner would be to push the
+     * CAIRO_INT_STATUS_NOTHING_TO_DO value down into
+     * _cairo_surface_acquire_dest_image and its backend
+     * counterparts. */
+    if (state->image == NULL)
+	return CAIRO_INT_STATUS_NOTHING_TO_DO;
+
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static void
-_fallback_cleanup (fallback_state_t *state)
+_fallback_fini (fallback_state_t *state)
 {
     _cairo_surface_release_dest_image (state->dst, &state->extents,
-				       state->image, &state->image_rect, state->image_extra);
+				       state->image, &state->image_rect,
+				       state->image_extra);
 }
 
 static cairo_status_t
@@ -524,18 +642,20 @@
     cairo_status_t status;
 
     status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
-    if (status || !state.image)
+    if (status) {
+	if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+	    return CAIRO_STATUS_SUCCESS;
 	return status;
+    }
 
-    state.image->base.backend->composite (operator, src, mask,
-					  &state.image->base,
-					  src_x, src_y, mask_x, mask_y,
-					  dst_x - state.image_rect.x,
-					  dst_y - state.image_rect.y,
-					  width, height);
+    status = state.image->base.backend->composite (operator, src, mask,
+						   &state.image->base,
+						   src_x, src_y, mask_x, mask_y,
+						   dst_x - state.image_rect.x,
+						   dst_y - state.image_rect.y,
+						   width, height);
+    _fallback_fini (&state);
 
-    _fallback_cleanup (&state);
-	
     return status;
 }
 
@@ -555,6 +675,9 @@
 {
     cairo_int_status_t status;
 
+    if (dst->status)
+	return dst->status;
+	
     if (dst->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
@@ -588,6 +711,9 @@
 {
     cairo_rectangle_t rect;
 
+    if (surface->status)
+	return surface->status;
+
     if (surface->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
@@ -636,16 +762,19 @@
     }
 
     status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1);
-    if (status || !state.image)
+    if (status) {
+	if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+	    return CAIRO_STATUS_SUCCESS;
 	return status;
+    }
 
     /* If the fetched image isn't at 0,0, we need to offset the rectangles */
     
     if (state.image_rect.x != 0 || state.image_rect.y != 0) {
 	offset_rects = malloc (sizeof (cairo_rectangle_t) * num_rects);
-	if (!offset_rects) {
+	if (offset_rects == NULL) {
 	    status = CAIRO_STATUS_NO_MEMORY;
-	    goto FAIL;
+	    goto DONE;
 	}
 
 	for (i = 0; i < num_rects; i++) {
@@ -658,15 +787,15 @@
 	rects = offset_rects;
     }
 
-    state.image->base.backend->fill_rectangles (&state.image->base, operator, color,
-						rects, num_rects);
+    status = state.image->base.backend->fill_rectangles (&state.image->base,
+							 operator, color,
+							 rects, num_rects);
 
-    if (offset_rects)
-	free (offset_rects);
+    free (offset_rects);
+
+ DONE:
+    _fallback_fini (&state);
 
- FAIL:
-    _fallback_cleanup (&state);
-    
     return status;
 }
 
@@ -679,6 +808,9 @@
 {
     cairo_int_status_t status;
 
+    if (surface->status)
+	return surface->status;
+
     if (surface->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
@@ -705,11 +837,11 @@
 			  cairo_fill_rule_t	fill_rule,
 			  double		tolerance)
 {
-  if (dst->backend->fill_path)
-    return dst->backend->fill_path (operator, pattern, dst, path,
-				    fill_rule, tolerance);
-  else
-    return CAIRO_INT_STATUS_UNSUPPORTED;
+    if (dst->backend->fill_path)
+	return dst->backend->fill_path (operator, pattern, dst, path,
+					fill_rule, tolerance);
+    else
+	return CAIRO_INT_STATUS_UNSUPPORTED;
 }
 
   
@@ -732,8 +864,11 @@
     int i;
 
     status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
-    if (status || !state.image)
+    if (status) {
+	if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+	    return CAIRO_STATUS_SUCCESS;
 	return status;
+    }
 
     /* If the destination image isn't at 0,0, we need to offset the trapezoids */
     
@@ -745,7 +880,7 @@
 	offset_traps = malloc (sizeof (cairo_trapezoid_t) * num_traps);
 	if (!offset_traps) {
 	    status = CAIRO_STATUS_NO_MEMORY;
-	    goto FAIL;
+	    goto DONE;
 	}
 
 	for (i = 0; i < num_traps; i++) {
@@ -773,13 +908,12 @@
     if (offset_traps)
 	free (offset_traps);
 
- FAIL:
-    _fallback_cleanup (&state);
+ DONE:
+    _fallback_fini (&state);
     
     return status;
 }
 
-
 cairo_status_t
 _cairo_surface_composite_trapezoids (cairo_operator_t		operator,
 				     cairo_pattern_t		*pattern,
@@ -795,6 +929,9 @@
 {
     cairo_int_status_t status;
 
+    if (dst->status)
+	return dst->status;
+
     if (dst->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
@@ -809,16 +946,19 @@
 	    return status;
     }
 
-    return _fallback_composite_trapezoids (operator, pattern, dst,
-					   src_x, src_y,
-					   dst_x, dst_y,
-					   width, height,
-					   traps, num_traps);
+    return  _fallback_composite_trapezoids (operator, pattern, dst,
+					    src_x, src_y,
+					    dst_x, dst_y,
+					    width, height,
+					    traps, num_traps);
 }
 
 cairo_status_t
 _cairo_surface_copy_page (cairo_surface_t *surface)
 {
+    if (surface->status)
+	return surface->status;
+
     if (surface->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
@@ -826,12 +966,15 @@
     if (surface->backend->copy_page == NULL)
 	return CAIRO_STATUS_SUCCESS;
 
-    return  surface->backend->copy_page (surface);
+    return surface->backend->copy_page (surface);
 }
 
 cairo_status_t
 _cairo_surface_show_page (cairo_surface_t *surface)
 {
+    if (surface->status)
+	return surface->status;
+
     if (surface->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
@@ -861,15 +1004,19 @@
  * _cairo_surface_allocate_clip_serial:
  * @surface: the #cairo_surface_t to allocate a serial number from
  *
- * Each surface has a separate set of clipping serial numbers,
- * and this function allocates one from the specified surface.
- * As zero is reserved for the special no-clipping case,
- * this function will not return that.
+ * Each surface has a separate set of clipping serial numbers, and
+ * this function allocates one from the specified surface.  As zero is
+ * reserved for the special no-clipping case, this function will not
+ * return that except for an in-error surface, (ie. surface->status !=
+ * CAIRO_STATUS_SUCCESS).
  */
 unsigned int
 _cairo_surface_allocate_clip_serial (cairo_surface_t *surface)
 {
     unsigned int    serial;
+    
+    if (surface->status)
+	return 0;
 
     if ((serial = ++(surface->next_clip_serial)) == 0)
 	serial = ++(surface->next_clip_serial);
@@ -890,6 +1037,9 @@
 {
     cairo_status_t  status;
 
+    if (surface->status)
+	return status;
+
     if (surface->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
     
@@ -909,6 +1059,7 @@
 	if (status)
 	    return status;
     }
+
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -927,12 +1078,16 @@
 				pixman_region16_t   *region,
 				unsigned int	    serial)
 {
+    if (surface->status)
+	return surface->status;
+
     if (surface->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
     
     assert (surface->backend->set_clip_region != NULL);
     
     surface->current_clip_serial = serial;
+
     return surface->backend->set_clip_region (surface, region);
 }
 
@@ -942,6 +1097,9 @@
 				    cairo_fill_rule_t   fill_rule,
 				    double		tolerance)
 {
+    if (surface->status)
+	return surface->status;
+
     if (surface->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
     
@@ -972,7 +1130,6 @@
 						  clip_path->tolerance);
 }
 
-
 /**
  * _cairo_surface_set_clip_path:
  * @surface: the #cairo_surface_t to reset the clip on
@@ -991,6 +1148,9 @@
 {
     cairo_status_t status;
 
+    if (surface->status)
+	return surface->status;
+
     if (surface->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
@@ -1031,6 +1191,9 @@
 _cairo_surface_get_extents (cairo_surface_t   *surface,
 			    cairo_rectangle_t *rectangle)
 {
+    if (surface->status)
+	return surface->status;
+
     if (surface->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
@@ -1053,6 +1216,9 @@
 {
     cairo_status_t status;
 
+    if (dst->status)
+	return dst->status;
+
     if (dst->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
 

Index: cairo-win32-font.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-win32-font.c,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -d -r1.26 -r1.27
--- cairo-win32-font.c	22 Jul 2005 14:15:57 -0000	1.26
+++ cairo-win32-font.c	27 Jul 2005 22:39:35 -0000	1.27
@@ -223,8 +223,10 @@
     cairo_matrix_t scale;
 
     f = malloc (sizeof(cairo_win32_scaled_font_t));
-    if (f == NULL) 
-      return NULL;
+    if (f == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return &_cairo_scaled_font_nil;
+    }
 
     f->logfont = *logfont;
     f->options = *options;
@@ -1009,7 +1011,7 @@
 
     image8 = (cairo_image_surface_t *)cairo_image_surface_create (CAIRO_FORMAT_A8,
 								  image24->width, image24->height);
-    if (!image8)
+    if (image8->status)
 	return NULL;
 
     for (i = 0; i < image24->height; i++) {
@@ -1082,8 +1084,8 @@
 	RECT r;
 
 	tmp_surface = (cairo_win32_surface_t *)_cairo_win32_surface_create_dib (CAIRO_FORMAT_ARGB32, width, height);
-	if (!tmp_surface)
-	    return CAIRO_STATUS_NO_MEMORY;
+	if (tmp_surface->status)
+	    return tmp_surface->status;
 
 	r.left = 0;
 	r.top = 0;
@@ -1387,6 +1389,11 @@
     HFONT old_hfont = NULL;
     int old_mode;
 
+    if (scaled_font->status) {
+	_cairo_scaled_font_set_error (scaled_font, scaled_font->status);
+	return scaled_font->status;
+    }
+
     hfont = _win32_scaled_font_get_scaled_hfont ((cairo_win32_scaled_font_t *)scaled_font);
     if (!hfont)
 	return CAIRO_STATUS_NO_MEMORY;

Index: cairo-win32-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-win32-surface.c,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -d -r1.29 -r1.30
--- cairo-win32-surface.c	14 Jul 2005 23:50:58 -0000	1.29
+++ cairo-win32-surface.c	27 Jul 2005 22:39:35 -0000	1.30
@@ -243,23 +243,29 @@
 				    int	            width,
 				    int	            height)
 {
+    cairo_status_t status;
     cairo_win32_surface_t *surface;
     char *bits;
     int rowstride;
 
     surface = malloc (sizeof (cairo_win32_surface_t));
-    if (!surface)
-	return NULL;
+    if (surface == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return &_cairo_surface_nil;
+    }
 
-    if (_create_dc_and_bitmap (surface, original_dc, format,
-			       width, height,
-			       &bits, &rowstride) != CAIRO_STATUS_SUCCESS)
+    status = _create_dc_and_bitmap (surface, original_dc, format,
+				    width, height,
+				    &bits, &rowstride);
+    if (status)
 	goto FAIL;
 
     surface->image = cairo_image_surface_create_for_data (bits, format,
 							  width, height, rowstride);
-    if (!surface->image)
+    if (surface->image->status) {
+	status = surface->image->status;
 	goto FAIL;
+    }
     
     surface->format = format;
     
@@ -283,9 +289,13 @@
     }
     if (surface)
 	free (surface);
-    
-    return NULL;
-    
+
+    if (status == CAIRO_STATUS_NO_MEMORY) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return &_cairo_surface_nil;
+    } else {
+	return _cairo_surface_create_in_error (status);
+    }
 }
 
 static cairo_surface_t *
@@ -359,8 +369,8 @@
 								       content,
 								       width,
 								       height);
-    if (!local)
-	return CAIRO_STATUS_NO_MEMORY;
+    if (local->status)
+	return local->status;
     
     if (!BitBlt (local->dc, 
 		 0, 0,
@@ -892,12 +902,16 @@
      */
     if (GetClipBox (hdc, &rect) == ERROR) {
 	_cairo_win32_print_gdi_error ("cairo_win32_surface_create");
-	return NULL;
+	/* XXX: Can we make a more reasonable guess at the error cause here? */
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return &_cairo_surface_nil;
     }
     
     surface = malloc (sizeof (cairo_win32_surface_t));
-    if (!surface)
-	return NULL;
+    if (surface == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return &_cairo_surface_nil;
+    }
 
     surface->image = NULL;
     surface->format = CAIRO_FORMAT_RGB24;

Index: cairo-xcb-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-xcb-surface.c,v
retrieving revision 1.40
retrieving revision 1.41
diff -u -d -r1.40 -r1.41
--- cairo-xcb-surface.c	21 Jul 2005 06:30:08 -0000	1.40
+++ cairo-xcb-surface.c	27 Jul 2005 22:39:35 -0000	1.41
@@ -503,6 +503,8 @@
 						 x2 - x1, 
 						 y2 - y1,
 						 bytes_per_line);
+	if (image->base.status)
+	    goto FAIL;
     } else {
 	/*
 	 * XXX This can't work.  We must convert the data to one of the
@@ -510,12 +512,14 @@
 	 * which takes data in an arbitrary format and converts it
 	 * to something supported by that library.
 	 */
-	image = _cairo_image_surface_create_with_masks (data,
-							&masks,
-							x2 - x1,
-							y2 - y1,
-							bytes_per_line);
-
+	image = (cairo_image_surface_t *)
+	    _cairo_image_surface_create_with_masks (data,
+						    &masks,
+						    x2 - x1,
+						    y2 - y1,
+						    bytes_per_line);
+	if (image->base.status)
+	    goto FAIL;
     }
 
     /* Let the surface take ownership of the data */
@@ -523,6 +527,10 @@
 
     *image_out = image;
     return CAIRO_STATUS_SUCCESS;
+
+ FAIL:
+    free (data);
+    return CAIRO_STATUS_NO_MEMORY;
 }
 
 static void
@@ -637,12 +645,15 @@
     } else if (_cairo_surface_is_image (src)) {
 	cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
 	cairo_content_t content = _cairo_content_from_format (image_src->format);
+
+	if (surface->base.status)
+	    return surface->base.status;
     
 	clone = (cairo_xcb_surface_t *)
 	    _cairo_xcb_surface_create_similar (surface, content,
 					       image_src->width, image_src->height);
-	if (clone == NULL)
-	    return CAIRO_STATUS_NO_MEMORY;
+	if (clone->base.status)
+	    return clone->base.status;
 	
 	_draw_image_surface (clone, image_src, 0, 0);
 	
@@ -1062,8 +1073,10 @@
     cairo_xcb_surface_t *surface;
 
     surface = malloc (sizeof (cairo_xcb_surface_t));
-    if (surface == NULL)
-	return NULL;
+    if (surface == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
 
     _cairo_surface_init (&surface->base, &cairo_xcb_surface_backend);
 

Index: cairo-xlib-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-xlib-surface.c,v
retrieving revision 1.97
retrieving revision 1.98
diff -u -d -r1.97 -r1.98
--- cairo-xlib-surface.c	27 Jul 2005 22:04:04 -0000	1.97
+++ cairo-xlib-surface.c	27 Jul 2005 22:39:35 -0000	1.98
@@ -430,11 +430,14 @@
      */
     if (_CAIRO_MASK_FORMAT (&masks, &format))
     {
-	image = (cairo_image_surface_t *) cairo_image_surface_create_for_data ((unsigned char *) ximage->data,
-									       format,
-									       ximage->width, 
-									       ximage->height,
-									       ximage->bytes_per_line);
+	image = (cairo_image_surface_t*)
+	    cairo_image_surface_create_for_data ((unsigned char *) ximage->data,
+						 format,
+						 ximage->width, 
+						 ximage->height,
+						 ximage->bytes_per_line);
+	if (image->base.status)
+	    goto FAIL;
     }
     else
     {
@@ -444,11 +447,14 @@
 	 * which takes data in an arbitrary format and converts it
 	 * to something supported by that library.
 	 */
-	image = _cairo_image_surface_create_with_masks ((unsigned char *) ximage->data,
-							&masks,
-							ximage->width, 
-							ximage->height,
-							ximage->bytes_per_line);
+	image = (cairo_image_surface_t*)
+	    _cairo_image_surface_create_with_masks ((unsigned char *) ximage->data,
+						    &masks,
+						    ximage->width, 
+						    ximage->height,
+						    ximage->bytes_per_line);
+	if (image->base.status)
+	    goto FAIL;
     }
 
     /* Let the surface take ownership of the data */
@@ -458,6 +464,10 @@
      
     *image_out = image;
     return CAIRO_STATUS_SUCCESS;
+
+ FAIL:
+    XDestroyImage (ximage);
+    return CAIRO_STATUS_NO_MEMORY;
 }
 
 static void
@@ -658,8 +668,8 @@
 	clone = (cairo_xlib_surface_t *)
 	    _cairo_xlib_surface_create_similar (surface, content,
 						image_src->width, image_src->height);
-	if (clone == NULL)
-	    return CAIRO_STATUS_NO_MEMORY;
+	if (clone->base.status)
+	    return clone->base.status;
 	
 	_draw_image_surface (clone, image_src, 0, 0);
 	
@@ -1400,12 +1410,16 @@
     cairo_xlib_screen_info_t *screen_info;
 
     screen_info = _cairo_xlib_screen_info_get (dpy, screen);
-    if (!screen_info)
-	return NULL;
+    if (screen_info == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
 
     surface = malloc (sizeof (cairo_xlib_surface_t));
-    if (surface == NULL)
-	return NULL;
+    if (surface == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
 
     _cairo_surface_init (&surface->base, &cairo_xlib_surface_backend);
 
@@ -1534,7 +1548,7 @@
     Screen *screen = _cairo_xlib_screen_from_visual (dpy, visual);
 
     if (screen == NULL)
-	return NULL;
+	return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_VISUAL);
     
     return _cairo_xlib_surface_create_internal (dpy, drawable, screen,
 						visual, NULL, width, height, 0);
@@ -2376,7 +2390,9 @@
 
     /* Work out the index size to use. */
     elt_size = 8;
-    _cairo_scaled_font_get_glyph_cache_key (scaled_font, &key);
+    status = _cairo_scaled_font_get_glyph_cache_key (scaled_font, &key);
+    if (status)
+	goto UNLOCK;
 
     for (i = 0; i < num_glyphs; ++i) {
 	key.index = glyphs[i].index;

Index: cairo.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo.c,v
retrieving revision 1.114
retrieving revision 1.115
diff -u -d -r1.114 -r1.115
--- cairo.c	25 Jul 2005 19:29:24 -0000	1.114
+++ cairo.c	27 Jul 2005 22:39:35 -0000	1.115
@@ -62,34 +62,52 @@
  * a bit of a pain, but it should be easy to always catch as long as
  * one adds a new test case to test a trigger of the new status value.
  */
-#define CAIRO_STATUS_LAST_STATUS CAIRO_STATUS_PATTERN_TYPE_MISMATCH
+#define CAIRO_STATUS_LAST_STATUS CAIRO_STATUS_INVALID_VISUAL
 
 /**
  * _cairo_error:
+ * @status: a status value indicating an error, (eg. not
+ * CAIRO_STATUS_SUCCESS)
+ * 
[...1174 lines suppressed...]
 	return "invalid matrix (not invertible)";
     case CAIRO_STATUS_INVALID_STATUS:
-	return " invalid value for an input cairo_status_t";
+	return "invalid value for an input cairo_status_t";
     case CAIRO_STATUS_NULL_POINTER:
 	return "NULL pointer";
     case CAIRO_STATUS_INVALID_STRING:
@@ -2374,6 +2389,12 @@
 	return "the surface type is not appropriate for the operation";
     case CAIRO_STATUS_PATTERN_TYPE_MISMATCH:
 	return "the pattern type is not appropriate for the operation";
+    case CAIRO_STATUS_INVALID_CONTENT:
+	return "invalid value for an input cairo_content_t";
+    case CAIRO_STATUS_INVALID_FORMAT:
+	return "invalid value for an input cairo_format_t";
+    case CAIRO_STATUS_INVALID_VISUAL:
+	return "invalid value for an input Visual*";
     }
 
     return "<unknown error status>";

Index: cairo.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo.h,v
retrieving revision 1.139
retrieving revision 1.140
diff -u -d -r1.139 -r1.140
--- cairo.h	25 Jul 2005 19:29:24 -0000	1.139
+++ cairo.h	27 Jul 2005 22:39:35 -0000	1.140
@@ -154,6 +154,9 @@
  * @CAIRO_STATUS_SURFACE_FINISHED: target surface has been finished
  * @CAIRO_STATUS_SURFACE_TYPE_MISMATCH: the surface type is not appropriate for the operation
  * @CAIRO_STATUS_PATTERN_TYPE_MISMATCH: the pattern type is not appropriate for the operation
+ * @CAIRO_STATUS_INVALID_CONTENT: invalid value for an input cairo_content_t
+ * @CAIRO_STATUS_INVALID_FORMAT: invalid value for an input cairo_format_t
+ * @CAIRO_STATUS_INVALID_VISUAL: invalid value for an input Visual*
  *
  * #cairo_status_t is used to indicate errors that can occur when
  * using Cairo. In some cases it is returned directly by functions.
@@ -175,7 +178,10 @@
     CAIRO_STATUS_WRITE_ERROR,
     CAIRO_STATUS_SURFACE_FINISHED,
     CAIRO_STATUS_SURFACE_TYPE_MISMATCH,
-    CAIRO_STATUS_PATTERN_TYPE_MISMATCH
+    CAIRO_STATUS_PATTERN_TYPE_MISMATCH,
+    CAIRO_STATUS_INVALID_CONTENT,
+    CAIRO_STATUS_INVALID_FORMAT,
+    CAIRO_STATUS_INVALID_VISUAL
 } cairo_status_t;
 
 /**
@@ -894,6 +900,9 @@
 cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font);
 
 cairo_status_t
+cairo_scaled_font_status (cairo_scaled_font_t *scaled_font);
+
+void
 cairo_scaled_font_extents (cairo_scaled_font_t  *scaled_font,
 			   cairo_font_extents_t *extents);
 
@@ -1102,6 +1111,9 @@
 cairo_surface_destroy (cairo_surface_t *surface);
 
 cairo_status_t
+cairo_surface_status (cairo_surface_t *surface);
+
+void
 cairo_surface_finish (cairo_surface_t *surface);
 
 #if CAIRO_HAS_PNG_FUNCTIONS

Index: cairoint.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairoint.h,v
retrieving revision 1.169
retrieving revision 1.170
diff -u -d -r1.169 -r1.170
--- cairoint.h	25 Jul 2005 23:23:05 -0000	1.169
+++ cairoint.h	27 Jul 2005 22:39:35 -0000	1.170
@@ -229,7 +229,8 @@
    offset */
 typedef enum cairo_int_status {
     CAIRO_INT_STATUS_DEGENERATE = 1000,
-    CAIRO_INT_STATUS_UNSUPPORTED
+    CAIRO_INT_STATUS_UNSUPPORTED,
+    CAIRO_INT_STATUS_NOTHING_TO_DO
 } cairo_int_status_t;
 
 typedef enum cairo_direction {
@@ -458,6 +459,7 @@
 };
 
 struct _cairo_scaled_font {
+    cairo_status_t status;
     int ref_count;
     cairo_matrix_t font_matrix;	  /* font space => user space */
     cairo_matrix_t ctm;	          /* user space => device space */
@@ -794,6 +796,7 @@
     const cairo_surface_backend_t *backend;
 
     unsigned int ref_count;
+    cairo_status_t status;
     cairo_bool_t finished;
     cairo_user_data_array_t user_data;
 
@@ -833,6 +836,8 @@
     pixman_image_t *pixman_image;
 };
 
+extern const cairo_surface_backend_t cairo_image_surface_backend;
+
 /* XXX: Right now, the cairo_color structure puts unpremultiplied
    color in the doubles and premultiplied color in the shorts. Yes,
    this is crazy insane, (but at least we don't export this
@@ -1294,6 +1299,10 @@
 /* cairo-font.c */
 
 cairo_private void
+_cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
+			      cairo_status_t status);
+
+cairo_private void
 _cairo_font_face_init (cairo_font_face_t               *font_face,
 		       const cairo_font_face_backend_t *backend);
 
@@ -1302,6 +1311,8 @@
 				cairo_font_slant_t    slant,
 				cairo_font_weight_t   weight);
 
+extern const cairo_scaled_font_t _cairo_scaled_font_nil;
+
 cairo_private void
 _cairo_scaled_font_init (cairo_scaled_font_t 	           *scaled_font, 
 			 const cairo_matrix_t              *font_matrix,
@@ -1360,7 +1371,7 @@
 			       int                  num_glyphs,
 			       cairo_path_fixed_t  *path);
 
-cairo_private void
+cairo_private cairo_status_t
 _cairo_scaled_font_get_glyph_cache_key (cairo_scaled_font_t     *scaled_font,
 					cairo_glyph_cache_key_t *key);
 
@@ -1468,6 +1479,9 @@
 				   cairo_traps_t      *traps);
 
 /* cairo-surface.c */
+
+extern const cairo_surface_t _cairo_surface_nil;
+
 cairo_private cairo_surface_t *
 _cairo_surface_create_similar_scratch (cairo_surface_t *other,
 				       cairo_content_t	content,
@@ -1481,6 +1495,9 @@
 				     int		  height,
 				     const cairo_color_t *color);
 
+cairo_surface_t *
+_cairo_surface_create_in_error (cairo_status_t status);
+
 cairo_private void
 _cairo_surface_init (cairo_surface_t			*surface,
 		     const cairo_surface_backend_t	*backend);
@@ -1627,7 +1644,7 @@
 cairo_private cairo_content_t
 _cairo_content_from_format (cairo_format_t format);
 
-cairo_private cairo_image_surface_t *
+cairo_private cairo_surface_t *
 _cairo_image_surface_create_with_masks (unsigned char	       *data,
 					cairo_format_masks_t   *format,
 					int			width,
@@ -1641,7 +1658,7 @@
 _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
 				      pixman_region16_t *region);
 
-cairo_private int
+cairo_private cairo_bool_t
 _cairo_surface_is_image (cairo_surface_t *surface);
 
 /* cairo_pen.c */
@@ -1909,6 +1926,9 @@
 cairo_output_stream_t *
 _cairo_output_stream_create_for_file (const char *filename);
 
+cairo_private void
+_cairo_error (cairo_status_t status);
+
 /* Avoid unnecessary PLT entries.  */
 
 slim_hidden_proto(cairo_get_current_point)




More information about the cairo-commit mailing list