Fonts and font sizes in Fedora on the internet: hold onto your hats...

So I threw a somewhat disorganized note on some fiddling I'd been doing with my systems' font configuration on G+ earlier today. Harish Pilay asked for some more detailed notes, so I'm throwing together another gigantic blog post. Hold on to your hats, folks...

Fonts in Fedora: fontconfig

There's a rather important library for font handling in Fedora (and all other modern distros) called fontconfig. I remember the time years ago when various things didn't go through fontconfig, but these days, almost everything does. You can set quite a lot of font configuration at the fontconfig level and it'll be respected - to some extent...see later - by just about every graphical app you run.

fontconfig configures...well, really, everything about fonts at a systemwide level. If the question is 'where can I configure X about fonts?', the answer is almost always 'fontconfig'. This makes things nice and simple.

Fontconfig configuration layout

You can find Fedora's (or most any distro's) default fontconfig settings in /etc/fonts/fonts.conf and /etc/fonts/conf.d . Looking at the files in /etc/fonts/conf.d can teach you quite a lot about how fontconfig settings work. man fonts.conf has a lot of useful information too. It's important to know that fontconfig configuration files loaded earlier take precedence over ones loaded later, when they conflict.

Note the files /etc/fonts/conf.d/50-user.conf and /etc/fonts/conf.d/51-local.conf. For any user account, where ~ is the user's home directory as usual, 50-user.conf will load any files in ~/.config/fontconfig/conf.d, then the file ~/.config/fontconfig/fonts.conf (and then files in ~/.fonts.conf.d and then ~/.fonts.conf, but those last two are deprecated and should no longer be used).

/etc/fonts/conf.d/51-local.conf will load the file /etc/fonts/local.conf.

So for most local configuration changes, you can change systemwide settings in /etc/fonts/local.conf and per-user settings in ~/.config/fontconfig/fonts.conf. If you need to override any systemwide settings from files in /etc/fonts/conf.d whose filename starts with a number lower than 50 you'll need to drop a lower-numbered file in that directory, but this is pretty unusual.

Doin' Stuff with fontconfig

What did I actually do with fontconfig this morning? I created a file /etc/fonts/local.conf with this in it:

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>

# Preferred serif, sans and mono fonts

    <alias>
            <family>serif</family>
            <prefer>
                    <family>Droid Serif</family>
            </prefer>
    </alias>
    <alias>
            <family>sans-serif</family>
            <prefer>
                    <family>Cantarell</family>
            </prefer>
    </alias>
    <alias>
            <family>monospace</family>
            <prefer>
                    <family>Droid Sans Mono</family>
            </prefer>
    </alias>

# Replace some crappy fonts with ones I like

    <match target="pattern">
            <test qual="any" name="family"><string>verdana</string></test>
            <edit name="family" mode="assign" binding="same"><string>Cantarell</string></edit>
    </match>
    <match target="pattern">
            <test qual="any" name="family"><string>arial</string></test>
            <edit name="family" mode="assign" binding="same"><string>Cantarell</string></edit>
    </match>
    <match target="pattern">
            <test qual="any" name="family"><string>times</string></test>
            <edit name="family" mode="assign" binding="same"><string>Droid Serif</string></edit>
    </match>
    <match target="pattern">
            <test qual="any" name="family"><string>helvetica</string></test>
            <edit name="family" mode="assign" binding="same"><string>Cantarell</string></edit>
    </match>
</fontconfig>

Mostly, I set my preferred fonts for the standard 'generic' families, and I changed the aliases for some common font names. What does this mean? Read on!

fontconfig (and the font world in general, really) has a concept of 'font families' which I won't really go into in detail. All we really need to know right now is this: as most people are probably familiar with, there are three broad categories of type into which almost all of the text we deal with on a daily basis fall - serif, sans-serif and monospace. Serif fonts have those little curly bits, sans-serif fonts don't, and monospace fonts are, well, monospaced - that is, all their characters have the same width, so monospaced text always lines up nicely in columns, which you want, sometimes. There's an obvious layering violation here, in that monospaced fonts can be either serif or sans-serif yet we're treating those three attributes as if they were alternatives to each other, but ah well - it's the world we live in.

If a program (or other thing) doesn't try to specify a particular font to render its text in, it will either not specify anything at all and leave it to the system to pick a font, or it might say 'this text should be sans-serif' or 'this text should be serif' or 'this text should be monospace'. When this happens, if nothing at a higher level overrides it, fontconfig will decide what font is used.

The stock configuration for Latin text in Fedora can be seen in /etc/fonts/conf.d/60-latin.conf. It specifies several particular 'families' - which you can really just think of as individual fonts for this purpose - for each of the three major generic families. The first will be used if it exists, the second if the first doesn't exist, and so on. I think this fallback order is also used if a given character is missing in a font - so if a character is missing in the first font in the list, fontconfig will check if it's in the second font in the list and get it from there if so, and so on.

If you take a look, you can see that Fedora's system-wide stock 'serif' font is Bitstream Vera Serif, our system-wide stock 'sans-serif' font is Bitstream Vera Sans, and our system-wide stock 'monospace' font is Bitstream Vera Sans Mono, with first fallbacks to DejaVu, which are derived from Bitstream but add a lot more character coverage. This is a pretty common stock config for Linux distros these days. Let me tell you, the day the heroes at Bitstream (now sadly deceased - the company, not the heroes, AFAIK...) open sourced those fonts they did the F/OSS community a huge favour. We had some pretty poor fonts before then. Hands up if you remember Luxi.

But Bitstream fonts aren't actually my favourites. I'm very, very partial to the GNOME 3 stock font, which is a sans-serif font called Cantarell. I think it's awesome. I don't like serif fonts in general but if I have to look at one I prefer Droid Serif to Bitstream, and ditto for monospace - I quite like Droid Sans Mono. The Droid fonts were created for Android (though Android has now switched to a font called Roboto) and are available in the packages google-droid-sans-mono-fonts, google-droid-serif-fonts and google-droid-sans-fonts in Fedora.

So what the first chunk of that local.conf does is enforce my preferences: because of the order in which the config files are read, the effect is that my preferred fonts are put at the top of the lists from /etc/fonts/conf.d/60-latin.conf. I copied the skeleton from that file just to make it easy to edit - it's always a pain writing XML from scratch.

The second half of the file does something different. Here's the question: what happens if a program wants to render some text in a font you don't have?

Of course, the answer is determined by fontconfig. If you check the stock rules, various files have directives that 'alias' various commonly-used fonts that aren't always (or often) present on Linux systems to other fonts. The main one is /etc/fonts/conf.d/30-metric-aliases.conf , which makes an attempt to map a lot of commonly used fonts to their closest metric equivalents.

What's a metric equivalent? Well, it's pretty simple: it's a font whose characters are all the same size as another. Some F/OSS fonts exist explicitly to be metric equivalents of non-F/OSS fonts. The Liberation family, for instance, is designed to provide metric equivalents of the stock Windows fonts.

If you think about it for a second, it's obvious that the actual size of the characters in a given font is going to be very important in some contexts. The classic example is a word processed document. Say you write a document on one computer, carefully laying it out such that it fits perfectly on a single page...then you open it on another computer and it doesn't any more! Why? One of the common reasons is that the second computer doesn't have the font you used to write the document, and the font it substitutes is not a perfect metric equivalent. If, say, the characters in the 'replacement' font are 10% wider than those in the original, the text will wind up taking up near 10% more space than it did on the other computer, and suddenly your document doesn't fit precisely on one page any more.

Hence: metric equivalents. Metric equivalents also usually try to use the same broad 'style' as the fonts they're replacing, too - obviously they can't look the same, as that'd be copyright infringement, but if the original is a very conservatively-styled font, the replacement likely will be too, for instance.

So, yeah, stock freetype generally tries quite hard to replace commonly-used fonts with metric equivalents. But I don't actually run into cases where this is important to me very often. And web sites often specify fonts like Arial and Verdana and Helvetica that I don't have, and don't much like so I wouldn't install them anyway. I don't usually like their metric equivalents either.

So what the second part of my config does is override fontconfig's aliases for some fonts. Attentive readers may be wondering how this works given that metric-aliases.conf is numbered 30 - well done, a cookie for you! The answer is that the mechanism I use is a 'stronger' one than the one 30-metric-aliases.conf uses, so it wins out even though it gets loaded later. 30-metric-aliases.conf uses aliases, whereas my directives actually effectively 'rename' the fonts wherever they're encountered - they say 'when you run across verdana, just pretend it's Cantarell', and so forth. That means the aliases don't kick in, because the font basically isn't considered to be verdana any more.

You can do all sorts of stuff with fontconfig. Really, I'm not joking - it's incredibly powerful, and I only just scratched the surface. I actually have another bit in my config, which does this:

# Use medium hinting for Droid Sans Mono only

    <match target="pattern">
            <test qual="any" name="family"><string>Droid Sans Mono</string></test>
            <edit name="hintstyle" mode="assign"><const>hintmedium</const></edit>
    </match>

What that does is use medium strength hinting just for the font Droid Sans Mono. Hinting is another insanely complex area of fonts, but at a very high level it more or less means 'when rendering this font, how much should the font rendering engine mess with it to make it the precise size and shape requested'. Really, don't go into any more detail unless you don't value your sanity or want to become a font designer, but it's somewhat useful to know it exists and it can affect how your fonts look rather drastically. In GNOME tweak tool, you can set a default hinting strength for all fonts, and see the changes on the fly. I find 'slight' hinting is best for almost everything on my desktop, but Droid Sans Mono looks a bit wonky with 'slight', and this config snippet overrides just that font to use 'medium' and lets everything else use what GNOME says. (I'm actually surprised GNOME's setting doesn't override fontconfig's in this case, but layering of font configuration is another rather complex area, as we'll see to some degree later).

That's just an example, anyway, you can do all sorts of crazy stuff.

Next post: how fonts work on the Web, and how to control them!

Comments

Rajeesh wrote on 2014-01-18 07:47:
Excellent introductory article, Adam. I fiddle with the fontconfig settings every new Fedora release. I found the system default DejaVu fonts really unpleasant, Liberation looks much better. And I'm one of those who (fondly) remember Luxi. In fact, from RedHat 8 to Fedora 20, there is one font I always used - Luxi Mono. It's a shame the copyright was not permissive. I agree with hinting - that stay away from it if you want to remain sane, and slight hinting looks generally better. If you have not tried Infinality fontconfig, I urge you to try and see the difference it makes. Unfortunately it is not updated for freetype 2.5 yet. Always felt like the font situation in Fedora could be improved.
Harish Pillay wrote on 2014-01-20 03:17:
Thanks Adam for posting this. I am not one to poke around fonts much but there are many times I wish I had a greater understanding of the nuances. I guess your post will help me in that direction. Thanks again!
Michael Catanzaro wrote on 2014-01-20 14:56:
On Fedora 20 Live Desktop, Bitstream Vera is not even installed. The defaults seem to be DejaVu.
Ingo Weiss wrote on 2014-02-11 08:10:
You should try Infinality, http://www.infinality.net/. It's a set of patches that makes fonts on Linux something decent without too much fiddling. They have Fedora RPMs which work perfectly.
adamw wrote on 2014-02-11 08:29:
You'll notice that neither of my posts on the topic is about font rendering. That's by intent: I'm not interested in that particular hornet's nest. It's incredibly subjective, subject to all sorts of magical thinking, and also involves legal complications. So I mostly just leave it alone. I don't particularly care for infinality's rendering myself. Even if you like it, it's pretty much orthogonal to the question of your choice of font *faces* and *sizes*, and how you go about making that choice.
MariuszS wrote on 2014-09-16 19:12:
infinality is abandoned now, most of the code is already included in fedora.