[merge] Remove lookup_id() / feature_id(), use custom dict

I added the id() trick because normal objects are not hashable in Python3.
Remove that hack and use a custom dict subclass that allows us to use
objects as keys as long as they don't change.

The custom dict has a different, desirable, property as well: upon seeing
keys it does not know, it just adds them to the end of the list.  Will use
this feature in next commits to merge ScriptList properly.
This commit is contained in:
Behdad Esfahbod 2017-09-14 21:35:43 -04:00
parent 93763eec0b
commit d76d6c1a5f

View File

@ -496,9 +496,6 @@ ttLib.getTableClass('MATH').mergeMap = \
'table': mergeObjects,
}
lookup_id = id
feature_id = id
@_add_method(ttLib.getTableClass('GSUB'))
def merge(self, m, tables):
@ -506,15 +503,13 @@ def merge(self, m, tables):
for i,(table,dups) in enumerate(zip(tables, m.duplicateGlyphsPerFont)):
if not dups: continue
assert (table is not None and table is not NotImplemented), "Have duplicates to resolve for font %d but no GSUB" % (i + 1)
lookupMap = {lookup_id(v):v for v in table.table.LookupList.Lookup}
featureMap = {feature_id(v):v for v in table.table.FeatureList.FeatureRecord}
synthFeature = None
synthLookup = None
for script in table.table.ScriptList.ScriptRecord:
if script.ScriptTag == 'DFLT': continue # XXX
for langsys in [script.Script.DefaultLangSys] + [l.LangSys for l in script.Script.LangSysRecord]:
if langsys is None: continue # XXX Create!
feature = [featureMap[v] for v in langsys.FeatureIndex if featureMap[v].FeatureTag == 'locl']
feature = [v for v in langsys.FeatureIndex if v.FeatureTag == 'locl']
assert len(feature) <= 1
if feature:
feature = feature[0]
@ -526,9 +521,8 @@ def merge(self, m, tables):
f.FeatureParams = None
f.LookupCount = 0
f.LookupListIndex = []
langsys.FeatureIndex.append(feature_id(synthFeature))
featureMap[feature_id(synthFeature)] = synthFeature
langsys.FeatureIndex.sort(key=lambda v: featureMap[v].FeatureTag)
langsys.FeatureIndex.append(synthFeature)
langsys.FeatureIndex.sort(key=lambda v: v.FeatureTag)
table.table.FeatureList.FeatureRecord.append(synthFeature)
table.table.FeatureList.FeatureCount += 1
feature = synthFeature
@ -544,7 +538,7 @@ def merge(self, m, tables):
table.table.LookupList.Lookup.append(synthLookup)
table.table.LookupList.LookupCount += 1
feature.Feature.LookupListIndex[:0] = [lookup_id(synthLookup)]
feature.Feature.LookupListIndex[:0] = [synthLookup]
feature.Feature.LookupCount += 1
DefaultTable.merge(self, m, tables)
@ -761,6 +755,21 @@ class Options(object):
return ret
class _GregariousDict(dict):
"""A dictionary-like object that:
1. Allows keys to be unhashable objects, so far as they don't change underneath, and
2. Welcomes guests without reservations and adds them to the end of the list.
"""
def __init__(self, lst):
self.l = lst
self.d = {id(v):i for i,v in enumerate(lst)}
def __getitem__(self, v):
if id(v) not in self.d:
self.d[id(v)] = len(self.l)
self.l.append(v)
return self.d[id(v)]
class Merger(object):
@ -874,14 +883,14 @@ class Merger(object):
if not t: continue
if t.table.LookupList:
lookupMap = {i:lookup_id(v) for i,v in enumerate(t.table.LookupList.Lookup)}
lookupMap = {i:v for i,v in enumerate(t.table.LookupList.Lookup)}
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:feature_id(v) for i,v in enumerate(t.table.FeatureList.FeatureRecord)}
featureMap = {i:v for i,v in enumerate(t.table.FeatureList.FeatureRecord)}
t.table.ScriptList.mapFeatures(featureMap)
# TODO GDEF/Lookup MarkFilteringSets
@ -899,16 +908,18 @@ class Merger(object):
if not t: continue
if t.table.LookupList:
lookupMap = {lookup_id(v):i for i,v in enumerate(t.table.LookupList.Lookup)}
lookupMap = _GregariousDict(t.table.LookupList.Lookup)
t.table.LookupList.mapLookups(lookupMap)
if t.table.FeatureList:
# XXX Handle present FeatureList but absent LookupList
t.table.FeatureList.mapLookups(lookupMap)
t.table.LookupList.LookupCount = len(t.table.LookupList.Lookup)
if t.table.FeatureList and t.table.ScriptList:
# XXX Handle present ScriptList but absent FeatureList
featureMap = {feature_id(v):i for i,v in enumerate(t.table.FeatureList.FeatureRecord)}
featureMap = _GregariousDict(t.table.FeatureList.FeatureRecord)
t.table.ScriptList.mapFeatures(featureMap)
t.table.FeatureList.FeatureCount = len(t.table.FeatureList.FeatureRecord)
# TODO GDEF/Lookup MarkFilteringSets
# TODO FeatureParams nameIDs