You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			527 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			527 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
# Copyright 2013 Google, Inc. All Rights Reserved.
 | 
						|
#
 | 
						|
# Google Author(s): Behdad Esfahbod, Roozbeh Pournader
 | 
						|
 | 
						|
from fontTools import ttLib
 | 
						|
from fontTools.ttLib.tables.DefaultTable import DefaultTable
 | 
						|
from fontTools.ttLib.tables import otTables
 | 
						|
from fontTools.merge.base import add_method, mergeObjects
 | 
						|
from fontTools.merge.util import *
 | 
						|
import logging
 | 
						|
 | 
						|
 | 
						|
log = logging.getLogger("fontTools.merge")
 | 
						|
 | 
						|
 | 
						|
def mergeLookupLists(lst):
 | 
						|
    # TODO Do smarter merge.
 | 
						|
    return sumLists(lst)
 | 
						|
 | 
						|
 | 
						|
def mergeFeatures(lst):
 | 
						|
    assert lst
 | 
						|
    self = otTables.Feature()
 | 
						|
    self.FeatureParams = None
 | 
						|
    self.LookupListIndex = mergeLookupLists(
 | 
						|
        [l.LookupListIndex for l in lst if l.LookupListIndex]
 | 
						|
    )
 | 
						|
    self.LookupCount = len(self.LookupListIndex)
 | 
						|
    return self
 | 
						|
 | 
						|
 | 
						|
def mergeFeatureLists(lst):
 | 
						|
    d = {}
 | 
						|
    for l in lst:
 | 
						|
        for f in l:
 | 
						|
            tag = f.FeatureTag
 | 
						|
            if tag not in d:
 | 
						|
                d[tag] = []
 | 
						|
            d[tag].append(f.Feature)
 | 
						|
    ret = []
 | 
						|
    for tag in sorted(d.keys()):
 | 
						|
        rec = otTables.FeatureRecord()
 | 
						|
        rec.FeatureTag = tag
 | 
						|
        rec.Feature = mergeFeatures(d[tag])
 | 
						|
        ret.append(rec)
 | 
						|
    return ret
 | 
						|
 | 
						|
 | 
						|
def mergeLangSyses(lst):
 | 
						|
    assert lst
 | 
						|
 | 
						|
    # TODO Support merging ReqFeatureIndex
 | 
						|
    assert all(l.ReqFeatureIndex == 0xFFFF for l in lst)
 | 
						|
 | 
						|
    self = otTables.LangSys()
 | 
						|
    self.LookupOrder = None
 | 
						|
    self.ReqFeatureIndex = 0xFFFF
 | 
						|
    self.FeatureIndex = mergeFeatureLists(
 | 
						|
        [l.FeatureIndex for l in lst if l.FeatureIndex]
 | 
						|
    )
 | 
						|
    self.FeatureCount = len(self.FeatureIndex)
 | 
						|
    return self
 | 
						|
 | 
						|
 | 
						|
def mergeScripts(lst):
 | 
						|
    assert lst
 | 
						|
 | 
						|
    if len(lst) == 1:
 | 
						|
        return lst[0]
 | 
						|
    langSyses = {}
 | 
						|
    for sr in lst:
 | 
						|
        for lsr in sr.LangSysRecord:
 | 
						|
            if lsr.LangSysTag not in langSyses:
 | 
						|
                langSyses[lsr.LangSysTag] = []
 | 
						|
            langSyses[lsr.LangSysTag].append(lsr.LangSys)
 | 
						|
    lsrecords = []
 | 
						|
    for tag, langSys_list in sorted(langSyses.items()):
 | 
						|
        lsr = otTables.LangSysRecord()
 | 
						|
        lsr.LangSys = mergeLangSyses(langSys_list)
 | 
						|
        lsr.LangSysTag = tag
 | 
						|
        lsrecords.append(lsr)
 | 
						|
 | 
						|
    self = otTables.Script()
 | 
						|
    self.LangSysRecord = lsrecords
 | 
						|
    self.LangSysCount = len(lsrecords)
 | 
						|
    dfltLangSyses = [s.DefaultLangSys for s in lst if s.DefaultLangSys]
 | 
						|
    if dfltLangSyses:
 | 
						|
        self.DefaultLangSys = mergeLangSyses(dfltLangSyses)
 | 
						|
    else:
 | 
						|
        self.DefaultLangSys = None
 | 
						|
    return self
 | 
						|
 | 
						|
 | 
						|
def mergeScriptRecords(lst):
 | 
						|
    d = {}
 | 
						|
    for l in lst:
 | 
						|
        for s in l:
 | 
						|
            tag = s.ScriptTag
 | 
						|
            if tag not in d:
 | 
						|
                d[tag] = []
 | 
						|
            d[tag].append(s.Script)
 | 
						|
    ret = []
 | 
						|
    for tag in sorted(d.keys()):
 | 
						|
        rec = otTables.ScriptRecord()
 | 
						|
        rec.ScriptTag = tag
 | 
						|
        rec.Script = mergeScripts(d[tag])
 | 
						|
        ret.append(rec)
 | 
						|
    return ret
 | 
						|
 | 
						|
 | 
						|
otTables.ScriptList.mergeMap = {
 | 
						|
    "ScriptCount": lambda lst: None,  # TODO
 | 
						|
    "ScriptRecord": mergeScriptRecords,
 | 
						|
}
 | 
						|
otTables.BaseScriptList.mergeMap = {
 | 
						|
    "BaseScriptCount": lambda lst: None,  # TODO
 | 
						|
    # TODO: Merge duplicate entries
 | 
						|
    "BaseScriptRecord": lambda lst: sorted(
 | 
						|
        sumLists(lst), key=lambda s: s.BaseScriptTag
 | 
						|
    ),
 | 
						|
}
 | 
						|
 | 
						|
otTables.FeatureList.mergeMap = {
 | 
						|
    "FeatureCount": sum,
 | 
						|
    "FeatureRecord": lambda lst: sorted(sumLists(lst), key=lambda s: s.FeatureTag),
 | 
						|
}
 | 
						|
 | 
						|
otTables.LookupList.mergeMap = {
 | 
						|
    "LookupCount": sum,
 | 
						|
    "Lookup": sumLists,
 | 
						|
}
 | 
						|
 | 
						|
otTables.Coverage.mergeMap = {
 | 
						|
    "Format": min,
 | 
						|
    "glyphs": sumLists,
 | 
						|
}
 | 
						|
 | 
						|
otTables.ClassDef.mergeMap = {
 | 
						|
    "Format": min,
 | 
						|
    "classDefs": sumDicts,
 | 
						|
}
 | 
						|
 | 
						|
otTables.LigCaretList.mergeMap = {
 | 
						|
    "Coverage": mergeObjects,
 | 
						|
    "LigGlyphCount": sum,
 | 
						|
    "LigGlyph": sumLists,
 | 
						|
}
 | 
						|
 | 
						|
otTables.AttachList.mergeMap = {
 | 
						|
    "Coverage": mergeObjects,
 | 
						|
    "GlyphCount": sum,
 | 
						|
    "AttachPoint": sumLists,
 | 
						|
}
 | 
						|
 | 
						|
# XXX Renumber MarkFilterSets of lookups
 | 
						|
otTables.MarkGlyphSetsDef.mergeMap = {
 | 
						|
    "MarkSetTableFormat": equal,
 | 
						|
    "MarkSetCount": sum,
 | 
						|
    "Coverage": sumLists,
 | 
						|
}
 | 
						|
 | 
						|
otTables.Axis.mergeMap = {
 | 
						|
    "*": mergeObjects,
 | 
						|
}
 | 
						|
 | 
						|
# XXX Fix BASE table merging
 | 
						|
otTables.BaseTagList.mergeMap = {
 | 
						|
    "BaseTagCount": sum,
 | 
						|
    "BaselineTag": sumLists,
 | 
						|
}
 | 
						|
 | 
						|
otTables.GDEF.mergeMap = otTables.GSUB.mergeMap = otTables.GPOS.mergeMap = (
 | 
						|
    otTables.BASE.mergeMap
 | 
						|
) = otTables.JSTF.mergeMap = otTables.MATH.mergeMap = {
 | 
						|
    "*": mergeObjects,
 | 
						|
    "Version": max,
 | 
						|
}
 | 
						|
 | 
						|
ttLib.getTableClass("GDEF").mergeMap = ttLib.getTableClass("GSUB").mergeMap = (
 | 
						|
    ttLib.getTableClass("GPOS").mergeMap
 | 
						|
) = ttLib.getTableClass("BASE").mergeMap = ttLib.getTableClass(
 | 
						|
    "JSTF"
 | 
						|
).mergeMap = ttLib.getTableClass(
 | 
						|
    "MATH"
 | 
						|
).mergeMap = {
 | 
						|
    "tableTag": onlyExisting(equal),  # XXX clean me up
 | 
						|
    "table": mergeObjects,
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
@add_method(ttLib.getTableClass("GSUB"))
 | 
						|
def merge(self, m, tables):
 | 
						|
    assert len(tables) == len(m.duplicateGlyphsPerFont)
 | 
						|
    for i, (table, dups) in enumerate(zip(tables, m.duplicateGlyphsPerFont)):
 | 
						|
        if not dups:
 | 
						|
            continue
 | 
						|
        if table is None or table is NotImplemented:
 | 
						|
            log.warning(
 | 
						|
                "Have non-identical duplicates to resolve for '%s' but no GSUB. Are duplicates intended?: %s",
 | 
						|
                m.fonts[i]._merger__name,
 | 
						|
                dups,
 | 
						|
            )
 | 
						|
            continue
 | 
						|
 | 
						|
        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 = [v for v in langsys.FeatureIndex if v.FeatureTag == "locl"]
 | 
						|
                assert len(feature) <= 1
 | 
						|
                if feature:
 | 
						|
                    feature = feature[0]
 | 
						|
                else:
 | 
						|
                    if not synthFeature:
 | 
						|
                        synthFeature = otTables.FeatureRecord()
 | 
						|
                        synthFeature.FeatureTag = "locl"
 | 
						|
                        f = synthFeature.Feature = otTables.Feature()
 | 
						|
                        f.FeatureParams = None
 | 
						|
                        f.LookupCount = 0
 | 
						|
                        f.LookupListIndex = []
 | 
						|
                        table.table.FeatureList.FeatureRecord.append(synthFeature)
 | 
						|
                        table.table.FeatureList.FeatureCount += 1
 | 
						|
                    feature = synthFeature
 | 
						|
                    langsys.FeatureIndex.append(feature)
 | 
						|
                    langsys.FeatureIndex.sort(key=lambda v: v.FeatureTag)
 | 
						|
 | 
						|
                if not synthLookup:
 | 
						|
                    subtable = otTables.SingleSubst()
 | 
						|
                    subtable.mapping = dups
 | 
						|
                    synthLookup = otTables.Lookup()
 | 
						|
                    synthLookup.LookupFlag = 0
 | 
						|
                    synthLookup.LookupType = 1
 | 
						|
                    synthLookup.SubTableCount = 1
 | 
						|
                    synthLookup.SubTable = [subtable]
 | 
						|
                    if table.table.LookupList is None:
 | 
						|
                        # mtiLib uses None as default value for LookupList,
 | 
						|
                        # while feaLib points to an empty array with count 0
 | 
						|
                        # TODO: make them do the same
 | 
						|
                        table.table.LookupList = otTables.LookupList()
 | 
						|
                        table.table.LookupList.Lookup = []
 | 
						|
                        table.table.LookupList.LookupCount = 0
 | 
						|
                    table.table.LookupList.Lookup.append(synthLookup)
 | 
						|
                    table.table.LookupList.LookupCount += 1
 | 
						|
 | 
						|
                if feature.Feature.LookupListIndex[:1] != [synthLookup]:
 | 
						|
                    feature.Feature.LookupListIndex[:0] = [synthLookup]
 | 
						|
                    feature.Feature.LookupCount += 1
 | 
						|
 | 
						|
    DefaultTable.merge(self, m, tables)
 | 
						|
    return self
 | 
						|
 | 
						|
 | 
						|
@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 __merge_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__, "_merge__ContextHelpers"):
 | 
						|
        self.__class__._merge__ContextHelpers = {}
 | 
						|
    if self.Format not in self.__class__._merge__ContextHelpers:
 | 
						|
        helper = ContextHelper(self.__class__, self.Format)
 | 
						|
        self.__class__._merge__ContextHelpers[self.Format] = helper
 | 
						|
    return self.__class__._merge__ContextHelpers[self.Format]
 | 
						|
 | 
						|
 | 
						|
@add_method(
 | 
						|
    otTables.ContextSubst,
 | 
						|
    otTables.ChainContextSubst,
 | 
						|
    otTables.ContextPos,
 | 
						|
    otTables.ChainContextPos,
 | 
						|
)
 | 
						|
def mapLookups(self, lookupMap):
 | 
						|
    c = self.__merge_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.ExtensionSubst, otTables.ExtensionPos)
 | 
						|
def mapLookups(self, lookupMap):
 | 
						|
    if self.Format == 1:
 | 
						|
        self.ExtSubTable.mapLookups(lookupMap)
 | 
						|
    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.Lookup)
 | 
						|
def mapMarkFilteringSets(self, markFilteringSetMap):
 | 
						|
    if self.LookupFlag & 0x0010:
 | 
						|
        self.MarkFilteringSet = markFilteringSetMap[self.MarkFilteringSet]
 | 
						|
 | 
						|
 | 
						|
@add_method(otTables.LookupList)
 | 
						|
def mapMarkFilteringSets(self, markFilteringSetMap):
 | 
						|
    for l in self.Lookup:
 | 
						|
        if not l:
 | 
						|
            continue
 | 
						|
        l.mapMarkFilteringSets(markFilteringSetMap)
 | 
						|
 | 
						|
 | 
						|
@add_method(otTables.Feature)
 | 
						|
def mapLookups(self, lookupMap):
 | 
						|
    self.LookupListIndex = [lookupMap[i] for i in self.LookupListIndex]
 | 
						|
 | 
						|
 | 
						|
@add_method(otTables.FeatureList)
 | 
						|
def mapLookups(self, lookupMap):
 | 
						|
    for f in self.FeatureRecord:
 | 
						|
        if not f or not f.Feature:
 | 
						|
            continue
 | 
						|
        f.Feature.mapLookups(lookupMap)
 | 
						|
 | 
						|
 | 
						|
@add_method(otTables.DefaultLangSys, otTables.LangSys)
 | 
						|
def mapFeatures(self, featureMap):
 | 
						|
    self.FeatureIndex = [featureMap[i] for i in self.FeatureIndex]
 | 
						|
    if self.ReqFeatureIndex != 65535:
 | 
						|
        self.ReqFeatureIndex = featureMap[self.ReqFeatureIndex]
 | 
						|
 | 
						|
 | 
						|
@add_method(otTables.Script)
 | 
						|
def mapFeatures(self, featureMap):
 | 
						|
    if self.DefaultLangSys:
 | 
						|
        self.DefaultLangSys.mapFeatures(featureMap)
 | 
						|
    for l in self.LangSysRecord:
 | 
						|
        if not l or not l.LangSys:
 | 
						|
            continue
 | 
						|
        l.LangSys.mapFeatures(featureMap)
 | 
						|
 | 
						|
 | 
						|
@add_method(otTables.ScriptList)
 | 
						|
def mapFeatures(self, featureMap):
 | 
						|
    for s in self.ScriptRecord:
 | 
						|
        if not s or not s.Script:
 | 
						|
            continue
 | 
						|
        s.Script.mapFeatures(featureMap)
 | 
						|
 | 
						|
 | 
						|
def layoutPreMerge(font):
 | 
						|
    # Map indices to references
 | 
						|
 | 
						|
    GDEF = font.get("GDEF")
 | 
						|
    GSUB = font.get("GSUB")
 | 
						|
    GPOS = font.get("GPOS")
 | 
						|
 | 
						|
    for t in [GSUB, GPOS]:
 | 
						|
        if not t:
 | 
						|
            continue
 | 
						|
 | 
						|
        if t.table.LookupList:
 | 
						|
            lookupMap = {i: v for i, v in enumerate(t.table.LookupList.Lookup)}
 | 
						|
            t.table.LookupList.mapLookups(lookupMap)
 | 
						|
            t.table.FeatureList.mapLookups(lookupMap)
 | 
						|
 | 
						|
            if (
 | 
						|
                GDEF
 | 
						|
                and GDEF.table.Version >= 0x00010002
 | 
						|
                and GDEF.table.MarkGlyphSetsDef
 | 
						|
            ):
 | 
						|
                markFilteringSetMap = {
 | 
						|
                    i: v for i, v in enumerate(GDEF.table.MarkGlyphSetsDef.Coverage)
 | 
						|
                }
 | 
						|
                t.table.LookupList.mapMarkFilteringSets(markFilteringSetMap)
 | 
						|
 | 
						|
        if t.table.FeatureList and t.table.ScriptList:
 | 
						|
            featureMap = {i: v for i, v in enumerate(t.table.FeatureList.FeatureRecord)}
 | 
						|
            t.table.ScriptList.mapFeatures(featureMap)
 | 
						|
 | 
						|
    # TODO FeatureParams nameIDs
 | 
						|
 | 
						|
 | 
						|
def layoutPostMerge(font):
 | 
						|
    # Map references back to indices
 | 
						|
 | 
						|
    GDEF = font.get("GDEF")
 | 
						|
    GSUB = font.get("GSUB")
 | 
						|
    GPOS = font.get("GPOS")
 | 
						|
 | 
						|
    for t in [GSUB, GPOS]:
 | 
						|
        if not t:
 | 
						|
            continue
 | 
						|
 | 
						|
        if t.table.FeatureList and t.table.ScriptList:
 | 
						|
            # Collect unregistered (new) features.
 | 
						|
            featureMap = GregariousIdentityDict(t.table.FeatureList.FeatureRecord)
 | 
						|
            t.table.ScriptList.mapFeatures(featureMap)
 | 
						|
 | 
						|
            # Record used features.
 | 
						|
            featureMap = AttendanceRecordingIdentityDict(
 | 
						|
                t.table.FeatureList.FeatureRecord
 | 
						|
            )
 | 
						|
            t.table.ScriptList.mapFeatures(featureMap)
 | 
						|
            usedIndices = featureMap.s
 | 
						|
 | 
						|
            # Remove unused features
 | 
						|
            t.table.FeatureList.FeatureRecord = [
 | 
						|
                f
 | 
						|
                for i, f in enumerate(t.table.FeatureList.FeatureRecord)
 | 
						|
                if i in usedIndices
 | 
						|
            ]
 | 
						|
 | 
						|
            # Map back to indices.
 | 
						|
            featureMap = NonhashableDict(t.table.FeatureList.FeatureRecord)
 | 
						|
            t.table.ScriptList.mapFeatures(featureMap)
 | 
						|
 | 
						|
            t.table.FeatureList.FeatureCount = len(t.table.FeatureList.FeatureRecord)
 | 
						|
 | 
						|
        if t.table.LookupList:
 | 
						|
            # Collect unregistered (new) lookups.
 | 
						|
            lookupMap = GregariousIdentityDict(t.table.LookupList.Lookup)
 | 
						|
            t.table.FeatureList.mapLookups(lookupMap)
 | 
						|
            t.table.LookupList.mapLookups(lookupMap)
 | 
						|
 | 
						|
            # Record used lookups.
 | 
						|
            lookupMap = AttendanceRecordingIdentityDict(t.table.LookupList.Lookup)
 | 
						|
            t.table.FeatureList.mapLookups(lookupMap)
 | 
						|
            t.table.LookupList.mapLookups(lookupMap)
 | 
						|
            usedIndices = lookupMap.s
 | 
						|
 | 
						|
            # Remove unused lookups
 | 
						|
            t.table.LookupList.Lookup = [
 | 
						|
                l for i, l in enumerate(t.table.LookupList.Lookup) if i in usedIndices
 | 
						|
            ]
 | 
						|
 | 
						|
            # Map back to indices.
 | 
						|
            lookupMap = NonhashableDict(t.table.LookupList.Lookup)
 | 
						|
            t.table.FeatureList.mapLookups(lookupMap)
 | 
						|
            t.table.LookupList.mapLookups(lookupMap)
 | 
						|
 | 
						|
            t.table.LookupList.LookupCount = len(t.table.LookupList.Lookup)
 | 
						|
 | 
						|
            if GDEF and GDEF.table.Version >= 0x00010002:
 | 
						|
                markFilteringSetMap = NonhashableDict(
 | 
						|
                    GDEF.table.MarkGlyphSetsDef.Coverage
 | 
						|
                )
 | 
						|
                t.table.LookupList.mapMarkFilteringSets(markFilteringSetMap)
 | 
						|
 | 
						|
    # TODO FeatureParams nameIDs
 |