Mark to mark positioning

Tutorial
by Rainer Erich Scheichelbauer

12 December 2014 Published on 21 October 2012

Important: As of version 1.3.17, the mark and mkmk features are built automatically if there are combining marks with top and _top anchors present in the font. Glyphs 2 and later also auto-builds the ccmp feature. So you do not need to fiddle around with feature code anymore. However, if you do want to make your own feature coding, then note that, since version 2, dotlessi and dotlessj have been renamed to idotless and jdotless, respectively.

Mark to base positioning

Last time we learned that, through the magic powers of OpenType and Unicode, we can put any accent on any base letter. To sum it up in a nutshell, we created a Prefix in the Features tab of the Font Info and entered this:

markClass [gravecomb acutecomb circumflexcomb] <anchor 0 500> @MARK_TOP_CENTER;
markClass cedillacomb <anchor 0 0> @MARK_BOT_CENTER;

feature ccmp {
  # Glyph Composition/Decomposition
  sub i' @MARK_TOP_CENTER by dotlessi;
  sub j' @MARK_TOP_CENTER by dotlessj;
} ccmp;

feature mark {
  # Mark to Base positioning
  pos base [a n] <anchor 310 500> mark @MARK_TOP_CENTER
                 <anchor 310 0>   mark @MARK_BOT_CENTER;
  pos base [c e g o] <anchor 290 500> mark @MARK_TOP_CENTER
                     <anchor 290 0>   mark @MARK_BOT_CENTER;
  pos base [dotlessi dotlessj] <anchor 130 500> mark @MARK_TOP_CENTER
                               <anchor 130 0>   mark @MARK_BOT_CENTER;
  pos base [b h l] <anchor 130 700> mark @MARK_TOP_CENTER
                   <anchor 130 0>   mark @MARK_BOT_CENTER;
} mark;

@BASE = [ a n c e g o b h l dotlessi dotlessj ];
@MARKS = [ @MARK_TOP_CENTER @MARK_BOT_CENTER ];

table GDEF {
  GlyphClassDef @BASE,,@MARKS,;
} GDEF;

This allowed us to put a circumflex on an n and hang a cedilla on an o. Not very useful, you might say, but what if someone comes up with such an idea for a new letter? Or what if we find that a poet put dots below some of his letters in his handwritten diary to indicate syllable stress? With Unicode, we can encode it, thus type it, and with OpenType, we can actually build a font for that, and we can now make a true historical-critical edition of that poet’s archive.

Mark to mark positioning

Plus: we want to be compatible with a type rendering engine that employs character decomposition with combining accents. And in such an environment, a character sequence such as this one is possible: U+006E LATIN SMALL LETTER NU+0302 COMBINING CIRCUMFLEX ACCENTU+0303 COMBINING TILDE. In other words, first we have an n, then a circumflex that sits on top of it, and finally a tilde on top of all of that. Okay, we can encode it. But can we build it?

Yes, we can! OpenType has a feature called mkmk (Mark to Mark Positioning) which allows the positioning of accents relative to other accents. To cut a long story short, here’s what we inject into our Prefix, right after the mark feature:

feature mkmk {
  # Mark to Mark positioning

  lookup STACK_ON_TOP {
    lookupflag MarkAttachmentType @MARK_TOP_CENTER;
    pos mark [acutecomb circumflexcomb dieresiscomb dotaccentcomb gravecomb] <anchor 0 680> mark @MARK_TOP_CENTER;
    pos mark tildecomb <anchor 0 630> mark @MARK_TOP_CENTER;
  } STACK_ON_TOP;

  lookup STACK_BELOW {
    lookupflag MarkAttachmentType @MARK_BOT_CENTER;
    pos mark cedillacomb <anchor 0 -200> mark @MARK_BOT_CENTER;
  } STACK_BELOW;
} mkmk;

Okay, let’s take a closer look at this. The mkmk feature is subdivided into several lookups. Each lookup represents a certain type of attachment. In our case, we have one for attaching an accent on top of another glyph, and another one for hanging accents at the bottom. This is why the lookupflag defines a MarkAttachmentType. The MarkAttachmentType must be a previously defined markClass. We have one called @MARK_TOP_CENTER and one called @MARK_BOT_CENTER. So that’s why we have two lookups here: lookup STACK_ON_TOP and lookup STACK_BELOW.

Inside these lookups, we can define anchor positions for individual accents, or even groups of accents. This works very much like the pos base rules from the mark feature, but this time we connect to other accents with pos mark instead.

As of version 1.3.16, there is a bug which causes negative anchor coordinates to be turned positive at export time. This will likely affect the mark to mark positioning of bottom accents. As a workaround, you can either move up bottom accents until all anchors are above the baseline and change the y coordinates in your markClass definition and pos mark rule accordingly. Or you can fix the values directly in the features file of that font’s folder inside ~/Library/Application Support/Glyphs/Temp/, and re-export by double clicking generateFont.command in the same folder.

Ha, now we can have fun and shove anchors on top of other anchors, and even give each of them a different color:

Yay!

Update 2014-12-12: Updated the note and moved it to the top.