simoncozens / fontFeatures

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

Support mark-to-ligature rules #38

Open simoncozens opened 3 years ago

simoncozens commented 3 years ago

Currently the only thing that otf2fea / fontFeatures.ttLib.GPOSUnparser is missing is support for mark to ligature rules.

The reason I haven't implemented them is that I am not sure how to fit them into fontFeatures' model of layout. fontFeatures deliberately does not follow the OpenType GSUB/GPOS layout model (the idea being that when another font layout model comes along we can target that as well). So collections of rules are called Routines not Lookups to help you remember that this is not specifically OpenType, but font layout in general.

In fontFeatures model of layout, there are four fundamental operations, Substitution, Positioning, Attach, Chain. Attach sticks two glyphs together. OpenType splits this operation into mark-to-base and mark-to-mark, which I think is unnecessary. You do something different for marks that you do for bases, fine, but you know if something is a mark or a base because of GDEF. So in fontFeatures, you just have an attachment between two sets of glyphs, and if the first one of those glyphs is defined as being a mark glyph, then when we convert to OpenType, a mark-to-mark rule is emitted instead of a mark-to-base rule.

But mark-to-ligature is a bit of an outlier because it can stick glyphs together in different places, not just one-to-one. I don't know if this can be represented with our simple "Attach" model, because to be honest I don't understand mark-to-ligature well enough.

So to support mark-to-ligature:

khaledhosny commented 3 years ago

You could add the component index to anchor names (top_1 like Glyphs does) when defining the anchors:

Anchors f_i { top_1 <...> top_2 <...> bottom_1 <...>  bottom_2 <...>};

Then add ligatures class filter that would look for anchors named with this pattern and the routine would be:

Feature mark { Attach &top &_top ligatures; };
khaledhosny commented 3 years ago

(or bases filter could be overloaded to look for ligature anchors as well).

simoncozens commented 3 years ago

That would work OK for FEE but at the fontFeatures representation level I want to avoid magic naming conventions. I already do that for cursive and it feels like a bit of a hack. I think what needs to happen is to have arrays of base/mark dictionaries instead of a single dictionary. That would be more nicely parallel with Substitution/Position where we have arrays of glyphclasses with each element representing a “slot” in the glyphstream.

khaledhosny commented 3 years ago

Even better. I don't like hard-coded naming conventions either.

arrowtype commented 2 years ago

Sorry, but just to be sure I understand – is this issue the reason for a warning like # [warning] # XXX Unparsable rule: Mark to lig pos in 3 when I run otf2fea on a font?

In other words, is it correct that the warning is simply letting me know of a non-supported feature in otf2fea, rather than a problem in my font? (If so, maybe the language could be adjusted slightly, perhaps even pointing to this issue? Something like... # [warning] Unparsable rule: Mark to ligature in lookup 3. otf2fea does not currently support the parsing of mark-to-ligature lookups. See https://github.com/simoncozens/fontFeatures/issues/38 for details.)

And just to clarify so I properly get it ... when might a mark-to-ligature rule this happen? (I've spent some time searching for this in the OpenType spec, but I'm having trouble finding specific references)

Lookup 3 in this particular font is replacing the i with idotless and j with jdotless ... I'm a little confused by how my locl fea code translates into the GSUB table, but I suppose this must be tied up with how NLD is supported...

      <Lookup index="3">
        <LookupType value="1"/>
        <LookupFlag value="0"/>
        <!-- SubTableCount=1 -->
        <SingleSubst index="0">
          <Substitution in="uni0069" out="uni0131"/>
          <Substitution in="uni006A" out="jdotless"/>
        </SingleSubst>
      </Lookup>

Thanks for any help in understanding this! I'm on a wild goose chase, and not sure whether or not this is part of my current problem or not.

simoncozens commented 2 years ago

You’re right that this is about a valid rule within the font that the fontFeatures library can’t represent. So fixing the message would be good.

mark to ligature lookups are about placing accents on ligature glyphs. They’re positioning rules so the lookup number refers to the GPOS table, not the GSUB table.

arrowtype commented 2 years ago

Ah, that helps a lot! Thanks so much for the quick and informative reply.