[cairo] Problem with text rendering on Win32+ClearType, and possible fix

Tor Lillqvist tml at iki.fi
Tue Oct 3 17:28:56 PDT 2006


I have for a long time been noticing a problem you can see in the
screenshots http://www.saunalahti.fi/tlillqvi/ctbug.png and
http://www.saunalahti.fi/tlillqvi/ctbug2.png (note how the "1" digits
that occur as the final character of a string have been partially cut
off). This problem happens only when ClearType is active, and it
started happening between cairo 1.0.2 and 1.0.4 (yes, that long
ago...).  Today I finally did some searching for the root cause.

At first, the problem seemed stem from the fact that starting with
1.0.4, cairo_win32_surface_create() sets the surface format to
CAIRO_FORMAT_ARGB32 if GetDeviceCaps(hdc,BITSPIXEL) returns 32. (In
1.0.2, the format was always set to CAIRO_FORMAT_RGB24.) If the
surface format is ARGB32, _cairo_win32_scaled_font_show_glyphs() uses
its software fallback branch, and I thought, maybe that code is buggy.

If I changed cairo_win32_surface_create() to use RGB24 also when
BITSPIXEL is 32, the problem went away, as
_cairo_win32_scaled_font_show_glyphs() then uses the "direct"
branch. But this seemed like using a awfully large hammer to fix the
problem.

I then tried if I could fix the problem by some clever hacking on the
code in the software fallback branch in
_cairo_win32_scaled_font_show_glyphs(). What worked was to use width+1
and height+1 instead of width and height there in all places. But that
didn't really seem proper either. Anyway, clearly the problem had
something to do with the metrics of glyph strings to be rendered.

I then looked for a way to make cairo use slightly wider and higher
metrics for a string to be rendered. It turns out that adding one to
the GLYPHMETRICS::gmBlackBoxX and GLYPHMETRICS::gmBlackBoxY that are
filled in by the GetGlyphOutlineW() calls in
_cairo_win32_scaled_font_init_glyph_metrics() had the desired effect.

Could this be the proper fix? Is there a fencepost error in the
interpretation of the GLYPHMETRICS::gmBlackBoxX and gmBlackBoxY
values?

I.e., my potential patch is:

--- 1.2.4/src/cairo-win32-font.c	Fri Aug 18 17:20:16 2006
+++ 1.2.4-tml/src/cairo-win32-font.c	Wed Oct  4 02:42:27 2006
@@ -773,15 +773,15 @@ _cairo_win32_scaled_font_init_glyph_metr
 	if (scaled_font->swap_axes) {
 	    extents.x_bearing = - metrics.gmptGlyphOrigin.y / scaled_font->y_scale;
 	    extents.y_bearing = metrics.gmptGlyphOrigin.x / scaled_font->x_scale;
-	    extents.width = metrics.gmBlackBoxY / scaled_font->y_scale;
-	    extents.height = metrics.gmBlackBoxX / scaled_font->x_scale;
+	    extents.width = (metrics.gmBlackBoxY+1) / scaled_font->y_scale;
+	    extents.height = (metrics.gmBlackBoxX+1) / scaled_font->x_scale;
 	    extents.x_advance = metrics.gmCellIncY / scaled_font->x_scale;
 	    extents.y_advance = metrics.gmCellIncX / scaled_font->y_scale;
 	} else {
 	    extents.x_bearing = metrics.gmptGlyphOrigin.x / scaled_font->x_scale;
 	    extents.y_bearing = - metrics.gmptGlyphOrigin.y / scaled_font->y_scale;
-	    extents.width = metrics.gmBlackBoxX / scaled_font->x_scale;
-	    extents.height = metrics.gmBlackBoxY / scaled_font->y_scale;
+	    extents.width = (metrics.gmBlackBoxX+1) / scaled_font->x_scale;
+	    extents.height = (metrics.gmBlackBoxY+1) / scaled_font->y_scale;
 	    extents.x_advance = metrics.gmCellIncX / scaled_font->x_scale;
 	    extents.y_advance = metrics.gmCellIncY / scaled_font->y_scale;
 	}
@@ -811,8 +811,8 @@ _cairo_win32_scaled_font_init_glyph_metr
 
 	extents.x_bearing = (double)metrics.gmptGlyphOrigin.x / scaled_font->em_square;
 	extents.y_bearing = - (double)metrics.gmptGlyphOrigin.y / scaled_font->em_square;
-	extents.width = (double)metrics.gmBlackBoxX / scaled_font->em_square;
-	extents.height = (double)metrics.gmBlackBoxY / scaled_font->em_square;
+	extents.width = (double)(metrics.gmBlackBoxX+1) / scaled_font->em_square;
+	extents.height = (double)(metrics.gmBlackBoxY+1) / scaled_font->em_square;
 	extents.x_advance = (double)metrics.gmCellIncX / scaled_font->em_square;
 	extents.y_advance = (double)metrics.gmCellIncY / scaled_font->em_square;
     }

--tml



More information about the cairo mailing list