Introduction to OpenType Programming
The Adobe feature language
Basic feature coding - substitutions and ligatures
Glyph Classes and Named Classes
Features and lookups
Scripts and languages
How OpenType shaping works<br>Mapping and reordering
Rule selection
Lookup application
Lookup Flags
Positioning rules
Building a testing environment<br>Using hb-shape for feature testing
How features are stored
Decompiling a font
In the previous chapter we looked at some of the data tables hiding inside an OpenType font. And let’s face it, they weren’t all that interesting - metrics, character mappings, a few Bézier splines or drawing instructions. The really cool part about OpenType (and its one-time rival, Apple Advanced Typography) is the ability to program the font. OpenType’s collaborative model, which we discussed in our chapter on history, allows the font to give instructions to the shaping engine and control its operation.
When I use the word “instruction” in this chapter, I’m using the term in the computer programming sense - programs are made up of instructions which tell the computer what to do, and we want to be telling our shaping engine what to do. In the font world, the word “instruction” also has a specific sense related to hinting of TrueType outlines, which we’ll cover in the chapter on hinting.
“Smart fonts”, such as those enabled by OpenType features, can perform a range of typographic refinements based on data within the font, from kerning, ligature substitution, making alternate glyphs available to the user, script-specific and language-specific forms, through to complete substitution, reordering and repositioning of glyphs.
Specifically, two tables within the font - the GPOS and GSUB tables - provide for a wide range of context-sensitive font transformations. GPOS contains instructions for altering the position of glyph. The canonical example of context-sensitive repositioning is kerning, which modifies the space between two glyphs depending on what those glyphs are, but GPOS allows for many other kinds of repositioning instructions.
The other table, GSUB, contains instructions for substituting some glyphs for others based on certain conditions. The obvious example here is ligatures, which substitutes a pair (or more) of glyphs for another: the user types “f” and then “i” but rather than displaying those two separate glyphs, the font tells the shaping engine to fetch the single glyph “fi” instead. But once again, GSUB allows for many, many interesting substitutions - some of which aren’t merely typographic niceties but are absolutely essential when engineering fonts for complex scripts.
In this chapter, we’re going to begin to look at these instructions, how we get them into our font, and how they work; in the following two chapters, we’ll look more systematically at what instructions are available, and how we can use them to create fonts which support our global scripts.
The Adobe feature language
OpenType instructions - more usually known as “rules” - are normally written in a language that doesn’t exactly have a name; it’s known variously as “AFDKO” (from the “Adobe Font Development Kit for OpenType”, a set of software tools one of which reads this syntax and adds the rules into binary font files), “Adobe feature language”, “fea”, or “feature format”. Other ways of representing rules are available, (and inside the font they are stored in quite a different representation) but this is the most common way that we can write the rules to program our fonts.
There are a number of alternatives to AFDKO for specifying OpenType layout features - Microsoft’s VOLT (Visual OpenType Layout Tool), my own FLUX (Font Layout UX), and High Logic FontCreator all allow you to create features and proof and preview them visually. Monotype also has their own internal editor, FontDame, which lays out OpenType features in a text file. (I’ve also written an alternative syntax called FEE, which allows for extensions and plugins to add higher-level commands to the language.)
But Adobe’s language is the one that almost everyone uses, and as a font engineer, you’re going to need to know it very well. So let’s begin.
Basic feature coding - substitutions and ligatures
Here is the simplest complete OpenType program:
feature liga {<br>sub f f by f_f;<br>} liga;
Read this as “in the liga feature, substitute the glyphs f f by f_f.” This assumes that we have at least two glyphs in our font, one of which is called f and another which is called f_f. Later on we’ll see precisely what we mean by “feature” and why we made one called liga, but for now what you need to know is that we have created a rule that will be applied by the shaper whenever some text is set in our font.
The feature language has a simple syntax. The full details are available as part of the AFDKO Documentation, but the basics are fairly easy to pick up by inspection; a feature is defined like so:
feature { ... } ;
We created a feature called liga...