[cairo-commit] 12 commits - src/cairo-atsui-font.c src/cairo-quartz-surface.c test/make-html.pl

Brian Ewins brianewins at kemper.freedesktop.org
Sat Oct 20 06:13:09 PDT 2007


 src/cairo-atsui-font.c     |  141 ++++++++++++++++++++++++++++++++++++---------
 src/cairo-quartz-surface.c |  134 +++++++++++++++++++++++++++++++++++-------
 test/make-html.pl          |  136 +++++++++++++++++++++++--------------------
 3 files changed, 302 insertions(+), 109 deletions(-)

New commits:
commit 481ce2b8cb2dc376419e7d6cbdd73bd4ebcd5b5b
Author: Brian Ewins <Brian.Ewins at gmail.com>
Date:   Sun Jul 1 14:37:57 2007 +0100

    implement clipping with surface masks.
    
    This implements clipping using CGContextClipToMask, which
    means that it will only have an effect on OS X 10.4+.
    No additional tests pass with this fix - mainly due to
    text effects and problems with the IN, OUT, DEST_IN, DEST_ATOP
    operators.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 24745b3..9a27612 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -89,6 +89,8 @@ CG_EXTERN void CGContextReplacePathWithStrokedPath (CGContextRef);
 CG_EXTERN CGImageRef CGBitmapContextCreateImage (CGContextRef);
 #endif
 
+/* missing in 10.3.9 */
+extern void CGContextClipToMask (CGContextRef, CGRect, CGImageRef) __attribute__((weak_import));
 
 /*
  * Utility functions
@@ -1503,6 +1505,43 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
 }
 #endif /* CAIRO_HAS_ATSUI_FONT */
 
+static cairo_status_t
+_cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
+                                         cairo_operator_t op,
+                                         cairo_pattern_t *source,
+                                         cairo_surface_pattern_t *mask)
+{
+    cairo_rectangle_int16_t extents;
+    cairo_quartz_surface_t *quartz_surf;
+    CGRect rect;
+    CGImageRef img;
+    cairo_surface_t *pat_surf = mask->surface;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+    status = _cairo_surface_get_extents (pat_surf, &extents);
+    if (status)
+	return status;
+
+    quartz_surf = _cairo_quartz_surface_to_quartz (NULL, pat_surf);
+
+    img = CGBitmapContextCreateImage (quartz_surf->cgContext);
+    if (!img) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto BAIL;
+    }
+
+    rect = CGRectMake (-mask->base.matrix.x0, -mask->base.matrix.y0, extents.width, extents.height);
+    CGContextSaveGState (surface->cgContext);
+    CGContextClipToMask (surface->cgContext, rect, img);
+    status = _cairo_quartz_surface_paint (surface, op, source);
+
+    CGContextRestoreGState (surface->cgContext);
+    CGImageRelease (img);
+  BAIL:
+    cairo_surface_destroy ((cairo_surface_t*) quartz_surf);
+    return status;
+}
+
 static cairo_int_status_t
 _cairo_quartz_surface_mask (void *abstract_surface,
 			     cairo_operator_t op,
@@ -1519,6 +1558,10 @@ _cairo_quartz_surface_mask (void *abstract_surface,
 	cairo_solid_pattern_t *solid_mask = (cairo_solid_pattern_t *) mask;
 
 	CGContextSetAlpha (surface->cgContext, solid_mask->color.alpha);
+    } else if (CGContextClipToMask &&
+               mask->type == CAIRO_PATTERN_TYPE_SURFACE &&
+	       mask->extend == CAIRO_EXTEND_NONE) {
+	return _cairo_quartz_surface_mask_with_surface (surface, op, source, (cairo_surface_pattern_t *) mask);
     } else {
 	/* So, CGContextClipToMask is not present in 10.3.9, so we're
 	 * doomed; if we have imageData, we can do fallback, otherwise
commit b9c065df74027b06e15e105fee5e4a4d350e0abf
Author: Brian Ewins <Brian.Ewins at gmail.com>
Date:   Sun Jun 24 23:53:47 2007 +0100

    fix dash-zero-length test
    
    Quartz was failing the dash-zero-length test for odd numbers
    of dashes; it seems cairo wants 3 dashes to be on-off-on,
    off-on-off, wheras quartz uses on-off-on, on-off-on. Fixed
    by doubling the number of dashes used.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 8818768..24745b3 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -1287,17 +1287,23 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
 #define STATIC_DASH 32
 	float sdash[STATIC_DASH];
 	float *fdash = sdash;
+	unsigned int max_dashes = style->num_dashes;
 	unsigned int k;
-	if (style->num_dashes > STATIC_DASH)
+
+	if (style->num_dashes%2)
+	    max_dashes *= 2;
+	if (max_dashes > STATIC_DASH)
 	    fdash = _cairo_malloc_ab (style->num_dashes, sizeof (float));
 	if (fdash == NULL)
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-	for (k = 0; k < style->num_dashes; k++)
-	    fdash[k] = (float) style->dash[k];
-	
-	CGContextSetLineDash (surface->cgContext, style->dash_offset, fdash, style->num_dashes);
+	if (max_dashes > STATIC_DASH)
+	    fdash = malloc (sizeof(float)*max_dashes);
 
+	for (k = 0; k < max_dashes; k++)
+	    fdash[k] = (float) style->dash[k % style->num_dashes];
+	
+	CGContextSetLineDash (surface->cgContext, style->dash_offset, fdash, max_dashes);
 	if (fdash != sdash)
 	    free (fdash);
     }
commit f334ee0397963e12c9efcb2690792aac83734661
Author: Brian Ewins <Brian.Ewins at gmail.com>
Date:   Sun Jun 24 01:17:58 2007 +0100

    Implement EXTEND_NONE for gradients.
    
    Fixes linear and radial gradients, which were displaying with
    extend_pad when extend_none was requested. Makes the
    radial-gradient test pass.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 25169f8..8818768 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -373,6 +373,7 @@ _cairo_quartz_cairo_gradient_pattern_to_quartz (cairo_pattern_t *abspat)
 	CGPoint start, end;
 	CGFunctionRef gradFunc;
 	CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
+	bool extend = abspat->extend == CAIRO_EXTEND_PAD;
 
 	start = CGPointMake (_cairo_fixed_to_double (lpat->p1.x) - x0,
 			     _cairo_fixed_to_double (lpat->p1.y) - y0);
@@ -384,7 +385,7 @@ _cairo_quartz_cairo_gradient_pattern_to_quartz (cairo_pattern_t *abspat)
 	shading = CGShadingCreateAxial (rgb,
 					start, end,
 					gradFunc,
-					true, true);
+					extend, extend);
 	CGColorSpaceRelease(rgb);
 	CGFunctionRelease(gradFunc);
 
@@ -397,6 +398,7 @@ _cairo_quartz_cairo_gradient_pattern_to_quartz (cairo_pattern_t *abspat)
 	CGPoint start, end;
 	CGFunctionRef gradFunc;
 	CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
+	bool extend = abspat->extend == CAIRO_EXTEND_PAD;
 
 	start = CGPointMake (_cairo_fixed_to_double (rpat->c1.x) - x0,
 			     _cairo_fixed_to_double (rpat->c1.y) - y0);
@@ -411,7 +413,7 @@ _cairo_quartz_cairo_gradient_pattern_to_quartz (cairo_pattern_t *abspat)
 					 end,
 					 _cairo_fixed_to_double (rpat->r2),
 					 gradFunc,
-					 true, true);
+					 extend, extend);
 	CGColorSpaceRelease(rgb);
 	CGFunctionRelease(gradFunc);
 
commit 0eeec372c0e7849d81bde8c8c5bf491919f51a6e
Author: Brian Ewins <Brian.Ewins at gmail.com>
Date:   Sat Jun 23 23:36:32 2007 +0100

    call _cairo_error on failure
    
    Call _cairo_error to enable setting a breakpoint on quartz errors.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 80d8216..25169f8 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -485,6 +485,7 @@ SurfacePatternDrawFunc (void *info, CGContextRef context)
     if (!img) {
 	// ... give up.
 	ND((stderr, "CGBitmapContextCreateImage failed\n"));
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
 	cairo_surface_destroy ((cairo_surface_t*)quartz_surf);
 	return;
     }
commit 8c8ec63903f8ad67a88394eff1359607bb93cf88
Author: Brian Ewins <Brian.Ewins at gmail.com>
Date:   Sat Jun 23 12:34:24 2007 +0100

    do not return a cairo_status_t of UNSUPPORTED
    
    We had a bug which converted cairo_int_status_t to cairo_status_t,
    causing an assertion; reported at http://developer.imendio.com/node/128.
    Return the generic out of memory error instead.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index fc21249..80d8216 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -899,13 +899,18 @@ _cairo_quartz_surface_acquire_source_image (void *abstract_surface,
 					     cairo_image_surface_t **image_out,
 					     void **image_extra)
 {
+    cairo_int_status_t status;
     cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
 
     //ND((stderr, "%p _cairo_quartz_surface_acquire_source_image\n", surface));
 
     *image_extra = NULL;
 
-    return _cairo_quartz_get_image (surface, image_out, NULL);
+    status = _cairo_quartz_get_image (surface, image_out, NULL);
+    if (status)
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static void
@@ -934,7 +939,7 @@ _cairo_quartz_surface_acquire_dest_image (void *abstract_surface,
 
     status = _cairo_quartz_get_image (surface, image_out, &data);
     if (status)
-	return status;
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
     *image_extra = data;
 
commit 6fec51990e90901ebafbb872a9e618cb70d17911
Author: Brian Ewins <Brian.Ewins at gmail.com>
Date:   Mon Jun 18 00:07:33 2007 +0100

    do not ignore errors, return NULL instead (moz#874315)
    
    In the quartz backend there are occasional errors where returning NULL
    can be used to signal that an error has occured.
    
    Mozilla bug #874315.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index f06f811..fc21249 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -437,17 +437,23 @@ _cairo_quartz_surface_to_quartz (cairo_surface_t *target, cairo_surface_t *pat_s
 	cairo_surface_t *ref_type = target;
 	cairo_surface_t *new_surf = NULL;
 	cairo_rectangle_int_t rect;
+	cairo_status_t status;
+
 	if (ref_type == NULL)
 	    ref_type = cairo_quartz_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
 
-	_cairo_surface_get_extents (pat_surf, &rect);
+	status = _cairo_surface_get_extents (pat_surf, &rect);
+	if (status)
+	    return NULL;
 
-	_cairo_surface_clone_similar (ref_type, pat_surf, rect.x, rect.y,
+	status = _cairo_surface_clone_similar (ref_type, pat_surf, rect.x, rect.y,
 				      rect.width, rect.height, &new_surf);
-
 	if (target == NULL)
 	    cairo_surface_destroy(ref_type);
 
+        if (status)
+	    return NULL;
+
 	quartz_surf = (cairo_quartz_surface_t *) new_surf;
     } else {
 	/* If it's a quartz surface, we can try to see if it's a CGBitmapContext;
@@ -455,7 +461,6 @@ _cairo_quartz_surface_to_quartz (cairo_surface_t *target, cairo_surface_t *pat_s
 	 */
 	cairo_surface_reference (pat_surf);
 	quartz_surf = (cairo_quartz_surface_t*) pat_surf;
-
     }
 
     return quartz_surf;
@@ -468,10 +473,15 @@ SurfacePatternDrawFunc (void *info, CGContextRef context)
     cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) info;
     cairo_surface_t *pat_surf = spat->surface;
 
-    cairo_quartz_surface_t *quartz_surf = _cairo_quartz_surface_to_quartz (NULL, pat_surf);
-    CGImageRef img = CGBitmapContextCreateImage (quartz_surf->cgContext);
+    cairo_quartz_surface_t *quartz_surf;
+    CGImageRef img;
     CGRect imageBounds;
 
+    quartz_surf = _cairo_quartz_surface_to_quartz (NULL, pat_surf);
+    if (!quartz_surf)
+	return;
+
+    img = CGBitmapContextCreateImage (quartz_surf->cgContext);
     if (!img) {
 	// ... give up.
 	ND((stderr, "CGBitmapContextCreateImage failed\n"));
@@ -554,6 +564,7 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t
 			      (CGFunctionReleaseInfoCallback) cairo_pattern_destroy };
     CGPatternRef cgpat;
     float rw, rh;
+    cairo_status_t status;
 
     cairo_pattern_union_t *snap_pattern = NULL;
     cairo_pattern_t *target_pattern = abspat;
@@ -566,7 +577,10 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t
     spat = (cairo_surface_pattern_t *) abspat;
     pat_surf = spat->surface;
 
-    _cairo_surface_get_extents (pat_surf, &extents);
+    status = _cairo_surface_get_extents (pat_surf, &extents);
+    if (status)
+	return NULL;
+
     pbounds.origin.x = 0;
     pbounds.origin.y = 0;
 
@@ -672,12 +686,17 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
     {
 	    cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) source;
 	    cairo_surface_t *pat_surf = spat->surface;
-	    cairo_quartz_surface_t *quartz_surf = _cairo_quartz_surface_to_quartz ((cairo_surface_t *) surface, pat_surf);
-	    CGImageRef img = CGBitmapContextCreateImage (quartz_surf->cgContext);
+	    cairo_quartz_surface_t *quartz_surf;
+	    CGImageRef img;
 	    cairo_matrix_t m = spat->base.matrix;
 	    cairo_rectangle_int_t extents;
 	    cairo_status_t status;
 
+	    quartz_surf = _cairo_quartz_surface_to_quartz ((cairo_surface_t *) surface, pat_surf);
+	    if (!quartz_surf)
+		return DO_UNSUPPORTED;
+
+	    img = CGBitmapContextCreateImage (quartz_surf->cgContext);
 	    if (!img)
 		return DO_UNSUPPORTED;
 
commit 07fd091e3e6b925c588b9a16f6f10efcd46615c2
Author: Brian Ewins <Brian.Ewins at gmail.com>
Date:   Mon Jun 18 00:07:33 2007 +0100

    do not ignore errors in setup_source
    
    In setup_source we were ignoring a return value, but we can't relay
    it to the caller. This patch treats the error as an unsupported
    operation.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 3bcbc42..f06f811 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -676,6 +676,7 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
 	    CGImageRef img = CGBitmapContextCreateImage (quartz_surf->cgContext);
 	    cairo_matrix_t m = spat->base.matrix;
 	    cairo_rectangle_int_t extents;
+	    cairo_status_t status;
 
 	    if (!img)
 		return DO_UNSUPPORTED;
@@ -685,7 +686,10 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
 	    cairo_matrix_invert(&m);
 	    _cairo_quartz_cairo_matrix_to_quartz (&m, &surface->sourceImageTransform);
 
-	    _cairo_surface_get_extents (pat_surf, &extents);
+	    status = _cairo_surface_get_extents (pat_surf, &extents);
+	    if (status)
+		return DO_UNSUPPORTED;
+
 	    surface->sourceImageRect = CGRectMake (0, 0, extents.width, extents.height);
 
 	    surface->sourceImageSurface = (cairo_surface_t *)quartz_surf;
commit b6b9cef7136453f97543173bcb2ade46b1c46b77
Author: Brian Ewins <Brian.Ewins at gmail.com>
Date:   Tue Jun 19 21:13:39 2007 +0100

    do not ignore errors when creating styles.
    
    This fixes statuses being ignored when calling
    CreateSizedCopyOfStyle. As a side effect, it cleans up
    two other bugs - the font object was sometimes not
    freed, and a the scaled font mutex was aquired recursively,
    causing a hang in the invalid-matrix test.

diff --git a/src/cairo-atsui-font.c b/src/cairo-atsui-font.c
index 4a1037d..f3cf8a5 100644
--- a/src/cairo-atsui-font.c
+++ b/src/cairo-atsui-font.c
@@ -175,30 +175,35 @@ cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id)
     return &font_face->base;
 }
 
-static ATSUStyle
+static OSStatus
 CreateSizedCopyOfStyle(ATSUStyle inStyle, 
 		       const Fixed *theSize, 
-		       const CGAffineTransform *theTransform)
+                      const CGAffineTransform *theTransform,
+                      ATSUStyle *style)
 {
-    ATSUStyle style;
     OSStatus err;
     const ATSUAttributeTag theFontStyleTags[] = { kATSUSizeTag, 
-						  kATSUFontMatrixTag };
+                                                 kATSUFontMatrixTag };
     const ByteCount theFontStyleSizes[] = { sizeof(Fixed), 
-					    sizeof(CGAffineTransform) };
+                                           sizeof(CGAffineTransform) };
     ATSUAttributeValuePtr theFontStyleValues[] = { (Fixed *)theSize, 
-						   (CGAffineTransform *)theTransform };
+                                                  (CGAffineTransform *)theTransform };
 
-    err = ATSUCreateAndCopyStyle(inStyle, &style);
+    err = ATSUCreateAndCopyStyle (inStyle, style);
+    if (err != noErr)
+	return err;
 
-    err = ATSUSetAttributes(style,
+    err = ATSUSetAttributes(*style,
                             sizeof(theFontStyleTags) /
                             sizeof(ATSUAttributeTag), theFontStyleTags,
                             theFontStyleSizes, theFontStyleValues);
+    if (err != noErr)
+	ATSUDisposeStyle (*style);
 
-    return style;
+    return err;
 }
 
+
 static cairo_status_t
 _cairo_atsui_font_set_metrics (cairo_atsui_font_t *font)
 {
@@ -265,7 +270,12 @@ _cairo_atsui_font_create_scaled (cairo_font_face_t *font_face,
 					       0., 0.);
     font->size = FloatToFixed (xscale);
 
-    font->style = CreateSizedCopyOfStyle (style, &font->size, &font->font_matrix);
+    err = CreateSizedCopyOfStyle (style, &font->size, &font->font_matrix, &font->style);
+    if (err != noErr) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	status = CAIRO_STATUS_NO_MEMORY;
+	goto FAIL;
+    }
 
     {
 	Fixed theSize = FloatToFixed(1.0);
@@ -292,7 +302,12 @@ _cairo_atsui_font_create_scaled (cairo_font_face_t *font_face,
 
   FAIL:
     if (status) {
-	cairo_scaled_font_destroy (&font->base);
+	if (font) {
+	    if (font->style)
+		ATSUDisposeStyle(font->style);
+	    free (font);
+	}
+
 	return status;
     }
 
commit 4885a12c6863321a566e7103bf6dccdd5d13a986
Author: Brian Ewins <Brian.Ewins at gmail.com>
Date:   Mon Jun 18 00:07:33 2007 +0100

    do not ignore ATSUI errors.
    
    This fixes multiple instances where the return value of an ATSUI
    call was ignored and converts them into CAIRO_STATUS_NO_MEMORY.
    As a side effect it fixes a utf8 array not being freed.

diff --git a/src/cairo-atsui-font.c b/src/cairo-atsui-font.c
index 1404780..4a1037d 100644
--- a/src/cairo-atsui-font.c
+++ b/src/cairo-atsui-font.c
@@ -111,6 +111,7 @@ _cairo_atsui_font_face_scaled_font_create (void	*abstract_face,
 					   const cairo_font_options_t *options,
 					   cairo_scaled_font_t **font)
 {
+    cairo_status_t status;
     cairo_atsui_font_face_t *font_face = abstract_face;
     OSStatus err;
     ATSUAttributeTag styleTags[] = { kATSUFontTag };
@@ -119,11 +120,22 @@ _cairo_atsui_font_face_scaled_font_create (void	*abstract_face,
     ATSUStyle style;
 
     err = ATSUCreateStyle (&style);
+    if (err != noErr)
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
     err = ATSUSetAttributes(style, ARRAY_LENGTH (styleTags),
                             styleTags, styleSizes, styleValues);
+    if (err != noErr) {
+        ATSUDisposeStyle (style);
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
 
-    return _cairo_atsui_font_create_scaled (&font_face->base, font_face->font_id, style,
+    status = _cairo_atsui_font_create_scaled (&font_face->base, font_face->font_id, style,
 					    font_matrix, ctm, options, font);
+    if (status)
+        ATSUDisposeStyle (style);
+
+    return status;
 }
 
 static const cairo_font_face_backend_t _cairo_atsui_font_face_backend = {
@@ -294,6 +306,7 @@ _cairo_atsui_font_create_toy(cairo_toy_font_face_t *toy_face,
 			     const cairo_font_options_t *options,
 			     cairo_scaled_font_t **font_out)
 {
+    cairo_status_t status;
     ATSUStyle style;
     ATSUFontID fontID;
     OSStatus err;
@@ -302,6 +315,9 @@ _cairo_atsui_font_create_toy(cairo_toy_font_face_t *toy_face,
     const char *full_name;
 
     err = ATSUCreateStyle(&style);
+    if (err != noErr) {
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
 
     switch (toy_face->weight) {
     case CAIRO_FONT_WEIGHT_BOLD:
@@ -375,6 +391,10 @@ _cairo_atsui_font_create_toy(cairo_toy_font_face_t *toy_face,
 				       kFontNoPlatformCode,
 				       kFontRomanScript,
 				       kFontNoLanguageCode, &fontID);
+	    if (err != noErr) {
+		ATSUDisposeStyle (style);
+		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    }
 	}
     }
 
@@ -387,10 +407,18 @@ _cairo_atsui_font_create_toy(cairo_toy_font_face_t *toy_face,
 
 	err = ATSUSetAttributes(style, ARRAY_LENGTH (styleTags),
 				styleTags, styleSizes, styleValues);
+	if (err != noErr) {
+	    ATSUDisposeStyle (style);
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	}
     }
 
-    return _cairo_atsui_font_create_scaled (&toy_face->base, fontID, style,
+    status = _cairo_atsui_font_create_scaled (&toy_face->base, fontID, style,
 					    font_matrix, ctm, options, font_out);
+    if (status)
+	ATSUDisposeStyle (style);
+
+    return status;
 }
 
 static void
@@ -601,6 +629,10 @@ _cairo_atsui_scaled_font_init_glyph_path (cairo_atsui_font_t *scaled_font,
 				 lineProc,
 				 curveProc,
 				 closePathProc, (void *)&scaled_path, &err);
+    if (err != noErr) {
+	_cairo_path_fixed_destroy (scaled_path.path);
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
 
     _cairo_scaled_glyph_set_path (scaled_glyph, &scaled_font->base, 
 				  scaled_path.path);
@@ -664,6 +696,10 @@ _cairo_atsui_scaled_font_init_glyph_surface (cairo_atsui_font_t *scaled_font,
     err = ATSUGlyphGetScreenMetrics (scaled_font->style,
 				     1, &theGlyph, 0, false,
 				     false, &metricsH);    
+    if (err != noErr) {
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
     left = metricsH.sideBearing.x - 1.0;
     width = metricsH.deviceAdvance.x 
 	- metricsH.sideBearing.x 
@@ -809,28 +845,45 @@ _cairo_atsui_font_text_to_glyphs (void		*abstract_font,
 
     status = _cairo_utf8_to_utf16 ((unsigned char *)utf8, -1, &utf16, &n16);
     if (status)
-	return status;
+	goto BAIL3;
 
     err = ATSUCreateTextLayout(&textLayout);
+    if (err != noErr) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto BAIL3;
+    }
 
     err = ATSUSetTextPointerLocation(textLayout, utf16, 0, n16, n16);
+    if (err != noErr) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto BAIL2;
+    }
 
     /* Set the style for all of the text */
     err = ATSUSetRunStyle(textLayout,
 			  font->style, kATSUFromTextBeginning, kATSUToTextEnd);
+    if (err != noErr) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto BAIL2;
+    }
 
     err = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout,
 							0,
 							kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
 							(void *)&layoutRecords,
 							&glyphCount);
+    if (err != noErr) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto BAIL2;
+    }
 
     *num_glyphs = glyphCount - 1;
     *glyphs =
 	(cairo_glyph_t *) _cairo_malloc_ab(*num_glyphs, sizeof (cairo_glyph_t));
-    if (*glyphs == NULL)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
+    if (*glyphs == NULL) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto BAIL1;
+    }
     _cairo_matrix_compute_scale_factors (&font->base.ctm, &xscale, &yscale, 1);
     device_to_user_scale = 
 	CGAffineTransformInvert (CGAffineTransformMake (xscale, 0,
@@ -846,14 +899,17 @@ _cairo_atsui_font_text_to_glyphs (void		*abstract_font,
 	(*glyphs)[i].y = y;
     }
 
-    free (utf16);
-
+  BAIL1:
+    /* TODO ignored return value. Is there anything we should do? */
     ATSUDirectReleaseLayoutDataArrayPtr(NULL,
 					kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
 					(void *) &layoutRecords);
+  BAIL2:
     ATSUDisposeTextLayout(textLayout);
+  BAIL3:
+    free (utf16);
 
-    return CAIRO_STATUS_SUCCESS;
+    return status;
 }
 
 ATSUStyle
commit b498c928be73635614596243d17a922e9d5ff008
Author: Brian Ewins <Brian.Ewins at gmail.com>
Date:   Mon Jun 18 00:07:33 2007 +0100

    do not ignore errors in glyph paths
    
    When interpreting glyph paths in ATSUI callbacks we were ignoring
    the cairo status. We need to return this to the caller. In order
    to do this we introduce a custom OSStatus code in the range that
    Apple reccommend.

diff --git a/src/cairo-atsui-font.c b/src/cairo-atsui-font.c
index b677185..1404780 100644
--- a/src/cairo-atsui-font.c
+++ b/src/cairo-atsui-font.c
@@ -63,6 +63,9 @@
 /* Public in 10.4, present in 10.3.9 */
 CG_EXTERN CGRect CGRectApplyAffineTransform (CGRect, CGAffineTransform);
 
+/* Error code for path callbacks */
+static OSStatus CAIRO_CG_PATH_ERROR = 1001;
+
 typedef struct _cairo_atsui_font_face cairo_atsui_font_face_t;
 typedef struct _cairo_atsui_font cairo_atsui_font_t;
 typedef struct _cairo_atsui_scaled_path cairo_atsui_scaled_path_t;
@@ -462,16 +465,22 @@ static OSStatus
 _move_to (const Float32Point *point,
 	  void *callback_data)
 {
+    cairo_status_t status;
     cairo_atsui_scaled_path_t *scaled_path = callback_data;
     double x = point->x;
     double y = point->y;
     
     cairo_matrix_transform_point (scaled_path->scale, &x, &y);
-    _cairo_path_fixed_close_path (scaled_path->path);
-    _cairo_path_fixed_move_to (scaled_path->path,
+    status = _cairo_path_fixed_close_path (scaled_path->path);
+    if (status)
+	return CAIRO_CG_PATH_ERROR;
+
+    status = _cairo_path_fixed_move_to (scaled_path->path,
 			       _cairo_fixed_from_double (x),
 			       _cairo_fixed_from_double (y));
-
+    if (status)
+	return CAIRO_CG_PATH_ERROR;
+    
     return noErr;
 }
 
@@ -479,15 +488,18 @@ static OSStatus
 _line_to (const Float32Point *point,
 	  void *callback_data)
 {
+    cairo_status_t status;
     cairo_atsui_scaled_path_t *scaled_path = callback_data;
     double x = point->x;
     double y = point->y;
     
     cairo_matrix_transform_point (scaled_path->scale, &x, &y);
 
-    _cairo_path_fixed_line_to (scaled_path->path,
+    status = _cairo_path_fixed_line_to (scaled_path->path,
 			       _cairo_fixed_from_double (x),
 			       _cairo_fixed_from_double (y));
+    if (status)
+	return CAIRO_CG_PATH_ERROR;
 
     return noErr;
 }
@@ -498,6 +510,7 @@ _curve_to (const Float32Point *point1,
 	   const Float32Point *point3,
 	   void *callback_data)
 {
+    cairo_status_t status;
     cairo_atsui_scaled_path_t *scaled_path = callback_data;
     double x1 = point1->x;
     double y1 = point1->y;
@@ -510,13 +523,15 @@ _curve_to (const Float32Point *point1,
     cairo_matrix_transform_point (scaled_path->scale, &x2, &y2);
     cairo_matrix_transform_point (scaled_path->scale, &x3, &y3);
 
-    _cairo_path_fixed_curve_to (scaled_path->path,
+    status = _cairo_path_fixed_curve_to (scaled_path->path,
 				_cairo_fixed_from_double (x1),
 				_cairo_fixed_from_double (y1),
 				_cairo_fixed_from_double (x2),
 				_cairo_fixed_from_double (y2),
 				_cairo_fixed_from_double (x3),
 				_cairo_fixed_from_double (y3));
+    if (status)
+	return CAIRO_CG_PATH_ERROR;
 
     return noErr;
 }
@@ -525,9 +540,12 @@ static OSStatus
 _close_path (void *callback_data)
 
 {
+    cairo_status_t status;
     cairo_atsui_scaled_path_t *scaled_path = callback_data;
 
-    _cairo_path_fixed_close_path (scaled_path->path);
+    status = _cairo_path_fixed_close_path (scaled_path->path);
+    if (status)
+	return CAIRO_CG_PATH_ERROR;
 
     return noErr;
 }
commit 95c708c717a367205845cefc81ae0afd9bd3d18f
Author: Brian Ewins <Brian.Ewins at gmail.com>
Date:   Mon Jun 18 00:07:33 2007 +0100

    propagate cairo_status_t return values
    
    There are several places in the quartz surface where we ignored
    the returned status. This fixes the simple cases where the error
    can just be returned to the caller.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 88fe4b0..3bcbc42 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -1171,7 +1171,9 @@ _cairo_quartz_surface_fill (void *abstract_surface,
 
     stroke.cgContext = surface->cgContext;
     stroke.ctm_inverse = NULL;
-    _cairo_quartz_cairo_path_to_quartz_context (path, &stroke);
+    rv = _cairo_quartz_cairo_path_to_quartz_context (path, &stroke);
+    if (rv)
+        goto BAIL;
 
     if (action == DO_SOLID || action == DO_PATTERN) {
 	if (fill_rule == CAIRO_FILL_RULE_WINDING)
@@ -1207,6 +1209,7 @@ _cairo_quartz_surface_fill (void *abstract_surface,
 	rv = CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
+  BAIL:
     _cairo_quartz_teardown_source (surface, source);
 
     CGContextRestoreGState (surface->cgContext);
@@ -1280,7 +1283,9 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
 
     stroke.cgContext = surface->cgContext;
     stroke.ctm_inverse = ctm_inverse;
-    _cairo_quartz_cairo_path_to_quartz_context (path, &stroke);
+    rv = _cairo_quartz_cairo_path_to_quartz_context (path, &stroke);
+    if (rv)
+	goto BAIL;
 
     if (action == DO_SOLID || action == DO_PATTERN) {
 	CGContextStrokePath (surface->cgContext);
@@ -1304,6 +1309,7 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
 	rv = CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
+  BAIL:
     _cairo_quartz_teardown_source (surface, source);
 
     CGContextRestoreGState (surface->cgContext);
@@ -1507,6 +1513,7 @@ _cairo_quartz_surface_intersect_clip_path (void *abstract_surface,
 {
     cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
     quartz_stroke_t stroke;
+    cairo_status_t status;
 
     ND((stderr, "%p _cairo_quartz_surface_intersect_clip_path path: %p\n", surface, path));
 
@@ -1524,7 +1531,10 @@ _cairo_quartz_surface_intersect_clip_path (void *abstract_surface,
 	CGContextBeginPath (surface->cgContext);
 	stroke.cgContext = surface->cgContext;
 	stroke.ctm_inverse = NULL;
-	_cairo_quartz_cairo_path_to_quartz_context (path, &stroke);
+	status = _cairo_quartz_cairo_path_to_quartz_context (path, &stroke);
+	if (status)
+	    return status;
+
 	if (fill_rule == CAIRO_FILL_RULE_WINDING)
 	    CGContextClip (surface->cgContext);
 	else
commit 7072959e3da0e8814cfd5193f8915aeb1341cc37
Author: Brian Ewins <Brian.Ewins at gmail.com>
Date:   Sat Oct 20 11:46:54 2007 +0100

    Fix to support new similar tests.
    
    The patch to repeat tests for similar surfaces changed the
    format of the test log files, which were parsed to produce
    index.html. This fixes the parser to understand those changes.

diff --git a/test/make-html.pl b/test/make-html.pl
index 7ded7d2..9720c06 100755
--- a/test/make-html.pl
+++ b/test/make-html.pl
@@ -57,16 +57,17 @@ foreach (<@files>) {
   my $fn = $_;
   (open LOG, $fn) || next;
   while (<LOG>) {
-    next unless /^TEST: (.*) TARGET: (.*) FORMAT: (.*) OFFSET: (.*) RESULT: ([A-Z]*).*$/;
+    next unless /^TEST: (.*) TARGET: (.*) FORMAT: (.*) OFFSET: (.*) SIMILAR: (.*) RESULT: ([A-Z]*).*$/;
     $testname = $1 if !defined($testname);
     $tests->{$1} = {} unless $tests->{$1};
     $tests->{$1}->{$2} = {} unless $tests->{$1}->{$2};
     $tests->{$1}->{$2}->{$3} = {} unless $tests->{$1}->{$2}->{$3};
-    $tests->{$1}->{$2}->{$3}->{$4} = $5;
+    $tests->{$1}->{$2}->{$3}->{$4} = {} unless $tests->{$1}->{$2}->{$3}->{$4};
+    $tests->{$1}->{$2}->{$3}->{$4}->{$5} = $6;
 
     $teststats->{$2} = {"PASS" => 0, "FAIL" => 0, "XFAIL" => 0, "UNTESTED" => 0, "CRASHED" =>0}
       unless $teststats->{$2};
-    ($teststats->{$2}->{$5})++;
+    ($teststats->{$2}->{$6})++;
   }
   close LOG;
 
@@ -81,6 +82,7 @@ foreach (<@files>) {
 my $targeth = {};
 my $formath = {};
 my $offseth = {};
+my $similarh = {};
 
 foreach my $testname (sort(keys %$tests)) {
   my $v0 = $tests->{$testname};
@@ -93,7 +95,12 @@ foreach my $testname (sort(keys %$tests)) {
 
       $formath->{$formatname} = 1;
       foreach my $offsetval (sort(keys %$v2)) {
+        my $v3 = $v2->{$offsetval};
+
         $offseth->{$offsetval} = 1;
+        foreach my $similarval (sort(keys %$v3)) {
+          $similarh->{$similarval} = 1;
+        }
       }
     }
   }
@@ -102,6 +109,7 @@ foreach my $testname (sort(keys %$tests)) {
 my @targets = sort(keys %$targeth);
 my @formats = sort(keys %$formath);
 my @offsets = sort(keys %$offseth);
+my @similars = sort(keys %$similarh);
 
 sub printl {
   print @_, "\n";
@@ -181,20 +189,24 @@ sub testref {
 }
 
 sub testfiles {
-  my ($test, $target, $format, $offset, $rest) = @_;
+  my ($test, $target, $format, $offset, $similar, $rest) = @_;
   my $fmtstr = "";
   my $offstr = "";
+  my $simstr = "";
   if ($format eq "rgb24") {
     $fmtstr = "-rgb24";
   } elsif ($format eq "argb32") {
     $fmtstr = "-argb32";
   }
+  if ($similar ne "0") {
+    $simstr = "-similar";
+  }
   if ($offset ne "0") {
     $offstr = "-" . $offset;
   }
 
-  return ("out" => "$test-$target$fmtstr$offstr-out.png",
-	  "diff" => "$test-$target$fmtstr$offstr-diff.png");
+  return ("out" => "$test-$target$fmtstr$simstr$offstr-out.png",
+	  "diff" => "$test-$target$fmtstr$simstr$offstr-diff.png");
 }
 
 sub img_for {
@@ -216,72 +228,74 @@ sub img_for {
 
 foreach my $test (sort(keys %$tests)) {
   foreach my $offset (@offsets) {
-    foreach my $format (@formats) {
-      my $testline = "";
-
-      foreach my $target (@targets) {
-        my $tgtdata = $tests->{$test}->{$target};
-        if ($tgtdata) {
-          my $testres = $tgtdata->{$format}->{$offset};
-          if ($testres) {
-            my %testfiles = testfiles($test, $target, $format, $offset);
-            $testline .= "<td class=\"$testres\">";
-            $teststats{$target}{$testres}++;
-            if ($testres eq "PASS") {
-              if ($config_show_all) {
-		$testline .= img_for($testfiles{'out'},1);
-              }
-            } elsif ($testres eq "FAIL") {
-              if ($config_show_fail || $config_show_all) {
-		$testline .= img_for($testfiles{'out'},1);
-                $testline .= " ";
-		$testline .= img_for($testfiles{'diff'},1);
-              }
-            } elsif ($testres eq "CRASHED") {
-	       $testline .= "!!!CRASHED!!!";
-            } elsif ($testres eq "XFAIL") {
-              #nothing
-              if ($config_show_all) {
-		$testline .= img_for($testfiles{'out'},1);
-                #$testline .= "<hr size=\"1\">";
-                $testline .= " ";
-		$testline .= img_for($testfiles{'diff'},1);
-              }
-            } elsif ($testres eq "UNTESTED") {
-              #nothing
+    foreach my $similar (@similars) {
+      foreach my $format (@formats) {
+        my $testline = "";
+
+        foreach my $target (@targets) {
+          my $tgtdata = $tests->{$test}->{$target};
+          if ($tgtdata) {
+            my $testres = $tgtdata->{$format}->{$offset}->{$similar};
+            if ($testres) {
+              my %testfiles = testfiles($test, $target, $format,
+                                         $offset, $similar);
+              $testline .= "<td class=\"$testres\">";
+              $teststats{$target}{$testres}++;
+              if ($testres eq "PASS") {
+                if ($config_show_all) {
+		  $testline .= img_for($testfiles{'out'},1);
+                }
+              } elsif ($testres eq "FAIL") {
+                if ($config_show_fail || $config_show_all) {
+		  $testline .= img_for($testfiles{'out'},1);
+                  $testline .= " ";
+		  $testline .= img_for($testfiles{'diff'},1);
+                }
+              } elsif ($testres eq "CRASHED") {
+	         $testline .= "!!!CRASHED!!!";
+              } elsif ($testres eq "XFAIL") {
+                #nothing
+                if ($config_show_all) {
+		  $testline .= img_for($testfiles{'out'},1);
+                  #$testline .= "<hr size=\"1\">";
+                  $testline .= " ";
+		  $testline .= img_for($testfiles{'diff'},1);
+                }
+              } elsif ($testres eq "UNTESTED") {
+                #nothing
+              } else {
+	        $testline .= "UNSUPPORTED STATUS (update make-html.pl)";
+	      }
+
+              $testline .= "</td>";
             } else {
-	      $testline .= "UNSUPPORTED STATUS (update make-html.pl)";
-	    }
-
-            $testline .= "</td>";
+              $testline .= '<td></td>';
+            }
           } else {
             $testline .= '<td></td>';
           }
+        }
+        my $testref = testref($test, $format);
+        print '<tr><td>';
+
+        if ($config_show_inline) {
+	  print "$test ($format/$offset) ";
+	  print "(<a href=\"" . string_to_data("text/plain",$logs->{$test}) . "\">log</a>)";
         } else {
-          $testline .= '<td></td>';
+	  print "<a href=\"$testref\">", $test, ' (', $format, '/', $offset, ($similar ? ' similar' : ''), ')</a> ';
+	  print "(<a href=\"$test.log\">log</a>)";
         }
-      }
 
-      my $testref = testref($test, $format);
-      print '<tr><td>';
+        print '</td>';
 
-      if ($config_show_inline) {
-	print "$test ($format/$offset) ";
-	print "(<a href=\"" . string_to_data("text/plain",$logs->{$test}) . "\">log</a>)";
-      } else {
-	print "<a href=\"$testref\">", $test, ' (', $format, '/', $offset, ')</a> ';
-	print "(<a href=\"$test.log\">log</a>)";
-      }
+        if ($config_show_ref) {
+	  print "<td>" . img_for($testref,1) . "</td>";
+        }
 
-      print '</td>';
+        print $testline;
 
-      if ($config_show_ref) {
-	print "<td>" . img_for($testref,1) . "</td>";
+        print "</tr>\n";
       }
-
-      print $testline;
-
-      print "</tr>\n";
     }
   }
 }


More information about the cairo-commit mailing list