See pull request: https://github.com/fonttools/fonttools/pull/2326
The new module `otlLib.optimize.gpos` provides `compact` functions that
can reduce the file size of GPOS PairPos lookups by splitting subtables
in a smart way to avoid storing zero-valued pairs.
The compaction methods are called from `otlLib.builder` and
`varLib.merger` so that static and variable fonts can benefit from the
optimization at compile time.
The new module `otlLib.optimize` is also executable, to allow running
the optimization on existing fonts.
The optimization is a trade-off because on the one hand it can reduce
significantly the byte size of the GPOS table (up to 50% in random
Google Fonts) but on the other hand it adds to the compilation time and
may make fonts very slightly bigger once compressed to WOFF2 (because
WOFF2 doesn't mind about zero values and compresses them very well).
As such, the optimization is off by default, and you can activate it by
providing the environment variable `FONTTOOLS_GPOS_COMPACT_MODE=5` for
example (values from 0 = off to 9 = max file size savings, but many more
subtables).
isPairPos and isSinglePos are mutually exclusive and isSinglePos is only defined if isPairPos is False
so it is safe to use it in 'else' or 'elif' branches (logical expressions short-circuit)
When a SinglePost lookup is compiled, pretty much all compilers do some compression by combining similar ValueRecords into a single subtable. This compression produces different lengths of the list of subtables between source fonts. The original code required that all SinglePos lookups have the same subtables, often doesn't work.
I fixed this in varLib.merger.py by first flattening a SinglePos lookup to a single subtable, using the same record format for all records, and then merging the source fonts. After the merge is complete, I call fontTools.otlLib.builder.buildSinglePos() to rebuild the lookup subtables.
The code was setting GlyphClassDef.classDefs for the base font to an
empty dict then reading it from all fonts. It accidentally works when
creating variable fonts because the GlyphClassDef of the other fonts
will be used, but when mutating there is only one font.
Fix by reading the glyph classes before assigning to an empty dict.