Hello Bedhad,<br><br>for the maximum precision, simply tell FreeType to load glyph outlines in "original units"<br>the outline points will be in integer coordinates, that should be scaled to whatever device pixels with the equation:<br>
<br> device_x = original_x * character_size_in_pixels / face->units_per_EM<br><br>which is equivalent to:<br><br> device_x = original_x * character_size_in_points / ( 72 * device_dpi * face->units_per_EM )<br><br>
(simply use the FT_LOAD_NO_SCALE bitflag when loading the glyph; this will also keep the metrics in font units too, by the way).<br><br><a href="http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_LOAD_XXX">http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_LOAD_XXX</a><br>
<br>if it turns out that you prefer to not use FreeType for rasterization, (which can be a good idea, depending on context), I encourage you to do your own pixel filtering as well. the algorithms are relatively simple.<br>
<br>cheers<br><br>- David<br><br><div class="gmail_quote">2008/5/15 Behdad Esfahbod <<a href="mailto:behdad@behdad.org">behdad@behdad.org</a>>:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Hi,<br>
<br>
<br>
It's quite well-known by now that in cairo animation, text is always<br>
jagged and jittery, even with all hintings disabled. The main reason<br>
for that is that we currently do not support sub-pixel text positioning<br>
and round glyph positions to integers. Our workaround so far has been<br>
to recommend cairo_text_path();cairo_fill() instead of<br>
cairo_show_text(). That's far from perfect, but should do the job. Or<br>
one would think so... Apparently it doesn't. So I sat down a while ago<br>
and tried to figure out what's going on. And I did.<br>
<br>
Check the image:<br>
<br>
<a href="http://www.flickr.com/photos/behdad/2493693932/sizes/o/" target="_blank">http://www.flickr.com/photos/behdad/2493693932/sizes/o/</a><br>
<br>
source code is attached. The left column is what you get from<br>
cairo_show_text(), the middle one is cairo_text_path();cairo_fill(),<br>
and the last column is if you take the path of the font at size 12 and<br>
let cairo scale the path, then fill it. The graph suggests that the<br>
problem with the middle column is that we are asking FreeType for glyph<br>
outline at each size, and being beat by FreeType's limited precision<br>
(26.6 fixed type). In fact, seems like that's contributing to our ugly<br>
show_text() results too. Needless to say, we want to achieve results<br>
as good as the third column.<br>
<br>
So how do fix this then? For show_text(), we want to implement<br>
sub-pixel glyph positioning. I suggest we do a 4x4 or 8x4 grid. Each<br>
glyph then will have up to 32 renderings. May also make sense to add a<br>
new metrics-hinting mode to just hint the Y metrics. That's what Apple<br>
does I guess. Anyway, to implement subpixel positioning, I suggest we<br>
add something like:<br>
<br>
cairo_int_status_t<br>
_cairo_scaled_glyph_lookup_subpixel (cairo_scaled_font_t *scaled_font,<br>
unsigned long index,<br>
cairo_fixed_t x, cairo_fixed_y,<br>
cairo_scaled_glyph_info_t info,<br>
cairo_scaled_glyph_t **scaled_glyph_ret);<br>
<br>
unsigned long<br>
_cairo_scaled_glyph_get_subpixel_index (cairo_scaled_glyph_t *scaled_glyph);<br>
<br>
<br>
Basically this will create a new cairo_scaled_glyph_t for each position<br>
on the subpixel grid. Each position on the subpixel grid also has an<br>
index, with index 0 mapping to pixel-aligned coordinate.<br>
<br>
Raster backends (and the fallback path) then will be changed to:<br>
<br>
- convert glyph position to fixed<br>
- fetch the glyph for the fixed position<br>
- round the fixed position and render the fetched glyph there<br>
<br>
To make it less error-prune we can make the x,y in/out such that the<br>
rounding is done in one place. Or better, make it take double x,y as<br>
input and return int x,y as output.<br>
<br>
The bigger problem though, is how to implement this in the xlib backend.<br>
Obvious solution is to make the Xrender glyph id be the combination of<br>
input glyph id and the subpixel index. That works great for most fonts<br>
as their glyph id is limited (to 64k), but not for user-fonts. With<br>
user-fonts one may use the full range of glyph ids and that's a valid<br>
usecase. Then the input-glyph-id + subpixel-index space is larger than<br>
the Xrender glyph space and we have to use multiple Xrender glyphsets.<br>
Maybe we can reserve the high byte of the Xrender glyph space for<br>
subpixel-index, and upon seeing input glyphs that have non-zero high<br>
byte, use additional glyphsets for those. That definitely works. Is<br>
just a bit clumsy.<br>
<br>
<br>
Next step is, fixing paths. Turns out we are going towards completely<br>
skipping FreeType's rasterizer and having cairo rasterize all fonts. We<br>
may need to fix bugs in the non-AA rasterizer to match FreeType's, but<br>
ignoring that fact, it's quite possible to do that currently. But!<br>
With the current plan to move to calling into FreeType for subpixel<br>
filtering, we may have some problems. Worst case it's that we<br>
rasterize, then convert into a FT bitmap, do filtering, then convert<br>
back. Not terribly bad, but also not ideal. While doing that, we may<br>
as well add font-backend API for subpixel filtering. Then we can use<br>
FreeType to do subpixel rendering of user-fonts. Yay!<br>
<br>
Ok, to paths. So, if hinting is set to none, we want to always ask font<br>
backend for glyph path at a fixed font size, and scale it in cairo. I'm<br>
not sure if we need to cache the scaled version. If not, then we can<br>
cache the path on the font_face instead of the scaled_font. That would<br>
be neat indeed, but needs quite some code refactoring. What should the<br>
fixed size we pass to FreeType be? It should be something to maximize<br>
precision. We can actually use some really large size (like 1024), that<br>
makes FreeType do all its math in 16.16 instead of 26.6. And we'll then<br>
"scale it down" to 256, such that cairo essentially holds it as 16.16<br>
instead of 24.8 too. That gives us more than enough precision. The<br>
sharing should happen based on whether hinting=off or not. So much for<br>
paths.<br>
<br>
It's only fair to also talk about metrics at this point. If<br>
metrics-hinting is off, we should also use metrics from a fixed size,<br>
scaled by cairo. It gets trickier here. Cairo returns metrics in user<br>
space. So, for a fixed font matrix, regardless of the ctm matrix, one<br>
should get the same metrics. This is indeed needed to ensure that a<br>
zoomed-in print preview of a book typeset using pangocairo has the exact<br>
same line breaks that the actual print does. The scaled-font code takes<br>
glyph metrics from backends in font space and converts to user-space by<br>
applying the font matrix. That is, it's completely independent of the<br>
ctm. That's good. We just need to ensure that for metrics-hinting=off,<br>
we use the metrics for the font at a fixed size. That is, like what we<br>
need for paths. This time however, we probably do need to cache the<br>
sizes for different font matrices. So we can't just cache it on<br>
font_face_t. We need a new object, that has all the identifying<br>
properties of cairo_scaled_font_t except for the CTM. Then whether<br>
metrics-hinting is off or on decides whether we should share or not<br>
share this object across scaled-fonts with different CTMs.<br>
<br>
Humm... To add to the confusion... we currently don't share anything<br>
across scaled fonts that have different ctm/font_matrix, but the same<br>
ctm*font_matrix. We can share the glyph renderings. So that's another<br>
thing to share. And that one is in fact unconditional.<br>
<br>
And if and when we fix these all. We should also make the scaled-font<br>
layer not cache glyphs for sizes larger than some large value (128?),<br>
and just do path();fill() everytime. Some measurements are in order.<br>
<br>
<br>
So, that's it. Who volunteers for which part? :)<br>
<br>
<br>
Cheers,<br>
<font color="#888888">--<br>
behdad<br>
<a href="http://behdad.org/" target="_blank">http://behdad.org/</a><br>
<br>
"Those who would give up Essential Liberty to purchase a little<br>
Temporary Safety, deserve neither Liberty nor Safety."<br>
-- Benjamin Franklin, 1759<br>
</font><br>_______________________________________________<br>
cairo mailing list<br>
<a href="mailto:cairo@cairographics.org">cairo@cairographics.org</a><br>
<a href="http://lists.cairographics.org/mailman/listinfo/cairo" target="_blank">http://lists.cairographics.org/mailman/listinfo/cairo</a><br></blockquote></div><br>