Tutorial #7

Conditional Features

OpenType and Apple fonts both provide contextual features. These are features which only take place in a given context and are essential for typesetting Indic and Arabic scripts. In OpenType a context is specified by a set of patterns that are tested against the glyph stream of a document. If a pattern matches then any substitutions it defines will be applied. In an Apple font, the context is specified by a state machine -- a mini program which parses and transforms the glyph stream.

Conditional features may involve substitutions, ligatures or kerning (and some more obscure behaviors). First I shall provide an example of a contextual substitution, later of contextual ligatures.

Instead of an Indic or Arabic example, let us take something I'm more familiar with, the problem of typesetting a latin script font where the letters ``b,'' ``o,'' ``v'' and ``w'' join their following letter near the x-height, while all other letters join near the baseline. Thus we need two variants for each glyph, one that joins (on the left) at the baseline (the default variant) and one which joins at the x-height. Let us call this second set of letters the ``high'' letters and name them ``a.high,'' ``b.high'' and so forth.

OpenType Example

Warning
The following example may not work! The font tables produced by it are all correct, but the designers of OpenType (or its implementors) decided that the latin script does not need complex conditional features and many implementations of OpenType do not support them for latin. This is not even mentioned in the standard, but is hidden away in supplemental information on microsoft's site.

Why do I provide an example which doesn't work? It's the best I can do. If I knew enough about Indic or Arabic typesetting I would provide an example for those scripts. But I don't. The procedures are the same. If you follow them for some other scripts they will work.

On some systems and in some applications 'calt' is supported for latn and this example will work. On other systems/applications the example can be made to work by replacing the 'calt' feature tag (conditional alternatives) with a Required tag (but I gather that is now deprecated).

We divide the set of possible glyphs into three classes: the letters ``bovw'', all other letters, and all other glyphs. We need to create two patterns, the first will match a glyph in the ``bovw'' class followed by another glyph in the ``bovw'' class, while the second will match a glyph in the ``bovw'' class followed by any other letter. If either of these matches the second glyph should be transformed into its high variant.

(You might wonder why I don't just have a class of all letters and use one rule instead of two? Because in this case all my classes must be disjoint, I mayn't have one glyph appearing in two classes).

The first thing we must do is create a simple substitution mapping each low letter to its high variant. Let us call this substitution by the four character OpenType tag ``high.'' To define the substitution we use Element -> Glyph Info as before except that here we use the special ``script / language'' called ``--- Nested ---'' (an option in the pulldown menu).

The tricky part is defining the context. This is done with the Contextual tab in the Element -> Font Info dialog, revealing five different types of contextual behavior, we are interested in contextual chaining substitutions.

You can add a new entry by pressing the [New] button. This brings up a series of dialogs, the first requests a four character OpenType tag and a script / language (much as we saw earlier).

In this example we are using 'calt'. That seems an apropriate tag, until you discover that it is not implemented for the Latin script. Indeed there seems to be no appropriate feature that is implemented for Latin. The example will produce a font, which while syntactically correct, will never do anything. It is frustrating that OpenType provides the capabilities needed to do wonderous things, and then to find that MicroSoft doesn't let that happen in Latin.

The next dialog allows you to specify the overall format of the substitution. We want a class based system -- we've already mentioned what the glyph classes will be.

The next dialog finally shows something interesting. At the top are a series of patterns to match and substitutions that will be applied if the string matches. Underneath that are the glyph classes that this substitution uses. A contextual chaining dialog divides the glyph stream into three categories: those glyphs before the current glyph (these are called backtracking glyphs), the current glyph itself (you may specify more than one), and this (these) glyphs may have simple substitutions applied to them, and finally glyphs after the current glyph (these are called lookahead glyphs).

Each category of glyphs may divide glyphs into a different set of classes, but in this example we use the same classes for all categories (this makes it easier to convert the substitution to Apple's format). The first line (in the ``List of lists'' field) should be read thus: If a backtracking glyph (the glyph before the current one) in class 1 is followed by the current glyph in class 2, then location 0 --the only location -- in the match string (that is the current glyph) should have simple substitution `high' applied to it.

If you look at the glyph class definitions you will see that class 1 includes those glyphs which must be followed by a high variant, so this seems reasonable.

The second line is similar except that it matches glyphs in class 1. Looking at the class definitions we see that classes 1 & 2 include all the letters, so these two lines mean that if any letter follows one of ``bovw'' then that letter should be converted to its `high' variant.

To edit a glyph class simply double click on it. To create a new one press the [New] button (under the class list). This produces another dialog showing all the names of all the glyphs in the current class. Pressing the [Select] button will set the selection in the font window to match the glyphs in the class, while the [Set] button will do the reverse and set the class to the selection in the font window. These provide a short cut to typing in a lot of glyph names.

Pressing the [Next] button defines the class and returns to the overview dialog.

To edit a pattern double click on it, or to create a new one press the [New] button (under the List of lists). Again the pattern string is divided into three categories, those glyphs before the current one, the current one itself, and any glyphs after the current one. You choose which category of the pattern you are editing with the tabs at the top of the dialog.

Underneath these is the subset of the pattern that falls within the current category, the classes defined for this category, and finally the substitutions for the current glyph(s). Clicking on one of the classes will add the class number to the pattern.

To edit a substitution double click on it, or to create a new one press the [New] button (under ``An ordered list...''). The sequence number specifies which glyph among the current glyphs should be modified, and the tag specifies a four character substitution name

A warning about contextual behavior: Not all software supports them. And even more confusing software may support them for some scripts and not for others.

Apple advanced typography

Apple specifies a context with a finite state machine, which is essentially a tiny program that looks at the glyph stream and decides what substitutions to apply. Each state machine has a set of glyph class definitions (just as in the OpenType example), and a set of states. The process begins in state 0 at the start of the glyph stream. The computer determines what class the current glyph is in and then looks at the current state to see how it will behave when given input from that class. The behavior includes the ability to change to a different state, advancing the input to the next glyph, applying a substitution to either the current glyph or a previous one (the ``marked'' glyph).

Using the same example of a latin script font... We again need a simple substitution to convert each letter into its high alternate. The process is the same as it was for OpenType, and indeed we can use the same substitution. Again we divide the glyphs into three classes (Apple gives us some extra classes whether we want them or no, but conceptually we use the same three classes as in the OpenType example). We want a state machine with two states (again Apple gives us an extra state for free, but we shall ignore that), one is the start state (the base state -- where nothing changes), and the other is the state where we've just read a glyph from the ``bovw'' class.

Again we use the Element -> Font Info dialog and the Mac SM tag to look at the contextual substitutions available. Again there are several types of contextual behavior, and we are interested in contextual substitutions. Double clicking on a state machine, or pressing the [New] button provides an overview of the given state machine.

At the top of the dialog we see a field specifying the feature / setting of the machine, this is Apple's equivalent of the OpenType 4 character feature tag. Under this is a set of class definitions, and at the bottom is a representation of the state machine itself.

Double clicking on a class brings up a dialog similar to that used in OpenType

Clicking on a transition in the state machine (there is a transition for each state / class combination) produces a transition dialog. This controls how the state machine behaves when it is in a given state and receives a glyph in a given class. In this example it is in state 2 (which means it has already read a ``bovw'' glyph), and it has received a glyph in class 4 (which is another ``bovw'' glyph). In this case the next state will be state 2 again (we will have just read a new ``bovw'' glyph), read another glyph and apply the ``high'' substitution to the current glyph.

At the bottom of the dialog are a series of buttons that allow you to navigate through the transitions of the state machine.

Pressing [OK] many times will extract you from this chain of dialogs and add a new state machine to your font.

OpenType, Greek ligatures

Greek has a character (U+03D7) which is equivalent to the Latin ampersand. Just as the ampersand is (originally) a ligature of "E" and "t", so U+03D7 is a ligature of "kappa" and "iota". However this ligature should only be used if "kappa" and "iota" make up a word unto themselves, it should not be used for more normal occurances of the two within a longer word.

So the first thing to do is create the ligature itself. Add an unencoded glyph to your font with Encoding->Add Encoding Slots, name it "kappa_iota.word" (with Element->Glyph Info), then draw your glyph, and finally with Element->Glyph Info->Ligature make it be a ligature of "kappa" and "iota". As above we make up a tag (in this case called "WORD") and we use "Nested" for the Script. This feature (lookup actually) will never be used directly -- only under the control of another, a conditional feature, so we don't want it to look anything like something which might get invoked on its own.

Next the conditional bit.

I'm going to use the notation <letters> to represent a class consisting of all greek letters.

  1. <letters> kappa iota => no substitution
  2. kappa iota <letters> => no substitution
  3. kappa iota => apply the ligature "WORD"

These rules will be executed in order, and the first one that matches the input text will be the (one and only) rule applied. Consider these three strings, , , all contain kappa and iota but none contains only those two letters, so none should be replaced by the ligature.

You might wonder why I don't just have one rule

  1. <any non-letter> kappa iota <any non-letter> => apply our ligature

It seems much simpler.

Well there's one main reason:

Now how do we convert these rules into a contextual feature?

We use Element->Font Info->Contextual->Chain Sub to bring up a list of all Contextual Chaining substitutions in this font (so far there are none).

Then we press the [New...] button to create our conditional ligature. As always we need to specify a tag an a script. This feature is one we want applied directly, so we want a standard script and tag. The script is greek, and the tag is for Historic Ligatures.

After pressing the [OK] button we will be asked to design the contextual feature itself.

Since we are planning on using the class of all greek letters we will want to use a class format for this feature. Then we press the [Next>] button.

The main match will be on the letters kappa and iota in all three rules, so we need one class for each of them. So in the Match Classes area we press the [New] button...

And type in the word "kappa" and press [Next>]

Now we have a class containing the single glyph "kappa". We want to do the same thing for "iota" so we press [New] again.

Again type in "iota" and press [Next>]

Now we have all the classes we need here. We still need to create classes for the lookahead and backtrack. We only need one class for these groups and that class will consist of all greek letters.

The check box [*] Same as Match Classes is set, but we don't want that, we want our own classes here. So uncheck it.

Now the buttons become active and we can create a new class by pressing [New]

Before doing anything else, go back to the font view and select all the greek letters.

Then, in the dialog, press the [Set From Font] button, and the font's selection is transfered and becomes the current class. Then press [Next>].

Then go through the same process for the look ahead classes (adding one class which consists of all the greek letters.
Now we have all our classes defined and are finally ready to create the patterns for our rules. So underneath "List of lists of class numbers" press the [New] button.
The first rule begins with all the greek letters in the backtrack area, so click on the "Backtrack" tab, and then press on the class consisting of all the greek letters. This puts the class number into the pattern area (the List of class numbers)
In the match area we want to match kappa and then iota, so click on the Match tab, and then on the entries for "kappa" and "iota".

This rule has no substitutions, so leave the bottom area blank and press [Next>].
We are done with the first rule. It says:
  • The previous character should match class 1 of the backtrack classes (and that class contains all greek letters, which is what we want)
  • The current character should match class 1 of the match classes (and that class contains "kappa")
  • The next character should match class 2 of the match classes (which is iota)
  • And if the match is successful, do absolutely nothing.


We've got two more rules though, so press [New] again and go through the same steps, except using the lookahead area rather than the backtrack.

We are done with the second rule. It says:
  • The current character should match class 1 of the match classes (and that class contains "kappa")
  • The next character should match class 2 of the match classes (which is iota)
  • The character after that should match class 1 of the lookahead classes (and that class contains all the greek letters)
  • And if the match is successful, do absolutely nothing.


Press [New] for the final rule.


This rule does have substitutions -- we want to take the two characters and convert them into a ligature. So Press [New] under the sequence position list, we want to start at the first character (sequence position 0) and apply the ligature we called "WORD":
So if anything doesn't match the first two rules, and does contain a kappa followed by an iota, it must be a two letter stand-alone greek word. And we want to apply our ligature to it.
Now we are done. Press a series of [OK]s until all the dialogs have been accepted.

-- Prev -- TOC -- Next --