[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.
This commit is contained in:
Sascha Brawer 2015-09-08 12:05:44 +02:00
parent 683a8f5dbc
commit 792a958d6c
4 changed files with 28 additions and 6 deletions

View File

@ -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)

View File

@ -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():

View File

@ -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

View File

@ -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 {"