[merge] Map recursive lookups
Fixes https://github.com/behdad/fonttools/issues/109
diff --git a/Lib/fontTools/merge.py b/Lib/fontTools/merge.py
index c3ae1cc..5f5bc2a 100644
--- a/Lib/fontTools/merge.py
+++ b/Lib/fontTools/merge.py
@@ -422,6 +422,99 @@
}
+@_add_method(otTables.SingleSubst,
+ otTables.MultipleSubst,
+ otTables.AlternateSubst,
+ otTables.LigatureSubst,
+ otTables.ReverseChainSingleSubst,
+ otTables.SinglePos,
+ otTables.PairPos,
+ otTables.CursivePos,
+ otTables.MarkBasePos,
+ otTables.MarkLigPos,
+ otTables.MarkMarkPos)
+def mapLookups(self, lookupMap):
+ pass
+
+# Copied and trimmed down from subset.py
+@_add_method(otTables.ContextSubst,
+ otTables.ChainContextSubst,
+ otTables.ContextPos,
+ otTables.ChainContextPos)
+def __classify_context(self):
+
+ class ContextHelper(object):
+ def __init__(self, klass, Format):
+ if klass.__name__.endswith('Subst'):
+ Typ = 'Sub'
+ Type = 'Subst'
+ else:
+ Typ = 'Pos'
+ Type = 'Pos'
+ if klass.__name__.startswith('Chain'):
+ Chain = 'Chain'
+ else:
+ Chain = ''
+ ChainTyp = Chain+Typ
+
+ self.Typ = Typ
+ self.Type = Type
+ self.Chain = Chain
+ self.ChainTyp = ChainTyp
+
+ self.LookupRecord = Type+'LookupRecord'
+
+ if Format == 1:
+ self.Rule = ChainTyp+'Rule'
+ self.RuleSet = ChainTyp+'RuleSet'
+ elif Format == 2:
+ self.Rule = ChainTyp+'ClassRule'
+ self.RuleSet = ChainTyp+'ClassSet'
+
+ if self.Format not in [1, 2, 3]:
+ return None # Don't shoot the messenger; let it go
+ if not hasattr(self.__class__, "__ContextHelpers"):
+ self.__class__.__ContextHelpers = {}
+ if self.Format not in self.__class__.__ContextHelpers:
+ helper = ContextHelper(self.__class__, self.Format)
+ self.__class__.__ContextHelpers[self.Format] = helper
+ return self.__class__.__ContextHelpers[self.Format]
+
+
+@_add_method(otTables.ContextSubst,
+ otTables.ChainContextSubst,
+ otTables.ContextPos,
+ otTables.ChainContextPos)
+def mapLookups(self, lookupMap):
+ c = self.__classify_context()
+
+ if self.Format in [1, 2]:
+ for rs in getattr(self, c.RuleSet):
+ if not rs: continue
+ for r in getattr(rs, c.Rule):
+ if not r: continue
+ for ll in getattr(r, c.LookupRecord):
+ if not ll: continue
+ ll.LookupListIndex = lookupMap[ll.LookupListIndex]
+ elif self.Format == 3:
+ for ll in getattr(self, c.LookupRecord):
+ if not ll: continue
+ ll.LookupListIndex = lookupMap[ll.LookupListIndex]
+ else:
+ assert 0, "unknown format: %s" % self.Format
+
+@_add_method(otTables.Lookup)
+def mapLookups(self, lookupMap):
+ for st in self.SubTable:
+ if not st: continue
+ st.mapLookups(lookupMap)
+
+@_add_method(otTables.LookupList)
+def mapLookups(self, lookupMap):
+ for l in self.Lookup:
+ if not l: continue
+ l.mapLookups(lookupMap)
+
@_add_method(otTables.Feature)
def mapLookups(self, lookupMap):
self.LookupListIndex = [lookupMap[i] for i in self.LookupListIndex]
@@ -630,9 +723,12 @@
for t in [GSUB, GPOS]:
if not t: continue
- if t.table.LookupList and t.table.FeatureList:
+ if t.table.LookupList:
lookupMap = {i:id(v) for i,v in enumerate(t.table.LookupList.Lookup)}
- t.table.FeatureList.mapLookups(lookupMap)
+ t.table.LookupList.mapLookups(lookupMap)
+ if t.table.FeatureList:
+ # XXX Handle present FeatureList but absent LookupList
+ t.table.FeatureList.mapLookups(lookupMap)
if t.table.FeatureList and t.table.ScriptList:
featureMap = {i:id(v) for i,v in enumerate(t.table.FeatureList.FeatureRecord)}
@@ -650,11 +746,15 @@
for t in [GSUB, GPOS]:
if not t: continue
- if t.table.LookupList and t.table.FeatureList:
+ if t.table.LookupList:
lookupMap = {id(v):i for i,v in enumerate(t.table.LookupList.Lookup)}
- t.table.FeatureList.mapLookups(lookupMap)
+ t.table.LookupList.mapLookups(lookupMap)
+ if t.table.FeatureList:
+ # XXX Handle present FeatureList but absent LookupList
+ t.table.FeatureList.mapLookups(lookupMap)
if t.table.FeatureList and t.table.ScriptList:
+ # XXX Handle present ScriptList but absent FeatureList
featureMap = {id(v):i for i,v in enumerate(t.table.FeatureList.FeatureRecord)}
t.table.ScriptList.mapFeatures(featureMap)