From 792a958d6c80fa09653d2d100bc3d0baa1b070f2 Mon Sep 17 00:00:00 2001 From: Sascha Brawer Date: Tue, 8 Sep 2015 12:05:44 +0200 Subject: [PATCH] [feaLib] Implement parser for multiple substitutions (GSUB LookupType 2) Actually building the GSUB table is not implemented yet, since this will probably need changes to otTables. --- Lib/fontTools/feaLib/ast.py | 9 +++++++++ Lib/fontTools/feaLib/builder.py | 7 +++++++ Lib/fontTools/feaLib/parser.py | 9 +++++++++ Lib/fontTools/feaLib/parser_test.py | 9 +++------ 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/Lib/fontTools/feaLib/ast.py b/Lib/fontTools/feaLib/ast.py index 101a22984..419760aad 100644 --- a/Lib/fontTools/feaLib/ast.py +++ b/Lib/fontTools/feaLib/ast.py @@ -124,6 +124,15 @@ class LookupReferenceStatement(Statement): self.location, self.lookup = (location, lookup) +class MultipleSubstitution(Statement): + def __init__(self, location, glyph, replacement): + Statement.__init__(self, location) + self.glyph, self.replacement = glyph, replacement + + def build(self, builder): + builder.add_multiple_substitution(self.location, glyph, replacement) + + class SingleSubstitution(Statement): def __init__(self, location, mapping): Statement.__init__(self, location) diff --git a/Lib/fontTools/feaLib/builder.py b/Lib/fontTools/feaLib/builder.py index 473f8935a..da8ac539c 100644 --- a/Lib/fontTools/feaLib/builder.py +++ b/Lib/fontTools/feaLib/builder.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals from fontTools.feaLib.error import FeatureLibError from fontTools.feaLib.parser import Parser from fontTools.ttLib.tables import otTables +import warnings def addOpenTypeFeatures(featurefile_path, font): @@ -222,6 +223,12 @@ class Builder(object): lookup = self.get_lookup_(location, LigatureSubstBuilder) lookup.ligatures[glyphs] = replacement + def add_multiple_substitution(self, location, glyph, replacements): + # TODO(sascha): Implement this, possibly via a new class + # otTables.MultipleSubst modeled after otTables.SingleSubst. + warnings.warn('Multiple substitution (GPOS LookupType 2) ' + 'is not yet implemented') + def add_single_substitution(self, location, mapping): lookup = self.get_lookup_(location, SingleSubstBuilder) for (from_glyph, to_glyph) in mapping.items(): diff --git a/Lib/fontTools/feaLib/parser.py b/Lib/fontTools/feaLib/parser.py index ca333a968..e2078f602 100644 --- a/Lib/fontTools/feaLib/parser.py +++ b/Lib/fontTools/feaLib/parser.py @@ -259,6 +259,15 @@ class Parser(object): return ast.SingleSubstitution(location, dict(zip(glyphs, replacements))) + # GSUB lookup type 2: Multiple substitution. + # Format: "substitute f_f_i by f f i;" + if (len(old_prefix) == 0 and len(old_suffix) == 0 and + len(old) == 1 and len(old[0]) == 1 and + len(new) > 1 and max([len(n) for n in new]) == 1 and + num_lookups == 0): + return ast.MultipleSubstitution(location, tuple(old[0])[0], + tuple([list(n)[0] for n in new])) + # GSUB lookup type 4: Ligature substitution. # Format: "substitute f f i by f_f_i;" if (len(old_prefix) == 0 and len(old_suffix) == 0 and diff --git a/Lib/fontTools/feaLib/parser_test.py b/Lib/fontTools/feaLib/parser_test.py index e87d5edda..5debf963c 100644 --- a/Lib/fontTools/feaLib/parser_test.py +++ b/Lib/fontTools/feaLib/parser_test.py @@ -310,12 +310,9 @@ class ParserTest(unittest.TestCase): def test_substitute_multiple(self): # GSUB LookupType 2 doc = self.parse("lookup Look {substitute f_f_i by f f i;} Look;") sub = doc.statements[0].statements[0] - self.assertEqual(type(sub), ast.SubstitutionRule) - self.assertEqual(sub.old_prefix, []) - self.assertEqual(sub.old, [{"f_f_i"}]) - self.assertEqual(sub.old_suffix, []) - self.assertEqual(sub.new, [{"f"}, {"f"}, {"i"}]) - self.assertEqual(sub.lookups, [None]) + self.assertEqual(type(sub), ast.MultipleSubstitution) + self.assertEqual(sub.glyph, "f_f_i") + self.assertEqual(sub.replacement, ("f", "f", "i")) def test_substitute_from(self): # GSUB LookupType 3 doc = self.parse("feature test {"