Using X fonts in Pango

The Pango font model presents fonts to the application developer and user in a way that it is most suitable for handling fonts that are scaleable and encoded in a script-independent-fashion. This model is well suited to, for instance, OpenType fonts or CID-keyed postscript fonts. However, this model is not well matched to X fonts since X fonts are frequently only present as bitmaps and also appear separately for each encoding. The X interface for Pango uses a number of different techniques to cover up these deficiencies. It allows fonts to be fontsets, implicitely merges related fonts, allows aliases to be defined, and does most of the font matching internally to allow it to intelligently choose whether to scale fonts or not.

A font in the X renderer for Pango is represented as a fontset and a size. That is, it is a list of XLFDs, with wildcards for size and character set, and a point-size. These fonts that the X renderer lists when queried come from two sources:

  1. Merging of fonts with identifical names and styles. For instance, if the following fonts are in the list queried from the server:

    • -adobe-times-bold-i-normal--14-140-75-75-p-77-iso8859-1
    • -cronyx-times-bold-i-normal--14-100-100-100-p-54-koi8-r
    • -urw-times-bold-i-normal--0-0-0-0-p-0-iso8859-1

    Then the X renderer reports the single font:

    FamilyStyleVariantWeightStretch
    timesitalicnormalboldnormal

    with the corresponding font set:

    • -*-times-bold-i-normal--*-*-*-*-*-*-*-*

    The renderer uses the Cronyx font if it needs a font in the koi8-r encoding, the Adobe font if it needs a 14 pt font in the iso8859-1 encoding, and finally the URW font if it needs any other size for iso8859-1. It is assumed that when a bitmap is present for a particular size, it is superior to scaling the scaleable font at the same size. (It might be desirable to change this behavior so if there is a scaleable font and a bitmap font present, the bitmap font is only ever used if the foundry for the bitmap matches the foundry for the scaleable font.)

  2. Aliases specified in configuration files. The above works reasonable well for creating fonts that the user can pick for a particular piece of text. The problem is that fonts created as above usually don't cover all scripts equally well. Especially for CJK scripts, fonts are usually not designed to go with the standard roman families. You won't find a Japanese-capable font called "times". Also, due to the size and complexity of these fonts, there are typically only a few fonts installed on any given system.

    The solution that Pango takes to this problem is to introduce font aliases. The X renderer looks for alias files $(sysconfdir)/pango/pangox_aliases and $(HOME)/.pangox_aliases. These files are comprised of a list of mapping of the Pango font descriptions into font lists. For instance, we can have:

    sans normal normal normal normal \
    	"-*-helvetica-medium-r-normal--*-*-*-*-*-*-*-*,\
    	-*-fixed-medium-r-normal--*-*-*-*-*-*-*-*"
    sans bold   normal normal normal \
    	"-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*,\
    	-*-fixed-medium-r-normal--*-*-*-*-*-*-*-*"
          

    (lines broken for formatting purposes ... current each alias must be a single line)

    These lines map both the normal and bold variants of the "Sans" face (a standard alias) to normal and bold variants of helvetica, for encodings where Helvetica is found. But when helvetica is not found, they both fall back to the same XLFD for fixed. The primary purpose of the alias file is to define the standard aliases. In addition to "Sans", they include "Serif", and "Monospace". (I'm not sure the last is the best name for a fixed-pitch font, the alias names are not yet finalized.)

These two mechanisms combine to provide the user with a pretty complete list of useable fonts. One problem that does occur, though, is that the first mechanism may end up listing quite a few fonts that the user is not interested in, and that produce odd results when the user chooses it. For instance, if the system has the commonly available chinese-language fonts installed, there will a family shown as "Song Ti" that has no Roman characters in it. The average user will only be confused by this. There is no obvious clean solution to this. One thing that could be done is to only display fonts that include the characters necessary to render text in the user's locale. (But this might be awkward for user's who actually are interested in dealing with text in languages other than there own.) It's also quite possible that this problem is more severe for the developers of Pango (who have installed every font known to man) than to the average user, and isn't worth worrying about.

We mentioned some aspects of the algorithm used to select the X font for a particular character set above. We'll now describe it in more detail. The following is presented mostly for reference purposes. The details of the algorithm are not something that application writers need to deal with. They are perhaps of some interest to those creating font aliases or writing Pango modules, though you should not depend on the following details remaining constant.

The fontset for and size for the Pango font are known when the font is created --- the size is specified by the application, while the fontset is found from a lookup in Pango's internal databases. A shape engine then can query Pango for a list of X fonts corresponding to the Pango font and a list of character sets using the call:

int    pango_x_list_subfonts  (PangoFont      *font,
                               char          **charsets,
                               int             n_charsets,
                               PangoXSubfont **subfont_ids,
                               int           **subfont_charsets);
  

This call takes a PangoFont and list of charsets as input, and then produces a list of matching X fonts within the Pango font. For each pair of a character set and a XLFD within the Pango font's fontset, it checks to see if there is a font that matches that character set and XLFD, and lists those fonts ordered, first by position in the font list, and then secondarily within that by the order of the supplied character sets.

Matching is currently defined as "matching at any size". As mentioned above, when there are multiple different fonts matching the XLFD charset pair, then the one closest in size is picked, except that for exact matches, non-scaleable fonts are preferred over scaleable fonts.

As an example of the matching process, for a 14pt font, with the fontset:

-*-times-medium-r-normal--*-*-*-*-*-*-*-*,
-*-fixed-medium-r-normal--*-*-*-*-*-*-*-*
  

if the following fonts are available:

  • -adobe-times-bold-i-normal--14-140-75-75-p-77-iso8859-1
  • -cronyx-times-bold-i-normal--14-100-100-100-p-54-koi8-r
  • -urw-times-bold-i-normal--0-0-0-0-p-0-iso8859-1
  • -jis-fixed-medium-r-normal--16-150-75-75-c-160-jisx0208.1983-0
  • -sony-fixed-medium-r-normal--16-150-75-75-c-80-iso8859-1

Then a query that supplied the character sets iso8859-1, isox0208.1983-0, and koi8-r, in that order. Would get the list of font back:

  • -adobe-times-bold-i-normal--14-140-75-75-p-77-iso8859-1
  • -cronyx-times-bold-i-normal--14-100-100-100-p-54-koi8-r
  • -sony-fixed-medium-r-normal--16-150-75-75-c-80-iso8859-1
  • -jis-fixed-medium-r-normal--16-150-75-75-c-160-jisx0208.1983-0

But if the two XLFDs in the fontset were reversed, then the ordering would be:

  • -sony-fixed-medium-r-normal--16-150-75-75-c-80-iso8859-1
  • -jis-fixed-medium-r-normal--16-150-75-75-c-160-jisx0208.1983-0
  • -adobe-times-bold-i-normal--14-140-75-75-p-77-iso8859-1
  • -cronyx-times-bold-i-normal--14-100-100-100-p-54-koi8-r

Note that the 16 point Sony Fixed font for iso8859-1 is returned first in the list, although a fourteen point font is available for Times. The ordering implemented in this way so that rendering is reasonably consistent between sizes. (Consistency here is valued over appearance, since it is assumed that in appearance-critical applications, a better font technology will be used.)



Last modified 15-Feb-2000
Owen Taylor <otaylor@redhat.com>