When demonstrating OTM at TYPO Labs 2018 last April, I briefly showed a small experiment with contextually offsetting diacritics that I made last year. Inspired by a Renaissance practice of moving diacritics sideways to the right to prevent collisions with terminals as, for example, can be found in the famous roman type of Nicolas Jenson, I wrote a small piece of features code that replaces precomposed characters with diacritics by mark-to-base ones.
Today the prevention of collisions of letter parts is often handled via kerning pairs. However, this can be a rather crude method because one solves the collision at the price of a gap between characters, which cripples the pattern. For example, the combination /f with /? can be improved by positive kerning, but a more elegant alternative is to provide a /f with a shortened terminal for this combination. In case of positioning accented characters, offsetting of the diacritics can be applied whether or not in combination with kerning.
The script below is a rough start that I made last year; unfortunately I did not find time to enhance it any further. I use OTM for the precise positioning of the diacritics (in the image above especially the vertical positioning of the dieresis is a bit arbitrary). It is quite possible that the generation of the mark-to-base stuff on basis of the accented characters will be included in FoundryMaster in the near future.
If you are interested, please feel free to adapt and enhance the code below. I am pretty sure that some on this forum will find room for improvement of its structure (I am not an expert).
---------------------
# --- Uses GPOS mark-to-base for characters with (contextually positioned) diacritics
# --- For the Latin script
# --- AFDKO syntax
# --- Basis for further development
# --- (c) FEB, last update: 1 May 2017
# --- LANGUAGE SYSTEMS
languagesystem DFLT dflt;
languagesystem latn dflt;
# --- KERNING
# --- To test the interaction with the stuff below:
feature kern {
pos T a -60;
pos T aacute -35;
pos T adieresis -35;
pos T ccedilla -75;
pos T e -70;
pos T eacute -70;
pos T edieresis -70;
pos T iacute 15;
pos T oacute -45;
pos T ocircumflex -15;
pos T yacute 15;
pos f a 20;
pos f aacute 10;
pos f adieresis 20;
pos f eacute -5;
pos f edieresis -15;
pos f iacute 25;
pos f oacute -10;
pos f yacute 40;
} kern;
# --- MARK CLASSES
# --- To prevent that all diacritics are combined with all base letters, lookups are used to form groups
lookup MRKCLS_1 {
# --- Standard combinations with diacritics on top:
markClass [gravecomb acutecomb circumflexcomb dieresiscomb tildecomb caroncomb macroncomb] <anchor 0 0>
@DIACRITIC_TOP_1;
pos base [a c e o s u y z] <anchor 0 0> mark
@DIACRITIC_TOP_1;
} MRKCLS_1;
lookup MRKCLS_2 {
# --- Variant of MRKCLS_1 to offset diacritics in relation to T (‘calt' feature):
markClass [gravecomb acutecomb circumflexcomb dieresiscomb tildecomb caroncomb macroncomb] <anchor -50 0>
@DIACRITIC_TOP_2;
pos base [a c e o s u y z] <anchor 0 0> mark
@DIACRITIC_TOP_2;
} MRKCLS_2;
lookup MRKCLS_3 {
# --- Variant of MRKCLS_1 to offset diacritics in relation to f (‘calt' feature):
markClass [gravecomb acutecomb circumflexcomb dieresiscomb tildecomb caroncomb macroncomb] <anchor -30 0>
@DIACRITIC_TOP_3;
pos base [a c e o s u y z] <anchor 0 0> mark
@DIACRITIC_TOP_3;
} MRKCLS_3;
lookup MRKCLS_4 {
# --- Adapted diacritics for i and j:
markClass [gravecomb.i acutecomb.i circumflexcomb.i dieresiscomb.i tildecomb.i caroncomb.i macroncomb.i] <anchor 0 0>
@DIACRITIC_TOP_4;
pos base [dotlessi] <anchor 0 0> mark
@DIACRITIC_TOP_4;
} MRKCLS_4;
lookup MRKCLS_5 {
# --- Combinations with diacritics below baseline:
markClass [cedillacomb ogonekcomb] <anchor 0 0>
@DIACRITIC_BELOW_1;
pos base [a c] <anchor 0 0> mark
@DIACRITIC_BELOW_1;
} MRKCLS_5;
feature ccmp {
# --- Glyph Composition/Decomposition:
# --- Substitutes the i and j:
sub i'
@DIACRITIC_TOP_3 by dotlessi;
sub j'
@DIACRITIC_TOP_3 by dotlessj;
# --- Substitutes precomposed characters with diacritics with mark-to-base variants:
sub agrave by a gravecomb;
sub egrave by e gravecomb;
sub igrave by i gravecomb.i;
sub ograve by o gravecomb;
sub ugrave by u gravecomb;
sub aacute by a acutecomb;
sub eacute by e acutecomb;
sub iacute by i acutecomb.i;
sub oacute by o acutecomb;
sub uacute by u acutecomb;
sub yacute by y acutecomb;
sub acircumflex by a circumflexcomb;
sub ecircumflex by e circumflexcomb;
sub icircumflex by i circumflexcomb.i;
sub ocircumflex by o circumflexcomb;
sub ucircumflex by u circumflexcomb;
sub adieresis by a dieresiscomb;
sub edieresis by e dieresiscomb;
sub idieresis by i dieresiscomb.i;
sub odieresis by o dieresiscomb;
sub udieresis by u dieresiscomb;
sub ydieresis by y dieresiscomb;
sub atilde by a tildecomb;
sub etilde by e tildecomb;
sub itilde by i tildecomb.i;
sub ntilde by n tildecomb;
sub otilde by o tildecomb;
sub utilde by u tildecomb;
sub ytilde by y tildecomb;
sub scaron by s caroncomb;
sub zcaron by z caroncomb;
} ccmp;
feature calt {
# --- For offsetting diacritics based on contextual characters:
sub T
@DIACRITIC_TOP_1' by
@DIACRITIC_TOP_2;
sub f
@DIACRITIC_TOP_1' by
@DIACRITIC_TOP_3;
} calt;
feature mark {
# --- Mark-to-base positioning
lookup MRKCLS_1;
lookup MRKCLS_2;
lookup MRKCLS_3;
lookup MRKCLS_4;
lookup MRKCLS_5;
} mark;
# --- Declaring base characters and marks for the Glyph Definition table:
@BASE = [a c e o s u y z dotlessi];
@MARKS = [
@DIACRITIC_TOP_1 @DIACRITIC_TOP_2 @DIACRITIC_TOP_3 @DIACRITIC_TOP_4 @DIACRITIC_BELOW_1];
table GDEF {
GlyphClassDef
@BASE,,
@MARKS,;
} GDEF;
---------------------
Comments
Are there combinations like ffá and the like?
Do you have a similar script for Vietnamese?
Yes. Initially, I thought InDesign was failing to apply contextual ccmp substitutions (i.e. decomposing precomposed diacritics only when followed by a combining mark), but then noted that the same problems occurred when I removed the context statement from the lookups. As you say, it looks like they're post-processing recomposition of Unicode precomposed diacritics after running ccmp. Which is as you say, unintuitive and non-compliant, and to which I might add a few less polite adjectives.