googlefonts / ufo2ft

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

use instantiator when decomposing "sparse" composite glyphs #826

Closed anthrotype closed 7 months ago

anthrotype commented 8 months ago

https://github.com/googlefonts/glyphsLib/issues/954

So.. In Glyphs.app there's a nifty feature which I'll call "sparse" composite glyph for lack of better name, whereby you can have a composite glyph that defines additional or fewer masters (sources, layers, whatever you call it) than some of its component glyphs.

Eg. imagine a font with 1 weight axis and 3 masters, Regular (default), Medium and Bold; the "Agrave" composite glyph references "A" and "gravecomb" as components; "A" and "gravecomb" are only defined for Regular and Bold, but not Medium; in the Medium master the "Agrave" glyph needed some adjustments to the component offsets (or maybe the advance width). Or, another example, you could have the "Agrave" (composite) and "gravecomb" (component) only be defined for Regular and Bold masters, while "A" (component) is also defined in the Medium master (e.g. contours needed some adjustments), so you have a composite glyph "Agrave" defined in 2 masters using a component defined in 3 masters.

This usually works fine for TrueType fonts, however problems arise when you need to decompose the composite glyph (for CFF fonts, or for TTF when contours and components are mixed, or components have different 2x2 transforms across masters). If you decompose these sparse composite glyphs without taking into account the fact that they have incomplete or additional master definitions, you either end up with a decomposed simple glyph that doesn't look exactly as the composite did, or the compilation fails because some components appear to be missing in some masters...

In order to fix this, it is necessary to interpolate the glyphs for the missing locations while or just before decomposing the sparse composite glyph, which is why I added the new instantiator module originally in fontmake (#825).

More precisely, in the first case (composite with more masters than its components), we need to interpolate the component glyphs on-the-fly at the missing locations while decomposing the composite glyph. For the second case (composite with fewer masters than its component[s]), we first traverse all the components across all masters and collect the set of locations in which they may be defined; then we interpolate our composite glyph at the new locations that it doesn't already define, and finally we proceed with decomposing it.

Right now, fontmake requires the font developer to manually ensure that all the composite glyphs and all their components are "aligned", i.e. are exactly defined for the same set of masters.

I hope you'll find this useful, as this is taking me more than I had anticipated. Initially I started with fixing it in glyphsLib, then of course I got tangled up in its complexity and decided I would rather fix in ufo2ft so this would work regardless of input source format.

Have a nice weekend!