Hello Bedhad,<br><br>for the maximum precision, simply tell FreeType to load glyph outlines in &quot;original units&quot;<br>the outline points will be in integer coordinates, that should be scaled to whatever device pixels with the equation:<br>
<br>&nbsp;&nbsp; device_x = original_x * character_size_in_pixels / face-&gt;units_per_EM<br><br>which is equivalent to:<br><br>&nbsp;&nbsp; device_x = original_x * character_size_in_points / ( 72 * device_dpi * face-&gt;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 &lt;<a href="mailto:behdad@behdad.org">behdad@behdad.org</a>&gt;:<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&#39;s quite well-known by now that in cairo animation, text is always<br>
jagged and jittery, even with all hintings disabled. &nbsp;The main reason<br>
for that is that we currently do not support sub-pixel text positioning<br>
and round glyph positions to integers. &nbsp;Our workaround so far has been<br>
to recommend cairo_text_path();cairo_fill() instead of<br>
cairo_show_text(). &nbsp;That&#39;s far from perfect, but should do the job. &nbsp;Or<br>
one would think so... &nbsp;Apparently it doesn&#39;t. &nbsp;So I sat down a while ago<br>
and tried to figure out what&#39;s going on. &nbsp;And I did.<br>
<br>
Check the image:<br>
<br>
 &nbsp;<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. &nbsp;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. &nbsp;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&#39;s limited precision<br>
(26.6 fixed type). &nbsp;In fact, seems like that&#39;s contributing to our ugly<br>
show_text() results too. &nbsp; Needless to say, we want to achieve results<br>
as good as the third column.<br>
<br>
So how do fix this then? &nbsp;For show_text(), we want to implement<br>
sub-pixel glyph positioning. &nbsp;I suggest we do a 4x4 or 8x4 grid. &nbsp;Each<br>
glyph then will have up to 32 renderings. &nbsp;May also make sense to add a<br>
new metrics-hinting mode to just hint the Y metrics. &nbsp;That&#39;s what Apple<br>
does I guess. &nbsp;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>
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; unsigned long index,<br>
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cairo_fixed_t x, cairo_fixed_y,<br>
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cairo_scaled_glyph_info_t info,<br>
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 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. &nbsp;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>
 &nbsp;- convert glyph position to fixed<br>
 &nbsp;- fetch the glyph for the fixed position<br>
 &nbsp;- 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. &nbsp;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. &nbsp;That works great for most fonts<br>
as their glyph id is limited (to 64k), but not for user-fonts. &nbsp;With<br>
user-fonts one may use the full range of glyph ids and that&#39;s a valid<br>
usecase. &nbsp;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. &nbsp;That definitely works. &nbsp;Is<br>
just a bit clumsy.<br>
<br>
<br>
Next step is, fixing paths. &nbsp;Turns out we are going towards completely<br>
skipping FreeType&#39;s rasterizer and having cairo rasterize all fonts. &nbsp;We<br>
may need to fix bugs in the non-AA rasterizer to match FreeType&#39;s, but<br>
ignoring that fact, it&#39;s quite possible to do that currently. &nbsp;But!<br>
With the current plan to move to calling into FreeType for subpixel<br>
filtering, we may have some problems. &nbsp;Worst case it&#39;s that we<br>
rasterize, then convert into a FT bitmap, do filtering, then convert<br>
back. &nbsp;Not terribly bad, but also not ideal. &nbsp;While doing that, we may<br>
as well add font-backend API for subpixel filtering. &nbsp;Then we can use<br>
FreeType to do subpixel rendering of user-fonts. &nbsp;Yay!<br>
<br>
Ok, to paths. &nbsp;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. &nbsp;I&#39;m<br>
not sure if we need to cache the scaled version. &nbsp;If not, then we can<br>
cache the path on the font_face instead of the scaled_font. &nbsp;That would<br>
be neat indeed, but needs quite some code refactoring. &nbsp;What should the<br>
fixed size we pass to FreeType be? &nbsp;It should be something to maximize<br>
precision. &nbsp;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. &nbsp;And we&#39;ll then<br>
&quot;scale it down&quot; to 256, such that cairo essentially holds it as 16.16<br>
instead of 24.8 too. &nbsp;That gives us more than enough precision. &nbsp;The<br>
sharing should happen based on whether hinting=off or not. &nbsp;So much for<br>
paths.<br>
<br>
It&#39;s only fair to also talk about metrics at this point. &nbsp;If<br>
metrics-hinting is off, we should also use metrics from a fixed size,<br>
scaled by cairo. &nbsp;It gets trickier here. &nbsp;Cairo returns metrics in user<br>
space. &nbsp;So, for a fixed font matrix, regardless of the ctm matrix, one<br>
should get the same metrics. &nbsp;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. &nbsp;The scaled-font code takes<br>
glyph metrics from backends in font space and converts to user-space by<br>
applying the font matrix. &nbsp;That is, it&#39;s completely independent of the<br>
ctm. &nbsp;That&#39;s good. &nbsp;We just need to ensure that for metrics-hinting=off,<br>
we use the metrics for the font at a fixed size. &nbsp;That is, like what we<br>
need for paths. &nbsp;This time however, we probably do need to cache the<br>
sizes for different font matrices. &nbsp;So we can&#39;t just cache it on<br>
font_face_t. &nbsp;We need a new object, that has all the identifying<br>
properties of cairo_scaled_font_t except for the CTM. &nbsp;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... &nbsp;To add to the confusion... we currently don&#39;t share anything<br>
across scaled fonts that have different ctm/font_matrix, but the same<br>
ctm*font_matrix. &nbsp;We can share the glyph renderings. &nbsp;So that&#39;s another<br>
thing to share. &nbsp;And that one is in fact unconditional.<br>
<br>
And if and when we fix these all. &nbsp;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. &nbsp;Some measurements are in order.<br>
<br>
<br>
So, that&#39;s it. &nbsp;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>
&quot;Those who would give up Essential Liberty to purchase a little<br>
&nbsp;Temporary Safety, deserve neither Liberty nor Safety.&quot;<br>
 &nbsp; &nbsp; &nbsp; &nbsp;-- 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>