ufo2ft feature writer calls feaLib builder with tables=[GSUB] first, to run closure
over glyph substitutions; if the GSUB features contains 'featureNames' blocks, then
an AssertionError will be raised; in this case, we can simply skip building the
FeatureParams tables as we haven't build the name records they point to.
In the IncludedFeaNotFound error, pass on the filename token as
it was included in the include statement, so that a client can do their
thing (e.g. issue a warning to suggest the user to write the path
relative to the UFO itself, instead of relative to the feautures.fea
which is inside a UFO).
Also. resolve includes relative to current working directory when the
IncludingLexer' filename is None because it originates from an in-memory stream.
This would make it easier to construct feaLib AST from code,
where the location is not defined and thus should be None.
Also, we can make other arguments as kwargs with a default
value, now that the first parameter is no longer 'location'.
all otData arrays are decompiled as lists (see otConverters.BaseConverter.readArray).
If one tries to call the subsetter on a GSUB table that was not read from file
but was just built from feaLib, it crases with a TypeError because it's expecting
list but finds tuples.
Traceback (most recent call last):
File /home/clupo/Github/fonttools/Lib/fontTools/subset/__init__.py, line 1462, in prune_lookups
lookup_indices = self.table.FeatureList.collect_lookups(feature_indices)
File /home/clupo/Github/fonttools/Lib/fontTools/subset/__init__.py, line 1263, in collect_lookups
if i < self.FeatureCount), [])
TypeError: can only concatenate list (not tuple) to list
`tables=None` by default will build all supported tables;
To build only some of these and ignore the others, one can pass a
subset of supported tables tags: .e.g. `tables={'GSUB'}` will only
build the GSUB, even if the feature file may contain e.g. GPOS
related features.
Currently, the feature file parser always resolves included files,
parses their content and inserts it in the resulting AST. The original
`include` statement is lost.
This commit introduces an option to not follow inclusions. Instead, the
output AST will contain an `include` statement. This allows to process a
feature file on its own, and allows to round-trip it.
For example in glyphsLib, when going from a UFO to a .glyphs file, a
UFO feature file will be sliced up into Glyphs.app classes (e.g. a
GSFeaturePrefix with code `include(../family.fea);`) and when going back
from .glyphs to UFO, the feature file will be patched back together.
A multiple substitution may have a single destination, in which case
it will look just like a single substitution. So if there are both
multiple and single substitutions, upgrade all the single ones to
multiple substitutions. Previously we would just give an error message
in the builder and abort, which means certain valid OpenType lookups
can’t be represented by feature files.
This is the same logic implemented by FontForge (actually the
explanation above is almost copied verbatim from its source), makeotf
does not do this AFAIK but I consider it a bug not a feature.
Fixes https://github.com/fonttools/fonttools/issues/612
As Martin Hosken reported in https://github.com/fonttools/fonttools/pull/1096,
feaLib currently incorrectly handles the case where a marked input
glyph sequence in a contextual chaining sub/pos rule is split into
multiple runs, rather than being a single continuous run of ' marked
glyphs.
The consensus there was to raise a syntax error like makeotf instead of
second-guessing and silently fixing it like fontforge does.
... instead of a glyphMap dict.
The parser does not actually need a reverse glyph order mapping as
it is not interested in knowing the glyphID from the glyph name,
but only whether a glyph is in the font or not.
This makes it easier for client code (e.g. ufo2ft feature compiler)
to use the feaLib Parser, without having to first construct and pass
it a glyphMap argument.
Before this change, the following glyph class:
@Vowels = [@Vowels.lc @Vowels.uc y Y];
Would be written back as:
@Vowels = [@Vowels.lc = [a e i o u]; @Vowels.uc = [A E I O U]; y Y];
Which is clearly invalid. It seems for GlyphClass.asFea() to work
correctly here we should be using GlyphClassName not GlyphClass
for the nested classes (similar to the code at the beginning of
parse_glyphclass_()).