这几天Arch下Chrome的文泉驿正黑的渲染总是有问题,缩小到一定比例的时候字体看起来残缺不全,非常糟糕。因为Chrome只有一处修改字体的选项,为了追求英文字符的显示效果,浏览器的字体都显式设置为Droid字体。于是中文字体的渲染都是系统自动匹配的(其时是文泉驿正黑)。其间尝试把字体都改为字体类别,即Serif改成Serif,Sans改成Sans,Mono改成Mono,结果很囧地发现英文字体都是清一色的Bitstream Vera,而且怎么改local.conf都无用,真无语。最后发现这个问题居然是文泉驿正黑挑起来的,更加无语。

为了说明问题,先对fontconfig的工作原理有个了解。fontconfig顾名思义就是字体配置工具,用于向应用程序提供指定字体。其最根本的配置文件(以Arch为例)为/etc/fonts/fonts.conf。但当打开后会发现里面有

DO NOT EDIT THIS FILE.

IT WILL BE REPLACED WHEN FONTCONFIG IS UPDATED.

LOCAL CHANGES BELONG IN ‘local.conf’.

字样。而且/etc/fonts/conf.avail和/etc/fonts/conf.d下有好多配置文件。可想而知这些是要被fonts.conf链接的。注意到fonts.conf中有一行

conf.d

就是链接conf.d目录下配置文件的命令。需要指出的是,conf.d下的配置文件只是conf.avail下配置文件的链接。用这种方式可以灵活地加载和卸载配置文件。

那么就去conf.d下一探究竟。这下面有一堆两位数字开头的配置文件。数字越小越先被加载(这就是造成日后痛苦的原因之一……)。x0~x9为一个系列(x=1,2,3,…,9),其中关于字体类别设置的系列是40~49和60~69(其他请见该目录下README)。

这里面的两个概念是family和generic。family即字体名称,如Bitstream Vera Sans,Times New Roman。generic即字体类别,如Serif,Sans Serif,Mono。

40~49说明了family -> generic的mapping,即某字体属于某类别。用

<alias>
    <family></family>
    ...
    <family></family>
    <default><family></family></default>
</alias>

实现。60~69说明了generic -> family的mapping,即某类别的代表字体,用

<alias>
    <family></family>
    <prefer>
        <family></family>
        ...
        <family></family>
    </prefer>
</alias>

实现。

比如,我想要把Bitstream Vera Serif和Droid Serif都归入Serif类别,用

<alias>
    <family>Bitstream Vera Serif</family>
    <family>Droid Serif</family>
    <default><family>serif</family></default>
</alias>

即可。我要指定Serif类别的代表字体为Droid Serif,用

<alias>
    <family>serif</family>
    <prefer>
        <family>Droid Serif</family>
        <family>Bitstream Vera Serif</family>
    </prefer>
</alias>

即可。这样在系统调用Serif字体时,会先寻找Droid Serif,若不存在,再寻找Bitstream Vera Serif。

问题至此就要水落石出了。让我们看看44-wqy-zenhei.conf干了些什么:

<alias>
    <family>serif</family>
    <prefer>
        <family>Bitstream Vera Serif</family>
        <family>DejaVu Serif</family>
        <family>WenQuanYi Zen Hei</family>
    </prefer>
</alias>

明白了么?每次调用Serif字体都会先找Bitstream Vera Serif,不存在再找DejaVu Serif,再不行就WenQuanYi Zen Hei。local.conf(local.conf是conf.d/51-local.conf链过去的)和60~69里面的配置根本就用不上!哭泣了……

当然wqy-zenhei这样做有它的道理,因为这样就可以实现中英文用不同字体渲染。Bitstream Vera Serif和DejaVu Serif都是非常漂亮的英文字体,而文泉驿正黑的中文也十分出色。但问题在于44-wqy-zenhei.conf这个配置文件没有遵循fontconfig的规范,在错误的地方做了generic -> family的mapping,而且……完全不考虑Bitstream Vera和DejaVu完全满足不了我对Droid的渴望,我要Droid Serif,Droid Sans和Droid Sans Mono!那就自己改了吧……

最后必须指出世界上存在着比文泉驿正黑更好的中英文字体,那就是——文泉驿微米黑(WenQuanYi Micro Hei)。这个字体的英文居然和Droid别无二致,中文是介于黑体和幼圆之间的感觉,非常cool。于是我很快就把local.conf改成

<?xml version="1.0"?>
<fontconfig>
    <alias>
        <family>serif</family>
        <prefer>
            <family>Droid Serif</family>
            <family>WenQuanYi Micro Hei</family>
        </prefer>
    </alias>
    <alias>
        <family>sans-serif</family>
        <prefer>
            <family>Droid Sans</family>
            <family>WenQuanYi Micro Hei</family>
        </prefer>
    </alias>
    <alias>
        <family>monospace</family>
        <prefer>
            <family>Droid Sans Mono</family>
            <family>WenQuanYi Micro Hei Mono</family>
        </prefer>
    </alias>
</fontconfig>

世界太平了……