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_()).
The syntax tree representation now reflects the syntax of feature files.
Before this change, FeatureNames did not have their own `ast.Block`,
which had made the code quite messy.
Before this change, some table statements would allow empty statements
(just a semicolon) while others would not allow them. After this change,
we're more consistent.
The items() of self.markFilterSets_ dictionary are not guaranteed to be always
ordered the same (may vary across python implementations or on subsequent runs).
To ensure deterministic order of Coverage subtables in MarkGlyphSetsDef tables,
we sort the mark sets by the order in which 'UseMarkFilteringSet' statements appear
in the feature file.
Glyph classes from feaLib parser are tuples of strings, with an order and possibly containing duplicates.
However when building MarkGlyphSetsDef or MarkAttachClassDef we are only interested in the *set* of glyphs they contain, i.e. the unordered collection of unique glyph names.
Also, note how in the tests for otlLib.builder.buildMarkGlyphSetsDef, the input is given as set literals, not tuples:
https://github.com/fonttools/fonttools/blob/78ad48e/Tests/otlLib/builder_test.py#L633
If a zero value appears in a SinglePos statement, feaLib continues to
produce ValueRecords of format 0. But if a zero value appears in a
PairPos statement inside a horizontal compilation context, feaLib now
produces ValueRecords of format 4. Likewise, if a zero value appears
in a PairPos statement inside a vertical compilation context, feaLib
now produces ValueRecords of format 8.
The OpenType Feature Syntax specification is completely silent about this,
but the new behavior matches that of makeotf.
https://github.com/fonttools/fonttools/issues/633
We now correctly handle nameid statements with surrogate pairs and
old-style macOS-encoded names (provided that fonttools supports the
specified encoding).
Resolves https://github.com/fonttools/fonttools/issues/842.
Also fixes a bug where glyph alternates in MTI feature files were
wrongly sorted by glyph name. After this change, the output is using
the same ordering as in the input MTI feature file.
Fixes https://github.com/fonttools/fonttools/issues/833.
* [feaLib.ast] fix checking multiple markClass definitions don't redefine same glyphs
As pointed out by @mhosken, we are looking in the wrong list for glyphs
that have already been defined in a previous markClass definition.
With this patch, the current markClass.fea test case fails becuase it defines 'acute'
twice for the same @TOP_MARKS class:
fontTools.feaLib.error.FeatureLibError: Lib/fontTools/feaLib/testdata/markClass.fea:6:5: Glyph acute already defined at Lib/fontTools/feaLib/testdata/markClass.fea:3:1
Also see conversation at:
3b79d51755 (r94622074)
* feaLib/testdat/markClass.fea: remove duplicate 'acute' in @TOP_MARKS
Now the test pass, after 45c77b7
* [feaLib.builder_test] test case for redefined glyph in multiple markClass definitions
This should be a bit more efficient as we don't need to create a temporary list
object before passing it to "".join() method of str; the latter accepts any
Iterable