Implementing OpenType calt or init with Latin script in 2024

Hello,

At my job we use a typeface created by an artist on our team for labeling diagrams and illustrations. As part of the style guidelines, there’s a special use around the letter “i”. We always use all caps, and if the letter I is the first letter of a word, then we use the I with crossbars on the top and bottom. If the I is not first and inside a word, we use an I without crossbars. The problem is the default capital I has crossbars, and anytime an “I” is in between the word, we type a lowercase L. 

I thought it might be possible to bake in a rule like that, to change the default upper case i to have zero crossbars, and for the font to identify when an I is at the beginning of a word, and change it to use the glyph with crossbars. However it is unclear to me if something like that is supported for Latin script and the English language in OpenType.

Glyphs says that opentype positional features do not apply to Latin: https://glyphsapp.com/learn/features-part-4-positional-alternates

Fontforge documentation says support for calt in latn has possibly improved over time: https://fontforge.org/docs/tutorial/editexample6-5.html

However the Opentype cookbook doesn’t mention any support issues with init/word boundary detection: https://opentypecookbook.com/common-techniques/

I’m new to font editor software so I want to try to edit the .otf file in fontforge, and maybe try glyphs if that doesn’t work. Each guide I look at also does it in a different way. Is there a method anyone recommends? Is there even opentype support for what I want to do?

Comments

  • Nick Shinn
    Nick Shinn Posts: 2,187
    edited October 17
    You can use the “ignore” method in, for instance, the Contextual Alternates feature.
    This is how the Swash feature is used to make initial cap letters swash.

    ignore sub @capitals I';
    sub I' by I.crossbarred;

    This means that unless I is preceded by a capital (e.g. in all-cap text) the crossbarred alternate will be substituted.
  • Erwin Denissen
    Erwin Denissen Posts: 299
    edited October 17
    Glyph positioning is irrelevant in this case, as your request is about glyph substitution.

    You haven’t mentioned which software you're using, so it’s unclear how well it supports OpenType features.

    If it does support contextual substitutions, Nick's approach should work effectively.

    Here is a complete Adobe fea feature file:
    languagesystem latn dflt; # Latin default
    
    @capitals = [A-Z Agrave Ccedilla I.crossbarred Macute];
    feature calt { # Contextual Alternates
        ignore sub @capitals I';
        sub I' by I.crossbarred;
    } calt;
    
    You can import it directly into the OpenType Designer dialog in FontCreator (both Windows and Mac).
  • John Hudson
    John Hudson Posts: 3,133
    The init, medi, fina, and isol features are now explicitly defined as implementing Unicode joining behaviour for e.g. Arabic. The earlier descriptions of these features in the OT features registry mistakenly described them as being applied based on position in a word, but that was never actually how they were implemented in layout engines* because that is not how Arabic and other scripts with joining behaviour actually work.

    So now the feature descriptions reference ArabicShaping.txt which is the Unicode standard that defines joining behaviour, and this conforms to how the features are actually implemented in shaping engines.

    This means that if you want to apply word-positional glyph substitutions in scripts—including scripts like Arabic if, for example, you wanted to apply a specific swash form at the end of a word—, then you would need to do this via contextual substitutions. As Nick suggests, the ignore key word is useful in capturing the beginnings and ends of things in FEA code.

    You could put the substitutions in the calt feature if you want users to have the opportunity to disable them, or put them in the rclt feature if you want them to be active by default and on all the time.

    _____

    *With the unique exception of a couple of prescript vowel signs in Bengali, which get init applied at the beginning of words; this behaviour is maintained for backwards compatibility reasons.