[Tex/LaTex] Fixing fonts with LuaTeX feature files

fontskerningluatextypography

Bringhurst urges us in Chapter 10 of The Elements of Typographic Style: Version 4.0 to fix the font files if needed. See below a summary of the chapter using the section titles.

Bringhurst suggests to modify the font file so the fixes are done forever.
But I think that for some fixes we can use feature files in LuaTeX.
This can make easier to transfer projects from computers with fonts installed system-wide.

I ask for help to identify what can be corrected using feature files and show an example file.
(Would it be better to make this question a comunity wiki?)

List of possible issues to be fixed

  1. Letterform

    Sometimes the glyphs are completely wrong. Usually due to missing glyphs taken from other fonts.
    In this case the only possibility is to use a font editor. Not possible with feature files.

  2. Hinting

    Hinting is not an easy process and sometimes is wrong or missing Altogether.
    In this case the only possibility is to use a font editor. Not possible with feature files.

  3. Vertical position

    Some characters' vertical position (specially +, -, dashes, …) could be improved.
    Is it posible to fix it with feature files?

  4. Sidebering

    This is the blank space at the right and left of the outline of the glyph insie the box.
    Bringhurst says that he has to fix these values usually to fix the space between letters and puntuation symbols
    (He describes his style in this regards as a halfway between british and french typographic traditions).
    Can/Should it be done with feature files?
    (The microtype package can do the french typeseting style. Does it use kerning correction for that?)

  5. Character substitution

    Some characters could be in an inappropriate encoding position.
    I guess this can be fix with a GSUB rule.

  6. Kerning

    What to say about bad kerning, that the audience of this forum doesn't already know!
    This is an easy one; I can even answer myself 🙂

Summary of Chapter 10

10 Grooming the font

10.1 Legal considerations

10.1 Check the license before tuning a digital font

10.2 Ethical & aesthetic considerations

!0.2.1 If ain't broken…

10.2.2 If the font is out of tune, fix it once and for all

10.2.3 Respect the font first of all, the letterform second, the type designer third, the foundry fourth

10.2.4 Keep on fixing

10.3 Honing the character set

10.3.1 If there are defective glyphs, meal them

10.3.2 If text figures, ligatures or other glyphs you need on a regular basis don't reside on the base font, install them there

10.3.3 if glyphs you need are missing altogether, make them

10.3.4 Check and correct the sidebering

10.3.5 Refine the kerning table

10.3.6 Check the kerning of the word space

10.4 Hinting

10.4.1 If the font looks poor at low resolutions, check the hinting

10.5 Naming convention

Best Answer

A little guide to feature files

With feature files you can define two types of operation in lookups: substitute (sub) glyphs by others and position (pos) glyphs. What is impossible, is to modify the letterforms or add missing glyphs. Also, wrong encoding can’t be corrected by feature files. The only thing one can do in this case is to a glyph by another from the font so at least the visual appearance is as expected.

Simple lookups

The simplest positioning is kerning:

lookup mykern {
  pos A V -70; # 'pos' is short for the keyword 'position'
  pos T e -100;
} mykern;

Substitution is possible as 1:1, n:1 (ligature), 1:n

lookup mysmallcaps {
  sub u by v.sc;  # have a v shaped smallcap glyph instead of a u-shaped one; with copy/paste this gets copied as "v"!
} mysmallcaps;

lookup myligatures {
  sub a e by ae; # 'sub' is short for the keyword 'substitute'
} myligatures;

lookup unligate {
  sub f_f_l by f f l;
} unligate;

Contextual lookups

More complex lookups can define in which context an operation takes place:

lookup myordinals {
  sub one s' by s.sups;
  sub s.sups t' by t.sups;
} myordinals;

lookup kernwithdiacritics {
  pos T' 50 e acutecomb;  # this is accumulative to a previous kern of T e
} kernwithdiacritics;

With the keyword ignore one can exclude contexts from the substitution. The following will substitute e with a final form if it’s not followed by one of the letters A-Z or a-z:

lookup finals {
  ignore sub e' [A-Z a-z]; # the content inside the brackets is a "glyph class"
  sub e' by e.fina;
} finals;

Advanced positioning

The two kinds of position parameters in the kern lookups are short formats. The full format is <xplacement yplacement xadvance yadvance>. So, for example adjust the vertical position of a superscript glyph with:

lookup mysuperscript {
 pos e.sups <0 50 0 0>;  # e.sups is positioned 50 design-units higher
} mysuperscript;

To illustrate let’s adjust the greek letter Η with polytonic accents. In the first example it’s Eta with grave (Ὴ, needs space to the left), in the second we add a iota adscriptum (ῌ needs space to the right. xplacement shifts the image of the glyph by the given value without changing its box, xadvance changes the size of the glyph’s box:

lookup greekaccents1 {
 pos Eta' <79 0 79 0> gravecomb.grk;
} greekaccents1;

lookup greekaccents2 {
 pos Eta' <0 0 200 0> ypogegrammeni.cap;
 pos Eta' <79 0 279 0> ypogegrammeni.cap gravecomb.grk;
} greekaccents1;

Important:

  • Lookups are accessible via features, where one feature can activate one or more lookups and different features can activate the same lookup:
    feature gacc {          # featurenames are four-letter tags
      lookup greekaccents1;
      lookup greekaccents2;
    } gacc;
  • Lookups are applied to a language-system which needs to be defined, but make sure that that system exists in the font. The language-systems can be defined at the beginning of the feature-file, they will be applied to lookups in all subsequent features. If one needs to apply a lookup only in specific language-systems on has to do so explicitly inside the feature:
    languagesystem DFLT dflt;
    languagesystem grek dflt;
    languagesystem latn dflt;
    languagesystem latn TRK ;

    feature mkrn {
      lookup mykern; # This will be applied to all above language-systems
    } mkrn;

    feature itrk {
      script latn;
        language TRK  exclude_dflt;
          lookup turkish_i {
            sub i.sc by i.sc dotaccent; # this will only be applied to Turkish in latin script
          } turkish_i;
    } itrk;
  • As you can see above, lookups can be defined separately or nested inside features.
  • For bigger tasks, you can define glyphclasses (eg. before the lookups):
    @letters = [a-z aacute eacute adieresis odieresis];
    @LETTERS = [A-Z Aacute Eacute Adieresis Odieresis];
  • Make sure that you use the glyphnames as they appear in the font. This can be tricky and you might need to open the font in a font-editor or dump it with some tool (does somebody know a more direct way?) For example, the glyphname Delta can refer either to the greek letter or to the symbol in different versions of the same Adobe spec. Also, font-designers can name the glyphs different from Adobes proposals.
Related Question