Fix GSUB/GPOS recursive lookup subsetting
Subsets IranNastaliq2.ttf correctly now. Yay!
This commit is contained in:
parent
ffdc8e135c
commit
78661bbd08
128
pyotlss.py
128
pyotlss.py
@ -12,6 +12,10 @@ def add_method (*clazzes):
|
||||
setattr (clazz, method.func_name, method)
|
||||
return wrapper
|
||||
|
||||
def unique_sorted (l):
|
||||
return sorted ({v:1 for v in l}.keys ())
|
||||
|
||||
|
||||
# Subset
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.Coverage)
|
||||
@ -28,7 +32,7 @@ def __nonzero__ (self):
|
||||
def subset (self, glyphs):
|
||||
"Returns ascending list of remaining classes."
|
||||
self.classDefs = {g:v for g,v in self.classDefs.items() if g in glyphs}
|
||||
return {v:1 for v in self.classDefs.values ()}.keys ()
|
||||
return unique_sorted (self.classDefs.values ())
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.ClassDef)
|
||||
def remap (self, class_map):
|
||||
@ -144,7 +148,7 @@ def subset (self, glyphs):
|
||||
self.BaseArray.BaseRecord = [self.BaseArray.BaseRecord[i] for i in base_indices]
|
||||
self.BaseArray.BaseCount = len (self.BaseArray.BaseRecord)
|
||||
# Prune empty classes
|
||||
class_indices = {v.Class:1 for v in self.MarkArray.MarkRecord}.keys ()
|
||||
class_indices = unique_sorted (v.Class for v in self.MarkArray.MarkRecord)
|
||||
self.ClassCount = len (class_indices)
|
||||
for m in self.MarkArray.MarkRecord:
|
||||
m.Class = class_indices.index (m.Class)
|
||||
@ -164,7 +168,7 @@ def subset (self, glyphs):
|
||||
self.LigatureArray.LigatureAttach = [self.LigatureArray.LigatureAttach[i] for i in ligature_indices]
|
||||
self.LigatureArray.LigatureCount = len (self.LigatureArray.LigatureAttach)
|
||||
# Prune empty classes
|
||||
class_indices = {v.Class:1 for v in self.MarkArray.MarkRecord}.keys ()
|
||||
class_indices = unique_sorted (v.Class for v in self.MarkArray.MarkRecord)
|
||||
self.ClassCount = len (class_indices)
|
||||
for m in self.MarkArray.MarkRecord:
|
||||
m.Class = class_indices.index (m.Class)
|
||||
@ -185,7 +189,7 @@ def subset (self, glyphs):
|
||||
self.Mark2Array.Mark2Record = [self.Mark2Array.Mark2Record[i] for i in mark2_indices]
|
||||
self.Mark2Array.MarkCount = len (self.Mark2Array.Mark2Record)
|
||||
# Prune empty classes
|
||||
class_indices = {v.Class:1 for v in self.Mark1Array.MarkRecord}.keys ()
|
||||
class_indices = unique_sorted (v.Class for v in self.Mark1Array.MarkRecord)
|
||||
self.ClassCount = len (class_indices)
|
||||
for m in self.Mark1Array.MarkRecord:
|
||||
m.Class = class_indices.index (m.Class)
|
||||
@ -195,6 +199,34 @@ def subset (self, glyphs):
|
||||
else:
|
||||
assert 0, "unknown format: %s" % self.Format
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.SingleSubst,
|
||||
fontTools.ttLib.tables.otTables.MultipleSubst,
|
||||
fontTools.ttLib.tables.otTables.AlternateSubst,
|
||||
fontTools.ttLib.tables.otTables.LigatureSubst,
|
||||
fontTools.ttLib.tables.otTables.ReverseChainSingleSubst,
|
||||
fontTools.ttLib.tables.otTables.SinglePos,
|
||||
fontTools.ttLib.tables.otTables.PairPos,
|
||||
fontTools.ttLib.tables.otTables.CursivePos,
|
||||
fontTools.ttLib.tables.otTables.MarkBasePos,
|
||||
fontTools.ttLib.tables.otTables.MarkLigPos,
|
||||
fontTools.ttLib.tables.otTables.MarkMarkPos)
|
||||
def subset_lookups (self, lookup_indices):
|
||||
pass
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.SingleSubst,
|
||||
fontTools.ttLib.tables.otTables.MultipleSubst,
|
||||
fontTools.ttLib.tables.otTables.AlternateSubst,
|
||||
fontTools.ttLib.tables.otTables.LigatureSubst,
|
||||
fontTools.ttLib.tables.otTables.ReverseChainSingleSubst,
|
||||
fontTools.ttLib.tables.otTables.SinglePos,
|
||||
fontTools.ttLib.tables.otTables.PairPos,
|
||||
fontTools.ttLib.tables.otTables.CursivePos,
|
||||
fontTools.ttLib.tables.otTables.MarkBasePos,
|
||||
fontTools.ttLib.tables.otTables.MarkLigPos,
|
||||
fontTools.ttLib.tables.otTables.MarkMarkPos)
|
||||
def collect_lookups (self):
|
||||
return []
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.ContextSubst, fontTools.ttLib.tables.otTables.ContextPos)
|
||||
def subset (self, glyphs):
|
||||
if self.Format == 1:
|
||||
@ -236,6 +268,18 @@ def subset (self, glyphs):
|
||||
else:
|
||||
assert 0, "unknown format: %s" % self.Format
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.ContextSubst, fontTools.ttLib.tables.otTables.ContextPos,
|
||||
fontTools.ttLib.tables.otTables.ChainContextSubst, fontTools.ttLib.tables.otTables.ChainContextPos)
|
||||
def subset_lookups (self, lookup_indices):
|
||||
self.SubstLookupRecord = [ll for ll in self.SubstLookupRecord if ll.LookupListIndex in lookup_indices]
|
||||
for ll in self.SubstLookupRecord:
|
||||
ll.LookupListIndex = lookup_indices.index (ll.LookupListIndex)
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.ContextSubst, fontTools.ttLib.tables.otTables.ContextPos,
|
||||
fontTools.ttLib.tables.otTables.ChainContextSubst, fontTools.ttLib.tables.otTables.ChainContextPos)
|
||||
def collect_lookups (self):
|
||||
return [ll.LookupListIndex for ll in self.SubstLookupRecord]
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.ExtensionSubst, fontTools.ttLib.tables.otTables.ExtensionPos)
|
||||
def subset (self, glyphs):
|
||||
if self.Format == 1:
|
||||
@ -243,12 +287,35 @@ def subset (self, glyphs):
|
||||
else:
|
||||
assert 0, "unknown format: %s" % self.Format
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.ExtensionSubst, fontTools.ttLib.tables.otTables.ExtensionPos)
|
||||
def subset_lookups (self, lookup_indices):
|
||||
if self.Format == 1:
|
||||
return self.ExtSubTable.subset_lookups (lookup_indices)
|
||||
else:
|
||||
assert 0, "unknown format: %s" % self.Format
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.ExtensionSubst, fontTools.ttLib.tables.otTables.ExtensionPos)
|
||||
def collect_lookups (self):
|
||||
if self.Format == 1:
|
||||
return self.ExtSubTable.collect_lookups ()
|
||||
else:
|
||||
assert 0, "unknown format: %s" % self.Format
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.Lookup)
|
||||
def subset (self, glyphs):
|
||||
self.SubTable = [s for s in self.SubTable if s.subset (glyphs)]
|
||||
self.SubTableCount = len (self.SubTable)
|
||||
return self.SubTableCount
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.Lookup)
|
||||
def subset_lookups (self, lookup_indices):
|
||||
for s in self.SubTable:
|
||||
s.subset_lookups (lookup_indices)
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.Lookup)
|
||||
def collect_lookups (self):
|
||||
return unique_sorted (sum ((s.collect_lookups () for s in self.SubTable), []))
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.LookupList)
|
||||
def subset (self, glyphs):
|
||||
"Returns the indices of nonempty lookups."
|
||||
@ -258,6 +325,17 @@ def subset (self, glyphs):
|
||||
def subset_lookups (self, lookup_indices):
|
||||
self.Lookup = [self.Lookup[i] for i in lookup_indices]
|
||||
self.LookupCount = len (self.Lookup)
|
||||
for l in self.Lookup:
|
||||
l.subset_lookups (lookup_indices)
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.LookupList)
|
||||
def closure_lookups (self, lookup_indices):
|
||||
while True:
|
||||
recurse_lookups = sum ((self.Lookup[i].collect_lookups () for i in lookup_indices), [])
|
||||
recurse_lookups = [l for l in recurse_lookups if l not in lookup_indices]
|
||||
if not recurse_lookups:
|
||||
return lookup_indices
|
||||
lookup_indices = unique_sorted (lookup_indices + recurse_lookups)
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.Feature)
|
||||
def subset_lookups (self, lookup_indices):
|
||||
@ -267,6 +345,10 @@ def subset_lookups (self, lookup_indices):
|
||||
self.LookupCount = len (self.LookupListIndex)
|
||||
return self.LookupCount
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.Feature)
|
||||
def collect_lookups (self):
|
||||
return self.LookupListIndex[:]
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.FeatureList)
|
||||
def subset_lookups (self, lookup_indices):
|
||||
"Returns the indices of nonempty features."
|
||||
@ -275,6 +357,11 @@ def subset_lookups (self, lookup_indices):
|
||||
self.FeatureCount = len (self.FeatureRecord)
|
||||
return feature_indices
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.FeatureList)
|
||||
def collect_lookups (self, feature_indices):
|
||||
return unique_sorted (sum ((self.FeatureRecord[i].Feature.collect_lookups () for i in feature_indices
|
||||
if i < self.FeatureCount), []))
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.DefaultLangSys, fontTools.ttLib.tables.otTables.LangSys)
|
||||
def subset_features (self, feature_indices):
|
||||
if self.ReqFeatureIndex in feature_indices:
|
||||
@ -285,7 +372,14 @@ def subset_features (self, feature_indices):
|
||||
# Now map them.
|
||||
self.FeatureIndex = [feature_indices.index (f) for f in self.FeatureIndex if f in feature_indices]
|
||||
self.FeatureCount = len (self.FeatureIndex)
|
||||
return self.FeatureCount
|
||||
return self.FeatureCount or self.ReqFeatureIndex != 65535
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.DefaultLangSys, fontTools.ttLib.tables.otTables.LangSys)
|
||||
def collect_features (self):
|
||||
feature_indices = self.FeatureIndex[:]
|
||||
if self.ReqFeatureIndex != 65535:
|
||||
feature_indices.append (self.ReqFeatureIndex)
|
||||
return unique_sorted (feature_indices)
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.Script)
|
||||
def subset_features (self, feature_indices):
|
||||
@ -293,7 +387,14 @@ def subset_features (self, feature_indices):
|
||||
self.DefaultLangSys = None
|
||||
self.LangSysRecord = [l for l in self.LangSysRecord if l.LangSys.subset_features (feature_indices)]
|
||||
self.LangSysCount = len (self.LangSysRecord)
|
||||
return self.LangSysCount
|
||||
return self.LangSysCount or self.DefaultLangSys
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.Script)
|
||||
def collect_features (self):
|
||||
feature_indices = [l.LangSys.collectFeatures () for l in self.LangSysRecord]
|
||||
if self.DefaultLangSys:
|
||||
feature_indices.append (self.DefaultLangSys.collect_features ())
|
||||
return unique_sorted (sum (feature_indices, []))
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.ScriptList)
|
||||
def subset_features (self, feature_indices):
|
||||
@ -301,11 +402,16 @@ def subset_features (self, feature_indices):
|
||||
self.ScriptCount = len (self.ScriptRecord)
|
||||
return self.ScriptCount
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.ScriptList)
|
||||
def collect_features (self):
|
||||
return unique_sorted (sum ((s.Script.collect_features () for s in self.ScriptRecord), []))
|
||||
|
||||
@add_method(fontTools.ttLib.getTableClass('GSUB'), fontTools.ttLib.getTableClass('GPOS'))
|
||||
def subset (self, glyphs):
|
||||
lookup_indices = self.table.LookupList.subset (glyphs)
|
||||
self.subset_lookups (lookup_indices)
|
||||
return True # Retain the possibly empty table
|
||||
self.prune_lookups ()
|
||||
return True
|
||||
|
||||
@add_method(fontTools.ttLib.getTableClass('GSUB'), fontTools.ttLib.getTableClass('GPOS'))
|
||||
def subset_lookups (self, lookup_indices):
|
||||
@ -314,6 +420,14 @@ def subset_lookups (self, lookup_indices):
|
||||
feature_indices = self.table.FeatureList.subset_lookups (lookup_indices)
|
||||
self.table.ScriptList.subset_features (feature_indices)
|
||||
|
||||
@add_method(fontTools.ttLib.getTableClass('GSUB'), fontTools.ttLib.getTableClass('GPOS'))
|
||||
def prune_lookups (self):
|
||||
"Remove unreferenced lookups"
|
||||
feature_indices = self.table.ScriptList.collect_features ()
|
||||
lookup_indices = self.table.FeatureList.collect_lookups (feature_indices)
|
||||
lookup_indices = self.table.LookupList.closure_lookups (lookup_indices)
|
||||
self.subset_lookups (lookup_indices)
|
||||
|
||||
@add_method(fontTools.ttLib.getTableClass('GDEF'))
|
||||
def subset (self, glyphs):
|
||||
table = self.table
|
||||
|
Loading…
x
Reference in New Issue
Block a user