[cairo-commit] 4 commits - ROADMAP src/cairo-image-surface.c src/cairoint.h src/cairo-pdf-surface.c src/cairo-ps-surface.c src/cairo-scaled-font.c src/cairo-svg-surface.c test/bitmap-font.c test/bitmap-font-ref.png test/bitmap-font-rgb24-ref.png

Carl Worth cworth at kemper.freedesktop.org
Thu Aug 17 17:51:28 PDT 2006


 ROADMAP                        |    4 -
 src/cairo-image-surface.c      |   26 +++++++++++
 src/cairo-pdf-surface.c        |    9 +++
 src/cairo-ps-surface.c         |    9 +++
 src/cairo-scaled-font.c        |   96 ++++++++++++++++++++++++++++++++++++++++-
 src/cairo-svg-surface.c        |   10 +++-
 src/cairoint.h                 |    4 +
 test/bitmap-font-ref.png       |binary
 test/bitmap-font-rgb24-ref.png |binary
 test/bitmap-font.c             |   20 +++++++-
 10 files changed, 169 insertions(+), 9 deletions(-)

New commits:
diff-tree 9878a033531e6b96b5f27e69e10e90dee7440cd9 (from e4e5002c48ec9cea37b4347689f193b54439383e)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Aug 17 17:48:40 2006 -0700

    Add (primitive) bitmap glyph tracing to fix bug #7889

diff --git a/ROADMAP b/ROADMAP
index 2d38d38..1c8b1c5 100644
--- a/ROADMAP
+++ b/ROADMAP
@@ -33,8 +33,8 @@ cairo-1.2.4 (August 21, 2006): Fix build
  - xlib detection requires libXt
  - 7744: Compile troubles on AIX
  - SVG backend requires PNG
- - 7888: assertion failure with rotated bitmap glyphs
- - 7889: cairo_text_path assertion failure on bitmap fonts
+✓- 7888: assertion failure with rotated bitmap glyphs
+✓- 7889: cairo_text_path assertion failure on bitmap fonts
  - Type1 on Windows (Adrian has a patch)
 ✓- source-clip-scale
  - PS/PDF Type1/Type3 problem with rotated font_matrices
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index e96d844..9a13fb7 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -1052,6 +1052,74 @@ _scaled_glyph_path_close_path (void *abs
     return _cairo_path_fixed_close_path (closure->path);
 }
 
+
+/**
+ * _trace_mask_to_path:
+ * @bitmap: An alpha mask (either CAIRO_FORMAT_A1 or _A8)
+ * @path: An initialized path to hold the result
+ *
+ * Given a mask surface, (an alpha image), fill out the provided path
+ * so that when filled it would result in something that approximates
+ * the mask.
+ *
+ * Note: The current tracing code here is extremely primitive. It
+ * operates only on an A1 surface, (converting an A8 surface to A1 if
+ * necessary), and performs the tracing by drawing a little square
+ * around each pixel that is on in the mask. We do not pretend that
+ * this is a high-quality result. But we are leaving it up to somone
+ * who cares enough about getting a better result to implement
+ * something more sophisticated.
+ **/
+static cairo_status_t
+_trace_mask_to_path (cairo_image_surface_t *mask,
+		     cairo_path_fixed_t *path)
+{
+    cairo_image_surface_t *a1_mask;
+    unsigned char *row, *byte_ptr, byte;
+    int rows, cols, bytes_per_row;
+    int x, y, bit;
+    double xoff, yoff;
+
+    if (mask->format == CAIRO_FORMAT_A1)
+	a1_mask = mask;
+    else
+	a1_mask = _cairo_image_surface_clone (mask, CAIRO_FORMAT_A1);
+
+    if (cairo_surface_status (&a1_mask->base))
+	return cairo_surface_status (&a1_mask->base);
+
+    cairo_surface_get_device_offset (&mask->base, &xoff, &yoff);
+
+    bytes_per_row = (a1_mask->width + 7) / 8;
+    for (y = 0, row = a1_mask->data, rows = a1_mask->height; rows; row += a1_mask->stride, rows--, y++) {
+	for (x = 0, byte_ptr = row, cols = (a1_mask->width + 7) / 8; cols; byte_ptr++, cols--) {
+	    byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte_ptr);
+	    for (bit = 7; bit >= 0 && x < a1_mask->width; bit--, x++) {
+		if (byte & (1 << bit)) {
+		    _cairo_path_fixed_move_to (path,
+					       _cairo_fixed_from_int (x + xoff),
+					       _cairo_fixed_from_int (y + yoff));
+		    _cairo_path_fixed_rel_line_to (path,
+						   _cairo_fixed_from_int (1),
+						   _cairo_fixed_from_int (0));
+		    _cairo_path_fixed_rel_line_to (path,
+						   _cairo_fixed_from_int (0),
+						   _cairo_fixed_from_int (1));
+		    _cairo_path_fixed_rel_line_to (path,
+						   _cairo_fixed_from_int (-1),
+						   _cairo_fixed_from_int (0));
+		    _cairo_path_fixed_close_path (path);
+		}
+	    }
+	}
+    }
+
+    if (a1_mask != mask)
+	cairo_surface_destroy (&a1_mask->base);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
 cairo_status_t
 _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
 			       const cairo_glyph_t *glyphs,
@@ -1061,6 +1129,7 @@ _cairo_scaled_font_glyph_path (cairo_sca
     cairo_status_t status;
     int	i;
     cairo_scaled_glyph_path_closure_t closure;
+    cairo_path_fixed_t *glyph_path;
 
     if (scaled_font->status)
 	return scaled_font->status;
@@ -1073,19 +1142,42 @@ _cairo_scaled_font_glyph_path (cairo_sca
 					     glyphs[i].index,
 					     CAIRO_SCALED_GLYPH_INFO_PATH,
 					     &scaled_glyph);
-	if (status)
+	if (status == CAIRO_STATUS_SUCCESS)
+	    glyph_path = scaled_glyph->path;
+	else if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return status;
 
+	/* If the font is incapable of providing a path, then we'll
+	 * have to trace our own from a surface. */
+	if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+	    status = _cairo_scaled_glyph_lookup (scaled_font,
+						 glyphs[i].index,
+						 CAIRO_SCALED_GLYPH_INFO_SURFACE,
+						 &scaled_glyph);
+
+	    glyph_path = _cairo_path_fixed_create ();
+	    if (glyph_path == NULL)
+		return CAIRO_STATUS_NO_MEMORY;
+
+	    status = _trace_mask_to_path (scaled_glyph->surface, glyph_path);
+	    if (status) {
+		_cairo_path_fixed_destroy (glyph_path);
+		return status;
+	    }
+	}
+
 	closure.offset.x = _cairo_fixed_from_double (glyphs[i].x);
 	closure.offset.y = _cairo_fixed_from_double (glyphs[i].y);
 
-	status = _cairo_path_fixed_interpret (scaled_glyph->path,
+	status = _cairo_path_fixed_interpret (glyph_path,
 					      CAIRO_DIRECTION_FORWARD,
 					      _scaled_glyph_path_move_to,
 					      _scaled_glyph_path_line_to,
 					      _scaled_glyph_path_curve_to,
 					      _scaled_glyph_path_close_path,
 					      &closure);
+	if (glyph_path != scaled_glyph->path)
+	    _cairo_path_fixed_destroy (glyph_path);
     }
 
     return CAIRO_STATUS_SUCCESS;
diff-tree e4e5002c48ec9cea37b4347689f193b54439383e (from 0bfa6d4f33b8ddb5dc55bbe419c15df4af856ff9)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Aug 17 17:45:14 2006 -0700

    bitmap-font: Add cairo_text_path;fill to demonstrate bug #7889

diff --git a/test/bitmap-font.c b/test/bitmap-font.c
index 594e813..ef9bbb6 100644
--- a/test/bitmap-font.c
+++ b/test/bitmap-font.c
@@ -97,16 +97,23 @@ draw (cairo_t *cr, int width, int height
 
     cairo_move_to (cr, 1, TEXT_SIZE - 3);
     cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); /* blue */
-    cairo_show_text (cr, "the quick brown fox jumps over a lazy dog");
+    cairo_show_text (cr, "the quick brown fox");
 
-    /* And test it rotated as well. */
+    /* Switch from show_text to text_path/fill to exercise bug #7889 */
+    cairo_text_path (cr, " jumps over a lazy dog");
+    cairo_fill (cr);
+
+    /* And test it rotated as well for the sake of bug #7888 */
 
     /* XXX: The math for the vertical positioning here is all wrong,
      * but it is landing where I want it. Someone who understands
      * fonts at all should fix this. */
     cairo_move_to (cr, width -1, 2 * (TEXT_SIZE - 5));
     cairo_rotate (cr, M_PI);
-    cairo_show_text (cr, "the quick brown fox jumps over a lazy dog");
+    cairo_show_text (cr, "the quick brown fox");
+
+    cairo_text_path (cr, " jumps over a lazy dog");
+    cairo_fill (cr);
 
     return CAIRO_TEST_SUCCESS;
 }
diff-tree 0bfa6d4f33b8ddb5dc55bbe419c15df4af856ff9 (from e8e7ccf602fdaa2f2e98743f96589f5b7b3faf17)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Aug 17 15:23:32 2006 -0700

    Fix assertion failures in bitmap-font test by coercing A8 images to A1
    
    There are still some problems in the resulting output:
    
    PDF: Rotated font ends up being blurry in final PNG (not too important)
    PS and SVG: There's an incorrect offset being applied somewhere.

diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 7f1947e..2037c3f 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -1050,3 +1050,29 @@ const cairo_surface_backend_t cairo_imag
     _cairo_image_surface_get_extents,
     NULL /* old_show_glyphs */
 };
+
+/* A convenience function for when one needs to coerce an image
+ * surface to an alternate format. */
+cairo_image_surface_t *
+_cairo_image_surface_clone (cairo_image_surface_t	*surface,
+			    cairo_format_t		 format)
+{
+    cairo_image_surface_t *clone;
+    cairo_t *cr;
+    double x, y;
+
+    clone = (cairo_image_surface_t *)
+	cairo_image_surface_create (format,
+				    surface->width, surface->height);
+
+    cr = cairo_create (&clone->base);
+    cairo_surface_get_device_offset (&surface->base, &x, &y);
+    cairo_set_source_surface (cr, &surface->base, x, y);
+    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+    cairo_paint (cr);
+    cairo_destroy (cr);
+
+    cairo_surface_set_device_offset (&clone->base, x, y);
+
+    return clone;
+}
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 8665ee2..6caee3d 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -1858,7 +1858,11 @@ _cairo_pdf_surface_emit_bitmap_glyph (ca
 	return status;
 
     image = scaled_glyph->surface;
-    assert (image->format == CAIRO_FORMAT_A1);
+    if (image->format != CAIRO_FORMAT_A1) {
+	image = _cairo_image_surface_clone (image, CAIRO_FORMAT_A1);
+	if (cairo_surface_status (image))
+	    return cairo_surface_status (image);
+    }
 
     *glyph_ret = _cairo_pdf_surface_open_stream (surface, NULL);
 
@@ -1900,6 +1904,9 @@ _cairo_pdf_surface_emit_bitmap_glyph (ca
 
     _cairo_pdf_surface_close_stream (surface);
 
+    if (image != scaled_glyph->surface)
+	cairo_surface_destroy (&image->base);
+
     return CAIRO_STATUS_SUCCESS;
 }
 
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index e809064..ba8a808 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -547,7 +547,11 @@ _cairo_ps_surface_emit_bitmap_glyph_data
 					 &scaled_glyph);
 
     image = scaled_glyph->surface;
-    assert (image->format == CAIRO_FORMAT_A1);
+    if (image->format != CAIRO_FORMAT_A1) {
+	image = _cairo_image_surface_clone (image, CAIRO_FORMAT_A1);
+	if (cairo_surface_status (image))
+	    return cairo_surface_status (image);
+    }
 
     _cairo_output_stream_printf (surface->final_stream,
 				 "0 0 %f %f %f %f setcachedevice\n",
@@ -591,6 +595,9 @@ _cairo_ps_surface_emit_bitmap_glyph_data
     _cairo_output_stream_printf (surface->final_stream,
 				 "imagemask\n");
 
+    if (image != scaled_glyph->surface)
+	cairo_surface_destroy (&image->base);
+
     return CAIRO_STATUS_SUCCESS;
 }
 
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 988f98b..7c99c97 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -573,7 +573,11 @@ _cairo_svg_document_emit_bitmap_glyph_da
 	return status;
 
     image = scaled_glyph->surface;
-    assert (image->format == CAIRO_FORMAT_A1);
+    if (image->format != CAIRO_FORMAT_A1) {
+	image = _cairo_image_surface_clone (image, CAIRO_FORMAT_A1);
+	if (cairo_surface_status (image))
+	    return cairo_surface_status (image);
+    }
 
     _cairo_output_stream_printf (document->xml_node_glyphs, "<g");
     emit_transform (document->xml_node_glyphs, " transform", ">/n", &image->base.device_transform);
@@ -592,6 +596,10 @@ _cairo_svg_document_emit_bitmap_glyph_da
 	}
     }
     _cairo_output_stream_printf (document->xml_node_glyphs, "</g>\n");
+
+    if (image != scaled_glyph->surface)
+	cairo_surface_destroy (image);
+
     return CAIRO_STATUS_SUCCESS;
 }
 
diff --git a/src/cairoint.h b/src/cairoint.h
index 034463a..13d19b1 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2023,6 +2023,10 @@ cairo_private cairo_int_status_t
 _cairo_image_surface_set_clip_region (void *abstract_surface,
 				      pixman_region16_t *region);
 
+cairo_image_surface_t *
+_cairo_image_surface_clone (cairo_image_surface_t	*surface,
+			    cairo_format_t		 format);
+
 cairo_private cairo_bool_t
 _cairo_surface_is_image (const cairo_surface_t *surface);
 
diff-tree e8e7ccf602fdaa2f2e98743f96589f5b7b3faf17 (from 751ff78ff2acba36614bae17744427c385413264)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Aug 17 13:54:06 2006 -0700

    Add rotation to bitmap-font to demonstrate failure of bug #7888

diff --git a/test/bitmap-font-ref.png b/test/bitmap-font-ref.png
index 886c62f..0718bf9 100644
Binary files a/test/bitmap-font-ref.png and b/test/bitmap-font-ref.png differ
diff --git a/test/bitmap-font-rgb24-ref.png b/test/bitmap-font-rgb24-ref.png
index abea9b1..8569064 100644
Binary files a/test/bitmap-font-rgb24-ref.png and b/test/bitmap-font-rgb24-ref.png differ
diff --git a/test/bitmap-font.c b/test/bitmap-font.c
index 16ad52c..594e813 100644
--- a/test/bitmap-font.c
+++ b/test/bitmap-font.c
@@ -40,7 +40,7 @@ static cairo_test_draw_function_t draw;
 cairo_test_t test = {
     "bitmap-font",
     "Test drawing with a font consisting only of bitmaps",
-    246 + 1, TEXT_SIZE,
+    246 + 1, 2 * TEXT_SIZE,
     draw
 };
 
@@ -99,6 +99,15 @@ draw (cairo_t *cr, int width, int height
     cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); /* blue */
     cairo_show_text (cr, "the quick brown fox jumps over a lazy dog");
 
+    /* And test it rotated as well. */
+
+    /* XXX: The math for the vertical positioning here is all wrong,
+     * but it is landing where I want it. Someone who understands
+     * fonts at all should fix this. */
+    cairo_move_to (cr, width -1, 2 * (TEXT_SIZE - 5));
+    cairo_rotate (cr, M_PI);
+    cairo_show_text (cr, "the quick brown fox jumps over a lazy dog");
+
     return CAIRO_TEST_SUCCESS;
 }
 


More information about the cairo-commit mailing list