[cairo-commit] src/cairo-image-surface.c src/cairoint.h src/cairo-scaled-font.c

Behdad Esfahbod behdad at kemper.freedesktop.org
Mon Jan 14 13:14:24 PST 2008


 src/cairo-image-surface.c |   18 +++++++++++++++
 src/cairo-scaled-font.c   |   54 +++++++++++++++++++++++++---------------------
 src/cairoint.h            |    3 ++
 3 files changed, 51 insertions(+), 24 deletions(-)

New commits:
commit 22d7f311f7733a57ece5d91708b2b5da9b71de86
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Jan 14 16:14:02 2008 -0500

    [scaled-font] Upgrade glyph mask as needed in case of mixed-format glyphs
    
    In ecb895803b9d2a3fd142f4a2c694ca08c5581f0e Carl made fallback show_glyphs
    always use a A8 mask in case of mixed-format glyphs.  That's suboptimal if
    there are ARGB32 glyphs.  Using masks smartly we can implement the desired
    behavior.  Done now.

diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index e3de7a4..cf19a8f 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -724,6 +724,24 @@ _cairo_content_from_format (cairo_format_t format)
     return CAIRO_CONTENT_COLOR_ALPHA;
 }
 
+cairo_private cairo_format_t
+_cairo_format_width (cairo_format_t format)
+{
+    switch (format) {
+    case CAIRO_FORMAT_ARGB32:
+	return 32;
+    case CAIRO_FORMAT_RGB24:
+	return 24;
+    case CAIRO_FORMAT_A8:
+	return 8;
+    case CAIRO_FORMAT_A1:
+	return 1;
+    default:
+	ASSERT_NOT_REACHED;
+	return 0;
+    }
+}
+
 static cairo_surface_t *
 _cairo_image_surface_create_similar (void	       *abstract_src,
 				     cairo_content_t	content,
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 03d8138..f8b124b 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -1173,8 +1173,9 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t    *scaled_font,
 {
     cairo_status_t status;
     cairo_surface_t *mask = NULL;
-    cairo_format_t mask_format;
+    cairo_format_t mask_format = CAIRO_FORMAT_A1; /* shut gcc up */
     cairo_surface_pattern_t mask_pattern;
+    cairo_solid_pattern_t white_pattern;
     int i;
 
     /* These operators aren't interpreted the same way by the backends;
@@ -1204,6 +1205,8 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t    *scaled_font,
 
     status = CAIRO_STATUS_SUCCESS;
 
+    _cairo_pattern_init_solid (&white_pattern, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR);
+
     _cairo_cache_freeze (scaled_font->glyphs);
 
     for (i = 0; i < num_glyphs; i++) {
@@ -1232,31 +1235,29 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t    *scaled_font,
 		status = mask->status;
 		goto CLEANUP_MASK;
 	    }
-
-	    status = _cairo_surface_fill_rectangle (mask,
-						    CAIRO_OPERATOR_CLEAR,
-						    CAIRO_COLOR_TRANSPARENT,
-						    0, 0,
-						    width, height);
-	    if (status)
-		goto CLEANUP_MASK;
-	    if (mask_format == CAIRO_FORMAT_ARGB32)
-		pixman_image_set_component_alpha (((cairo_image_surface_t*) mask)->
-						  pixman_image, TRUE);
 	}
 
-	/* If we have glyphs of different formats, then the only thing
-	 * we can easily do is to migrate to an A8 mask. This is
-	 * sub-optimal if there are any component-alpha ARGB32 glyphs,
-	 * but pixman doesn't actually give us anyoperators that will
-	 * correctly ADD to a component-alpha mask. So here we are. */
+	/* If we have glyphs of different formats, we "upgrade" the mask
+	 * to the wider of the formats. */
 	if (glyph_surface->format != mask_format &&
-	    mask_format != CAIRO_FORMAT_A8)
+	    _cairo_format_width (mask_format) < _cairo_format_width (glyph_surface->format) )
 	{
 	    cairo_surface_t *new_mask;
 	    cairo_surface_pattern_t mask_pattern;
 
-	    mask_format = CAIRO_FORMAT_A8;
+	    switch (glyph_surface->format) {
+	    case CAIRO_FORMAT_ARGB32:
+	    case CAIRO_FORMAT_A8:
+	    case CAIRO_FORMAT_A1:
+		mask_format = glyph_surface->format;
+		break;
+	    case CAIRO_FORMAT_RGB24:
+	    default:
+		ASSERT_NOT_REACHED;
+		mask_format = CAIRO_FORMAT_ARGB32;
+		break;
+	    }
+
 	    new_mask = cairo_image_surface_create (mask_format,
 						   width, height);
 	    if (new_mask->status) {
@@ -1267,9 +1268,9 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t    *scaled_font,
 
 	    _cairo_pattern_init_for_surface (&mask_pattern, mask);
 
-	    status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
+	    status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
+					       &white_pattern.base,
 					       &mask_pattern.base,
-					       NULL,
 					       new_mask,
 					       0, 0,
 					       0, 0,
@@ -1295,21 +1296,24 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t    *scaled_font,
 	_cairo_pattern_init_for_surface (&glyph_pattern, &glyph_surface->base);
 
 	status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
+					   &white_pattern.base,
 					   &glyph_pattern.base,
-					   NULL,
 					   mask,
 					   0, 0,
 					   0, 0,
-					   x - dest_x,
-					   y - dest_y,
+					   x - dest_x, y - dest_y,
 					   glyph_surface->width,
 					   glyph_surface->height);
 
 	_cairo_pattern_fini (&glyph_pattern.base);
+
 	if (status)
 	    goto CLEANUP_MASK;
     }
 
+    if (mask_format == CAIRO_FORMAT_ARGB32)
+	pixman_image_set_component_alpha (((cairo_image_surface_t*) mask)->
+					  pixman_image, TRUE);
     _cairo_pattern_init_for_surface (&mask_pattern, mask);
 
     status = _cairo_surface_composite (op, pattern, &mask_pattern.base,
@@ -1324,6 +1328,8 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t    *scaled_font,
 CLEANUP_MASK:
     _cairo_cache_thaw (scaled_font->glyphs);
 
+    _cairo_pattern_fini (&white_pattern.base);
+
     if (mask != NULL)
 	cairo_surface_destroy (mask);
     return _cairo_scaled_font_set_error (scaled_font, status);
diff --git a/src/cairoint.h b/src/cairoint.h
index efdf0f7..c284779 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1796,6 +1796,9 @@ _cairo_surface_has_device_transform (cairo_surface_t *surface);
 				       == 0))
 
 cairo_private cairo_format_t
+_cairo_format_width (cairo_format_t format);
+
+cairo_private cairo_format_t
 _cairo_format_from_content (cairo_content_t content);
 
 cairo_private cairo_content_t


More information about the cairo-commit mailing list