[cairo] Getting real linearly-scalable text

David Turner david at freetype.org
Sun May 18 11:02:23 PDT 2008

Hello Bedhad,

for the maximum precision, simply tell FreeType to load glyph outlines in
"original units"
the outline points will be in integer coordinates, that should be scaled to
whatever device pixels with the equation:

   device_x = original_x * character_size_in_pixels / face->units_per_EM

which is equivalent to:

   device_x = original_x * character_size_in_points / ( 72 * device_dpi *
face->units_per_EM )

(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).


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.


- David

2008/5/15 Behdad Esfahbod <behdad at behdad.org>:

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

More information about the cairo mailing list