Skip to content

Extending the Feature File Syntax

Rainer Erich Scheichelbauer edited this page Mar 14, 2021 · 8 revisions

Extending the Feature File Syntax in Glyphs

This is our suggestion for extending the .fea format and we would like to discuss it with the community. We like the overall structure, yet are open to changes. Some of the syntax extensions described here are already implemented in Glyphs 3.

GSUB Feature Variations

This example shows two things: firstly, the condition syntax for feature variations, and secondly, preprocessor macros for hiding code from static or variable exports, respectively:

#ifdef VARIABLE
    condition 600 < wght < 900;
    sub dollar by dollar.bold;

    condition 600 < wght < 900, 70 < wdth < 90;
    sub won by won.boldcondensed;
#endif

The condition rule defines one or more axis ranges for which the following sub rules apply. It only makes sense for variable font exports, and applies to all code that follows until another condition statement defines a new range, or until the preprocessor macro closes with #endif. A condition rule starts with the keyword condition, followed by one or more comma-separated axis ranges, and finished with a semicolon ;. Each axis range needs a range minimum, followed by a less sign <, followed by the four-letter axis tag, followed by another less sign < and the range maximum. Range minima ad maxima are written in axis coordinates.

Lines between #ifdef VARIABLE and #endif will be considered only in variable font exports and hidden in static exports. Lines between #ifndef VARIABLE (note the additional n in ifndef) and #endif are used for static fonts only, and are hidden in variable exports.

Status: already implemented in Glyphs 3 . For now, only the VARIABLE macro is defined, though other predefined and potentially also customised use cases are thinkable.

Variable GPOS

The following is an extension to the value record syntax for specifying multiple value records for different positions in the design space. Inside the value record delimiters < and >, additional comma-separated value sets can be added after the default value set. Each additional value set is prefixed with a design space position. A design space position is enclosed in ( and ) parentheses and contains a space-separated list of axistag:axisposition pairs. Followed by a set of the four numbers in the known format.

pos a b <10 0 10 0, (wght:180 wdth:12) 30 0 30 0, (wght:78 wdth:6) 25 0 25 0>;

For keeping things consistent and for saving some typing, design space positions can be defined and reused in references. Reference names must be unique single words, and prefixed with a § section sign. References must be defined with the reference name, followed by an equals sign =, followed by the parenthesis structure for the design space coordinate as described above, and closed with a semicolon ;:

§Bold = (wght:180 wdth:12);
§Cond = (wght:78 wdth:6);
pos a b <10 0 10 0, §Bold 30 0 30 0, §Cond 25 0 25 0>;

The same applies to anchor definitions:

markClass [dieresiscomb] <anchor 191 517, (wght:180 wdth:12) 203 512, (wght:78 wdth:6) 120 523> @mark_top;

§Bold = (wght:180 wdth:12);
§Cond = (wght:78 wdth:6);
markClass [dieresiscomb] <anchor 191 517, §Bold 203 512, §Cond 120 523> @mark_top;

Status: will be implemented in Glyphs 3 soon.

New Keywords

To improve the capability of feature code, we suggest a couple of new keywords.

Keyword delete

delete or del removes the glyphs or class that follows from the glyph stream:

del swashright;
del @SWASHES;

It is intended as a better and more flexible notation for the currently implemented substitution with null.

This can be useful for removing helper glyphs. Its true power, however, lies in the contextual notation:

del a connector' b c;
del @A @CONNECTORS' @B @C;

Status: not yet implemented in Glyphs 3.

Keyword swap

swap switches the the position of the two glyphs that follow:

swap a b;

The above example turns the glyphs sequence a b into b a.

As long as exactly two glyphs are marked, you can swap glyphs contextually:

swap a b' c' d e; # result: a c b d e
swap a b' c d' e; # result: a d c b e

Status: not yet implemented in Glyphs 3.

Tokens

Tokens are pieces of code preceded by a $ dollar sign. They expand into spelled-out code, and can be used anywhere the substituted result makes sense. Principally, you would use tokens for two purposes: number values and predicates.

Number values: interpolating variables

First, a token can serve as a number value which you can define previously either as static number (for keeping consistency) or as a variable value at certain design space coordinates. In short, number values are variables that interpolate. In the Glyphs UI, you can define number values in File > Font Info > Masters > Number Values.

Example 1: in Font Info > Masters, you define a number value called pad as 50 in the Light, and 5 in the Bold master. In your feature code, you add a kern feature with something like this:

pos @L @A $pad;

And in the resulting GPOS feature code, the respective interpolated value of pad would get inserted in the token’s place.

Example 2: in the cpsp (Capital Spacing feature, add a positioning rule like this:

pos @brackets <$pad 0 ${pad*2} 0>

Inside a ${...} structure, you can add calculations. For more examples and a detailed discussion, see the Glyphs tutorial ‘Positioning with Number Values’.

Status: Number values are currently implemented in Glyphs for static font exports. More details in the Tokens tutorial.

Predicate tokens: logical description of glyphs

Predicate tokens have a $[...] structure, and what you can put between these square brackets is pure NSPredicate code for dynamically collecting glyph names for feature classes. One example:

sub [ $[case==smallCaps] ] slash' by slash.sc;

The structure $[case==smallCaps] expands to a.sc b.sc c.sc d.sc and so on, so it expands to:

sub [ a.sc b.sc c.sc d.sc ] slash' by slash.sc;

More code samples for predicate tokens:

$[name endswith '.sc'] # will expand to all glyph names that end in ".sc"
$[layer0.width < 500] # layer0 = first master
$[layers.count > 1] # compare numbers with: == != <= >= < >
$[direction == 2] # 0=LTR, 1=BiDi, 2=RTL
$[colorIndex == 5]
$[case == smallCaps] # predefined constants: noCase, upper, lower, smallCaps, minor, other
$[name matches "S|s.*"] # "matches": regular expression
$[leftMetricsKey like "*"] # "like": wildcard search
$[name like "*e*"] # e anywhere in the name
$[script like "latin"]
$[category like "Separator"]
$[leftKerningGroup like "H"]
$[rightKerningGroup like "L"]
$[unicode beginswith "03"] # beginswith, endswith, contains
$[note contains "love it"] # glyph note
$[countOfUnicodes > 1]
$[countOfLayers > 1]
$[subCategory like "Arrow"]
$[hasHints == 0] # boolean: false, no, 0 versus true, yes, 1
$[isColorGlyph == true]
$[hasComponents == true and script == "latin"] # connect multiple conditions with OR, AND, XOR
$[hasTrueTypeHints == false]
$[hasAlignedWidth == true]
$[hasPostScriptHints == true]
$[hasAnnotations == true]
$[hasCorners == true] # corners = corner components
$[hasSpecialLayers == yes] # special layers = color, brace and bracket layers

Those keys are from the Glyphs API. We would be happy to standardize them.

Status: implemented in Glyphs 3. More details in the Tokens tutorial.