Subnavigation

Hacking on the font subsystem of Qtopia Core

Paul and I have been working the last two weeks on a new font system for Qtopia
Core. What we've come up with and what is now also in the Qt 4.3 snapshots will
hopefully solve a few problems and generally make it easier to use fonts with
Qtopia Core.

From a developer's perspective the biggest visible change is that TrueType
fonts are now worry-free in usage. You can just drop them into the lib/fonts/
directory and Qt will detect them automatically and store the collected
information in a binary cache. On top of that the glyphs rendered from a
TrueType font are now also shared between all Qtopia Core applications. That
speeds up text rendering, because often the glyph image is cached and doesn't
need to be rendered with FreeType anymore, and it obviously saves memory.

If you cannot use TrueType fonts but have to use a font pre-rendered in one or
two pixel sizes your device due to size restrictions then the new QPF2 (Qt
Pre-rendered Font) file format may be of interest for you, especially since the
makeqpf tool to create them is now fully cross-platform.

For the curious developers, here are the technical details of the implementation:

We started by designing the new QPF2 file format, along with a font engine that
can render from it. The basic idea is that one renders a set of (or all) glyphs
from a given font and stores the resulting images of the glyphs along with a
data structure to map from unicode characters to glyph indices, pointing to the
image data and the glyph metrics. Since we're lazy we just take the existing
so-called cmap (character map) table of a TrueType font if available (or
generate one if necessary).

In the resulting QPF2 file we also store the name of the original font file. If
that one happens to be a TrueType font and also happens to be available on the
device (or generally at run-time) we can make use of it. The most important
example of usage is the rendering of text that requires extra shaping, such as
indic or arabic text. For that OpenType tables are needed from the TrueType
font and with Qt being able to use those on-the-fly it is now possible to use
pre-rendered fonts together with complex scripts.

We decided to let the QPF2 file format be identical to the data structure we
need to share glyphs between applications where the glyphs are rendered
on-demand, when you only install for example TrueType fonts on your device. For
on-the-fly rendered but shared glyphs we needed to solve a few problems:

First of all we needed to be able to share memory between processes and at the
same time be able to resize the memory area. We decided to create files in a
sub-directory in /tmp (which is usually tmpfs) and use mmap() and mremap() to
share and resize the memory.

Then while an application renders glyphs that were not rendered previously
other applications need to be able to use already existing glyphs at the same
time. So besides pure write-locking on the file (which we implemented using
F_SETLKW with fcntl, thanks to Brad for the idea) we also needed to make sure that our data
structure supports extension while being used by other processes. We decided to
add a second level of indirection to the process of looking up the glyph data.
After looking up a glyph index using the TrueType cmap we use another
fixed-size array to quickly look up the offset to the glyph data from within
the file (or memory mapped region). This allows us to safely append to the file
while others read and afterwards write the offset into this fixed-size array
(we call it the glyph map).

And finally we added a bit of logic to the Qtopia Core display server to do
garbage collection of unused or possible corrupt/stale fonts after a client
crash. Note that the whole system is otherwise entirely distributed, there is
no round-trip to the display server before an application can start to use font
or start rendering glyphs. The server merely listens to messages the clients
send (one-way) to the server to notify about the use or end of use of fonts. If
the server in turn detects a corrupt font (if for example for some reason the
client rendering to a font crashes at the wrong time) it sends a message to all
clients to please stop using that font.

The detection of corrupt fonts after a client crash is quite interesting. When
a client decides to lock the font file and render some missing glyphs to it it
writes its unique client id into a fixed field in the header of the shared
file. When it finished it replaces that field with a zero. If for some obscure
reason the client crashes while holding the lock the server can read through
all the files after a client crash and identify the fonts the crashed client
held. Other clients won't attempt to render to that font either during that
time since this special field in the header is not set to zero.

After these boring technical details it is time for the obligatory screenshot.
But since a pre-rendered or on-the-fly rendered font looks exactly the same as
on the desktop I instead decided to show a screenshot of a neat little feature
that we built into the makeqpf tool as debugging aid for us. At some point
during development we had applications render glyphs to the font files in /tmp
but sometimes they failed to detect that a glyph was already rendered by
another process. Of course it turned out to be a stupid bug, but we were really
wondering if this was specific to certain glyphs and we wanted to find out
which glyphs were already rendered and how they looked (maybe they were
misrendered or the data was corrupt). So we added a little
show-me-everything-really-verbose option to makeqpf that takes the raw alpha values
of the glyph data and 'renders' them using ascii :-)

Screenshot of makeqpf's really-verbose-dump functionality


Blog Topics:

Comments