googlefonts / ufo2ft

A bridge from UFOs to FontTools objects (and therefore, OTFs and TTFs).
MIT License
152 stars 43 forks source link

Write GDEF feature writer #456

Closed madig closed 3 years ago

madig commented 3 years ago

Storing GDEF information in features.fea is possible and done today but is also very much annoying. One, it needs separate maintenance and two, it instance interpolation is not made to interpolate feature files, so ligature caret positions are taken from the default source.

The UFO spec now allows to generate a complete GDEF at compile time:

  1. LigatureCaretByPos can be generated from https://github.com/unified-font-object/ufo-spec/blob/gh-pages/versions/ufo3/glyphs/glif.md#ligature-carets (existing issue https://github.com/googlefonts/ufo2ft/issues/329)
  2. GlyphClassDef can be generated from https://unifiedfontobject.org/versions/ufo3/glyphs/glif/#publicopentypecategory

So, someone needs to sit down and write a GDEF writer for ufo2ft. Since it runs after all (anchor propagation) filters, we might not even need to store any categories, or only when you want to override something somewhere. GDEF generation is already done by code in glyphsLib, so that can be used as a start.

anthrotype commented 3 years ago

mind that the markFeatureWriter behaves differently when a GDEF with GlyphClassDefs is found in the feature file. So that the order in which you run the feature writers may influence the result.

When GDEF is not present, the mark-ness of a glyph is guessed by the presence of _-prefixed attaching anchors (i.e. with an accompanying non-_-prefixed anchor somewhere else); ligature-ness is guessed with the presence of base anchors with _1, _2 etc. suffixes (IIRC), etc. This in turn makes so that feaLib builder will generate a GDEF table based on the way glyphs are used in GPOS mark lookups: e.g. if a glyph is used as a mark, it gets mark category, etc.

When a GDEF is present, the explicit categories will limit the pool of glyphs that the mark feature writer is going to use. So if a glyph is not marked as "Mark" it'll be ignored even if it may have some attaching anchors. And that GDEF definition will be compiled verbatim by feaLib builder later in the pipeline.

anthrotype commented 3 years ago

so in general, you want to run that GDEF writer before the mark feature writer (like currently the GDEF generation happens in glyphsLib before the ufo2ft mark feature writer)

anthrotype commented 3 years ago

another approach could be that you teach the mark feature writer about these new public.openTypeCategory key, so that they have the same effect of an explicit GDEF table override in the features.fea.

Then you only add a LigatureCaretsFeatureWriter or something to handle the carets only

benkiel commented 3 years ago

@madig Feel free to steal from: https://github.com/arrowtype/recursive/blob/948937aa33b1b04713627475e4ad75cb3e5cadf1/mastering/utils.py#L156. Though, it's likely not robust enough. @anthrotype's idea of teaching the mark feature writer about the openTypeCategory keys is a good one.

Ligature carets are easy, that code above assumes left to right, so you'd want to order on the caret number, but the idea is there.

moyogo commented 3 years ago

Yes, the mark feature writer should use openTypeCategories, that's why it was added ;-) In case of disagreement between a GDEF glyph class definitions and openTypeCategories for a glyph, the GDEF in feature code should probably be preferred.

I don't think the GDEF should be written before the mark feature writer runs.

If a glyph has anchors that would make it base, mark or ligature, before or after anchor propagation, but it should not be in lookups that would classify it in one of those GDEF mark glyph class: set its openTypeCategories value to the desired value. The propagate anchors filter should not copy anchors that would change its class from openTypeCategories. The mark feature writer should not use that glyph in those lookups.

If a glyph doesn't have anchors that would place it in lookups defining its GDEF glyph class, before or after anchor propagation, but it should be in one of those classes for lookups with ignoreBasesGlyphs/Ligatures/Marks: set its openTypeCategories value.

moyogo commented 3 years ago

I've opened https://github.com/googlefonts/ufo2ft/pull/480 to add a GDEF Feature Writer.