[cairo-commit] 8 commits - src/cairo-fixed-private.h src/cairo-paginated-surface.c src/cairo-quartz-surface.c src/cairo-win32-font.c src/cairo-win32-printing-surface.c

Vladimir Vukicevic vladimir at kemper.freedesktop.org
Fri Nov 9 12:51:22 PST 2007


 src/cairo-fixed-private.h          |   22 ++++++++++-
 src/cairo-paginated-surface.c      |    4 +-
 src/cairo-quartz-surface.c         |   69 +++++++++++++++++++++++++++++++++++--
 src/cairo-win32-font.c             |   54 ++++++++++++++++++----------
 src/cairo-win32-printing-surface.c |   11 +++++
 5 files changed, 134 insertions(+), 26 deletions(-)

New commits:
commit 28412f780ebf52914aa374bb2bdd3d539bd29241
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date:   Tue Nov 6 16:11:06 2007 -0800

    [win32-printing] bail out early if we don't have anything to do in paint_surf

diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index 58dc74f..57f1ab0 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -522,6 +522,11 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t   *surf
 	goto FINISH2;
     }
 
+    if (image->width == 0 || image->height == 0) {
+	status = CAIRO_STATUS_SUCCESS;
+	goto FINISH2;
+    }
+
     if (image->format != CAIRO_FORMAT_RGB24) {
 	opaque_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
 						     image->width,
commit d72bb8c12efcffe7c576afe63212b2fe47e8154c
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date:   Tue Nov 6 16:08:59 2007 -0800

    [win32] Fix FIXED_to_fixed when cairo's fixed format isn't 16.16

diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c
index 7d4a10c..992f675 100644
--- a/src/cairo-win32-font.c
+++ b/src/cairo-win32-font.c
@@ -1335,13 +1335,11 @@ _cairo_win32_transform_FIXED_to_fixed (cairo_matrix_t *matrix,
                                        FIXED Fx, FIXED Fy,
                                        cairo_fixed_t *fx, cairo_fixed_t *fy)
 {
-    double x, y;
-
-    x = _cairo_fixed_to_double (*((cairo_fixed_t *)&Fx));
-    y = _cairo_fixed_to_double (*((cairo_fixed_t *)&Fy));
+    double x = Fx.value + Fx.fract / 65536.0;
+    double y = Fy.value + Fy.fract / 65536.0;
     cairo_matrix_transform_point (matrix, &x, &y);
-    *fx =  _cairo_fixed_from_double (x);
-    *fy =  _cairo_fixed_from_double (y);
+    *fx = _cairo_fixed_from_double (x);
+    *fy = _cairo_fixed_from_double (y);
 }
 
 static cairo_status_t
commit 0901b83ca56e197d5c96d71ab8cfe53f21b4c8bb
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date:   Tue Nov 6 15:49:57 2007 -0800

    [win32] Don't use GetGlyphOutline on non-TrueType fonts
    
    win32-glyph-metrics.patch: GetGlyphOutline only works on Truetype fonts,
    so for non-Truetype fonts, assume no left or right bearing and use the
    font ascent and descent for the glyph extents.

diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c
index dbabbef..7d4a10c 100644
--- a/src/cairo-win32-font.c
+++ b/src/cairo-win32-font.c
@@ -99,6 +99,7 @@ typedef struct {
     HFONT scaled_hfont;
     HFONT unscaled_hfont;
 
+    cairo_bool_t is_truetype;
     cairo_bool_t glyph_indexing;
 
     cairo_bool_t delete_scaled_hfont;
@@ -741,11 +742,11 @@ _cairo_win32_scaled_font_set_metrics (cairo_win32_scaled_font_t *scaled_font)
 
     }
 
-    if ((metrics.tmPitchAndFamily & TMPF_TRUETYPE) ||
-        (GetFontData (hdc, OPENTYPE_CFF_TAG, 0, NULL, 0) != GDI_ERROR))
-        scaled_font->glyph_indexing = TRUE;
-    else
-        scaled_font->glyph_indexing = FALSE;
+    scaled_font->is_truetype = (metrics.tmPitchAndFamily & TMPF_TRUETYPE) != 0;
+    scaled_font->glyph_indexing = scaled_font->is_truetype ||
+	(GetFontData (hdc, OPENTYPE_CFF_TAG, 0, NULL, 0) != GDI_ERROR);
+    // XXX in what situations does this OPENTYPE_CFF thing not have the
+    // TMPF_TRUETYPE flag? GetFontData says it only works on Truetype fonts...
 
     _cairo_scaled_font_set_metrics (&scaled_font->base, &extents);
 
@@ -761,18 +762,35 @@ _cairo_win32_scaled_font_init_glyph_metrics (cairo_win32_scaled_font_t *scaled_f
     cairo_status_t status;
     cairo_text_extents_t extents;
     HDC hdc;
-    UINT glyph_index_option;
 
     hdc = _get_global_font_dc ();
     if (!hdc)
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-    if (scaled_font->glyph_indexing)
-        glyph_index_option = GGO_GLYPH_INDEX;
-    else
-        glyph_index_option = 0;
+    if (!scaled_font->is_truetype) {
+	/* GetGlyphOutline will not work. Assume that the glyph does not extend outside the font box. */
+	cairo_font_extents_t font_extents;
+	INT width = 0;
+	UINT charIndex = _cairo_scaled_glyph_index (scaled_glyph);
+
+	cairo_scaled_font_extents (&scaled_font->base, &font_extents);
+
+	status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
+	if (!status) {
+	    if (!GetCharWidth32(hdc, charIndex, charIndex, &width)) {
+		status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_init_glyph_metrics:GetCharWidth32");
+		width = 0;
+	    }
+	}
+	cairo_win32_scaled_font_done_font (&scaled_font->base);
 
-    if (scaled_font->preserve_axes && scaled_font->base.options.hint_style != CAIRO_HINT_METRICS_OFF) {
+	extents.x_bearing = 0;
+	extents.y_bearing = -font_extents.ascent / scaled_font->y_scale;
+	extents.width = width / scaled_font->x_scale;
+	extents.height = (font_extents.ascent + font_extents.descent) / scaled_font->y_scale;
+	extents.x_advance = extents.width;
+	extents.y_advance = 0;
+    } else if (scaled_font->preserve_axes && scaled_font->base.options.hint_style != CAIRO_HINT_METRICS_OFF) {
 	/* If we aren't rotating / skewing the axes, then we get the metrics
 	 * from the GDI in device space and convert to font space.
 	 */
@@ -780,7 +798,7 @@ _cairo_win32_scaled_font_init_glyph_metrics (cairo_win32_scaled_font_t *scaled_f
 	if (status)
 	    return status;
 	if (GetGlyphOutlineW (hdc, _cairo_scaled_glyph_index (scaled_glyph),
-			      GGO_METRICS | glyph_index_option,
+			      GGO_METRICS | GGO_GLYPH_INDEX,
 			      &metrics, 0, NULL, &matrix) == GDI_ERROR) {
 	  status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_init_glyph_metrics:GetGlyphOutlineW");
 	  memset (&metrics, 0, sizeof (GLYPHMETRICS));
@@ -819,7 +837,7 @@ _cairo_win32_scaled_font_init_glyph_metrics (cairo_win32_scaled_font_t *scaled_f
 	 */
 	status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc);
 	if (GetGlyphOutlineW (hdc, _cairo_scaled_glyph_index (scaled_glyph),
-			      GGO_METRICS | glyph_index_option,
+	                      GGO_METRICS | GGO_GLYPH_INDEX,
 			      &metrics, 0, NULL, &matrix) == GDI_ERROR) {
 	  status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_init_glyph_metrics:GetGlyphOutlineW");
 	  memset (&metrics, 0, sizeof (GLYPHMETRICS));
commit f11f7524b62df29aa377382f5ceeda8c3beb2d54
Author: Vladimir Vukicevic <vladimir at h-232.office.mozilla.org>
Date:   Tue Nov 6 15:40:30 2007 -0800

    [quartz] work around Quartz bugs with images bigger than a certain size
    
    Quartz has a bug with images greater than (signed) 16 bits in height; avoid
    creating or working with those.  Also fixes some memory leaks.
    
    Patch from John Daggett.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 5fa4cc2..508b8a3 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -47,6 +47,7 @@
 #endif
 
 #include <Carbon/Carbon.h>
+#include <limits.h>
 
 #undef QUARTZ_DEBUG
 
@@ -107,6 +108,26 @@ extern void CGContextClipToMask (CGContextRef, CGRect, CGImageRef) __attribute__
 static void quartz_surface_to_png (cairo_quartz_surface_t *nq, char *dest);
 static void quartz_image_to_png (CGImageRef, char *dest);
 
+/* CoreGraphics limitation with flipped CTM surfaces: height must be less than signed 16-bit max */
+
+#define CG_MAX_HEIGHT   SHRT_MAX
+#define CG_MAX_WIDTH    USHRT_MAX
+
+/* is the desired size of the surface within bounds? */
+static cairo_bool_t verify_surface_size(int width, int height)
+{
+    /* hmmm, allow width, height == 0 ? */
+    if (width < 0 || height < 0) {
+	return FALSE;
+    }
+
+    if (width > CG_MAX_WIDTH || height > CG_MAX_HEIGHT) {
+	return FALSE;
+    }
+
+    return TRUE;
+}
+
 /*
  * Cairo path -> Quartz path conversion helpers
  */
@@ -466,6 +487,14 @@ _cairo_quartz_surface_to_quartz (cairo_surface_t *target,
         if (status)
 	    return status;
 
+ 	if (new_surf &&
+	    cairo_surface_get_type (new_surf) != CAIRO_SURFACE_TYPE_QUARTZ)
+	{
+	    ND((stderr, "got a non-quartz surface, format=%d width=%u height=%u type=%d\n", cairo_surface_get_type (pat_surf), rect.width, rect.height, cairo_surface_get_type (new_surf)));
+	    cairo_surface_destroy (new_surf);
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+	}
+
 	*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;
@@ -979,6 +1008,7 @@ _cairo_quartz_surface_release_dest_image (void *abstract_surface,
 
     if (!CGBitmapContextGetData (surface->cgContext)) {
 	CGDataProviderRef dataProvider;
+	CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
 	CGImageRef img;
 
 	dataProvider = CGDataProviderCreateWithData (NULL, imageData,
@@ -988,12 +1018,13 @@ _cairo_quartz_surface_release_dest_image (void *abstract_surface,
 	img = CGImageCreate (surface->extents.width, surface->extents.height,
 			     8, 32,
 			     surface->extents.width * 4,
-			     CGColorSpaceCreateDeviceRGB(),
+			     rgb,
 			     kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
 			     dataProvider,
 			     NULL,
 			     false,
 			     kCGRenderingIntentDefault);
+	CGColorSpaceRelease (rgb);
 
 	CGContextSetCompositeOperation (surface->cgContext, kPrivateCGCompositeCopy);
 
@@ -1028,6 +1059,12 @@ _cairo_quartz_surface_create_similar (void *abstract_surface,
 	format = CAIRO_FORMAT_A8;
     else
 	return NULL;
+	
+    // verify width and height of surface
+    if (!verify_surface_size(width, height)) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return NULL;
+    }
 
     return cairo_quartz_surface_create (format, width, height);
 }
@@ -1043,6 +1080,13 @@ _cairo_quartz_surface_clone_similar (void *abstract_surface,
 {
     cairo_quartz_surface_t *new_surface = NULL;
     cairo_format_t new_format;
+    
+    *clone_out = NULL;
+
+    // verify width and height of surface
+    if (!verify_surface_size(width, height)) {
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
 
     CGImageRef quartz_image = NULL;
 
@@ -1107,8 +1151,10 @@ _cairo_quartz_surface_clone_similar (void *abstract_surface,
 	cairo_quartz_surface_create (new_format,
 				     CGImageGetWidth (quartz_image),
 				     CGImageGetHeight (quartz_image));
-    if (!new_surface || new_surface->base.status)
+    if (!new_surface || new_surface->base.status) {
+	CGImageRelease (quartz_image);
 	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
 
     CGContextSetCompositeOperation (new_surface->cgContext,
 				    kPrivateCGCompositeCopy);
@@ -1679,6 +1725,9 @@ static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
 #endif /* CAIRO_HAS_ATSUI_FONT */
 
     NULL, /* snapshot */
+    NULL, /* is_similar */
+    NULL, /* reset */
+    NULL  /* fill_stroke */
 };
 
 static cairo_quartz_surface_t *
@@ -1796,6 +1845,12 @@ cairo_quartz_surface_create (cairo_format_t format,
     int stride;
     int bitsPerComponent;
 
+    // verify width and height of surface
+    if (!verify_surface_size(width, height)) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
+
     if (format == CAIRO_FORMAT_ARGB32) {
 	cgColorspace = CGColorSpaceCreateDeviceRGB();
 	stride = width * 4;
@@ -1844,6 +1899,7 @@ cairo_quartz_surface_create (cairo_format_t format,
 
     if (!cgc) {
 	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	free (imageData);
 	return (cairo_surface_t*) &_cairo_surface_nil;
     }
 
@@ -1855,6 +1911,7 @@ cairo_quartz_surface_create (cairo_format_t format,
 						   width, height);
     if (!surf) {
 	CGContextRelease (cgc);
+	free (imageData);
 	// create_internal will have set an error
 	return (cairo_surface_t*) &_cairo_surface_nil;
     }
commit 95ede9ea59eb1e2d7fe10fbc698f3f9fff192e79
Author: Vladimir Vukicevic <vladimir at h-232.office.mozilla.org>
Date:   Tue Nov 6 15:06:06 2007 -0800

    Use correct surface resolution when creating paginated fallback image
    
    If a surface resolution is set via _cairo_surface_set_resolution, it
    needs to be used when the fallback image is created.  The user sets
    the fallback resolution on the paginated surface, so we need
    to divide that by the resolution of the actual (target) surface, not
    the paginated surface.

diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index e25204e..d3c6a45 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -241,8 +241,8 @@ static cairo_int_status_t
 _paint_fallback_image (cairo_paginated_surface_t *surface,
 		       cairo_box_int_t           *box)
 {
-    double x_scale = surface->base.x_fallback_resolution / surface->base.x_resolution;
-    double y_scale = surface->base.y_fallback_resolution / surface->base.y_resolution;
+    double x_scale = surface->base.x_fallback_resolution / surface->target->x_resolution;
+    double y_scale = surface->base.y_fallback_resolution / surface->target->y_resolution;
     cairo_matrix_t matrix;
     int x, y, width, height;
     cairo_status_t status;
commit 9b8d9f2859ce66b742c887eb673407a84095f488
Author: Vladimir Vukicevic <vladimir at h-232.office.mozilla.org>
Date:   Tue Nov 6 14:54:59 2007 -0800

    [win32] Skip doing some work if we can't call StretchDIBits

diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index 2dee9eb..58dc74f 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -494,6 +494,12 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t   *surf
     RECT clip;
     const cairo_color_t *background_color;
 
+    /* If we can't use StretchDIBits with this surface, we can't do anything
+     * here.
+     */
+    if (!(surface->flags & CAIRO_WIN32_SURFACE_CAN_STRETCHDIB))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
     if (surface->content == CAIRO_CONTENT_COLOR_ALPHA)
 	background_color = CAIRO_COLOR_WHITE;
     else
commit fa7e36669ae24fdbb5bd89a9fc1b6906408a5823
Author: Vladimir Vukicevic <vladimir at h-232.office.mozilla.org>
Date:   Tue Nov 6 14:53:09 2007 -0800

    [quartz] Fix for 10.5 SDK; the FloatToFixed macro started doing strange things

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 77911de..5fa4cc2 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -38,6 +38,14 @@
 
 #include "cairo-quartz-private.h"
 
+/* The 10.5 SDK includes a funky new definition of FloatToFixed which
+ * causes all sorts of breakage; so reset to old-style definition
+ */
+#ifdef FloatToFixed
+#undef FloatToFixed
+#define FloatToFixed(a)     ((Fixed)((float)(a) * fixed1))
+#endif
+
 #include <Carbon/Carbon.h>
 
 #undef QUARTZ_DEBUG
commit 236c52b095661be395021d511d2dca0b532f83e9
Author: Vladimir Vukicevic <vladimir at h-232.office.mozilla.org>
Date:   Tue Nov 6 14:52:24 2007 -0800

    Handle overflow/underflow gracefully when converting to 16.16 fixed

diff --git a/src/cairo-fixed-private.h b/src/cairo-fixed-private.h
index 35b3748..cb42ac1 100644
--- a/src/cairo-fixed-private.h
+++ b/src/cairo-fixed-private.h
@@ -51,7 +51,7 @@ typedef cairo_int128_t	cairo_fixed_96_32_t;
 
 /* Eventually, we should allow changing this, but I think
  * there are some assumptions in the tesselator about the
- * size of a fixed type.
+ * size of a fixed type.  For now, it must be 32.
  */
 #define CAIRO_FIXED_BITS	32
 
@@ -206,10 +206,26 @@ _cairo_fixed_integer_ceil (cairo_fixed_t f)
 static inline cairo_fixed_16_16_t
 _cairo_fixed_to_16_16 (cairo_fixed_t f)
 {
-#if CAIRO_FIXED_FRAC_BITS > 16
+#if (CAIRO_FIXED_FRAC_BITS == 16) && (CAIRO_FIXED_BITS == 32)
+    return f;
+#elif CAIRO_FIXED_FRAC_BITS > 16
+    /* We're just dropping the low bits, so we won't ever got over/underflow here */
     return f >> (CAIRO_FIXED_FRAC_BITS - 16);
 #else
-    return f << (16 - CAIRO_FIXED_FRAC_BITS);
+    cairo_fixed_16_16_t x;
+
+    /* Handle overflow/underflow by claping to the lowest/highest
+     * value representable as 16.16
+     */
+    if ((f >> CAIRO_FIXED_FRAC_BITS) < INT16_MIN) {
+	x = INT32_MIN;
+    } else if ((f >> CAIRO_FIXED_FRAC_BITS) > INT16_MAX) {
+	x = INT32_MAX;
+    } else {
+	x = f << (16 - CAIRO_FIXED_FRAC_BITS);
+    }
+
+    return x;
 #endif
 }
 


More information about the cairo-commit mailing list