simoncozens / fontFeatures

Python library for manipulating OpenType font features
BSD 3-Clause "New" or "Revised" License
72 stars 9 forks source link

otf2fea changes the behavior of chaining rules with non-single substitution lookup references #52

Closed dscorbett closed 2 years ago

dscorbett commented 2 years ago
$ curl -LOs https://github.com/googlefonts/noto-fonts/raw/6ba0153eb79a01d69f96fbd87512fe1ca1e778ef/unhinted/otf/NotoSansTirhuta/NotoSansTirhuta-Regular.otf
$ ttx -o - -q -t GSUB NotoSansTirhuta-Regular.otf | sed -n 741,757p
            <ChainSubClassRule index="2">
              <!-- BacktrackGlyphCount=0 -->
              <!-- InputGlyphCount=4 -->
              <Input index="0" value="4"/>
              <Input index="1" value="1"/>
              <Input index="2" value="2"/>
              <!-- LookAheadGlyphCount=0 -->
              <!-- SubstCount=2 -->
              <SubstLookupRecord index="0">
                <SequenceIndex value="0"/>
                <LookupListIndex value="6"/>
              </SubstLookupRecord>
              <SubstLookupRecord index="1">
                <SequenceIndex value="2"/>
                <LookupListIndex value="7"/>
              </SubstLookupRecord>
            </ChainSubClassRule>
$ otf2fea NotoSansTirhuta-Regular.otf | sed -n 394p
    sub ta_tirh' lookup LigatureSubstitution7 virama_tirh' @class2' lookup MultipleSubstitution8 @class3';

This changes the meaning of the rule. MultipleSubstitution8 is supposed to apply to @class3. otf2fea shows it as applying to @class2 because, after LigatureSubstitution7 is applied, subsequent glyphs’ sequence indices are one less than what they were. However, example 1 of section 5.f.i of the feature file spec shows that lookup references are written immediately after the glyphs they apply to, without taking into account how other lookups change glyphs’ sequence indices. Therefore, otf2fea should decompile this rule to:

    sub ta_tirh' lookup LigatureSubstitution7 virama_tirh' @class2' @class3' lookup MultipleSubstitution8;
simoncozens commented 2 years ago

I am literally dealing with this issue right now! (With that particular font, indeed.)

simoncozens commented 2 years ago

If you're doing exactly what I'm doing (and it does rather look like you're doing exactly what I'm doing), the new script otflayout2glyphs.py might prove useful.

dscorbett commented 2 years ago

See also fonttools/fonttools#2469.

simoncozens commented 2 years ago

The more relevant issue here is https://github.com/adobe-type-tools/afdko/issues/1167

The MTI rules call for the single subst to be applied first, and then the ligature lookup afterwards, which avoids the problem of the glyph positions changing. But in FEA chaining lookups are assumed to apply left to right. So in the general case this kind of rule cannot be decompiled for FEA.

simoncozens commented 2 years ago

(Or maybe that was Sharada. Very similar issue with multiple applications on the same chaining rule, anyway.)

dscorbett commented 2 years ago

I trusted the spec, but the spec lied. otf2fea is behaving correctly.