[cairo] User font feature

Kristian Høgsberg krh at bitplanet.net
Fri Apr 7 10:14:47 PDT 2006

On 4/6/06, Carl Worth <cworth at cworth.org> wrote:
> [1] For example, Emmanuel Pacaud recently let me know that he hopes to
> have the SVG backend ready for inclusion with the upcoming 1.2
> release. Similarly, Kristian Høgsberg just started a new "user font"
> capability which he hopes to have ready for 1.2 as well. I hope he'll
> let us hear more about it soon, but in the meantime, you can peak at
> it here:
> http://gitweb.freedesktop.org/?p=users-krh-cairo;a=shortlog;h=user-font

Yup, there's a first implementation in the user-font branch of that
repository and there's a user-font.c test case which demonstrates the
feature.  Based on discussion in irc with Carl and Behdad last night,
there's probably a few things that's going to change, but let me first
describe what this feature does and why it's interesting.

One of the most frequently reported performance problems with the
poppler[1] cairo backend is when a PDF document uses a Type3 font. 
Most PDF documents embed TrueType or Type1 fonts which we extract and
pass to freetype and then pass the FT_Face to cairo.  This uses the
cairo font cache behind the scenes and gives us pretty good
performance.  However, a Type3 font defines each glyph as a small
snippet of PDF code and the way the poppler cairo-backend works is
that we render that snippet each time the glyph is used.  This is of
course slow and especially when the Type3 font is a bitmap font, since
we're scaling the glyph bitmaps all the time, which ends up exercising
fbCompositeGeneral()  quite a bit.  PS also has Type3 fonts and SVG
has the <font> tag, which is a similar mechanism, so it's a problem
that shows up in a few other places.

The obvious way to fix this is to add a glyph cache, but instead of
reinventing that and having two disjoint glyph caches (the cairo one
and the poppler one) I'd like to be able to reuse the cairo glyph
cache for Type3 glyphs.  So my proposal as it looks in my git
repository at the moment is to add a new type of cairo_font_face_t, a
cairo user font:

  cairo_public cairo_font_face_t *
  cairo_user_font_face_create (cairo_ucs4_to_index_func_t     ucs4_to_index,
                               cairo_get_glyph_metrics_func_t get_glyph_metrics,
                               cairo_render_glyph_func_t      render_glyph,
                               cairo_get_glyph_path_func_t    get_glyph_path);

Using this API the application can create a font face given a set of
call backs.  The font face can be used as any other font face and
works with cairo_show_text() and cairo_show_glyphs() etc.  The idea is
that when cairo needs metrics or the glyph bitmap it calls out to the
application provided callbacks.  The glyphs bitmaps are cached and
evicted as needed etc. behind the scenes as for the other cairo font
face types.

While this API is sufficient to fix the poppler performance problem,
there's a few other issues to consider:

- PS and PDF Type3 fonts and SVG fonts allow for ARGB glyphs.  That
is, a glyph is either an alpha mask that is used in a mask operation
with the current source when painting the glyph (as in cairo today) or
it's a full ARGB image that just gets composited into the destination
when painting the glyph.  I believe it's not too difficult to extend
the glyph cache to also handle ARGB glyphs, we just need to inspect
the surface contents for each glyph surface and either mask it or
composite it as we paint the glyphs.

- Behdad suggests using the text_to_glyphs API instead of
ucs4_to_index, which makes it possible for the user font
implementation to substitute combined glyphs if necessary (I think
that was the motivation, anyway).

- We probably need a callback when a scaled font is created creation
to allow the user font implementation to attach per-scaled font data
and a callback to free that data.  Most of the built in font backends
extend cairo_scaled_font_t with backend specific data, after all.

- The render_glyph callback needs to take a cairo_t instead as
suggested by Behdad.  This way we can render alpha masks for the
glyphs we do now, but it will also be possible to render a user font
glyph into an SVG glyph or Type3 glyph.  The glyph path isn't
sufficient for outputting SVG or Type3 fonts as the source user glyphs
may be bitmap or ARGB glyphs.  Passing a cairo_t to the render_glyph
callback also let's us set the font matrix as the ctm for that cairo_t
and we can specify that the callback must render the glyph in a unit
sqare.  Not sure this works so well, though, if the application wants
to do hinting or pixel grid snapping.

- We still need the get_glyph_path callback for the cairo_text_path()
case. Alternatively, this could be done by passing a meta surface to
render_glyph and then extracting the path from that.  Of course that
isn't always possible - again, bitmap fonts and ARGB glyphs.

But anyway, that's a head up on the user-font work.  Feedback welcome.


[1] http://poppler.freedesktop.org

More information about the cairo mailing list