1*e1fe3e4aSElliott Hughes# Copyright 2013 Google, Inc. All Rights Reserved. 2*e1fe3e4aSElliott Hughes# 3*e1fe3e4aSElliott Hughes# Google Author(s): Behdad Esfahbod, Roozbeh Pournader 4*e1fe3e4aSElliott Hughes 5*e1fe3e4aSElliott Hughesfrom fontTools import ttLib 6*e1fe3e4aSElliott Hughesfrom fontTools.ttLib.tables.DefaultTable import DefaultTable 7*e1fe3e4aSElliott Hughesfrom fontTools.ttLib.tables import otTables 8*e1fe3e4aSElliott Hughesfrom fontTools.merge.base import add_method, mergeObjects 9*e1fe3e4aSElliott Hughesfrom fontTools.merge.util import * 10*e1fe3e4aSElliott Hughesimport logging 11*e1fe3e4aSElliott Hughes 12*e1fe3e4aSElliott Hughes 13*e1fe3e4aSElliott Hugheslog = logging.getLogger("fontTools.merge") 14*e1fe3e4aSElliott Hughes 15*e1fe3e4aSElliott Hughes 16*e1fe3e4aSElliott Hughesdef mergeLookupLists(lst): 17*e1fe3e4aSElliott Hughes # TODO Do smarter merge. 18*e1fe3e4aSElliott Hughes return sumLists(lst) 19*e1fe3e4aSElliott Hughes 20*e1fe3e4aSElliott Hughes 21*e1fe3e4aSElliott Hughesdef mergeFeatures(lst): 22*e1fe3e4aSElliott Hughes assert lst 23*e1fe3e4aSElliott Hughes self = otTables.Feature() 24*e1fe3e4aSElliott Hughes self.FeatureParams = None 25*e1fe3e4aSElliott Hughes self.LookupListIndex = mergeLookupLists( 26*e1fe3e4aSElliott Hughes [l.LookupListIndex for l in lst if l.LookupListIndex] 27*e1fe3e4aSElliott Hughes ) 28*e1fe3e4aSElliott Hughes self.LookupCount = len(self.LookupListIndex) 29*e1fe3e4aSElliott Hughes return self 30*e1fe3e4aSElliott Hughes 31*e1fe3e4aSElliott Hughes 32*e1fe3e4aSElliott Hughesdef mergeFeatureLists(lst): 33*e1fe3e4aSElliott Hughes d = {} 34*e1fe3e4aSElliott Hughes for l in lst: 35*e1fe3e4aSElliott Hughes for f in l: 36*e1fe3e4aSElliott Hughes tag = f.FeatureTag 37*e1fe3e4aSElliott Hughes if tag not in d: 38*e1fe3e4aSElliott Hughes d[tag] = [] 39*e1fe3e4aSElliott Hughes d[tag].append(f.Feature) 40*e1fe3e4aSElliott Hughes ret = [] 41*e1fe3e4aSElliott Hughes for tag in sorted(d.keys()): 42*e1fe3e4aSElliott Hughes rec = otTables.FeatureRecord() 43*e1fe3e4aSElliott Hughes rec.FeatureTag = tag 44*e1fe3e4aSElliott Hughes rec.Feature = mergeFeatures(d[tag]) 45*e1fe3e4aSElliott Hughes ret.append(rec) 46*e1fe3e4aSElliott Hughes return ret 47*e1fe3e4aSElliott Hughes 48*e1fe3e4aSElliott Hughes 49*e1fe3e4aSElliott Hughesdef mergeLangSyses(lst): 50*e1fe3e4aSElliott Hughes assert lst 51*e1fe3e4aSElliott Hughes 52*e1fe3e4aSElliott Hughes # TODO Support merging ReqFeatureIndex 53*e1fe3e4aSElliott Hughes assert all(l.ReqFeatureIndex == 0xFFFF for l in lst) 54*e1fe3e4aSElliott Hughes 55*e1fe3e4aSElliott Hughes self = otTables.LangSys() 56*e1fe3e4aSElliott Hughes self.LookupOrder = None 57*e1fe3e4aSElliott Hughes self.ReqFeatureIndex = 0xFFFF 58*e1fe3e4aSElliott Hughes self.FeatureIndex = mergeFeatureLists( 59*e1fe3e4aSElliott Hughes [l.FeatureIndex for l in lst if l.FeatureIndex] 60*e1fe3e4aSElliott Hughes ) 61*e1fe3e4aSElliott Hughes self.FeatureCount = len(self.FeatureIndex) 62*e1fe3e4aSElliott Hughes return self 63*e1fe3e4aSElliott Hughes 64*e1fe3e4aSElliott Hughes 65*e1fe3e4aSElliott Hughesdef mergeScripts(lst): 66*e1fe3e4aSElliott Hughes assert lst 67*e1fe3e4aSElliott Hughes 68*e1fe3e4aSElliott Hughes if len(lst) == 1: 69*e1fe3e4aSElliott Hughes return lst[0] 70*e1fe3e4aSElliott Hughes langSyses = {} 71*e1fe3e4aSElliott Hughes for sr in lst: 72*e1fe3e4aSElliott Hughes for lsr in sr.LangSysRecord: 73*e1fe3e4aSElliott Hughes if lsr.LangSysTag not in langSyses: 74*e1fe3e4aSElliott Hughes langSyses[lsr.LangSysTag] = [] 75*e1fe3e4aSElliott Hughes langSyses[lsr.LangSysTag].append(lsr.LangSys) 76*e1fe3e4aSElliott Hughes lsrecords = [] 77*e1fe3e4aSElliott Hughes for tag, langSys_list in sorted(langSyses.items()): 78*e1fe3e4aSElliott Hughes lsr = otTables.LangSysRecord() 79*e1fe3e4aSElliott Hughes lsr.LangSys = mergeLangSyses(langSys_list) 80*e1fe3e4aSElliott Hughes lsr.LangSysTag = tag 81*e1fe3e4aSElliott Hughes lsrecords.append(lsr) 82*e1fe3e4aSElliott Hughes 83*e1fe3e4aSElliott Hughes self = otTables.Script() 84*e1fe3e4aSElliott Hughes self.LangSysRecord = lsrecords 85*e1fe3e4aSElliott Hughes self.LangSysCount = len(lsrecords) 86*e1fe3e4aSElliott Hughes dfltLangSyses = [s.DefaultLangSys for s in lst if s.DefaultLangSys] 87*e1fe3e4aSElliott Hughes if dfltLangSyses: 88*e1fe3e4aSElliott Hughes self.DefaultLangSys = mergeLangSyses(dfltLangSyses) 89*e1fe3e4aSElliott Hughes else: 90*e1fe3e4aSElliott Hughes self.DefaultLangSys = None 91*e1fe3e4aSElliott Hughes return self 92*e1fe3e4aSElliott Hughes 93*e1fe3e4aSElliott Hughes 94*e1fe3e4aSElliott Hughesdef mergeScriptRecords(lst): 95*e1fe3e4aSElliott Hughes d = {} 96*e1fe3e4aSElliott Hughes for l in lst: 97*e1fe3e4aSElliott Hughes for s in l: 98*e1fe3e4aSElliott Hughes tag = s.ScriptTag 99*e1fe3e4aSElliott Hughes if tag not in d: 100*e1fe3e4aSElliott Hughes d[tag] = [] 101*e1fe3e4aSElliott Hughes d[tag].append(s.Script) 102*e1fe3e4aSElliott Hughes ret = [] 103*e1fe3e4aSElliott Hughes for tag in sorted(d.keys()): 104*e1fe3e4aSElliott Hughes rec = otTables.ScriptRecord() 105*e1fe3e4aSElliott Hughes rec.ScriptTag = tag 106*e1fe3e4aSElliott Hughes rec.Script = mergeScripts(d[tag]) 107*e1fe3e4aSElliott Hughes ret.append(rec) 108*e1fe3e4aSElliott Hughes return ret 109*e1fe3e4aSElliott Hughes 110*e1fe3e4aSElliott Hughes 111*e1fe3e4aSElliott HughesotTables.ScriptList.mergeMap = { 112*e1fe3e4aSElliott Hughes "ScriptCount": lambda lst: None, # TODO 113*e1fe3e4aSElliott Hughes "ScriptRecord": mergeScriptRecords, 114*e1fe3e4aSElliott Hughes} 115*e1fe3e4aSElliott HughesotTables.BaseScriptList.mergeMap = { 116*e1fe3e4aSElliott Hughes "BaseScriptCount": lambda lst: None, # TODO 117*e1fe3e4aSElliott Hughes # TODO: Merge duplicate entries 118*e1fe3e4aSElliott Hughes "BaseScriptRecord": lambda lst: sorted( 119*e1fe3e4aSElliott Hughes sumLists(lst), key=lambda s: s.BaseScriptTag 120*e1fe3e4aSElliott Hughes ), 121*e1fe3e4aSElliott Hughes} 122*e1fe3e4aSElliott Hughes 123*e1fe3e4aSElliott HughesotTables.FeatureList.mergeMap = { 124*e1fe3e4aSElliott Hughes "FeatureCount": sum, 125*e1fe3e4aSElliott Hughes "FeatureRecord": lambda lst: sorted(sumLists(lst), key=lambda s: s.FeatureTag), 126*e1fe3e4aSElliott Hughes} 127*e1fe3e4aSElliott Hughes 128*e1fe3e4aSElliott HughesotTables.LookupList.mergeMap = { 129*e1fe3e4aSElliott Hughes "LookupCount": sum, 130*e1fe3e4aSElliott Hughes "Lookup": sumLists, 131*e1fe3e4aSElliott Hughes} 132*e1fe3e4aSElliott Hughes 133*e1fe3e4aSElliott HughesotTables.Coverage.mergeMap = { 134*e1fe3e4aSElliott Hughes "Format": min, 135*e1fe3e4aSElliott Hughes "glyphs": sumLists, 136*e1fe3e4aSElliott Hughes} 137*e1fe3e4aSElliott Hughes 138*e1fe3e4aSElliott HughesotTables.ClassDef.mergeMap = { 139*e1fe3e4aSElliott Hughes "Format": min, 140*e1fe3e4aSElliott Hughes "classDefs": sumDicts, 141*e1fe3e4aSElliott Hughes} 142*e1fe3e4aSElliott Hughes 143*e1fe3e4aSElliott HughesotTables.LigCaretList.mergeMap = { 144*e1fe3e4aSElliott Hughes "Coverage": mergeObjects, 145*e1fe3e4aSElliott Hughes "LigGlyphCount": sum, 146*e1fe3e4aSElliott Hughes "LigGlyph": sumLists, 147*e1fe3e4aSElliott Hughes} 148*e1fe3e4aSElliott Hughes 149*e1fe3e4aSElliott HughesotTables.AttachList.mergeMap = { 150*e1fe3e4aSElliott Hughes "Coverage": mergeObjects, 151*e1fe3e4aSElliott Hughes "GlyphCount": sum, 152*e1fe3e4aSElliott Hughes "AttachPoint": sumLists, 153*e1fe3e4aSElliott Hughes} 154*e1fe3e4aSElliott Hughes 155*e1fe3e4aSElliott Hughes# XXX Renumber MarkFilterSets of lookups 156*e1fe3e4aSElliott HughesotTables.MarkGlyphSetsDef.mergeMap = { 157*e1fe3e4aSElliott Hughes "MarkSetTableFormat": equal, 158*e1fe3e4aSElliott Hughes "MarkSetCount": sum, 159*e1fe3e4aSElliott Hughes "Coverage": sumLists, 160*e1fe3e4aSElliott Hughes} 161*e1fe3e4aSElliott Hughes 162*e1fe3e4aSElliott HughesotTables.Axis.mergeMap = { 163*e1fe3e4aSElliott Hughes "*": mergeObjects, 164*e1fe3e4aSElliott Hughes} 165*e1fe3e4aSElliott Hughes 166*e1fe3e4aSElliott Hughes# XXX Fix BASE table merging 167*e1fe3e4aSElliott HughesotTables.BaseTagList.mergeMap = { 168*e1fe3e4aSElliott Hughes "BaseTagCount": sum, 169*e1fe3e4aSElliott Hughes "BaselineTag": sumLists, 170*e1fe3e4aSElliott Hughes} 171*e1fe3e4aSElliott Hughes 172*e1fe3e4aSElliott HughesotTables.GDEF.mergeMap = otTables.GSUB.mergeMap = otTables.GPOS.mergeMap = ( 173*e1fe3e4aSElliott Hughes otTables.BASE.mergeMap 174*e1fe3e4aSElliott Hughes) = otTables.JSTF.mergeMap = otTables.MATH.mergeMap = { 175*e1fe3e4aSElliott Hughes "*": mergeObjects, 176*e1fe3e4aSElliott Hughes "Version": max, 177*e1fe3e4aSElliott Hughes} 178*e1fe3e4aSElliott Hughes 179*e1fe3e4aSElliott HughesttLib.getTableClass("GDEF").mergeMap = ttLib.getTableClass("GSUB").mergeMap = ( 180*e1fe3e4aSElliott Hughes ttLib.getTableClass("GPOS").mergeMap 181*e1fe3e4aSElliott Hughes) = ttLib.getTableClass("BASE").mergeMap = ttLib.getTableClass( 182*e1fe3e4aSElliott Hughes "JSTF" 183*e1fe3e4aSElliott Hughes).mergeMap = ttLib.getTableClass( 184*e1fe3e4aSElliott Hughes "MATH" 185*e1fe3e4aSElliott Hughes).mergeMap = { 186*e1fe3e4aSElliott Hughes "tableTag": onlyExisting(equal), # XXX clean me up 187*e1fe3e4aSElliott Hughes "table": mergeObjects, 188*e1fe3e4aSElliott Hughes} 189*e1fe3e4aSElliott Hughes 190*e1fe3e4aSElliott Hughes 191*e1fe3e4aSElliott Hughes@add_method(ttLib.getTableClass("GSUB")) 192*e1fe3e4aSElliott Hughesdef merge(self, m, tables): 193*e1fe3e4aSElliott Hughes assert len(tables) == len(m.duplicateGlyphsPerFont) 194*e1fe3e4aSElliott Hughes for i, (table, dups) in enumerate(zip(tables, m.duplicateGlyphsPerFont)): 195*e1fe3e4aSElliott Hughes if not dups: 196*e1fe3e4aSElliott Hughes continue 197*e1fe3e4aSElliott Hughes if table is None or table is NotImplemented: 198*e1fe3e4aSElliott Hughes log.warning( 199*e1fe3e4aSElliott Hughes "Have non-identical duplicates to resolve for '%s' but no GSUB. Are duplicates intended?: %s", 200*e1fe3e4aSElliott Hughes m.fonts[i]._merger__name, 201*e1fe3e4aSElliott Hughes dups, 202*e1fe3e4aSElliott Hughes ) 203*e1fe3e4aSElliott Hughes continue 204*e1fe3e4aSElliott Hughes 205*e1fe3e4aSElliott Hughes synthFeature = None 206*e1fe3e4aSElliott Hughes synthLookup = None 207*e1fe3e4aSElliott Hughes for script in table.table.ScriptList.ScriptRecord: 208*e1fe3e4aSElliott Hughes if script.ScriptTag == "DFLT": 209*e1fe3e4aSElliott Hughes continue # XXX 210*e1fe3e4aSElliott Hughes for langsys in [script.Script.DefaultLangSys] + [ 211*e1fe3e4aSElliott Hughes l.LangSys for l in script.Script.LangSysRecord 212*e1fe3e4aSElliott Hughes ]: 213*e1fe3e4aSElliott Hughes if langsys is None: 214*e1fe3e4aSElliott Hughes continue # XXX Create! 215*e1fe3e4aSElliott Hughes feature = [v for v in langsys.FeatureIndex if v.FeatureTag == "locl"] 216*e1fe3e4aSElliott Hughes assert len(feature) <= 1 217*e1fe3e4aSElliott Hughes if feature: 218*e1fe3e4aSElliott Hughes feature = feature[0] 219*e1fe3e4aSElliott Hughes else: 220*e1fe3e4aSElliott Hughes if not synthFeature: 221*e1fe3e4aSElliott Hughes synthFeature = otTables.FeatureRecord() 222*e1fe3e4aSElliott Hughes synthFeature.FeatureTag = "locl" 223*e1fe3e4aSElliott Hughes f = synthFeature.Feature = otTables.Feature() 224*e1fe3e4aSElliott Hughes f.FeatureParams = None 225*e1fe3e4aSElliott Hughes f.LookupCount = 0 226*e1fe3e4aSElliott Hughes f.LookupListIndex = [] 227*e1fe3e4aSElliott Hughes table.table.FeatureList.FeatureRecord.append(synthFeature) 228*e1fe3e4aSElliott Hughes table.table.FeatureList.FeatureCount += 1 229*e1fe3e4aSElliott Hughes feature = synthFeature 230*e1fe3e4aSElliott Hughes langsys.FeatureIndex.append(feature) 231*e1fe3e4aSElliott Hughes langsys.FeatureIndex.sort(key=lambda v: v.FeatureTag) 232*e1fe3e4aSElliott Hughes 233*e1fe3e4aSElliott Hughes if not synthLookup: 234*e1fe3e4aSElliott Hughes subtable = otTables.SingleSubst() 235*e1fe3e4aSElliott Hughes subtable.mapping = dups 236*e1fe3e4aSElliott Hughes synthLookup = otTables.Lookup() 237*e1fe3e4aSElliott Hughes synthLookup.LookupFlag = 0 238*e1fe3e4aSElliott Hughes synthLookup.LookupType = 1 239*e1fe3e4aSElliott Hughes synthLookup.SubTableCount = 1 240*e1fe3e4aSElliott Hughes synthLookup.SubTable = [subtable] 241*e1fe3e4aSElliott Hughes if table.table.LookupList is None: 242*e1fe3e4aSElliott Hughes # mtiLib uses None as default value for LookupList, 243*e1fe3e4aSElliott Hughes # while feaLib points to an empty array with count 0 244*e1fe3e4aSElliott Hughes # TODO: make them do the same 245*e1fe3e4aSElliott Hughes table.table.LookupList = otTables.LookupList() 246*e1fe3e4aSElliott Hughes table.table.LookupList.Lookup = [] 247*e1fe3e4aSElliott Hughes table.table.LookupList.LookupCount = 0 248*e1fe3e4aSElliott Hughes table.table.LookupList.Lookup.append(synthLookup) 249*e1fe3e4aSElliott Hughes table.table.LookupList.LookupCount += 1 250*e1fe3e4aSElliott Hughes 251*e1fe3e4aSElliott Hughes if feature.Feature.LookupListIndex[:1] != [synthLookup]: 252*e1fe3e4aSElliott Hughes feature.Feature.LookupListIndex[:0] = [synthLookup] 253*e1fe3e4aSElliott Hughes feature.Feature.LookupCount += 1 254*e1fe3e4aSElliott Hughes 255*e1fe3e4aSElliott Hughes DefaultTable.merge(self, m, tables) 256*e1fe3e4aSElliott Hughes return self 257*e1fe3e4aSElliott Hughes 258*e1fe3e4aSElliott Hughes 259*e1fe3e4aSElliott Hughes@add_method( 260*e1fe3e4aSElliott Hughes otTables.SingleSubst, 261*e1fe3e4aSElliott Hughes otTables.MultipleSubst, 262*e1fe3e4aSElliott Hughes otTables.AlternateSubst, 263*e1fe3e4aSElliott Hughes otTables.LigatureSubst, 264*e1fe3e4aSElliott Hughes otTables.ReverseChainSingleSubst, 265*e1fe3e4aSElliott Hughes otTables.SinglePos, 266*e1fe3e4aSElliott Hughes otTables.PairPos, 267*e1fe3e4aSElliott Hughes otTables.CursivePos, 268*e1fe3e4aSElliott Hughes otTables.MarkBasePos, 269*e1fe3e4aSElliott Hughes otTables.MarkLigPos, 270*e1fe3e4aSElliott Hughes otTables.MarkMarkPos, 271*e1fe3e4aSElliott Hughes) 272*e1fe3e4aSElliott Hughesdef mapLookups(self, lookupMap): 273*e1fe3e4aSElliott Hughes pass 274*e1fe3e4aSElliott Hughes 275*e1fe3e4aSElliott Hughes 276*e1fe3e4aSElliott Hughes# Copied and trimmed down from subset.py 277*e1fe3e4aSElliott Hughes@add_method( 278*e1fe3e4aSElliott Hughes otTables.ContextSubst, 279*e1fe3e4aSElliott Hughes otTables.ChainContextSubst, 280*e1fe3e4aSElliott Hughes otTables.ContextPos, 281*e1fe3e4aSElliott Hughes otTables.ChainContextPos, 282*e1fe3e4aSElliott Hughes) 283*e1fe3e4aSElliott Hughesdef __merge_classify_context(self): 284*e1fe3e4aSElliott Hughes class ContextHelper(object): 285*e1fe3e4aSElliott Hughes def __init__(self, klass, Format): 286*e1fe3e4aSElliott Hughes if klass.__name__.endswith("Subst"): 287*e1fe3e4aSElliott Hughes Typ = "Sub" 288*e1fe3e4aSElliott Hughes Type = "Subst" 289*e1fe3e4aSElliott Hughes else: 290*e1fe3e4aSElliott Hughes Typ = "Pos" 291*e1fe3e4aSElliott Hughes Type = "Pos" 292*e1fe3e4aSElliott Hughes if klass.__name__.startswith("Chain"): 293*e1fe3e4aSElliott Hughes Chain = "Chain" 294*e1fe3e4aSElliott Hughes else: 295*e1fe3e4aSElliott Hughes Chain = "" 296*e1fe3e4aSElliott Hughes ChainTyp = Chain + Typ 297*e1fe3e4aSElliott Hughes 298*e1fe3e4aSElliott Hughes self.Typ = Typ 299*e1fe3e4aSElliott Hughes self.Type = Type 300*e1fe3e4aSElliott Hughes self.Chain = Chain 301*e1fe3e4aSElliott Hughes self.ChainTyp = ChainTyp 302*e1fe3e4aSElliott Hughes 303*e1fe3e4aSElliott Hughes self.LookupRecord = Type + "LookupRecord" 304*e1fe3e4aSElliott Hughes 305*e1fe3e4aSElliott Hughes if Format == 1: 306*e1fe3e4aSElliott Hughes self.Rule = ChainTyp + "Rule" 307*e1fe3e4aSElliott Hughes self.RuleSet = ChainTyp + "RuleSet" 308*e1fe3e4aSElliott Hughes elif Format == 2: 309*e1fe3e4aSElliott Hughes self.Rule = ChainTyp + "ClassRule" 310*e1fe3e4aSElliott Hughes self.RuleSet = ChainTyp + "ClassSet" 311*e1fe3e4aSElliott Hughes 312*e1fe3e4aSElliott Hughes if self.Format not in [1, 2, 3]: 313*e1fe3e4aSElliott Hughes return None # Don't shoot the messenger; let it go 314*e1fe3e4aSElliott Hughes if not hasattr(self.__class__, "_merge__ContextHelpers"): 315*e1fe3e4aSElliott Hughes self.__class__._merge__ContextHelpers = {} 316*e1fe3e4aSElliott Hughes if self.Format not in self.__class__._merge__ContextHelpers: 317*e1fe3e4aSElliott Hughes helper = ContextHelper(self.__class__, self.Format) 318*e1fe3e4aSElliott Hughes self.__class__._merge__ContextHelpers[self.Format] = helper 319*e1fe3e4aSElliott Hughes return self.__class__._merge__ContextHelpers[self.Format] 320*e1fe3e4aSElliott Hughes 321*e1fe3e4aSElliott Hughes 322*e1fe3e4aSElliott Hughes@add_method( 323*e1fe3e4aSElliott Hughes otTables.ContextSubst, 324*e1fe3e4aSElliott Hughes otTables.ChainContextSubst, 325*e1fe3e4aSElliott Hughes otTables.ContextPos, 326*e1fe3e4aSElliott Hughes otTables.ChainContextPos, 327*e1fe3e4aSElliott Hughes) 328*e1fe3e4aSElliott Hughesdef mapLookups(self, lookupMap): 329*e1fe3e4aSElliott Hughes c = self.__merge_classify_context() 330*e1fe3e4aSElliott Hughes 331*e1fe3e4aSElliott Hughes if self.Format in [1, 2]: 332*e1fe3e4aSElliott Hughes for rs in getattr(self, c.RuleSet): 333*e1fe3e4aSElliott Hughes if not rs: 334*e1fe3e4aSElliott Hughes continue 335*e1fe3e4aSElliott Hughes for r in getattr(rs, c.Rule): 336*e1fe3e4aSElliott Hughes if not r: 337*e1fe3e4aSElliott Hughes continue 338*e1fe3e4aSElliott Hughes for ll in getattr(r, c.LookupRecord): 339*e1fe3e4aSElliott Hughes if not ll: 340*e1fe3e4aSElliott Hughes continue 341*e1fe3e4aSElliott Hughes ll.LookupListIndex = lookupMap[ll.LookupListIndex] 342*e1fe3e4aSElliott Hughes elif self.Format == 3: 343*e1fe3e4aSElliott Hughes for ll in getattr(self, c.LookupRecord): 344*e1fe3e4aSElliott Hughes if not ll: 345*e1fe3e4aSElliott Hughes continue 346*e1fe3e4aSElliott Hughes ll.LookupListIndex = lookupMap[ll.LookupListIndex] 347*e1fe3e4aSElliott Hughes else: 348*e1fe3e4aSElliott Hughes assert 0, "unknown format: %s" % self.Format 349*e1fe3e4aSElliott Hughes 350*e1fe3e4aSElliott Hughes 351*e1fe3e4aSElliott Hughes@add_method(otTables.ExtensionSubst, otTables.ExtensionPos) 352*e1fe3e4aSElliott Hughesdef mapLookups(self, lookupMap): 353*e1fe3e4aSElliott Hughes if self.Format == 1: 354*e1fe3e4aSElliott Hughes self.ExtSubTable.mapLookups(lookupMap) 355*e1fe3e4aSElliott Hughes else: 356*e1fe3e4aSElliott Hughes assert 0, "unknown format: %s" % self.Format 357*e1fe3e4aSElliott Hughes 358*e1fe3e4aSElliott Hughes 359*e1fe3e4aSElliott Hughes@add_method(otTables.Lookup) 360*e1fe3e4aSElliott Hughesdef mapLookups(self, lookupMap): 361*e1fe3e4aSElliott Hughes for st in self.SubTable: 362*e1fe3e4aSElliott Hughes if not st: 363*e1fe3e4aSElliott Hughes continue 364*e1fe3e4aSElliott Hughes st.mapLookups(lookupMap) 365*e1fe3e4aSElliott Hughes 366*e1fe3e4aSElliott Hughes 367*e1fe3e4aSElliott Hughes@add_method(otTables.LookupList) 368*e1fe3e4aSElliott Hughesdef mapLookups(self, lookupMap): 369*e1fe3e4aSElliott Hughes for l in self.Lookup: 370*e1fe3e4aSElliott Hughes if not l: 371*e1fe3e4aSElliott Hughes continue 372*e1fe3e4aSElliott Hughes l.mapLookups(lookupMap) 373*e1fe3e4aSElliott Hughes 374*e1fe3e4aSElliott Hughes 375*e1fe3e4aSElliott Hughes@add_method(otTables.Lookup) 376*e1fe3e4aSElliott Hughesdef mapMarkFilteringSets(self, markFilteringSetMap): 377*e1fe3e4aSElliott Hughes if self.LookupFlag & 0x0010: 378*e1fe3e4aSElliott Hughes self.MarkFilteringSet = markFilteringSetMap[self.MarkFilteringSet] 379*e1fe3e4aSElliott Hughes 380*e1fe3e4aSElliott Hughes 381*e1fe3e4aSElliott Hughes@add_method(otTables.LookupList) 382*e1fe3e4aSElliott Hughesdef mapMarkFilteringSets(self, markFilteringSetMap): 383*e1fe3e4aSElliott Hughes for l in self.Lookup: 384*e1fe3e4aSElliott Hughes if not l: 385*e1fe3e4aSElliott Hughes continue 386*e1fe3e4aSElliott Hughes l.mapMarkFilteringSets(markFilteringSetMap) 387*e1fe3e4aSElliott Hughes 388*e1fe3e4aSElliott Hughes 389*e1fe3e4aSElliott Hughes@add_method(otTables.Feature) 390*e1fe3e4aSElliott Hughesdef mapLookups(self, lookupMap): 391*e1fe3e4aSElliott Hughes self.LookupListIndex = [lookupMap[i] for i in self.LookupListIndex] 392*e1fe3e4aSElliott Hughes 393*e1fe3e4aSElliott Hughes 394*e1fe3e4aSElliott Hughes@add_method(otTables.FeatureList) 395*e1fe3e4aSElliott Hughesdef mapLookups(self, lookupMap): 396*e1fe3e4aSElliott Hughes for f in self.FeatureRecord: 397*e1fe3e4aSElliott Hughes if not f or not f.Feature: 398*e1fe3e4aSElliott Hughes continue 399*e1fe3e4aSElliott Hughes f.Feature.mapLookups(lookupMap) 400*e1fe3e4aSElliott Hughes 401*e1fe3e4aSElliott Hughes 402*e1fe3e4aSElliott Hughes@add_method(otTables.DefaultLangSys, otTables.LangSys) 403*e1fe3e4aSElliott Hughesdef mapFeatures(self, featureMap): 404*e1fe3e4aSElliott Hughes self.FeatureIndex = [featureMap[i] for i in self.FeatureIndex] 405*e1fe3e4aSElliott Hughes if self.ReqFeatureIndex != 65535: 406*e1fe3e4aSElliott Hughes self.ReqFeatureIndex = featureMap[self.ReqFeatureIndex] 407*e1fe3e4aSElliott Hughes 408*e1fe3e4aSElliott Hughes 409*e1fe3e4aSElliott Hughes@add_method(otTables.Script) 410*e1fe3e4aSElliott Hughesdef mapFeatures(self, featureMap): 411*e1fe3e4aSElliott Hughes if self.DefaultLangSys: 412*e1fe3e4aSElliott Hughes self.DefaultLangSys.mapFeatures(featureMap) 413*e1fe3e4aSElliott Hughes for l in self.LangSysRecord: 414*e1fe3e4aSElliott Hughes if not l or not l.LangSys: 415*e1fe3e4aSElliott Hughes continue 416*e1fe3e4aSElliott Hughes l.LangSys.mapFeatures(featureMap) 417*e1fe3e4aSElliott Hughes 418*e1fe3e4aSElliott Hughes 419*e1fe3e4aSElliott Hughes@add_method(otTables.ScriptList) 420*e1fe3e4aSElliott Hughesdef mapFeatures(self, featureMap): 421*e1fe3e4aSElliott Hughes for s in self.ScriptRecord: 422*e1fe3e4aSElliott Hughes if not s or not s.Script: 423*e1fe3e4aSElliott Hughes continue 424*e1fe3e4aSElliott Hughes s.Script.mapFeatures(featureMap) 425*e1fe3e4aSElliott Hughes 426*e1fe3e4aSElliott Hughes 427*e1fe3e4aSElliott Hughesdef layoutPreMerge(font): 428*e1fe3e4aSElliott Hughes # Map indices to references 429*e1fe3e4aSElliott Hughes 430*e1fe3e4aSElliott Hughes GDEF = font.get("GDEF") 431*e1fe3e4aSElliott Hughes GSUB = font.get("GSUB") 432*e1fe3e4aSElliott Hughes GPOS = font.get("GPOS") 433*e1fe3e4aSElliott Hughes 434*e1fe3e4aSElliott Hughes for t in [GSUB, GPOS]: 435*e1fe3e4aSElliott Hughes if not t: 436*e1fe3e4aSElliott Hughes continue 437*e1fe3e4aSElliott Hughes 438*e1fe3e4aSElliott Hughes if t.table.LookupList: 439*e1fe3e4aSElliott Hughes lookupMap = {i: v for i, v in enumerate(t.table.LookupList.Lookup)} 440*e1fe3e4aSElliott Hughes t.table.LookupList.mapLookups(lookupMap) 441*e1fe3e4aSElliott Hughes t.table.FeatureList.mapLookups(lookupMap) 442*e1fe3e4aSElliott Hughes 443*e1fe3e4aSElliott Hughes if ( 444*e1fe3e4aSElliott Hughes GDEF 445*e1fe3e4aSElliott Hughes and GDEF.table.Version >= 0x00010002 446*e1fe3e4aSElliott Hughes and GDEF.table.MarkGlyphSetsDef 447*e1fe3e4aSElliott Hughes ): 448*e1fe3e4aSElliott Hughes markFilteringSetMap = { 449*e1fe3e4aSElliott Hughes i: v for i, v in enumerate(GDEF.table.MarkGlyphSetsDef.Coverage) 450*e1fe3e4aSElliott Hughes } 451*e1fe3e4aSElliott Hughes t.table.LookupList.mapMarkFilteringSets(markFilteringSetMap) 452*e1fe3e4aSElliott Hughes 453*e1fe3e4aSElliott Hughes if t.table.FeatureList and t.table.ScriptList: 454*e1fe3e4aSElliott Hughes featureMap = {i: v for i, v in enumerate(t.table.FeatureList.FeatureRecord)} 455*e1fe3e4aSElliott Hughes t.table.ScriptList.mapFeatures(featureMap) 456*e1fe3e4aSElliott Hughes 457*e1fe3e4aSElliott Hughes # TODO FeatureParams nameIDs 458*e1fe3e4aSElliott Hughes 459*e1fe3e4aSElliott Hughes 460*e1fe3e4aSElliott Hughesdef layoutPostMerge(font): 461*e1fe3e4aSElliott Hughes # Map references back to indices 462*e1fe3e4aSElliott Hughes 463*e1fe3e4aSElliott Hughes GDEF = font.get("GDEF") 464*e1fe3e4aSElliott Hughes GSUB = font.get("GSUB") 465*e1fe3e4aSElliott Hughes GPOS = font.get("GPOS") 466*e1fe3e4aSElliott Hughes 467*e1fe3e4aSElliott Hughes for t in [GSUB, GPOS]: 468*e1fe3e4aSElliott Hughes if not t: 469*e1fe3e4aSElliott Hughes continue 470*e1fe3e4aSElliott Hughes 471*e1fe3e4aSElliott Hughes if t.table.FeatureList and t.table.ScriptList: 472*e1fe3e4aSElliott Hughes # Collect unregistered (new) features. 473*e1fe3e4aSElliott Hughes featureMap = GregariousIdentityDict(t.table.FeatureList.FeatureRecord) 474*e1fe3e4aSElliott Hughes t.table.ScriptList.mapFeatures(featureMap) 475*e1fe3e4aSElliott Hughes 476*e1fe3e4aSElliott Hughes # Record used features. 477*e1fe3e4aSElliott Hughes featureMap = AttendanceRecordingIdentityDict( 478*e1fe3e4aSElliott Hughes t.table.FeatureList.FeatureRecord 479*e1fe3e4aSElliott Hughes ) 480*e1fe3e4aSElliott Hughes t.table.ScriptList.mapFeatures(featureMap) 481*e1fe3e4aSElliott Hughes usedIndices = featureMap.s 482*e1fe3e4aSElliott Hughes 483*e1fe3e4aSElliott Hughes # Remove unused features 484*e1fe3e4aSElliott Hughes t.table.FeatureList.FeatureRecord = [ 485*e1fe3e4aSElliott Hughes f 486*e1fe3e4aSElliott Hughes for i, f in enumerate(t.table.FeatureList.FeatureRecord) 487*e1fe3e4aSElliott Hughes if i in usedIndices 488*e1fe3e4aSElliott Hughes ] 489*e1fe3e4aSElliott Hughes 490*e1fe3e4aSElliott Hughes # Map back to indices. 491*e1fe3e4aSElliott Hughes featureMap = NonhashableDict(t.table.FeatureList.FeatureRecord) 492*e1fe3e4aSElliott Hughes t.table.ScriptList.mapFeatures(featureMap) 493*e1fe3e4aSElliott Hughes 494*e1fe3e4aSElliott Hughes t.table.FeatureList.FeatureCount = len(t.table.FeatureList.FeatureRecord) 495*e1fe3e4aSElliott Hughes 496*e1fe3e4aSElliott Hughes if t.table.LookupList: 497*e1fe3e4aSElliott Hughes # Collect unregistered (new) lookups. 498*e1fe3e4aSElliott Hughes lookupMap = GregariousIdentityDict(t.table.LookupList.Lookup) 499*e1fe3e4aSElliott Hughes t.table.FeatureList.mapLookups(lookupMap) 500*e1fe3e4aSElliott Hughes t.table.LookupList.mapLookups(lookupMap) 501*e1fe3e4aSElliott Hughes 502*e1fe3e4aSElliott Hughes # Record used lookups. 503*e1fe3e4aSElliott Hughes lookupMap = AttendanceRecordingIdentityDict(t.table.LookupList.Lookup) 504*e1fe3e4aSElliott Hughes t.table.FeatureList.mapLookups(lookupMap) 505*e1fe3e4aSElliott Hughes t.table.LookupList.mapLookups(lookupMap) 506*e1fe3e4aSElliott Hughes usedIndices = lookupMap.s 507*e1fe3e4aSElliott Hughes 508*e1fe3e4aSElliott Hughes # Remove unused lookups 509*e1fe3e4aSElliott Hughes t.table.LookupList.Lookup = [ 510*e1fe3e4aSElliott Hughes l for i, l in enumerate(t.table.LookupList.Lookup) if i in usedIndices 511*e1fe3e4aSElliott Hughes ] 512*e1fe3e4aSElliott Hughes 513*e1fe3e4aSElliott Hughes # Map back to indices. 514*e1fe3e4aSElliott Hughes lookupMap = NonhashableDict(t.table.LookupList.Lookup) 515*e1fe3e4aSElliott Hughes t.table.FeatureList.mapLookups(lookupMap) 516*e1fe3e4aSElliott Hughes t.table.LookupList.mapLookups(lookupMap) 517*e1fe3e4aSElliott Hughes 518*e1fe3e4aSElliott Hughes t.table.LookupList.LookupCount = len(t.table.LookupList.Lookup) 519*e1fe3e4aSElliott Hughes 520*e1fe3e4aSElliott Hughes if GDEF and GDEF.table.Version >= 0x00010002: 521*e1fe3e4aSElliott Hughes markFilteringSetMap = NonhashableDict( 522*e1fe3e4aSElliott Hughes GDEF.table.MarkGlyphSetsDef.Coverage 523*e1fe3e4aSElliott Hughes ) 524*e1fe3e4aSElliott Hughes t.table.LookupList.mapMarkFilteringSets(markFilteringSetMap) 525*e1fe3e4aSElliott Hughes 526*e1fe3e4aSElliott Hughes # TODO FeatureParams nameIDs 527