[cairo-commit] cairo/src cairo-ft-font.c,1.65,1.66

Owen Taylor commit at pdx.freedesktop.org
Fri Jun 24 15:06:45 PDT 2005


Committed by: otaylor

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

Modified Files:
	cairo-ft-font.c 
Log Message:
2005-06-24  Owen Taylor  <otaylor at redhat.com>

        * src/cairo-ft-font.c (_render_glyph_bitmap): Handle rendering
        bitmap glyphslots as well as outline glyphslots.

        * src/cairo-ft-font.c (_ft_unscaled_font_set_scale): When setting
        the scale for a non-scalable font, use the nearest available
        size (FreeType won't set the glyph metrics otherwise.)


Index: cairo-ft-font.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-ft-font.c,v
retrieving revision 1.65
retrieving revision 1.66
diff -u -d -r1.65 -r1.66
--- cairo-ft-font.c	15 Jun 2005 23:04:19 -0000	1.65
+++ cairo-ft-font.c	24 Jun 2005 22:06:41 -0000	1.66
@@ -34,6 +34,8 @@
  *	Owen Taylor <otaylor at redhat.com>
  */
 
+#include <float.h>
+
 #include "cairo-ft-private.h"
 
 #include <fontconfig/fontconfig.h>
@@ -448,6 +450,7 @@
 {
     ft_font_transform_t sf;
     FT_Matrix mat;
+    FT_UInt pixel_width, pixel_height;
 
     assert (unscaled->face != NULL);
     
@@ -472,10 +475,29 @@
     mat.yy = DOUBLE_TO_16_16(sf.shape[1][1]);
 
     FT_Set_Transform(unscaled->face, &mat, NULL);
-    
-    FT_Set_Pixel_Sizes(unscaled->face,
-		       (FT_UInt) sf.x_scale,
-		       (FT_UInt) sf.y_scale);
+
+    if ((unscaled->face->face_flags & FT_FACE_FLAG_SCALABLE) != 0) {
+	pixel_width = sf.x_scale;
+	pixel_height = sf.y_scale;
+    } else {
+	double min_distance = DBL_MAX;
+	int i;
+
+	pixel_width = pixel_height = 0;
+	
+	for (i = 0; i < unscaled->face->num_fixed_sizes; i++) {
+	    double size = unscaled->face->available_sizes[i].y_ppem / 64.;
+	    double distance = fabs (size - sf.y_scale);
+	    
+	    if (distance <= min_distance) {
+		min_distance = distance;
+		pixel_width = unscaled->face->available_sizes[i].x_ppem >> 6;
+		pixel_height = unscaled->face->available_sizes[i].y_ppem >> 6;
+	    }
+	}
+    }
+
+    FT_Set_Pixel_Sizes (unscaled->face, pixel_width, pixel_height);
 }
 
 static void 
@@ -515,59 +537,32 @@
     }
 }
 
-static cairo_status_t 
-_cairo_ft_unscaled_font_create_glyph (void                            *abstract_font,
-				      cairo_image_glyph_cache_entry_t *val)
+/* Converts an outline FT_GlyphSlot into an image
+ * 
+ * This could go through _render_glyph_bitmap as well, letting
+ * FreeType convert the outline to a bitmap, but doing it ourselves
+ * has two minor advantages: first, we save a copy of the bitmap
+ * buffer: we can directly use the buffer that FreeType renders
+ * into.
+ *
+ * Second, it may help when we add support for subpixel
+ * rendering: the Xft code does it this way. (Keith thinks that
+ * it may also be possible to get the subpixel rendering with
+ * FT_Render_Glyph: something worth looking into in more detail
+ * when we add subpixel support. If so, we may want to eliminate
+ * this version of the code path entirely.
+ */
+static cairo_status_t
+_render_glyph_outline (FT_Face                          face,
+		       cairo_image_glyph_cache_entry_t *val)
 {
-    ft_unscaled_font_t *unscaled = abstract_font;
-    FT_GlyphSlot glyphslot;
+    FT_GlyphSlot glyphslot = face->glyph;
+    FT_Outline *outline = &glyphslot->outline;
     unsigned int width, height, stride;
-    FT_Face face;
-    FT_Outline *outline;
-    FT_BBox cbox;
     FT_Bitmap bitmap;
-    FT_Glyph_Metrics *metrics;
+    FT_BBox cbox;
     cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
-    face = _ft_unscaled_font_lock_face (unscaled);
-    if (!face)
-	return CAIRO_STATUS_NO_MEMORY;
-
-    glyphslot = face->glyph;
-    metrics = &glyphslot->metrics;
-
-    _ft_unscaled_font_set_scale (unscaled, &val->key.scale);
-
-    if (FT_Load_Glyph (face, val->key.index, val->key.flags) != 0) {
-	status = CAIRO_STATUS_NO_MEMORY;
-	goto FAIL;
-    }
-
-    /*
-     * Note: the font's coordinate system is upside down from ours, so the
-     * Y coordinates of the bearing and advance need to be negated.
-     *
-     * Scale metrics back to glyph space from the scaled glyph space returned
-     * by FreeType
-     */
-
-    val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / unscaled->x_scale;
-    val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / unscaled->y_scale;
-
-    val->extents.width  = DOUBLE_FROM_26_6 (metrics->width) / unscaled->x_scale;
-    val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / unscaled->y_scale;
-
-    /*
-     * use untransformed advance values
-     * XXX uses horizontal advance only at present;
-     should provide FT_LOAD_VERTICAL_LAYOUT
-     */
-
-    val->extents.x_advance = DOUBLE_FROM_26_6 (face->glyph->metrics.horiAdvance) / unscaled->x_scale;
-    val->extents.y_advance = 0 / unscaled->y_scale;
-    
-    outline = &glyphslot->outline;
-
     FT_Outline_Get_CBox (outline, &cbox);
 
     cbox.xMin &= -64;
@@ -583,7 +578,7 @@
 	val->image = NULL;
     } else  {
 
-	bitmap.pixel_mode = ft_pixel_mode_grays;
+	bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
 	bitmap.num_grays  = 256;
 	bitmap.width = width;
 	bitmap.rows = height;
@@ -591,16 +586,14 @@
 	bitmap.buffer = calloc (1, stride * height);
 	
 	if (bitmap.buffer == NULL) {
-	    status = CAIRO_STATUS_NO_MEMORY;
-	    goto FAIL;
+	    return CAIRO_STATUS_NO_MEMORY;
 	}
 	
 	FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin);
 	
 	if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) {
 	    free (bitmap.buffer);
-	    status = CAIRO_STATUS_NO_MEMORY;
-	    goto FAIL;
+	    return CAIRO_STATUS_NO_MEMORY;
 	}
 	
 	val->image = (cairo_image_surface_t *)
@@ -609,8 +602,7 @@
 					     width, height, stride);
 	if (val->image == NULL) {
 	    free (bitmap.buffer);
-	    status = CAIRO_STATUS_NO_MEMORY;
-	    goto FAIL;
+	    return CAIRO_STATUS_NO_MEMORY;
 	}
 	
 	_cairo_image_surface_assume_ownership_of_data (val->image);
@@ -625,10 +617,167 @@
     val->size.height = (unsigned short) height;
     val->size.x =   (short) (cbox.xMin >> 6);
     val->size.y = - (short) (cbox.yMax >> 6);
+
+    return status;
+}
+
+/* Converts a bitmap (or other) FT_GlyphSlot into an image
+ * 
+ * This could go through _render_glyph_bitmap as well, letting
+ * FreeType convert the outline to a bitmap, but doing it ourselves
+ * has two minor advantages: first, we save a copy of the bitmap
+ * buffer: we can directly use the buffer that FreeType renders
+ * into.
+ *
+ * Second, it may help when we add support for subpixel
+ * rendering: the Xft code does it this way. (Keith thinks that
+ * it may also be possible to get the subpixel rendering with
+ * FT_Render_Glyph: something worth looking into in more detail
+ * when we add subpixel support. If so, we may want to eliminate
+ * this version of the code path entirely.
+ */
+static cairo_status_t
+_render_glyph_bitmap (FT_Face                          face,
+		      cairo_image_glyph_cache_entry_t *val)
+{
+    FT_GlyphSlot glyphslot = face->glyph;
+    FT_Bitmap *bitmap;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+    int width, height, stride;
+    unsigned char *data;
+    FT_Error error;
+    int i, j;
+
+    /* According to the FreeType docs, glyphslot->format could be
+     * something other than FT_GLYPH_FORMAT_OUTLINE or
+     * FT_GLYPH_FORMAT_BITMAP. Calling FT_Render_Glyph gives FreeType
+     * the opportunity to convert such to
+     * bitmap. FT_GLYPH_FORMAT_COMPOSITE will not be encountered since
+     * we avoid the FT_LOAD_NO_RECURSE flag.
+     */
+    error = FT_Render_Glyph (glyphslot, FT_RENDER_MODE_NORMAL);
+    if (error)
+	return CAIRO_STATUS_NO_MEMORY;
+
+    bitmap = &glyphslot->bitmap;
+
+    width = bitmap->width;
+    height = bitmap->rows;
+
+    if (width * height == 0) {
+	val->image = NULL;
+    } else {
+	switch (bitmap->pixel_mode) {
+	case FT_PIXEL_MODE_MONO:
+	    stride = (width + 3) & ~3;
+	    data = calloc (stride * height, 1);
+	    if (!data)
+		return CAIRO_STATUS_NO_MEMORY;
+	    for (j = 0; j < height; j++) {
+		const unsigned char *p = bitmap->buffer + j * bitmap->pitch;
+		unsigned char *q = data + j * stride;
+		for (i = 0; i < width; i++) {
+		    /* FreeType bitmaps are always stored MSB */
+		    unsigned char byte = p[i >> 3];
+		    unsigned char bit = 1 << (7 - (i % 8));
+
+		    if (byte & bit)
+			q[i] = 0xff;
+		}
+	    }
+	    break;
+	case FT_PIXEL_MODE_GRAY:
+	    stride = bitmap->pitch;
+	    data = malloc (stride * height);
+	    if (!data)
+		return CAIRO_STATUS_NO_MEMORY;
+	    memcpy (data, bitmap->buffer, stride * height);
+	    break;
+	case FT_PIXEL_MODE_GRAY2:
+	case FT_PIXEL_MODE_GRAY4:
+	    /* These could be triggered by very rare types of TrueType fonts */
+	case FT_PIXEL_MODE_LCD:
+	case FT_PIXEL_MODE_LCD_V:
+	    /* These should never be triggered unless we ask for them */
+	default:
+	    return CAIRO_STATUS_NO_MEMORY;
+	}
+	
+	val->image = (cairo_image_surface_t *)
+	    cairo_image_surface_create_for_data (data,
+						 CAIRO_FORMAT_A8,
+						 width, height, stride);
+	if (val->image == NULL) {
+	    free (data);
+	    return CAIRO_STATUS_NO_MEMORY;
+	}
+
+	_cairo_image_surface_assume_ownership_of_data (val->image);
+    }
+
+    val->size.width = width;
+    val->size.height = height;
+    val->size.x = - glyphslot->bitmap_left;
+    val->size.y = - glyphslot->bitmap_top;
+    
+    return status;
+}
+
+static cairo_status_t 
+_cairo_ft_unscaled_font_create_glyph (void                            *abstract_font,
+				      cairo_image_glyph_cache_entry_t *val)
+{
+    ft_unscaled_font_t *unscaled = abstract_font;
+    FT_GlyphSlot glyphslot;
+    FT_Face face;
+    FT_Glyph_Metrics *metrics;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+    face = _ft_unscaled_font_lock_face (unscaled);
+    if (!face)
+	return CAIRO_STATUS_NO_MEMORY;
+
+(    glyphslot = face->glyph;
+    metrics = &glyphslot->metrics;
+
+    _ft_unscaled_font_set_scale (unscaled, &val->key.scale);
+
+    if (FT_Load_Glyph (face, val->key.index, val->key.flags) != 0) {
+	status = CAIRO_STATUS_NO_MEMORY;
+	goto FAIL;
+    }
+
+    /*
+     * Note: the font's coordinate system is upside down from ours, so the
+     * Y coordinates of the bearing and advance need to be negated.
+     *
+     * Scale metrics back to glyph space from the scaled glyph space returned
+     * by FreeType
+     */
+
+    val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / unscaled->x_scale;
+    val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / unscaled->y_scale;
+
+    val->extents.width  = DOUBLE_FROM_26_6 (metrics->width) / unscaled->x_scale;
+    val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / unscaled->y_scale;
+
+    /*
+     * use untransformed advance values
+     * XXX uses horizontal advance only at present;
+     should provide FT_LOAD_VERTICAL_LAYOUT
+     */
+
+    val->extents.x_advance = DOUBLE_FROM_26_6 (face->glyph->metrics.horiAdvance) / unscaled->x_scale;
+    val->extents.y_advance = 0 / unscaled->y_scale;
+
+    if (glyphslot->format == FT_GLYPH_FORMAT_OUTLINE)
+	status = _render_glyph_outline (face, val);
+    else
+	status = _render_glyph_bitmap (face, val);
     
  FAIL:
     _ft_unscaled_font_unlock_face (unscaled);
-    
+
     return status;
 }
 




More information about the cairo-commit mailing list