https://github.com/behdad/fonttools/issues/445
Not sure whether it makes much sense to define a contextual chain
that points to a GSUB type 3, but the OpenType feature file syntax
does not explicitly forbid it. Adobe's `makeotf` tool rejects this
kind of input with "Contextual alternate rule not yet supported";
this implies that the construct is valid (albeit definitely exotic).
Resolves https://github.com/behdad/fonttools/issues/445 for single
substitutions. The compact forms for chaining to other GSUB types
are not yet supported; these will get fixed in follow-up changes.
For GPOS type 2, the OpenType Feature File format makes a semantic
difference between `glyph` and `[glyph]`, so we need to pass the
syntax tree for the kerned glyphs and glyph classes down to the builder.
Previously, we were expanding syntax tree nodes to glyphSets at
parsing time. Therefore, the builder could not distinguish a statement
for kerning two single glyphs from a statement for kerning two glyph
glasses, where each glyph class would consist of a singleton
glyph. (Debating whether or not it makes much sense to have this
distinction is outside the scope of fonttools; we want to implement
the language in its present form).
The builder does not yet use this information for building different
tables. This change is just about plumbing.
This will be needed for implementing class-based kerning. According
to the OpenType Feature File specification, a different table needs to
be built for `glyph` versus `[glyph]`.
Before this fix, the parser failed to process statements of the form
`lookupflag MarkAttachmentType @GLYPHCLASS;` when no other flag
were set after the glyph class. However, statements like
`lookupflag MarkAttachmentType @GLYPHCLASS RightToLeft;` were
getting recognized perfectly fine.
No output is generated yet, this change is just on the parser.
The OpenType Feature File specification is surprisingly vague about
the exact syntax of chaining contextual positioning rules, so I expect
that we will have to iterate on this parser. However, the test case
in parser_test.py gets recognized by `makeotf`, so the current
implementation is unlikely to be completely wrong.
While not really documented in the OpenType Feature File specification,
the AFDKO makeotf tool handles the `markClass` statement this way.
Also, some examples in the specification seem to imply this semantics.
The class names of tree nodes for substitution and positioning rules
are now consistent with `builder.py`, which in turn is consistent with
`otTables.py`.
However, not sure how to build the otTables object graph for emitting
GPOS tables with device values; the current code thus silently strips
off any device values. Left a TODO comment for implementing this.
It is example 1 in section 5.f.i of the specification, and there
more examples in the same section. For consistency, use the same convention
as the other test cases.
An earlier change made sure that language tags would always be
four characters in length, even when ending in whitespace.
This made a few test cases in parser_test.py fail. By accident,
I had only run builder_test (instead of all unittest in fonttools)
before committing that change.
Also add ';' to some langaugesystem test cases. This makes the
snippets syntactically valid. The parser is still expected to
reject them for other reasons, just as before this change.
This simplifies the public API to the library. For clients, it does
not matter which exact component was detecting an error. And we will
soon have more components; there would be little point in declaring
CompilerError, TableBuilderError, and so forth.