[cairo] glyph extents

Jonathan Kew jonathan at jfkew.plus.com
Mon Feb 16 07:54:26 PST 2009

I'd like to ask for clarification of the glyph extents returned by  
cairo_scaled_font_glyph_extents() (and related APIs that are relying  
on the same font data). There is an issue here for the Windows back- 
end that leads to poor visual results in certain situations.

The Cairo documentation says that:

     The extents describe a user-space rectangle that encloses the
     "inked" portion of the glyphs, (as they would be drawn by
     cairo_show_glyphs() if the cairo graphics state were set to
     the same font_face, font_matrix, ctm, and font_options as

It seems to me that the meaning of "inked" is a little unclear in the  
presence of antialiasing, especially at a subpixel level -- does it  
mean the area that a user perceives as the "solid ink" of the glyph,  
or does it mean every pixel that is touched in any way by drawing the  
glyph? The difference can be quite significant, especially on Windows  
with ClearType enabled.

The attached image shows some text (enlarged to make the pixels  
clearly visible) rendered through Cairo on Vista with no smoothing,  
with "standard" font smoothing, and with ClearType. Consider what the  
glyph extents of the initial "f" should be, for example.

In the first case, the "inked" portion of the "f" is obviously 4  
pixels wide, from (0,0) to (4,9) relative to the origin at which the  
glyph was drawn (where co-ordinates refer to the "grid lines" between  
pixels, not to the pixels themselves).

In the second case, with standard font smoothing, the inked area of  
the "f" is still 4 pixels wide (although note that other glyphs have  
changed their inked extents).

In the third case, with ClearType, note how many more pixels have been  
touched. There is a yellow pixel to the left of the crossbar of the  
"f", so its inked area now begins at (-1,0); not quite so obvious is  
that it also extends one pixel further right at the top, contributing  
a slight blue tint to the otherwise yellow antialiasing of the "i".  
(This faint blue pixel from the "f" can be seen clearly on the  
subsequent occurrences.) So the ClearType "f" touches pixels within  
the area (-1,0) to (5,9), two pixels wider than its non-ClearType  
counterpart. The "x" has similarly extended from 5 to 7 pixels wide,  
the "i" and "l" from 1 to 3, and the "e" from 4 to 6.

The problem we have is that on Windows, the "black box" returned in  
the GLYPHMETRICS structure by GetGlyphOutlineW, which provides the  
basis for Cairo's glyph extents, does NOT take account of these  
ClearType pixels that "bleed" beyond what we might call the "visual"  
ink rect. This means that the glyph extents Cairo uses and returns to  
callers do not actually include every pixel that is touched by  
painting the glyph.

This leads to problems when the glyph extents are used as a basis for  
clipping a drawing operation, for example, or for invalidating an area  
where text has been changed. We are seeing visual bugs in Firefox  
(clipped text drawing, and residual visual artifacts when text moves  
or changes) as a direct result of this issue.

   https://bugzilla.mozilla.org/show_bug.cgi?id=445087  (clipped  
drawing occurs within Cairo)
   https://bugzilla.mozilla.org/show_bug.cgi?id=475968  (antialiasing  
artifacts left on screen)

The first of these reports has a small standalone Cairo/Windows test  
program that demonstrates the issue:
along with a screenshot showing the results:

To resolve this, we'd like to patch the Cairo win32 font backend to  
add pixels on each side of the "black box" rect returned by GDI, so  
that the glyph extents Cairo is using will include the potential  
ClearType smoothing pixels; see attached patch. A question is whether  
this "padding" of the glyph box should be done in all cases, or only  
when ClearType is enabled. The latter might seem more correct, but on  
the other hand this means that glyph extents would change on the fly  
if the user (or application) changes the font smoothing settings; this  
might not be desirable.

It is also true that this patch will give extents that will sometimes  
be larger than strictly necessary. I think this is fairly innocuous;  
the effect will be that we do a little more redrawing than is actually  
needed, but that is vastly preferable to redrawing too little!  
Unfortunately, there does not appear to be any way to get "true" ink  
extents from Windows unless we were to actually paint the glyphs to a  
surface and then examine the pixels to see which ones have been  
colored, which would clearly be way too expensive for this purpose.

If the Cairo team feels that we should not be messing with the metrics  
returned by Windows, but allow those to remain "visual ink" extents  
rather than true "every touched pixel" extents, then it will be  
necessary to patch in a number of other places instead (both within  
and outside Cairo) to add the equivalent padding when these extents  
are used. (See the "alternative" patch at mozilla bug 445087 for one  
example of this, where the code in cairo-surface-fallback.c uses glyph  
extents to clip a text painting operation.)

Could this patch (or another solution to the issue) possibly go into  
1.10? That would be really helpful to us.
- Jonathan

-------------- next part --------------
A non-text attachment was scrubbed...
Name: cairo-win32-glyph-extents.patch
Type: application/octet-stream
Size: 1205 bytes
Desc: not available
Url : http://lists.cairographics.org/archives/cairo/attachments/20090216/83ce470b/attachment-0001.obj 
-------------- next part --------------

-------------- next part --------------
A non-text attachment was scrubbed...
Name: smoothing-examples.png
Type: image/png
Size: 10048 bytes
Desc: not available
Url : http://lists.cairographics.org/archives/cairo/attachments/20090216/83ce470b/attachment-0001.png 
-------------- next part --------------

More information about the cairo mailing list