There were two errors:
* We subtracted half the line width instead of adding it to the
baseline
* We rounded the line positioning and thickness before the positioning
calculation. In particular, rounding the thickness before using it
to adjust the position was wrong. Now we round just before the
pixman call.
But only do this when the font is scalable but not an outline. This is
only true for color bitmap fonts (emoji fonts), and not e.g. regular
bitmap fonts.
Each font instance has a ref-counter. Whenever we want to instantiate
a font that has already been loaded, we instead return the
already-loaded instance, and bump the ref counter.
When the last font instance is destroyed, it is also removed from the
cache.
When instantiating a primary font, build the fallback font list, but
don't actually instantiate the fallback fonts.
Instead, remember the (full) pattern that we should use if/when we
instantiate it.
Then, when looking up a glyph and we need a fallback font, loop the
list and instantiate the font(s) there and then.
The caching of fallback fonts didn't work. It "worked" because we
didn't free the fonts... When we started doing that, the fallback
fonts were no longer cached.
Another solution would have been to keep the cached fallback fonts
around until exit, and free them there. But that didn't seem very
clean.
So, for now, load *all* fallbacks when instantiating a
primary (non-fallback) font.
Note that this slows down initial startup time.
This greatly improves the performance when loading user-configured
fallback fonts.
Previously, we had to re-load these fallback fonts over and over again
for each (new) glyph.
*All* glyphs are cached.
But we never set the 'wc' member of failed glyphs, causing a later
cache lookup of the same glyph miss in the cache, and thus re-generate
yet another glyph (that is inserted into the cache). I.e. if the
same (invalid) glyph is rendered over and over again, we'll end up
growing the cache indefinitely.
Fix by setting the 'wc' member of invalid glyphs. This causes a cache
lookup to hit. But, we must also check the glyphs validity, and return
NULL if the glyph isn't valid.
Finally, when destroying a font, skip invalid glyphs, since they have
no resources that needs to be freed.
When we've exhausted our own fallback list, try the font list provided
by fontconfig.
This means, the user's fallback fonts have priority, but in case all
of them fail, we hopefully get lucky with fontconfig...
The 'attributes' struct is now 8 bytes and naturally packed (used to
be 9 bytes, artificially packed).
'cell' struct is now 12 bytes, naturally packed (used to be 13 bytes,
artificially packed).
Furthermore, the glyph is stored as a wchar instead of a char*. This
makes it easier (faster) to do glyph lookup when rendering.
Fonts are now loaded with FT_LOAD_COLOR and we recognize and support
the FT_PIXEL_MODE_BGRA pixel mode.
This is mapped to a CAIRO_FORMAT_ARGB32 surface, that is blitted
as-is (instead of used as a mask like we do for gray and mono glyphs).
Furthermore, since many emojis are double-width, we add initial
support for double-width glyphs.
These are assumed to always be utf8. When PRINT:ing an utf8 character,
we check its width, and add empty "spacer" cells after the cell with
the multi-column glyph.
When rendering, we render the columns in each row backwards. This
ensures the spacer cells get cleared *before* we render the glyph (so
that we don't end up erasing part of the glyph).
Finally, emoji fonts are usually bitmap fonts with *large*
glyphs. These aren't automatically scaled down. I.e. even if we
request a glyph of 13 pixels, we might end up getting a 100px glyph.
To handle this, fontconfig must be configured to scale bitmap
fonts. When it is, we can look at the 'scalable' and 'pixelsizefixup'
properties, and use these to scale the rendered glyph.
A top-level font now has a list of fallback fonts. When a glyph cannot
be found, we try each fallback font in turn, until we either find one
that has the glyph, or until we've exhausted the list.
To make this actually work in practise (read: to make performance
acceptable), the cache is re-worked and is now populated on demand.
It also supports non-ASCII characters, by using the 4-byte unicode
character as index instead.
Since having an array that can be indexed by a 4-byte value isn't
really viable, we now have a simple hash table instead of an array.
These properties aren't always included in the pattern, and when they
aren't, trying to get them will fail.
This isn't an error, just fallback to a default value.