From 27e23f9a954837ac9f113d87bc9231a23d17cbf0 Mon Sep 17 00:00:00 2001 From: Sascha Brawer Date: Thu, 4 Feb 2016 16:45:05 +0100 Subject: [PATCH] [feaLib] Emit context-free chains to single substitutions Resolves https://github.com/behdad/fonttools/issues/509 --- Lib/fontTools/feaLib/ast.py | 6 +- Lib/fontTools/feaLib/builder.py | 4 +- Lib/fontTools/feaLib/builder_test.py | 2 +- Lib/fontTools/feaLib/parser.py | 3 +- Lib/fontTools/feaLib/testdata/bug509.fea | 5 ++ Lib/fontTools/feaLib/testdata/bug509.ttx | 74 ++++++++++++++++++++++++ 6 files changed, 88 insertions(+), 6 deletions(-) create mode 100644 Lib/fontTools/feaLib/testdata/bug509.fea create mode 100644 Lib/fontTools/feaLib/testdata/bug509.ttx diff --git a/Lib/fontTools/feaLib/ast.py b/Lib/fontTools/feaLib/ast.py index 55c62dfdf..97e6b8850 100644 --- a/Lib/fontTools/feaLib/ast.py +++ b/Lib/fontTools/feaLib/ast.py @@ -451,14 +451,16 @@ class ReverseChainSingleSubstStatement(Statement): class SingleSubstStatement(Statement): - def __init__(self, location, mapping, prefix, suffix): + def __init__(self, location, mapping, prefix, suffix, forceChain): Statement.__init__(self, location) self.mapping, self.prefix, self.suffix = mapping, prefix, suffix + self.forceChain = forceChain def build(self, builder): prefix = [p.glyphSet() for p in self.prefix] suffix = [s.glyphSet() for s in self.suffix] - builder.add_single_subst(self.location, prefix, suffix, self.mapping) + builder.add_single_subst(self.location, prefix, suffix, self.mapping, + self.forceChain) class ScriptStatement(Statement): diff --git a/Lib/fontTools/feaLib/builder.py b/Lib/fontTools/feaLib/builder.py index 91c497e5a..c1f18a8f6 100644 --- a/Lib/fontTools/feaLib/builder.py +++ b/Lib/fontTools/feaLib/builder.py @@ -548,13 +548,13 @@ class Builder(object): lookup = self.get_lookup_(location, ReverseChainSingleSubstBuilder) lookup.substitutions.append((old_prefix, old_suffix, mapping)) - def add_single_subst(self, location, prefix, suffix, mapping): + def add_single_subst(self, location, prefix, suffix, mapping, forceChain): if self.cur_feature_name_ == "aalt": for (from_glyph, to_glyph) in mapping.items(): alts = self.aalt_alternates_.setdefault(from_glyph, set()) alts.add(to_glyph) return - if prefix or suffix: + if prefix or suffix or forceChain: chain = self.get_lookup_(location, ChainContextSubstBuilder) sub = self.get_chained_lookup_(location, SingleSubstBuilder) sub.mapping.update(mapping) diff --git a/Lib/fontTools/feaLib/builder_test.py b/Lib/fontTools/feaLib/builder_test.py index c1585236f..dfc314296 100644 --- a/Lib/fontTools/feaLib/builder_test.py +++ b/Lib/fontTools/feaLib/builder_test.py @@ -52,7 +52,7 @@ class BuilderTest(unittest.TestCase): spec5f_ii_1 spec5h1 spec6b_ii spec6d2 spec6e spec6f spec6h_ii spec6h_iii_1 spec8a spec9b spec9c1 spec9c2 spec9c3 - bug463 bug501 bug502 bug505 bug506 + bug463 bug501 bug502 bug505 bug506 bug509 """.split() def __init__(self, methodName): diff --git a/Lib/fontTools/feaLib/parser.py b/Lib/fontTools/feaLib/parser.py index bb7fe51cd..18c4bd46c 100644 --- a/Lib/fontTools/feaLib/parser.py +++ b/Lib/fontTools/feaLib/parser.py @@ -578,7 +578,8 @@ class Parser(object): (len(glyphs), len(replacements)), location) return ast.SingleSubstStatement(location, dict(zip(glyphs, replacements)), - old_prefix, old_suffix) + old_prefix, old_suffix, + forceChain=hasMarks) # GSUB lookup type 2: Multiple substitution. # Format: "substitute f_f_i by f f i;" diff --git a/Lib/fontTools/feaLib/testdata/bug509.fea b/Lib/fontTools/feaLib/testdata/bug509.fea new file mode 100644 index 000000000..b7af056fd --- /dev/null +++ b/Lib/fontTools/feaLib/testdata/bug509.fea @@ -0,0 +1,5 @@ +@LETTER_A = [A A.sc A.alt1]; +feature test { + ignore sub A; + sub @LETTER_A' by a; +} test; diff --git a/Lib/fontTools/feaLib/testdata/bug509.ttx b/Lib/fontTools/feaLib/testdata/bug509.ttx new file mode 100644 index 000000000..27aca5a09 --- /dev/null +++ b/Lib/fontTools/feaLib/testdata/bug509.ttx @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +